]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
Merge branch 'v2012.10-rc1' into master
authorMichal Simek <monstr@monstr.eu>
Mon, 24 Sep 2012 06:54:02 +0000 (08:54 +0200)
committerMichal Simek <monstr@monstr.eu>
Mon, 24 Sep 2012 09:47:47 +0000 (11:47 +0200)
19 files changed:
1  2 
Makefile
arch/arm/cpu/armv7/start.S
boards.cfg
config.mk
drivers/mmc/Makefile
drivers/mtd/cfi_flash.c
drivers/mtd/nand/Makefile
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/zynq_nand.c
drivers/mtd/spi/spansion.c
drivers/mtd/spi/spi_flash.c
drivers/mtd/spi/stmicro.c
drivers/mtd/spi/winbond.c
drivers/net/Makefile
drivers/rtc/Makefile
drivers/spi/Makefile
drivers/spi/zynq_qspi.c
fs/ubifs/super.c
include/linux/mtd/nand.h

diff --cc Makefile
index eb37ea19fadfbe668d61888901f790b2f0dc4790,e3a27c624939d10c584781582e83749378cfa594..e3a27c624939d10c584781582e83749378cfa594
mode 100755,100644..100755
+++ b/Makefile
Simple merge
diff --cc boards.cfg
Simple merge
diff --cc config.mk
Simple merge
Simple merge
Simple merge
index 4d2caccdf73b93978ff6eb682c9d3e5ce23b38e6,beb99cacb6636291e4c91a65f79710214e31cb35..6e932024db84e6db4b7a136f299acb73233edae1
@@@ -62,9 -62,9 +62,10 @@@ COBJS-$(CONFIG_NAND_NOMADIK) += nomadik
  COBJS-$(CONFIG_NAND_S3C2410) += s3c2410_nand.o
  COBJS-$(CONFIG_NAND_S3C64XX) += s3c64xx.o
  COBJS-$(CONFIG_NAND_SPEAR) += spr_nand.o
+ COBJS-$(CONFIG_TEGRA_NAND) += tegra_nand.o
  COBJS-$(CONFIG_NAND_OMAP_GPMC) += omap_gpmc.o
  COBJS-$(CONFIG_NAND_PLAT) += nand_plat.o
 +COBJS-$(CONFIG_NAND_ZYNQ) += zynq_nand.o
  endif
  
  COBJS := $(COBJS-y)
Simple merge
index c78f140933a5167b662149571b774eabc41a9eb5,0000000000000000000000000000000000000000..bd801673749cfc30cddf9f704ce67b1527020bb4
mode 100644,000000..100644
--- /dev/null
@@@ -1,1203 -1,0 +1,1203 @@@
- #include <linux/mtd/compat.h>
 +/*
 + * Xilinx PSS NAND Flash Controller Driver
 + *
 + * Copyright (C) 2009 Xilinx, Inc.
 + *
 + * This program is free software; you can redistribute it and/or modify it under
 + * the terms of the GNU General Public License version 2 as published by the
 + * Free Software Foundation; either version 2 of the License, or (at your
 + * option) any later version.
 + *
 + * You should have received a copy of the GNU General Public License along with
 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 + * Place, Suite 330, Boston, MA  02111-1307  USA
 + */
 +
 +/*
 + * This driver is based on plat_nand.c and mxc_nand.c drivers
 + */
 +#include "xbasic_types.h"
 +#include <common.h>
 +#include <malloc.h>
 +
 +#include <asm/arch/nand.h>
 +#include <asm/io.h>
++//#include <linux/mtd/compat.h>
 +#include <linux/mtd/mtd.h>
 +#include <linux/mtd/nand.h>
 +#include <linux/mtd/partitions.h>
 +#include <linux/mtd/nand_ecc.h>
 +#include "zynq_nand.h"
 +
 +/********** stubs - Make Linux code compile in this environment **************/
 +#define EIO              5
 +#define ENXIO            6
 +#define ENOMEM          12
 +
 +#define __devinitdata
 +#define __force
 +
 +/*
 + * The NAND flash driver defines
 + */
 +
 +#define XNANDPSS_CMD_PHASE    1       /* End command valid in command phase */
 +#define XNANDPSS_DATA_PHASE   2       /* End command valid in data phase */
 +#define XNANDPSS_ECC_SIZE     512     /* Size of data for ECC operation */
 +
 +/*
 + * Register values for using NAND interface of NAND controller
 + * The SET_CYCLES_REG register value depends on the flash device. Look in to the
 + * device datasheet and change its value, This value is for 2Gb Numonyx flash.
 + */
 +
 +/* Flash memory controller operating parameters */
 +#define XNANDPSS_CLR_CONFIG   ((0x1 << 1)  |  /* Disable interrupt */ \
 +                              (0x1 << 4)   |  /* Clear interrupt */ \
 +                              (0x1 << 6))     /* Disable ECC interrupt */
 +
 +/* Assuming 50MHz clock (20ns cycle time) and 3V operation */
 +#define XNANDPSS_SET_CYCLES   ((0x2 << 20) |  /* t_rr from nand_cycles */ \
 +                              (0x2 << 17)  |  /* t_ar from nand_cycles */ \
 +                              (0x1 << 14)  |  /* t_clr from nand_cycles */ \
 +                              (0x3 << 11)  |  /* t_wp from nand_cycles */ \
 +                              (0x2 << 8)   |  /* t_rea from nand_cycles */ \
 +                              (0x5 << 4)   |  /* t_wc from nand_cycles */ \
 +                              (0x5 << 0))     /* t_rc from nand_cycles */
 +
 +#define XNANDPSS_SET_OPMODE   0x0
 +
 +#define XNANDPSS_DIRECT_CMD   ((0x4 << 23) |  /* Chip 0 from interface 1 */ \
 +                              (0x2 << 21))    /* UpdateRegs operation */
 +
 +#define XNANDPSS_ECC_CONFIG   ((0x1 << 2)  |  /* ECC available on APB */ \
 +                              (0x1 << 4)   |  /* ECC read at end of page */ \
 +                              (0x0 << 5))     /* No Jumping */
 +
 +#define XNANDPSS_ECC_CMD1     ((0x80)      |  /* Write command */ \
 +                              (0x00 << 8)  |  /* Read command */ \
 +                              (0x30 << 16) |  /* Read End command */ \
 +                              (0x1 << 24))    /* Read End command calid */
 +
 +#define XNANDPSS_ECC_CMD2     ((0x85)      |  /* Write col change cmd */ \
 +                              (0x05 << 8)  |  /* Read col change cmd */ \
 +                              (0xE0 << 16) |  /* Read col change end cmd */ \
 +                              (0x1 << 24))    /* Read col change
 +                                                      end cmd valid */
 +/*
 + * AXI Address definitions
 + */
 +#define START_CMD_SHIFT               3
 +#define END_CMD_SHIFT         11
 +#define END_CMD_VALID_SHIFT   20
 +#define ADDR_CYCLES_SHIFT     21
 +#define CLEAR_CS_SHIFT                21
 +#define ECC_LAST_SHIFT                10
 +#define COMMAND_PHASE         (0 << 19)
 +#define DATA_PHASE            (1 << 19)
 +
 +#define XNANDPSS_ECC_LAST     (1 << ECC_LAST_SHIFT)   /* Set ECC_Last */
 +#define XNANDPSS_CLEAR_CS     (1 << CLEAR_CS_SHIFT)   /* Clear chip select */
 +
 +/*
 + * ECC block registers bit position and bit mask
 + */
 +#define XNANDPSS_ECC_BUSY     (1 << 6)        /* ECC block is busy */
 +#define XNANDPSS_ECC_MASK     0x00FFFFFF      /* ECC value mask */
 +
 +/*
 + * Macros for the NAND controller register read/write
 + */
 +extern void XIo_Out32(u32 OutAddress, u32 Value);
 +extern u32  XIo_In32(u32 InAddress);
 +
 +#define xnandps_read32(addr)       XIo_In32((u32)(addr))
 +#define xnandps_write32(addr, val)    XIo_Out32((u32)(addr), (val))
 +
 +
 +/**
 + * struct xnandps_command_format - Defines NAND flash command format
 + * @start_cmd:                First cycle command (Start command)
 + * @end_cmd:          Second cycle command (Last command)
 + * @addr_cycles:      Number of address cycles required to send the address
 + * @end_cmd_valid:    The second cycle command is valid for cmd or data phase
 + **/
 +struct xnandps_command_format {
 +      int start_cmd;
 +      int end_cmd;
 +      u8 addr_cycles;
 +      u8 end_cmd_valid;
 +};
 +
 +/**
 + * struct xnandps_info - Defines the NAND flash driver instance
 + * @parts:            Pointer to the mtd_partition structure
 + * @nand_base:                Virtual address of the NAND flash device
 + * @smc_regs:         Virtual address of the NAND controller registers
 + * @end_cmd_pending:  End command is pending
 + * @end_cmd:          End command
 + **/
 +struct xnandps_info {
 +#ifdef CONFIG_MTD_PARTITIONS
 +      struct mtd_partition    *parts;
 +#endif
 +      void __iomem            *nand_base;
 +      void __iomem            *smc_regs;
 +      unsigned long           end_cmd_pending;
 +      unsigned long           end_cmd;
 +};
 +
 +#define NAND_CMD_GET_FEATURES 0xEE
 +#define NAND_CMD_SET_FEATURES 0xEF
 +
 +#define ONDIE_ECC_FEATURE_ADDR        0x90
 +
 +/*
 + * The NAND flash operations command format
 + */
 +static struct xnandps_command_format xnandps_commands[] __devinitdata = {
 +      {NAND_CMD_READ0, NAND_CMD_READSTART, 5, XNANDPSS_CMD_PHASE},
 +      {NAND_CMD_RNDOUT, NAND_CMD_RNDOUTSTART, 2, XNANDPSS_CMD_PHASE},
 +      {NAND_CMD_READID, NAND_CMD_NONE, 1, NAND_CMD_NONE},
 +      {NAND_CMD_STATUS, NAND_CMD_NONE, 0, NAND_CMD_NONE},
 +      {NAND_CMD_SEQIN, NAND_CMD_PAGEPROG, 5, XNANDPSS_DATA_PHASE},
 +      {NAND_CMD_RNDIN, NAND_CMD_NONE, 2, NAND_CMD_NONE},
 +      {NAND_CMD_ERASE1, NAND_CMD_ERASE2, 3, XNANDPSS_CMD_PHASE},
 +      {NAND_CMD_RESET, NAND_CMD_NONE, 0, NAND_CMD_NONE},
 +      {NAND_CMD_PARAM, NAND_CMD_NONE, 1, NAND_CMD_NONE},
 +      {NAND_CMD_GET_FEATURES, NAND_CMD_NONE, 1, NAND_CMD_NONE},
 +      {NAND_CMD_SET_FEATURES, NAND_CMD_NONE, 1, NAND_CMD_NONE},
 +      {NAND_CMD_NONE, NAND_CMD_NONE, 0, 0},
 +      /* Add all the flash commands supported by the flash device and Linux */
 +      /* The cache program command is not supported by driver because driver
 +       * cant differentiate between page program and cached page program from
 +       * start command, these commands can be differentiated through end
 +       * command, which doesn't fit in to the driver design. The cache program
 +       * command is not supported by NAND subsystem also, look at 1612 line
 +       * number (in nand_write_page function) of nand_base.c file.
 +       * {NAND_CMD_SEQIN, NAND_CMD_CACHEDPROG, 5, XNANDPSS_YES}, */
 +};
 +
 +/* Define default oob placement schemes for large and small page devices */
 +static struct nand_ecclayout nand_oob_16 = {
 +      .eccbytes = 3,
 +      .eccpos = {13, 14, 15},
 +      .oobfree = {
 +              {.offset = 0,
 +               . length = 12} }
 +};
 +
 +static struct nand_ecclayout nand_oob_64 = {
 +      .eccbytes = 12,
 +      .eccpos = {
 +                 52, 53, 54, 55, 56, 57,
 +                 58, 59, 60, 61, 62, 63},
 +      .oobfree = {
 +              {.offset = 2,
 +               .length = 50} }
 +};
 +
 +static struct nand_ecclayout ondie_nand_oob_64 = {
 +      .eccbytes = 32,
 +
 +      .eccpos = {
 +              8, 9, 10, 11, 12, 13, 14, 15,
 +              24, 25, 26, 27, 28, 29, 30, 31,
 +              40, 41, 42, 43, 44, 45, 46, 47,
 +              56, 57, 58, 59, 60, 61, 62, 63
 +      },
 +
 +      .oobfree = {
 +              { .offset = 4, .length = 4 },
 +              { .offset = 20, .length = 4 },
 +              { .offset = 36, .length = 4 },
 +              { .offset = 52, .length = 4 }
 +      }
 +};
 +
 +/* Generic flash bbt decriptors
 +*/
 +static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
 +static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };
 +
 +static struct nand_bbt_descr bbt_main_descr = {
 +        .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
 +                | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
 +        .offs = 4,
 +        .len = 4,
 +        .veroffs = 20,
 +        .maxblocks = 4,
 +        .pattern = bbt_pattern
 +};
 +
 +static struct nand_bbt_descr bbt_mirror_descr = {
 +        .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
 +                | NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP,
 +        .offs = 4,
 +        .len = 4,
 +        .veroffs = 20,
 +        .maxblocks = 4,
 +        .pattern = mirror_pattern
 +};
 +
 +/**
 + * xnandps_init_nand_flash - Initialize NAND controller
 + * @smc_regs: Virtual address of the NAND controller registers
 + * @option:   Device property flags
 + *
 + * This function initializes the NAND flash interface on the NAND controller.
 + **/
 +static void xnandps_init_nand_flash(void __iomem *smc_regs, int option)
 +{
 +      /* disable interrupts */
 +      xnandps_write32(smc_regs + XSMCPSS_MC_CLR_CONFIG, XNANDPSS_CLR_CONFIG);
 +      /* Initialize the NAND interface by setting cycles and operation mode */
 +      xnandps_write32(smc_regs + XSMCPSS_MC_SET_CYCLES, XNANDPSS_SET_CYCLES);
 +      if (option & NAND_BUSWIDTH_16)
 +              xnandps_write32(smc_regs + XSMCPSS_MC_SET_OPMODE,
 +                              (XNANDPSS_SET_OPMODE | 0x1));
 +      else
 +              xnandps_write32(smc_regs + XSMCPSS_MC_SET_OPMODE,
 +                              XNANDPSS_SET_OPMODE);
 +      xnandps_write32(smc_regs + XSMCPSS_MC_DIRECT_CMD, XNANDPSS_DIRECT_CMD);
 +
 +      /* Wait till the ECC operation is complete */
 +      while ( (xnandps_read32(smc_regs + XSMCPSS_ECC_STATUS_OFFSET(
 +                      XSMCPSS_ECC_IF1_OFFSET))) & XNANDPSS_ECC_BUSY)
 +                      ;
 +      /* Set the command1 and command2 register */
 +      xnandps_write32(smc_regs +
 +              (XSMCPSS_ECC_MEMCMD1_OFFSET(XSMCPSS_ECC_IF1_OFFSET)),
 +              XNANDPSS_ECC_CMD1);
 +      xnandps_write32(smc_regs +
 +              (XSMCPSS_ECC_MEMCMD2_OFFSET(XSMCPSS_ECC_IF1_OFFSET)),
 +              XNANDPSS_ECC_CMD2);
 +}
 +
 +/**
 + * xnandps_calculate_hwecc - Calculate Hardware ECC
 + * @mtd:      Pointer to the mtd_info structure
 + * @data:     Pointer to the page data
 + * @ecc_code: Pointer to the ECC buffer where ECC data needs to be stored
 + *
 + * This function retrieves the Hardware ECC data from the controller and returns
 + * ECC data back to the MTD subsystem.
 + *
 + * returns:   0 on success or error value on failure
 + **/
 +static int
 +xnandps_calculate_hwecc(struct mtd_info *mtd, const u8 *data, u8 *ecc_code)
 +{
 +      struct xnandps_info *xnand;
 +      struct nand_chip *chip;
 +      u32 ecc_value = 0;
 +      u8 ecc_reg, ecc_byte;
 +      u32 ecc_status;
 +      
 +      chip = (struct nand_chip *)mtd->priv;
 +      xnand = (struct xnandps_info *)chip->priv;
 +
 +      /* Wait till the ECC operation is complete */
 +      do {
 +              ecc_status = xnandps_read32(xnand->smc_regs +
 +                      XSMCPSS_ECC_STATUS_OFFSET(XSMCPSS_ECC_IF1_OFFSET));
 +      } while (ecc_status & XNANDPSS_ECC_BUSY);
 +
 +      for (ecc_reg = 0; ecc_reg < 4; ecc_reg++) {
 +              /* Read ECC value for each block */
 +              ecc_value = (xnandps_read32(xnand->smc_regs +
 +                      (XSMCPSS_ECC_VALUE0_OFFSET(XSMCPSS_ECC_IF1_OFFSET) +
 +                      (ecc_reg*4))));
 +              ecc_status = (ecc_value >> 24) & 0xFF;
 +              /* ECC value valid */
 +              if (ecc_status & 0x40) {
 +                      for (ecc_byte = 0; ecc_byte < 3; ecc_byte++) {
 +                              /* Copy ECC bytes to MTD buffer */
 +                              *ecc_code = ecc_value & 0xFF;
 +                              ecc_value = ecc_value >> 8;
 +                              ecc_code++;
 +                      }
 +              } else {
 +                      printk(KERN_INFO "pl350: ecc status failed\n");
 +              }
 +      }
 +      return 0;
 +}
 +
 +/**
 + * onehot - onehot function
 + * @value:    value to check for onehot
 + *
 + * This function checks whether a value is onehot or not.
 + * onehot is if and only if onebit is set.
 + *
 + **/
 +int onehot(unsigned short value)
 +{
 +      return ((value & (value-1)) == 0);
 +}
 +
 +/**
 + * xnandps_correct_data - ECC correction function
 + * @mtd:      Pointer to the mtd_info structure
 + * @buf:      Pointer to the page data
 + * @read_ecc: Pointer to the ECC value read from spare data area
 + * @calc_ecc: Pointer to the calculated ECC value
 + *
 + * This function corrects the ECC single bit errors & detects 2-bit errors.
 + *
 + * returns:   0 if no ECC errors found
 + *            1 if single bit error found and corrected.
 + *            -1 if multiple ECC errors found.
 + **/
 +int xnandps_correct_data(struct mtd_info *mtd, unsigned char *buf,
 +                      unsigned char *read_ecc, unsigned char *calc_ecc)
 +{
 +      unsigned char bit_addr;
 +      unsigned int byte_addr;
 +      unsigned short ecc_odd, ecc_even;
 +      unsigned short read_ecc_lower, read_ecc_upper;
 +      unsigned short calc_ecc_lower, calc_ecc_upper;
 +
 +      read_ecc_lower = (read_ecc[0] | (read_ecc[1] << 8)) & 0xfff;
 +      read_ecc_upper = ((read_ecc[1] >> 4) | (read_ecc[2] << 4)) & 0xfff;
 +
 +      calc_ecc_lower = (calc_ecc[0] | (calc_ecc[1] << 8)) & 0xfff;
 +      calc_ecc_upper = ((calc_ecc[1] >> 4) | (calc_ecc[2] << 4)) & 0xfff;
 +
 +      ecc_odd = read_ecc_lower ^ calc_ecc_lower;
 +      ecc_even = read_ecc_upper ^ calc_ecc_upper;
 +
 +      if ((ecc_odd == 0) && (ecc_even == 0))
 +              return 0;       /* no error */
 +      else if (ecc_odd == (~ecc_even & 0xfff)) {
 +              /* bits [11:3] of error code is byte offset */
 +              byte_addr = (ecc_odd >> 3) & 0x1ff;
 +              /* bits [2:0] of error code is bit offset */
 +              bit_addr = ecc_odd & 0x7;
 +              /* Toggling error bit */
 +              buf[byte_addr] ^= (1 << bit_addr);
 +              return 1;
 +      } else if (onehot(ecc_odd | ecc_even) == 1) {
 +              return 1; /* one error in parity */
 +      } else {
 +              return -1; /* Uncorrectable error */
 +      }
 +}
 +
 +/**
 + * xnandps_read_oob - [REPLACABLE] the most common OOB data read function
 + * @mtd:      mtd info structure
 + * @chip:     nand chip info structure
 + * @page:     page number to read
 + * @sndcmd:   flag whether to issue read command or not
 + */
 +static int xnandps_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
 +                      int page, int sndcmd)
 +{
 +      unsigned long data_width = 4;
 +      unsigned long data_phase_addr = 0;
 +      uint8_t *p;
 +
 +      if (sndcmd) {
 +              chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
 +              sndcmd = 0;
 +      }
 +
 +      p = chip->oob_poi;
 +      chip->read_buf(mtd, p, (mtd->oobsize - data_width));
 +      p += (mtd->oobsize - data_width);
 +
 +      data_phase_addr = (unsigned long __force)chip->IO_ADDR_R;
 +      data_phase_addr |= XNANDPSS_CLEAR_CS;
 +      chip->IO_ADDR_R = (void __iomem *__force)data_phase_addr;
 +      chip->read_buf(mtd, p, data_width);
 +
 +      return sndcmd;
 +}
 +
 +/**
 + * xnandps_write_oob - [REPLACABLE] the most common OOB data write function
 + * @mtd:      mtd info structure
 + * @chip:     nand chip info structure
 + * @page:     page number to write
 + */
 +static int xnandps_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
 +                      int page)
 +{
 +      int status = 0;
 +      const uint8_t *buf = chip->oob_poi;
 +      unsigned long data_width = 4;
 +      unsigned long data_phase_addr = 0;
 +
 +      chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page);
 +
 +      chip->write_buf(mtd, buf, (mtd->oobsize - data_width));
 +      buf += (mtd->oobsize - data_width);
 +
 +      data_phase_addr = (unsigned long __force)chip->IO_ADDR_W;
 +      data_phase_addr |= XNANDPSS_CLEAR_CS;
 +      data_phase_addr |= (1 << END_CMD_VALID_SHIFT);
 +      chip->IO_ADDR_W = (void __iomem *__force)data_phase_addr;
 +      chip->write_buf(mtd, buf, data_width);
 +
 +      /* Send command to program the OOB data */
 +      chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
 +      status = chip->waitfunc(mtd, chip);
 +
 +      return status & NAND_STATUS_FAIL ? -EIO : 0;
 +}
 +
 +/**
 + * xnandps_read_page_raw - [Intern] read raw page data without ecc
 + * @mtd:        mtd info structure
 + * @chip:       nand chip info structure
 + * @buf:        buffer to store read data
 + * @page:       page number to read
 + *
 + */
 +static int xnandps_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
 +                            uint8_t *buf, int page)
 +{
 +      unsigned long data_width = 4;
 +      unsigned long data_phase_addr = 0;
 +      uint8_t *p;
 +
 +      chip->read_buf(mtd, buf, mtd->writesize);
 +
 +      p = chip->oob_poi;
 +      chip->read_buf(mtd, p, (mtd->oobsize - data_width));
 +      p += (mtd->oobsize - data_width);
 +
 +      data_phase_addr = (unsigned long __force)chip->IO_ADDR_R;
 +      data_phase_addr |= XNANDPSS_CLEAR_CS;
 +      chip->IO_ADDR_R = (void __iomem *__force)data_phase_addr;
 +
 +      chip->read_buf(mtd, p, data_width);
 +      return 0;
 +}
 +
 +static int xnandps_read_page_raw_nooob(struct mtd_info *mtd, struct nand_chip *chip,
 +                                      uint8_t *buf, int page)
 +{
 +      chip->read_buf(mtd, buf, mtd->writesize);
 +      return 0;
 +}
 +
 +static int xnandps_read_subpage_raw(struct mtd_info *mtd, struct nand_chip *chip,
 +                                      uint32_t data_offs, uint32_t readlen, uint8_t *buf)
 +{
 +      if (data_offs != 0) {
 +              chip->cmdfunc(mtd, NAND_CMD_RNDOUT, data_offs, -1);
 +              buf += data_offs;
 +      }
 +
 +      chip->read_buf(mtd, buf, readlen);
 +      return 0;
 +}
 +
 +/**
 + * xnandps_write_page_raw - [Intern] raw page write function
 + * @mtd:        mtd info structure
 + * @chip:       nand chip info structure
 + * @buf:        data buffer
 + *
 + */
 +static void xnandps_write_page_raw(struct mtd_info *mtd,
 +                      struct nand_chip *chip, const uint8_t *buf)
 +{
 +      unsigned long data_width = 4;
 +      unsigned long data_phase_addr = 0;
 +      uint8_t *p;
 +
 +      chip->write_buf(mtd, buf, mtd->writesize);
 +
 +      p = chip->oob_poi;
 +      chip->write_buf(mtd, p, (mtd->oobsize - data_width));
 +      p += (mtd->oobsize - data_width);
 +
 +      data_phase_addr = (unsigned long __force)chip->IO_ADDR_W;
 +      data_phase_addr |= XNANDPSS_CLEAR_CS;
 +      data_phase_addr |= (1 << END_CMD_VALID_SHIFT);
 +      chip->IO_ADDR_W = (void __iomem *__force)data_phase_addr;
 +
 +      chip->write_buf(mtd, p, data_width);
 +}
 +
 +/**
 + * nand_write_page_hwecc - Hardware ECC based page write function
 + * @mtd:      Pointer to the mtd info structure
 + * @chip:     Pointer to the NAND chip info structure
 + * @buf:      Pointer to the data buffer
 + *
 + * This functions writes data and hardware generated ECC values in to the page.
 + */
 +void xnandps_write_page_hwecc(struct mtd_info *mtd,
 +                              struct nand_chip *chip, const uint8_t *buf)
 +{
 +      int i, eccsize = chip->ecc.size;
 +      int eccsteps = chip->ecc.steps;
 +      uint8_t *ecc_calc = chip->buffers->ecccalc;
 +      const uint8_t *p = buf;
 +      uint32_t *eccpos = chip->ecc.layout->eccpos;
 +      unsigned long data_phase_addr = 0;
 +      unsigned long data_width = 4;
 +      uint8_t *oob_ptr;
 +
 +      for ( ; (eccsteps - 1); eccsteps--) {
 +              chip->write_buf(mtd, p, eccsize);
 +              p += eccsize;
 +      }
 +      chip->write_buf(mtd, p, (eccsize - data_width));
 +      p += (eccsize - data_width);
 +
 +      /* Set ECC Last bit to 1 */
 +      data_phase_addr = (unsigned long __force)chip->IO_ADDR_W;
 +      data_phase_addr |= XNANDPSS_ECC_LAST;
 +      chip->IO_ADDR_W = (void __iomem *__force)data_phase_addr;
 +      chip->write_buf(mtd, p, data_width);
 +
 +      /* Wait for ECC to be calculated and read the error values */
 +      p = buf;
 +      chip->ecc.calculate(mtd, p, &ecc_calc[0]);
 +
 +      for (i = 0; i < chip->ecc.total; i++)
 +              chip->oob_poi[eccpos[i]] = ~(ecc_calc[i]);
 +
 +      /* Clear ECC last bit */
 +      data_phase_addr = (unsigned long __force)chip->IO_ADDR_W;
 +      data_phase_addr &= ~XNANDPSS_ECC_LAST;
 +      chip->IO_ADDR_W = (void __iomem *__force)data_phase_addr;
 +
 +      /* Write the spare area with ECC bytes */
 +      oob_ptr = chip->oob_poi;
 +      chip->write_buf(mtd, oob_ptr, (mtd->oobsize - data_width));
 +
 +      data_phase_addr = (unsigned long __force)chip->IO_ADDR_W;
 +      data_phase_addr |= XNANDPSS_CLEAR_CS;
 +      data_phase_addr |= (1 << END_CMD_VALID_SHIFT);
 +      chip->IO_ADDR_W = (void __iomem *__force)data_phase_addr;
 +      oob_ptr += (mtd->oobsize - data_width);
 +      chip->write_buf(mtd, oob_ptr, data_width);
 +}
 +
 +/**
 + * xnandps_write_page_swecc - [REPLACABLE] software ecc based page write function
 + * @mtd:      mtd info structure
 + * @chip:     nand chip info structure
 + * @buf:      data buffer
 + */
 +static void xnandps_write_page_swecc(struct mtd_info *mtd,
 +                                              struct nand_chip *chip, const uint8_t *buf)
 +{
 +      int i, eccsize = chip->ecc.size;
 +      int eccbytes = chip->ecc.bytes;
 +      int eccsteps = chip->ecc.steps;
 +      uint8_t *ecc_calc = chip->buffers->ecccalc;
 +      const uint8_t *p = buf;
 +      uint32_t *eccpos = chip->ecc.layout->eccpos;
 +
 +      /* Software ecc calculation */
 +      for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
 +              chip->ecc.calculate(mtd, p, &ecc_calc[i]);
 +
 +      for (i = 0; i < chip->ecc.total; i++)
 +              chip->oob_poi[eccpos[i]] = ecc_calc[i];
 +
 +      chip->ecc.write_page_raw(mtd, chip, buf);
 +}
 +
 +/**
 + * nand_read_page_hwecc - Hardware ECC based page read function
 + * @mtd:      Pointer to the mtd info structure
 + * @chip:     Pointer to the NAND chip info structure
 + * @buf:      Pointer to the buffer to store read data
 + * @page:     page number to read
 + *
 + * This functions reads data and checks the data integrity by comparing hardware
 + * generated ECC values and read ECC values from spare area.
 + *
 + * returns:   0 always and updates ECC operation status in to MTD structure
 + */
 +int xnandps_read_page_hwecc(struct mtd_info *mtd,
 +                              struct nand_chip *chip, uint8_t *buf, int page)
 +{
 +      int i, stat, eccsize = chip->ecc.size;
 +      int eccbytes = chip->ecc.bytes;
 +      int eccsteps = chip->ecc.steps;
 +      uint8_t *p = buf;
 +      uint8_t *ecc_calc = chip->buffers->ecccalc;
 +      uint8_t *ecc_code = chip->buffers->ecccode;
 +      uint32_t *eccpos = chip->ecc.layout->eccpos;
 +      unsigned long data_phase_addr = 0;
 +      unsigned long data_width = 4;
 +      uint8_t *oob_ptr;
 +
 +      for ( ; (eccsteps - 1); eccsteps--) {
 +              chip->read_buf(mtd, p, eccsize);
 +              p += eccsize;
 +      }
 +      chip->read_buf(mtd, p, (eccsize - data_width));
 +      p += (eccsize - data_width);
 +
 +      /* Set ECC Last bit to 1 */
 +      data_phase_addr = (unsigned long __force)chip->IO_ADDR_R;
 +      data_phase_addr |= XNANDPSS_ECC_LAST;
 +      chip->IO_ADDR_R = (void __iomem *__force)data_phase_addr;
 +      chip->read_buf(mtd, p, data_width);
 +
 +      /* Read the calculated ECC value */
 +      p = buf;
 +      chip->ecc.calculate(mtd, p, &ecc_calc[0]);
 +
 +      /* Clear ECC last bit */
 +      data_phase_addr = (unsigned long __force)chip->IO_ADDR_R;
 +      data_phase_addr &= ~XNANDPSS_ECC_LAST;
 +      chip->IO_ADDR_R = (void __iomem *__force)data_phase_addr;
 +
 +      /* Read the stored ECC value */
 +      oob_ptr = chip->oob_poi;
 +      chip->read_buf(mtd, oob_ptr, (mtd->oobsize - data_width));
 +
 +      /* de-assert chip select */
 +      data_phase_addr = (unsigned long __force)chip->IO_ADDR_R;
 +      data_phase_addr |= XNANDPSS_CLEAR_CS;
 +      chip->IO_ADDR_R = (void __iomem *__force)data_phase_addr;
 +
 +      oob_ptr += (mtd->oobsize - data_width);
 +      chip->read_buf(mtd, oob_ptr, data_width);
 +
 +      for (i = 0; i < chip->ecc.total; i++)
 +              ecc_code[i] = ~(chip->oob_poi[eccpos[i]]);
 +
 +      eccsteps = chip->ecc.steps;
 +      p = buf;
 +
 +      /* Check ECC error for all blocks and correct if it is correctable */
 +      for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
 +              stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
 +              if (stat < 0)
 +                      mtd->ecc_stats.failed++;
 +              else
 +                      mtd->ecc_stats.corrected += stat;
 +      }
 +      return 0;
 +}
 +
 +/**
 + * xnandps_read_page_swecc - [REPLACABLE] software ecc based page read function
 + * @mtd:      mtd info structure
 + * @chip:     nand chip info structure
 + * @buf:      buffer to store read data
 + * @page:     page number to read
 + */
 +static int xnandps_read_page_swecc(struct mtd_info *mtd,
 +                              struct nand_chip *chip, uint8_t *buf, int page)
 +{
 +      int i, eccsize = chip->ecc.size;
 +      int eccbytes = chip->ecc.bytes;
 +      int eccsteps = chip->ecc.steps;
 +      uint8_t *p = buf;
 +      uint8_t *ecc_calc = chip->buffers->ecccalc;
 +      uint8_t *ecc_code = chip->buffers->ecccode;
 +      uint32_t *eccpos = chip->ecc.layout->eccpos;
 +
 +      chip->ecc.read_page_raw(mtd, chip, buf, page);
 +
 +      for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
 +              chip->ecc.calculate(mtd, p, &ecc_calc[i]);
 +
 +      for (i = 0; i < chip->ecc.total; i++)
 +              ecc_code[i] = chip->oob_poi[eccpos[i]];
 +
 +      eccsteps = chip->ecc.steps;
 +      p = buf;
 +
 +      for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
 +              int stat;
 +
 +              stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
 +              if (stat < 0)
 +                      mtd->ecc_stats.failed++;
 +              else
 +                      mtd->ecc_stats.corrected += stat;
 +      }
 +      return 0;
 +}
 +
 +/**
 + * xnandps_select_chip - Select the flash device
 + * @mtd:      Pointer to the mtd_info structure
 + * @chip:     Chip number to be selected
 + *
 + * This function is empty as the NAND controller handles chip select line
 + * internally based on the chip address passed in command and data phase.
 + **/
 +static void xnandps_select_chip(struct mtd_info *mtd, int chip)
 +{
 +      return;
 +}
 +
 +/**
 + * xnandps_cmd_function - Send command to NAND device
 + * @mtd:      Pointer to the mtd_info structure
 + * @command:  The command to be sent to the flash device
 + * @column:   The column address for this command, -1 if none
 + * @page_addr:        The page address for this command, -1 if none
 + */
 +static void xnandps_cmd_function(struct mtd_info *mtd, unsigned int command,
 +                          int column, int page_addr)
 +{
 +      struct nand_chip *chip = mtd->priv;
 +      struct xnandps_command_format *curr_cmd = NULL;
 +      struct xnandps_info *xnand;
 +      void *cmd_addr;
 +      unsigned long cmd_data = 0;
 +      unsigned long cmd_phase_addr = 0;
 +      unsigned long data_phase_addr = 0;
 +      unsigned long end_cmd = 0;
 +      unsigned long end_cmd_valid = 0;
 +      unsigned long i;
 +
 +      xnand = (struct xnandps_info *)chip->priv;
 +      if (xnand->end_cmd_pending) {
 +              /* Check for end command if this command request is same as the
 +               * pending command then return */
 +              if (xnand->end_cmd == command) {
 +                      xnand->end_cmd = 0;
 +                      xnand->end_cmd_pending = 0;
 +                      return;
 +              }
 +      }
 +
 +      /* Emulate NAND_CMD_READOOB for large page device */
 +      if ((mtd->writesize > XNANDPSS_ECC_SIZE) &&
 +              (command == NAND_CMD_READOOB)) {
 +              column += mtd->writesize;
 +              command = NAND_CMD_READ0;
 +      }
 +
 +      /* Get the command format */
 +      for (i = 0; (xnandps_commands[i].start_cmd != NAND_CMD_NONE ||
 +              xnandps_commands[i].end_cmd != NAND_CMD_NONE); i++) {
 +              if (command == xnandps_commands[i].start_cmd)
 +                      curr_cmd = &xnandps_commands[i];
 +      }
 +      if (curr_cmd == NULL)
 +              return;
 +
 +      /* Clear interrupt */
 +      xnandps_write32((xnand->smc_regs + XSMCPSS_MC_CLR_CONFIG), (1 << 4));
 +
 +      /* Get the command phase address */
 +      if (curr_cmd->end_cmd_valid == XNANDPSS_CMD_PHASE)
 +              end_cmd_valid = 1;
 +
 +      if (curr_cmd->end_cmd == NAND_CMD_NONE)
 +              end_cmd = 0x0;
 +      else
 +              end_cmd = curr_cmd->end_cmd;
 +
 +      cmd_phase_addr = (unsigned long __force)xnand->nand_base        |
 +                      (curr_cmd->addr_cycles << ADDR_CYCLES_SHIFT)    |
 +                      (end_cmd_valid << END_CMD_VALID_SHIFT)          |
 +                      (COMMAND_PHASE)                                 |
 +                      (end_cmd << END_CMD_SHIFT)                      |
 +                      (curr_cmd->start_cmd << START_CMD_SHIFT);
 +
 +      cmd_addr = (void __iomem * __force)cmd_phase_addr;
 +
 +      /* Get the data phase address */
 +      end_cmd_valid = 0;
 +
 +      data_phase_addr = (unsigned long __force)xnand->nand_base       |
 +                      (0x0 << CLEAR_CS_SHIFT)                         |
 +                      (end_cmd_valid << END_CMD_VALID_SHIFT)          |
 +                      (DATA_PHASE)                                    |
 +                      (end_cmd << END_CMD_SHIFT)                      |
 +                      (0x0 << ECC_LAST_SHIFT);
 +
 +      chip->IO_ADDR_R = (void  __iomem * __force)data_phase_addr;
 +      chip->IO_ADDR_W = chip->IO_ADDR_R;
 +
 +      /* Command phase AXI write */
 +      /* Read & Write */
 +      if (column != -1 && page_addr != -1) {
 +              /* Adjust columns for 16 bit bus width */
 +              if (chip->options & NAND_BUSWIDTH_16)
 +                      column >>= 1;
 +              cmd_data = column;
 +              if (mtd->writesize > XNANDPSS_ECC_SIZE) {
 +                      cmd_data |= page_addr << 16;
 +                      /* Another address cycle for devices > 128MiB */
 +                      if (chip->chipsize > (128 << 20)) {
 +                              xnandps_write32(cmd_addr, cmd_data);
 +                              cmd_data = (page_addr >> 16);
 +                      }
 +              } else
 +                      cmd_data |= page_addr << 8;
 +      }
 +      /* Erase */
 +      else if (page_addr != -1)
 +              cmd_data = page_addr;
 +      /* Change read/write column, read id etc */
 +      else if (column != -1) {
 +              /* Adjust columns for 16 bit bus width */
 +              if ((chip->options & NAND_BUSWIDTH_16) &&
 +                      ((command == NAND_CMD_READ0) ||
 +                      (command == NAND_CMD_SEQIN) ||
 +                      (command == NAND_CMD_RNDOUT) ||
 +                      (command == NAND_CMD_RNDIN)))
 +                      column >>= 1;
 +              cmd_data = column;
 +      } else
 +              ;
 +
 +      xnandps_write32(cmd_addr, cmd_data);
 +
 +      if (curr_cmd->end_cmd_valid) {
 +              xnand->end_cmd = curr_cmd->end_cmd;
 +              xnand->end_cmd_pending = 1;
 +      }
 +
 +      ndelay(100);
 +
 +      if ((command == NAND_CMD_READ0) ||
 +              (command == NAND_CMD_ERASE1) ||
 +              (command == NAND_CMD_RESET) ||
 +              (command == NAND_CMD_PARAM) ||
 +              (command == NAND_CMD_GET_FEATURES)) {
 +              while (!chip->dev_ready(mtd))
 +                              ;
 +              return;
 +      }
 +}
 +
 +/**
 + * xnandps_read_buf - read chip data into buffer
 + * @mtd:        MTD device structure
 + * @buf:        buffer to store date
 + * @len:        number of bytes to read
 + *
 + */
 +static void xnandps_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
 +{
 +      struct nand_chip *chip = mtd->priv;
 +      const u32 *nand = chip->IO_ADDR_R;
 +
 +      /* Make sure that buf is 32 bit aligned */
 +      if (((int)buf & 0x3) != 0) {
 +              if (((int)buf & 0x1) != 0) {
 +                      if (len) {
 +                              *buf = readb(nand);
 +                              buf += 1;
 +                              len--;
 +                      }
 +              }
 +
 +              if (((int)buf & 0x3) != 0) {
 +                      if (len >= 2) {
 +                              *(u16 *)buf = readw(nand);
 +                              buf += 2;
 +                              len -= 2;
 +                      }
 +              }
 +      }
 +
 +      /* copy aligned data */
 +      while (len >= 4) {
 +              *(u32 *)buf = readl(nand);
 +              buf += 4;
 +              len -= 4;
 +      }
 +
 +      /* mop up any remaining bytes */
 +      if (len) {
 +              if (len >= 2) {
 +                      *(u16 *)buf = readw(nand);
 +                      buf += 2;
 +                      len -= 2;
 +              }
 +
 +              if (len)
 +                      *buf = readb(nand);
 +      }
 +}
 +
 +/**
 + * xnandps_write_buf - write buffer to chip
 + * @mtd:        MTD device structure
 + * @buf:        data buffer
 + * @len:        number of bytes to write
 + *
 + */
 +static void xnandps_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
 +{
 +      struct nand_chip *chip = mtd->priv;
 +      const u32 *nand = chip->IO_ADDR_W;
 +
 +      /* Make sure that buf is 32 bit aligned */
 +      if (((int)buf & 0x3) != 0) {
 +              if (((int)buf & 0x1) != 0) {
 +                      if (len) {
 +                              writeb(*buf, nand);
 +                              buf += 1;
 +                              len--;
 +                      }
 +              }
 +
 +              if (((int)buf & 0x3) != 0) {
 +                      if (len >= 2) {
 +                              writew(*(u16 *)buf, nand);
 +                              buf += 2;
 +                              len -= 2;
 +                      }
 +              }
 +      }
 +
 +      /* copy aligned data */
 +      while (len >= 4) {
 +              writel(*(u32 *)buf, nand);
 +              buf += 4;
 +              len -= 4;
 +      }
 +
 +      /* mop up any remaining bytes */
 +      if (len) {
 +              if (len >= 2) {
 +                      writew(*(u16 *)buf, nand);
 +                      buf += 2;
 +                      len -= 2;
 +              }
 +
 +              if (len)
 +                      writeb(*buf, nand);
 +      }
 +}
 +
 +/**
 + * xnandps_device_ready - Check device ready/busy line
 + * @mtd:      Pointer to the mtd_info structure
 + *
 + * returns:   0 on busy or 1 on ready state
 + **/
 +static int xnandps_device_ready(struct mtd_info *mtd)
 +{
 +      struct xnandps_info *xnand;
 +      struct nand_chip *chip;
 +      unsigned long status;
 +
 +      chip = (struct nand_chip *)mtd->priv;
 +      xnand = (struct xnandps_info *)chip->priv;
 +
 +      /* Check the raw_int_status1 bit */
 +      status = xnandps_read32(xnand->smc_regs + XSMCPSS_MC_STATUS) & 0x40;
 +      /* Clear the interrupt condition */
 +      if (status)
 +              xnandps_write32((xnand->smc_regs + XSMCPSS_MC_CLR_CONFIG),
 +                                      (1<<4));
 +      return status ? 1 : 0;
 +}
 +
 +int zynq_nand_init(struct nand_chip *nand_chip)
 +{
 +      struct xnandps_info *xnand;
 +      struct mtd_info *mtd;
 +      extern struct mtd_info nand_info[];
 +      unsigned long ecc_page_size;
 +      int err = 0;
 +      u8 maf_id, dev_id;
 +      u8 get_feature[4];
 +      u8 set_feature[4] = {0x08, 0x00, 0x00, 0x00};
 +      unsigned long ecc_cfg;
 +      int ondie_ecc_enabled = 0;
 +
 +      xnand = malloc(sizeof(struct xnandps_info));
 +      memset(xnand, 0, sizeof(struct xnandps_info));
 +      if (!xnand) {
 +              printf("failed to allocate device structure.\n");
 +              return -ENOMEM;
 +      }
 +
 +      xnand->smc_regs = (void*)XPSS_CRTL_PARPORT_BASEADDR;
 +      xnand->nand_base = (void*)XPSS_NAND_BASEADDR;
 +      mtd = &nand_info[0];
 +
 +      nand_chip->priv = xnand;
 +      mtd->priv = nand_chip;
 +
 +      /* Set address of NAND IO lines */
 +      nand_chip->IO_ADDR_R = xnand->nand_base;
 +      nand_chip->IO_ADDR_W = xnand->nand_base;
 +
 +      /* Set the driver entry points for MTD */
 +      nand_chip->cmdfunc = xnandps_cmd_function;
 +      //nand_chip->dev_ready = NULL;
 +      nand_chip->dev_ready = xnandps_device_ready;
 +      nand_chip->select_chip = xnandps_select_chip;
 +
 +      /* If we don't set this delay driver sets 20us by default */
 +      nand_chip->chip_delay = 30;
 +
 +      /* Buffer read/write routines */
 +      nand_chip->read_buf = xnandps_read_buf;
 +      nand_chip->write_buf = xnandps_write_buf;
 +
 +#ifndef CONFIG_XILINX_ZYNQ_NAND_BUSWIDTH_16
 +      /* arch/arm/mach-xilinx/devices.c */
 +      nand_chip->options = NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT;
 +#else
 +      nand_chip->options = NAND_BUSWIDTH_16;
 +#endif
 +
 +      /* Initialize the NAND flash interface on NAND controller */
 +      xnandps_init_nand_flash(xnand->smc_regs, nand_chip->options);
 +
 +      /* first scan to find the device and get the page size */
 +      if (nand_scan_ident(mtd, 1, NULL)) {
 +              err = -ENXIO;
 +              printf("nand_scan_ident for NAND failed\n");
 +              goto out_unmap_all_mem;
 +      }
 +
 +      /* Send the command for reading device ID */
 +      nand_chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
 +      nand_chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
 +
 +      /* Read manufacturer and device IDs */
 +      maf_id = nand_chip->read_byte(mtd);
 +      dev_id = nand_chip->read_byte(mtd);
 +
 +      if ((maf_id == 0x2c) && ((dev_id == 0xf1) || (dev_id == 0xa1) || (dev_id == 0xb1) ||
 +                              (dev_id == 0xaa) || (dev_id == 0xba) ||
 +                              (dev_id == 0xda) || (dev_id == 0xca) ||
 +                              (dev_id == 0xac) || (dev_id == 0xbc) ||
 +                              (dev_id == 0xdc) || (dev_id == 0xcc) ||
 +                              (dev_id == 0xa3) || (dev_id == 0xb3) ||
 +                              (dev_id == 0xd3) || (dev_id == 0xc3))) {
 +              nand_chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES,
 +                                              ONDIE_ECC_FEATURE_ADDR, -1);
 +              nand_chip->write_buf(mtd, set_feature, 4);
 +
 +              nand_chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES,
 +                                              ONDIE_ECC_FEATURE_ADDR, -1);
 +              nand_chip->read_buf(mtd, get_feature, 4);
 +
 +              if (get_feature[0] & 0x08) {
 +                      printf("OnDie ECC flash\n");
 +                      ondie_ecc_enabled = 1;
 +              }
 +      }
 +
 +      if (ondie_ecc_enabled) {
 +              /* bypass the controller ECC block */
 +              ecc_cfg = xnandps_read32(xnand->smc_regs +
 +                      XSMCPSS_ECC_MEMCFG_OFFSET(XSMCPSS_ECC_IF1_OFFSET));
 +              ecc_cfg &= ~0xc;
 +              xnandps_write32(xnand->smc_regs +
 +                      (XSMCPSS_ECC_MEMCFG_OFFSET(XSMCPSS_ECC_IF1_OFFSET)),
 +                      ecc_cfg);
 +
 +              /* The software ECC routines won't work with the
 +                              SMC controller */
 +              nand_chip->ecc.mode = NAND_ECC_HW;
 +              nand_chip->ecc.read_page = xnandps_read_page_raw_nooob;
 +              nand_chip->ecc.read_subpage = xnandps_read_subpage_raw;
 +              nand_chip->ecc.write_page = xnandps_write_page_raw;
 +              nand_chip->ecc.read_page_raw = xnandps_read_page_raw;
 +              nand_chip->ecc.write_page_raw = xnandps_write_page_raw;
 +              nand_chip->ecc.read_oob = xnandps_read_oob;
 +              nand_chip->ecc.write_oob = xnandps_write_oob;
 +              nand_chip->ecc.size = mtd->writesize;
 +              nand_chip->ecc.bytes = 0;
 +
 +              /* NAND with on-die ECC supports subpage reads */
 +              nand_chip->options |= NAND_SUBPAGE_READ;
 +
 +              /* On-Die ECC spare bytes offset 8 is used for ECC codes */
 +              if (ondie_ecc_enabled) {
 +                      nand_chip->ecc.layout = &ondie_nand_oob_64;
 +                      /* Use the BBT pattern descriptors */
 +                      nand_chip->bbt_td = &bbt_main_descr;
 +                      nand_chip->bbt_md = &bbt_mirror_descr;
 +              }
 +      } else {
 +              /* Hardware ECC generates 3 bytes ECC code for each 512 bytes */
 +              nand_chip->ecc.mode = NAND_ECC_HW;
 +              nand_chip->ecc.size = XNANDPSS_ECC_SIZE;
 +              nand_chip->ecc.bytes = 3;
 +              nand_chip->ecc.calculate = xnandps_calculate_hwecc;
 +              nand_chip->ecc.correct = xnandps_correct_data;
 +              nand_chip->ecc.hwctl = NULL;
 +              nand_chip->ecc.read_page = xnandps_read_page_hwecc;
 +              nand_chip->ecc.write_page = xnandps_write_page_hwecc;
 +              nand_chip->ecc.read_page_raw = xnandps_read_page_raw;
 +              nand_chip->ecc.write_page_raw = xnandps_write_page_raw;
 +              nand_chip->ecc.read_oob = xnandps_read_oob;
 +              nand_chip->ecc.write_oob = xnandps_write_oob;
 +
 +              switch (mtd->writesize) {
 +              case 512:
 +                      ecc_page_size = 0x1;
 +                      /* Set the ECC memory config register */
 +                      xnandps_write32(xnand->smc_regs +
 +                              (XSMCPSS_ECC_MEMCFG_OFFSET(XSMCPSS_ECC_IF1_OFFSET)),
 +                              (XNANDPSS_ECC_CONFIG | ecc_page_size));
 +                      break;
 +              case 1024:
 +                      ecc_page_size = 0x2;
 +                      /* Set the ECC memory config register */
 +                      xnandps_write32(xnand->smc_regs +
 +                              (XSMCPSS_ECC_MEMCFG_OFFSET(XSMCPSS_ECC_IF1_OFFSET)),
 +                              (XNANDPSS_ECC_CONFIG | ecc_page_size));
 +                      break;
 +              case 2048:
 +                      ecc_page_size = 0x3;
 +                      /* Set the ECC memory config register */
 +                      xnandps_write32(xnand->smc_regs +
 +                              (XSMCPSS_ECC_MEMCFG_OFFSET(XSMCPSS_ECC_IF1_OFFSET)),
 +                              (XNANDPSS_ECC_CONFIG | ecc_page_size));
 +                      break;
 +              default:
 +                      /* The software ECC routines won't work with the
 +                                      SMC controller */
 +                      nand_chip->ecc.mode = NAND_ECC_HW;
 +                      nand_chip->ecc.calculate = nand_calculate_ecc;
 +                      nand_chip->ecc.correct = nand_correct_data;
 +                      nand_chip->ecc.read_page = xnandps_read_page_swecc;
 +                      /* nand_chip->ecc.read_subpage = nand_read_subpage; */
 +                      nand_chip->ecc.write_page = xnandps_write_page_swecc;
 +                      nand_chip->ecc.read_page_raw = xnandps_read_page_raw;
 +                      nand_chip->ecc.write_page_raw = xnandps_write_page_raw;
 +                      nand_chip->ecc.read_oob = xnandps_read_oob;
 +                      nand_chip->ecc.write_oob = xnandps_write_oob;
 +                      nand_chip->ecc.size = 256;
 +                      nand_chip->ecc.bytes = 3;
 +                      break;
 +              }
 +
 +              if (mtd->oobsize == 16)
 +                      nand_chip->ecc.layout = &nand_oob_16;
 +              else if (mtd->oobsize == 64)
 +                      nand_chip->ecc.layout = &nand_oob_64;
 +              else
 +                      ;
 +      }
 +
 +      /* second phase scan */
 +      if (nand_scan_tail(mtd)) {
 +              err = -ENXIO;
 +              printf("nand_scan_tail for NAND failed\n");
 +              goto out_unmap_all_mem;
 +      }
 +
 +      if (!err)
 +              return 0;
 +
 +      printf("%s: ERROR *********** %d\n", __func__, err);
 +      nand_release(mtd);
 +
 +out_unmap_all_mem:
 +      kfree(xnand);
 +      return err;
 +}
index b23e04f2fb0463fd4ba3e0160bdda83151e5cb26,32b76e0e9072196802b75963293f7ca2fddca106..335b5140defe600400b24064d788041180a41970
  
  #include "spi_flash_internal.h"
  
- #define SPSN_ID_S25FL008A     0x0213
- #define SPSN_ID_S25FL016A     0x0214
- #define SPSN_ID_S25FL032A     0x0215
- #define SPSN_ID_S25FL064A     0x0216
- #define SPSN_ID_S25FL256S     0x0219
- #define SPSN_ID_S25FL128P     0x2018
- #define SPSN_EXT_ID_S25FL128P_256KB   0x0300
- #define SPSN_EXT_ID_S25FL128P_64KB    0x0301
- #define SPSN_EXT_ID_S25FL032P         0x4d00
- #define SPSN_EXT_ID_S25FL129P         0x4d01
 +/* S25FLxx-specific commands */
 +#define CMD_S25FLXX_SE                0xd8    /* Sector Erase */
 +#define CMD_S25FLXX_BE                0xc7    /* Bulk Erase */
 +#define CMD_S25FLXX_DP                0xb9    /* Deep Power-down */
 +#define CMD_S25FLXX_RES               0xab    /* Release from DP, and Read Signature */
 +
  struct spansion_spi_flash_params {
        u16 idcode1;
        u16 idcode2;
@@@ -170,19 -138,11 +144,19 @@@ struct spi_flash *spi_flash_probe_spans
        flash->name = params->name;
  
        flash->write = spi_flash_cmd_write_multi;
-       flash->erase = spansion_erase;
+       flash->erase = spi_flash_cmd_erase;
        flash->read = spi_flash_cmd_read_fast;
-       flash->page_size = params->page_size;
-       flash->sector_size = params->page_size * params->pages_per_sector;
+       flash->page_size = 256;
+       flash->sector_size = 256 * params->pages_per_sector;
 -      flash->size = flash->sector_size * params->nr_sectors;
 +
 +      /* address width is 4 for dual and 3 for single qspi */
 +      if (flash->spi->is_dual == 1) {
 +              flash->addr_width = 4;
 +              flash->size = flash->sector_size * (2 * params->nr_sectors);
-       } else if (flash->spi->is_dual == 0) {
++      } else {
 +              flash->addr_width = 3;
 +              flash->size = flash->sector_size * params->nr_sectors;
 +      }
  
        return flash;
  }
Simple merge
index 7c10d4e426f66c916dfe842eaf4698ffea4a419c,30b626a39f8923a398f575cbbdb70abff2fb35f9..81d2f8583fdc9d4f2160d6470f316a34c6c443b3
@@@ -165,19 -156,11 +156,19 @@@ struct spi_flash *spi_flash_probe_stmic
        flash->name = params->name;
  
        flash->write = spi_flash_cmd_write_multi;
-       flash->erase = stmicro_erase;
+       flash->erase = spi_flash_cmd_erase;
        flash->read = spi_flash_cmd_read_fast;
-       flash->page_size = params->page_size;
-       flash->sector_size = params->page_size * params->pages_per_sector;
+       flash->page_size = 256;
+       flash->sector_size = 256 * params->pages_per_sector;
 -      flash->size = flash->sector_size * params->nr_sectors;
 +
 +      /* address width is 4 for dual and 3 for single qspi */
 +      if (flash->spi->is_dual == 1) {
 +              flash->addr_width = 4;
 +              flash->size = flash->sector_size * (2 * params->nr_sectors);
-       } else if (flash->spi->is_dual == 0) {
++      } else {
 +              flash->addr_width = 3;
 +              flash->size = flash->sector_size * params->nr_sectors;
 +      }
  
        return flash;
  }
index d1d2cdf984dc8a2a5228e4693c2cd38b840b42a8,f6aab3d32f459d82d0a9e606f4382fe67981160f..3ddd057009b119c2fd220993651323206b6d741f
@@@ -95,24 -62,13 +62,18 @@@ static const struct winbond_spi_flash_p
                .nr_blocks              = 256,
                .name                   = "W25Q128",
        },
-               .l2_page_size           = 8,
-               .pages_per_sector       = 16,
-               .sectors_per_block      = 16,
+       {
+               .id                     = 0x5014,
+               .nr_blocks              = 128,
+               .name                   = "W25Q80",
+       },
 +      {
 +              .id                     = 0x6017,
 +              .nr_blocks              = 128,
 +              .name                   = "W25Q64DW",
 +      },
  };
  
- static int winbond_erase(struct spi_flash *flash, u32 offset, size_t len)
- {
-       return spi_flash_cmd_erase(flash, CMD_W25_SE, offset, len);
- }
  struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode)
  {
        const struct winbond_spi_flash_params *params;
        flash->spi = spi;
        flash->name = params->name;
  
-       /* Assuming power-of-two page size initially. */
-       page_size = 1 << params->l2_page_size;
        flash->write = spi_flash_cmd_write_multi;
-       flash->erase = winbond_erase;
+       flash->erase = spi_flash_cmd_erase;
        flash->read = spi_flash_cmd_read_fast;
-       flash->page_size = page_size;
-       flash->sector_size = page_size * params->pages_per_sector;
+       flash->page_size = 256;
+       flash->sector_size = 4096;
 -      flash->size = 4096 * 16 * params->nr_blocks;
 +
 +      /* address width is 4 for dual and 3 for single qspi */
 +      if (flash->spi->is_dual == 1) {
 +              flash->addr_width = 4;
-               flash->size = page_size * params->pages_per_sector
-                               * params->sectors_per_block
-                               * (2 * params->nr_blocks);
-       } else if (flash->spi->is_dual == 0) {
++              flash->size = 4096 * 16 * (2 * params->nr_blocks);
++      } else {
 +              flash->addr_width = 3;
-               flash->size = page_size * params->pages_per_sector
-                               * params->sectors_per_block
-                               * params->nr_blocks;
++              flash->size = 4096 * 16 * params->nr_blocks;
 +      }
  
        return flash;
  }
Simple merge
Simple merge
index 4c21efa3f21313dd448e3e3c33929f6a9ce53013,f0b82c67f5babf48f1891d3e58e789ae29cce2d4..2fd98df6b5b50fb39655f369facc2f742fe95ad2
@@@ -44,7 -45,7 +45,8 @@@ COBJS-$(CONFIG_SOFT_SPI) += soft_spi.
  COBJS-$(CONFIG_SH_SPI) += sh_spi.o
  COBJS-$(CONFIG_FSL_ESPI) += fsl_espi.o
  COBJS-$(CONFIG_TEGRA_SPI) += tegra_spi.o
+ COBJS-$(CONFIG_XILINX_SPI) += xilinx_spi.o
 +COBJS-$(CONFIG_ZYNQ_SPI) += zynq_qspi.o zynq_qspi_wrap.o
  
  COBJS := $(COBJS-y)
  SRCS  := $(COBJS:.o=.c)
index 77bc9b7f2291ae42e1a43b2e0c43e4c1e3dfc207,0000000000000000000000000000000000000000..408caa9958111fae05bf9bfe4ee0b16f1b24a3c9
mode 100755,000000..100755
--- /dev/null
@@@ -1,1454 -1,0 +1,1454 @@@
- #include <linux/mtd/compat.h>
 +/*
 + * (C) Copyright 2011 Xilinx
 + *
 + * Xilinx PSS Quad-SPI (QSPI) controller driver (master mode only)
 + * based on Xilinx PSS SPI Driver (xspips.c)
 + *
 + * This program is free software; you can redistribute it and/or modify it under
 + * the terms of the GNU General Public License version 2 as published by the
 + * Free Software Foundation; either version 2 of the License, or (at your
 + * option) any later version.
 + *
 + * You should have received a copy of the GNU General Public License along with
 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 + * Place, Suite 330, Boston, MA  02111-1307  USA
 + */
 +
 +#ifdef LINUX_ONLY_NOT_UBOOT
 +#include <linux/module.h>
 +#include <linux/init.h>
 +#include <linux/interrupt.h>
 +#include <linux/platform_device.h>
 +#include <linux/spi/spi.h>
 +#include <linux/io.h>
 +#include <linux/spinlock.h>
 +#include <linux/workqueue.h>
 +#include <linux/delay.h>
 +#include <linux/xilinx_devices.h>
 +#else
 +
 +#include "xbasic_types.h"
 +#include <common.h>
 +#include <malloc.h>
 +
++//#include <linux/mtd/compat.h>
 +#include <ubi_uboot.h>
 +#include <spi.h>
 +
 +#include "zynq_qspi.h"
 +
 +#define DEBUG
 +#define DEBUG_REG
 +#undef DEBUG
 +#undef DEBUG_REG
 +
 +#endif
 +
 +/****** stubs to make this Linux driver build in this environment **/
 +
 +#define spin_lock_irqsave(__X__, flags) \
 +              flags = 0;
 +#define spin_unlock_irqrestore(__X__, flags) \
 +              flags |= 0;
 +#define MODULE_ALIAS(__X__)
 +
 +#define dev_dbg(dev, format, arg...) \
 +        printf(format , ## arg)
 +
 +#define dev_err(dev, format, arg...) \
 +        printf(format , ## arg)
 +
 +#define wait_for_completion(__X__) \
 +      { \
 +              u32 data; \
 +\
 +              do { \
 +                      data = xqspips_irq_poll(xqspi); \
 +              } while (data == 0); \
 +      }
 +
 +#define __devinit
 +#define __devinitdata
 +#define __devexit
 +#define __devexitdata
 +#define __force
 +
 +extern void XIo_Out32(u32 OutAddress, u32 Value);
 +extern u32  XIo_In32(u32 InAddress);
 +
 +#define spi_master_get_devdata(__X__)  (&(__X__))
 +#define INIT_COMPLETION(__X__)
 +
 +/**
 + * enum irqreturn
 + * @IRQ_NONE            interrupt was not from this device
 + * @IRQ_HANDLED         interrupt was handled by this device
 + * @IRQ_WAKE_THREAD     handler requests to wake the handler thread
 + */
 +enum irqreturn {
 +        IRQ_NONE,
 +        IRQ_HANDLED,
 +        IRQ_WAKE_THREAD,
 +};
 +typedef enum irqreturn irqreturn_t;
 +
 +/*******************************************************************/
 +
 +#undef HACK_WRITE_NO_DELAY
 +
 +/*
 + * Name of this driver
 + */
 +#define DRIVER_NAME                   "Xilinx_PSS_QSPI"
 +
 +/*
 + * Register offset definitions
 + */
 +#define XQSPIPSS_CONFIG_OFFSET                0x00 /* Configuration  Register, RW */
 +#define XQSPIPSS_STATUS_OFFSET                0x04 /* Interrupt Status Register, RO */
 +#define XQSPIPSS_IEN_OFFSET           0x08 /* Interrupt Enable Register, WO */
 +#define XQSPIPSS_IDIS_OFFSET          0x0C /* Interrupt Disable Reg, WO */
 +#define XQSPIPSS_IMASK_OFFSET         0x10 /* Interrupt Enabled Mask Reg,RO */
 +#define XQSPIPSS_ENABLE_OFFSET                0x14 /* Enable/Disable Register, RW */
 +#define XQSPIPSS_DELAY_OFFSET                 0x18 /* Delay Register, RW */
 +#define XQSPIPSS_TXD_00_00_OFFSET     0x1C /* Transmit 4-byte inst, WO */
 +#define XQSPIPSS_TXD_00_01_OFFSET     0x80 /* Transmit 1-byte inst, WO */
 +#define XQSPIPSS_TXD_00_10_OFFSET     0x84 /* Transmit 2-byte inst, WO */
 +#define XQSPIPSS_TXD_00_11_OFFSET     0x88 /* Transmit 3-byte inst, WO */
 +#define XQSPIPSS_RXD_OFFSET           0x20 /* Data Receive Register, RO */
 +#define XQSPIPSS_SIC_OFFSET           0x24 /* Slave Idle Count Register, RW */
 +#define XQSPIPSS_TX_THRESH_OFFSET     0x28 /* TX FIFO Watermark Reg, RW */
 +#define XQSPIPSS_RX_THRESH_OFFSET     0x2C /* RX FIFO Watermark Reg, RW */
 +#define XQSPIPSS_GPIO_OFFSET          0x30 /* GPIO Register, RW */
 +#define XQSPIPSS_LINEAR_CFG_OFFSET    0xA0 /* Linear Adapter Config Ref, RW */
 +#define XQSPIPSS_MOD_ID_OFFSET                0xFC /* Module ID Register, RO */
 +
 +/*
 + * QSPI Configuration Register bit Masks
 + *
 + * This register contains various control bits that effect the operation
 + * of the QSPI controller
 + */
 +#define XQSPIPSS_CONFIG_MANSRT_MASK   0x00010000 /* Manual TX Start */
 +#define XQSPIPSS_CONFIG_CPHA_MASK     0x00000004 /* Clock Phase Control */
 +#define XQSPIPSS_CONFIG_CPOL_MASK     0x00000002 /* Clock Polarity Control */
 +#define XQSPIPSS_CONFIG_SSCTRL_MASK   0x00003C00 /* Slave Select Mask */
 +
 +/*
 + * QSPI Interrupt Registers bit Masks
 + *
 + * All the four interrupt registers (Status/Mask/Enable/Disable) have the same
 + * bit definitions.
 + */
 +#define XQSPIPSS_IXR_TXNFULL_MASK     0x00000004 /* QSPI TX FIFO Overflow */
 +#define XQSPIPSS_IXR_TXFULL_MASK      0x00000008 /* QSPI TX FIFO is full */
 +#define XQSPIPSS_IXR_RXNEMTY_MASK     0x00000010 /* QSPI RX FIFO Not Empty */
 +#define XQSPIPSS_IXR_ALL_MASK         (XQSPIPSS_IXR_TXNFULL_MASK | \
 +                                       XQSPIPSS_IXR_RXNEMTY_MASK)
 +
 +/*
 + * QSPI Enable Register bit Masks
 + *
 + * This register is used to enable or disable the QSPI controller
 + */
 +#define XQSPIPSS_ENABLE_ENABLE_MASK   0x00000001 /* QSPI Enable Bit Mask */
 +
 +/*
 + * The modebits configurable by the driver to make the SPI support different
 + * data formats
 + */
 +#define MODEBITS                      (SPI_CPOL | SPI_CPHA)
 +
 +/*
 + * Definitions for the status of queue
 + */
 +#define XQSPIPSS_QUEUE_STOPPED                0
 +#define XQSPIPSS_QUEUE_RUNNING                1
 +
 +/*
 + * Definitions of the flash commands
 + */
 +/* Flash opcodes in ascending order */
 +#define       XQSPIPSS_FLASH_OPCODE_WRSR      0x01    /* Write status register */
 +#define       XQSPIPSS_FLASH_OPCODE_PP        0x02    /* Page program */
 +#define       XQSPIPSS_FLASH_OPCODE_NORM_READ 0x03    /* Normal read data bytes */
 +#define       XQSPIPSS_FLASH_OPCODE_WRDS      0x04    /* Write disable */
 +#define       XQSPIPSS_FLASH_OPCODE_RDSR1     0x05    /* Read status register 1 */
 +#define       XQSPIPSS_FLASH_OPCODE_WREN      0x06    /* Write enable */
 +#define       XQSPIPSS_FLASH_OPCODE_FAST_READ 0x0B    /* Fast read data bytes */
 +#define       XQSPIPSS_FLASH_OPCODE_BE_4K     0x20    /* Erase 4KiB block */
 +#define       XQSPIPSS_FLASH_OPCODE_RDSR2     0x35    /* Read status register 2 */
 +#define       XQSPIPSS_FLASH_OPCODE_DUAL_READ 0x3B    /* Dual read data bytes */
 +#define       XQSPIPSS_FLASH_OPCODE_BE_32K    0x52    /* Erase 32KiB block */
 +#define       XQSPIPSS_FLASH_OPCODE_QUAD_READ 0x6B    /* Quad read data bytes */
 +#define       XQSPIPSS_FLASH_OPCODE_ERASE_SUS 0x75    /* Erase suspend */
 +#define       XQSPIPSS_FLASH_OPCODE_ERASE_RES 0x7A    /* Erase resume */
 +#define       XQSPIPSS_FLASH_OPCODE_RDID      0x9F    /* Read JEDEC ID */
 +#define       XQSPIPSS_FLASH_OPCODE_BE        0xC7    /* Erase whole flash block */
 +#define       XQSPIPSS_FLASH_OPCODE_SE        0xD8    /* Sector erase (usually 64KB)*/
 +
 +/*
 + * Macros for the QSPI controller read/write
 + */
 +#ifdef LINUX_ONLY_NOT_UBOOT
 +#define xqspips_read(addr)            __raw_readl(addr)
 +#define xqspips_write(addr, val)      __raw_writel((val), (addr))
 +#else
 +static inline
 +u32 xqspips_read(void *addr)
 +{                                     
 +      u32 val;
 +
 +      val =  XIo_In32((unsigned)addr);
 +#ifdef DEBUG_REG
 +      printf("xqspips_read:  addr: 0x%08x = 0x%08x\n",
 +              addr, val);
 +#endif
 +      return val;
 +}
 +static inline
 +void xqspips_write(void *addr, u32 val)
 +{
 +#ifdef DEBUG_REG
 +      printf("xqspips_write: addr: 0x%08x = 0x%08x\n",
 +              addr, val);
 +#endif
 +      XIo_Out32((unsigned)addr, val);
 +}
 +#endif
 +
 +#ifdef LINUX_ONLY_NOT_UBOOT
 +
 +/**
 + * struct xqspips - Defines qspi driver instance
 + * @workqueue:                Queue of all the transfers
 + * @work:             Information about current transfer
 + * @queue:            Head of the queue
 + * @queue_state:      Queue status
 + * @regs:             Virtual address of the QSPI controller registers
 + * @input_clk_hz:     Input clock frequency of the QSPI controller in Hz
 + * @irq:              IRQ number
 + * @speed_hz:         Current QSPI bus clock speed in Hz
 + * @trans_queue_lock: Lock used for accessing transfer queue
 + * @config_reg_lock:  Lock used for accessing configuration register
 + * @txbuf:            Pointer to the TX buffer
 + * @rxbuf:            Pointer to the RX buffer
 + * @bytes_to_transfer:        Number of bytes left to transfer
 + * @bytes_to_receive: Number of bytes left to receive
 + * @dev_busy:         Device busy flag
 + * @done:             Transfer complete status
 + * @curr_inst:                Current executing instruction format
 + * @inst_response:    Responce to the instruction or data
 + * @is_inst:          Flag to indicate the first message in a Transfer request
 + **/
 +struct xqspips {
 +      struct workqueue_struct *workqueue;
 +      struct work_struct work;
 +      struct list_head queue;
 +
 +      u8 queue_state;
 +      void __iomem *regs;
 +      u32 input_clk_hz;
 +      u32 irq;
 +      u32 speed_hz;
 +      spinlock_t trans_queue_lock;
 +      spinlock_t config_reg_lock;
 +      const void *txbuf;
 +      void *rxbuf;
 +      int bytes_to_transfer;
 +      int bytes_to_receive;
 +      u8 dev_busy;
 +      struct completion done;
 +      struct xqspips_inst_format *curr_inst;
 +      u8 inst_response;
 +      bool is_inst;
 +};
 +
 +#endif
 +
 +/**
 + * struct xqspips_inst_format - Defines qspi flash instruction format
 + * @opcode:           Operational code of instruction
 + * @inst_size:                Size of the instruction including address bytes
 + * @offset:           Register address where instruction has to be written
 + **/
 +struct xqspips_inst_format {
 +      u8 opcode;
 +      u8 inst_size;
 +      u8 offset;
 +};
 +
 +/*
 + * List of all the QSPI instructions and its format
 + */
 +static struct xqspips_inst_format __devinitdata flash_inst[] = {
 +      { XQSPIPSS_FLASH_OPCODE_WREN, 1, XQSPIPSS_TXD_00_01_OFFSET },
 +      { XQSPIPSS_FLASH_OPCODE_WRDS, 1, XQSPIPSS_TXD_00_01_OFFSET },
 +      { XQSPIPSS_FLASH_OPCODE_RDSR1, 1, XQSPIPSS_TXD_00_01_OFFSET },
 +      { XQSPIPSS_FLASH_OPCODE_RDSR2, 1, XQSPIPSS_TXD_00_01_OFFSET },
 +      { XQSPIPSS_FLASH_OPCODE_WRSR, 1, XQSPIPSS_TXD_00_01_OFFSET },
 +      { XQSPIPSS_FLASH_OPCODE_PP, 4, XQSPIPSS_TXD_00_00_OFFSET },
 +      { XQSPIPSS_FLASH_OPCODE_SE, 4, XQSPIPSS_TXD_00_00_OFFSET },
 +      { XQSPIPSS_FLASH_OPCODE_BE_32K, 4, XQSPIPSS_TXD_00_00_OFFSET },
 +      { XQSPIPSS_FLASH_OPCODE_BE_4K, 4, XQSPIPSS_TXD_00_00_OFFSET },
 +      { XQSPIPSS_FLASH_OPCODE_BE, 1, XQSPIPSS_TXD_00_01_OFFSET },
 +      { XQSPIPSS_FLASH_OPCODE_ERASE_SUS, 1, XQSPIPSS_TXD_00_01_OFFSET },
 +      { XQSPIPSS_FLASH_OPCODE_ERASE_RES, 1, XQSPIPSS_TXD_00_01_OFFSET },
 +      { XQSPIPSS_FLASH_OPCODE_RDID, 1, XQSPIPSS_TXD_00_01_OFFSET },
 +      { XQSPIPSS_FLASH_OPCODE_NORM_READ, 4, XQSPIPSS_TXD_00_00_OFFSET },
 +      { XQSPIPSS_FLASH_OPCODE_FAST_READ, 1, XQSPIPSS_TXD_00_01_OFFSET },
 +      { XQSPIPSS_FLASH_OPCODE_DUAL_READ, 1, XQSPIPSS_TXD_00_01_OFFSET },
 +      { XQSPIPSS_FLASH_OPCODE_QUAD_READ, 1, XQSPIPSS_TXD_00_01_OFFSET },
 +      /* Add all the instructions supported by the flash device */
 +};
 +
 +/**
 + * xqspips_init_hw - Initialize the hardware
 + * @regs_base:                Base address of QSPI controller
 + * @is_dual:          Indicates whether dual memories are used
 + *
 + * The default settings of the QSPI controller's configurable parameters on
 + * reset are
 + *    - Master mode
 + *    - Baud rate divisor is set to 2
 + *    - Threshold value for TX FIFO not full interrupt is set to 1
 + *    - Flash memory interface mode enabled
 + *    - Size of the word to be transferred as 8 bit
 + * This function performs the following actions
 + *    - Disable and clear all the interrupts
 + *    - Enable manual slave select
 + *    - Enable manual start
 + *    - Deselect all the chip select lines
 + *    - Set the size of the word to be transferred as 32 bit
 + *    - Set the little endian mode of TX FIFO and
 + *    - Enable the QSPI controller
 + **/
 +void xqspips_init_hw(void __iomem *regs_base, unsigned int is_dual)
 +{
 +      u32 config_reg;
 +
 +      xqspips_write(regs_base + XQSPIPSS_ENABLE_OFFSET,
 +              ~XQSPIPSS_ENABLE_ENABLE_MASK);
 +      xqspips_write(regs_base + XQSPIPSS_IDIS_OFFSET, 0x7F);
 +
 +      /* Disable linear mode as the boot loader may have used it */
 +      xqspips_write(regs_base + XQSPIPSS_LINEAR_CFG_OFFSET, 0);
 +
 +      /* Clear the RX FIFO */
 +      while (xqspips_read(regs_base + XQSPIPSS_STATUS_OFFSET) &
 +                      XQSPIPSS_IXR_RXNEMTY_MASK)
 +              xqspips_read(regs_base + XQSPIPSS_RXD_OFFSET);
 +
 +      xqspips_write(regs_base + XQSPIPSS_STATUS_OFFSET , 0x7F);
 +      config_reg = xqspips_read(regs_base + XQSPIPSS_CONFIG_OFFSET);
 +      config_reg &= 0xFBFFFFFF; /* Set little endian mode of TX FIFO */
 +      config_reg |= 0x8000FCC1;
 +      xqspips_write(regs_base + XQSPIPSS_CONFIG_OFFSET, config_reg);
 +
 +      if (is_dual == 1)
 +              /* Enable two memories on seperate buses */
 +              xqspips_write(regs_base + XQSPIPSS_LINEAR_CFG_OFFSET,
 +                              0x6400016B);
 +
 +      xqspips_write(regs_base + XQSPIPSS_ENABLE_OFFSET,
 +                      XQSPIPSS_ENABLE_ENABLE_MASK);
 +}
 +
 +/**
 + * xqspips_copy_read_data - Copy data to RX buffer
 + * @xqspi:    Pointer to the xqspips structure
 + * @data:     The 32 bit variable where data is stored
 + * @size:     Number of bytes to be copied from data to RX buffer
 + **/
 +static void xqspips_copy_read_data(struct xqspips *xqspi, u32 data, u8 size)
 +{
 +      u8 byte3;
 +
 +#ifdef DEBUG
 +      printf("%s data 0x%04x rxbuf addr: 0x%08x size %d\n",
 +              __FUNCTION__, data, (unsigned)(xqspi->rxbuf), size);
 +#endif
 +
 +      if (xqspi->rxbuf) {
 +              switch (size) {
 +              case 1:
 +                      *((u8 *)xqspi->rxbuf) = data;
 +                      xqspi->rxbuf += 1;
 +                      break;
 +              case 2:
 +                      *((u16 *)xqspi->rxbuf) = data;
 +                      xqspi->rxbuf += 2;
 +                      break;
 +              case 3:
 +                      *((u16 *)xqspi->rxbuf) = data;
 +                      xqspi->rxbuf += 2;
 +                      byte3 = (u8)(data >> 16);
 +                      *((u8 *)xqspi->rxbuf) = byte3;
 +                      xqspi->rxbuf += 1;
 +                      break;
 +              case 4:
 +#ifdef LINUX_ONLY_NOT_UBOOT
 +                      (*(u32 *)xqspi->rxbuf) = data;
 +#else
 +                      /* Can not assume word aligned buffer */
 +                      memcpy(xqspi->rxbuf, &data,  size);
 +#endif
 +                      xqspi->rxbuf += 4;
 +                      break;
 +              default:
 +                      /* This will never execute */
 +                      break;
 +              }
 +      }
 +      xqspi->bytes_to_receive -= size;
 +      if (xqspi->bytes_to_receive < 0) {
 +              xqspi->bytes_to_receive = 0;
 +      }
 +}
 +
 +/**
 + * xqspips_copy_write_data - Copy data from TX buffer
 + * @xqspi:    Pointer to the xqspips structure
 + * @data:     Pointer to the 32 bit variable where data is to be copied
 + * @size:     Number of bytes to be copied from TX buffer to data
 + **/
 +static void xqspips_copy_write_data(struct xqspips *xqspi, u32 *data, u8 size)
 +{
 +
 +      if (xqspi->txbuf) {
 +              switch (size) {
 +              case 1:
 +                      *data = *((u8 *)xqspi->txbuf);
 +                      xqspi->txbuf += 1;
 +                      *data |= 0xFFFFFF00;
 +                      break;
 +              case 2:
 +                      *data = *((u16 *)xqspi->txbuf);
 +                      xqspi->txbuf += 2;
 +                      *data |= 0xFFFF0000;
 +                      break;
 +              case 3:
 +                      *data = *((u16 *)xqspi->txbuf);
 +                      xqspi->txbuf += 2;
 +                      *data |= (*((u8 *)xqspi->txbuf) << 16);
 +                      xqspi->txbuf += 1;
 +                      *data |= 0xFF000000;
 +                      break;
 +              case 4:
 +#ifdef LINUX_ONLY_NOT_UBOOT
 +                      *data = *((u32 *)xqspi->txbuf);
 +#else
 +                      /* Can not assume word aligned buffer */
 +                      memcpy(data, xqspi->txbuf,  size);
 +#endif
 +                      xqspi->txbuf += 4;
 +                      break;
 +              default:
 +                      /* This will never execute */
 +                      break;
 +              }
 +      } else
 +              *data = 0;
 +
 +#ifdef DEBUG
 +      printf("%s data 0x%08x txbuf addr: 0x%08x size %d\n",
 +              __FUNCTION__, *data, (u32)xqspi->txbuf, size);
 +#endif
 +
 +      xqspi->bytes_to_transfer -= size;
 +      if (xqspi->bytes_to_transfer < 0) {
 +              xqspi->bytes_to_transfer = 0;
 +      }
 +}
 +
 +/**
 + * xqspips_chipselect - Select or deselect the chip select line
 + * @qspi:     Pointer to the spi_device structure
 + * @is_on:    Select(1) or deselect (0) the chip select line
 + **/
 +static void xqspips_chipselect(struct spi_device *qspi, int is_on)
 +{
 +      struct xqspips *xqspi = spi_master_get_devdata(qspi->master);
 +      u32 config_reg;
 +      unsigned long flags;
 +
 +#ifdef DEBUG
 +      printf("xqspips_chipselect: is_on: %d\n", is_on);
 +#endif
 +
 +      spin_lock_irqsave(&xqspi->config_reg_lock, flags);
 +
 +      config_reg = xqspips_read(xqspi->regs + XQSPIPSS_CONFIG_OFFSET);
 +
 +      if (is_on) {
 +              /* Select the slave */
 +              config_reg &= ~XQSPIPSS_CONFIG_SSCTRL_MASK;
 +              config_reg |= (((~(0x0001 << qspi->chip_select)) << 10) &
 +                              XQSPIPSS_CONFIG_SSCTRL_MASK);
 +      } else
 +              /* Deselect the slave */
 +              config_reg |= XQSPIPSS_CONFIG_SSCTRL_MASK;
 +
 +      xqspips_write(xqspi->regs + XQSPIPSS_CONFIG_OFFSET, config_reg);
 +
 +      spin_unlock_irqrestore(&xqspi->config_reg_lock, flags);
 +}
 +
 +/**
 + * xqspips_setup_transfer - Configure QSPI controller for specified transfer
 + * @qspi:     Pointer to the spi_device structure
 + * @transfer: Pointer to the spi_transfer structure which provides information
 + *            about next transfer setup parameters
 + *
 + * Sets the operational mode of QSPI controller for the next QSPI transfer and
 + * sets the requested clock frequency.
 + *
 + * returns:   0 on success and -EINVAL on invalid input parameter
 + *
 + * Note: If the requested frequency is not an exact match with what can be
 + * obtained using the prescalar value, the driver sets the clock frequency which
 + * is lower than the requested frequency (maximum lower) for the transfer. If
 + * the requested frequency is higher or lower than that is supported by the QSPI
 + * controller the driver will set the highest or lowest frequency supported by
 + * controller.
 + **/
 +int xqspips_setup_transfer(struct spi_device *qspi,
 +              struct spi_transfer *transfer)
 +{
 +      struct xqspips *xqspi = spi_master_get_devdata(qspi->master);
 +      u8 bits_per_word;
 +      u32 config_reg;
 +      u32 req_hz;
 +      u32 baud_rate_val = 0;
 +      unsigned long flags;
 +
 +#ifdef DEBUG
 +      printf("xqspips_setup_transfer: qspi: 0x%08x transfer: 0x%08x\n",
 +              (u32)qspi, (u32)transfer);
 +#endif
 +      bits_per_word = (transfer) ?
 +                      transfer->bits_per_word : qspi->bits_per_word;
 +      req_hz = (transfer) ? transfer->speed_hz : qspi->max_speed_hz;
 +
 +      if (qspi->mode & ~MODEBITS) {
 +              dev_err(&qspi->dev, "%s, unsupported mode bits %x\n",
 +                      __func__, qspi->mode & ~MODEBITS);
 +              return -EINVAL;
 +      }
 +
 +      if (bits_per_word != 32) {
 +              bits_per_word = 32;
 +      }
 +
 +      spin_lock_irqsave(&xqspi->config_reg_lock, flags);
 +
 +      config_reg = xqspips_read(xqspi->regs + XQSPIPSS_CONFIG_OFFSET);
 +
 +      /* Set the QSPI clock phase and clock polarity */
 +      config_reg &= (~XQSPIPSS_CONFIG_CPHA_MASK) &
 +                              (~XQSPIPSS_CONFIG_CPOL_MASK);
 +      if (qspi->mode & SPI_CPHA)
 +              config_reg |= XQSPIPSS_CONFIG_CPHA_MASK;
 +      if (qspi->mode & SPI_CPOL)
 +              config_reg |= XQSPIPSS_CONFIG_CPOL_MASK;
 +
 +      /* Set the clock frequency */
 +      if (xqspi->speed_hz != req_hz) {
 +              baud_rate_val = 0;
 +              while ((baud_rate_val < 8)  &&
 +                      (xqspi->input_clk_hz / (2 << baud_rate_val)) > req_hz) {
 +                              baud_rate_val++;
 +              }
 +              config_reg &= 0xFFFFFFC7;
 +              config_reg |= (baud_rate_val << 3);
 +              xqspi->speed_hz = req_hz;
 +      }
 +
 +      xqspips_write(xqspi->regs + XQSPIPSS_CONFIG_OFFSET, config_reg);
 +
 +      spin_unlock_irqrestore(&xqspi->config_reg_lock, flags);
 +
 +#ifdef DEBUG
 +      dev_dbg(&qspi->dev, "%s, mode %d, %u bits/w, %u clock speed\n",
 +              __func__, qspi->mode & MODEBITS, qspi->bits_per_word,
 +              xqspi->speed_hz);
 +#endif
 +
 +      return 0;
 +}
 +
 +#ifdef LINUX_ONLY_NOT_UBOOT
 +/**
 + * xqspips_setup - Configure the QSPI controller
 + * @qspi:     Pointer to the spi_device structure
 + *
 + * Sets the operational mode of QSPI controller for the next QSPI transfer, baud
 + * rate and divisor value to setup the requested qspi clock.
 + *
 + * returns:   0 on success and error value on failure
 + **/
 +static int xqspips_setup(struct spi_device *qspi)
 +{
 +
 +      if (qspi->mode & SPI_LSB_FIRST)
 +              return -EINVAL;
 +
 +      if (!qspi->max_speed_hz)
 +              return -EINVAL;
 +
 +      if (!qspi->bits_per_word)
 +              qspi->bits_per_word = 32;
 +
 +      return xqspips_setup_transfer(qspi, NULL);
 +}
 +#endif
 +
 +/**
 + * xqspips_fill_tx_fifo - Fills the TX FIFO with as many bytes as possible
 + * @xqspi:    Pointer to the xqspips structure
 + **/
 +static void xqspips_fill_tx_fifo(struct xqspips *xqspi)
 +{
 +      u32 data = 0;
 +
 +      while ((!(xqspips_read(xqspi->regs + XQSPIPSS_STATUS_OFFSET) &
 +              XQSPIPSS_IXR_TXFULL_MASK)) && (xqspi->bytes_to_transfer > 0)) {
 +              if (xqspi->bytes_to_transfer < 4) {
 +                      xqspips_copy_write_data(xqspi, &data,
 +                              xqspi->bytes_to_transfer);
 +              } else {
 +                      xqspips_copy_write_data(xqspi, &data, 4);
 +              }
 +
 +              xqspips_write(xqspi->regs + XQSPIPSS_TXD_00_00_OFFSET, data);
 +      }
 +}
 +
 +/**
 + * xqspips_irq - Interrupt service routine of the QSPI controller
 + * @irq:      IRQ number
 + * @dev_id:   Pointer to the xqspi structure
 + *
 + * This function handles TX empty and Mode Fault interrupts only.
 + * On TX empty interrupt this function reads the received data from RX FIFO and
 + * fills the TX FIFO if there is any data remaining to be transferred.
 + * On Mode Fault interrupt this function indicates that transfer is completed,
 + * the SPI subsystem will identify the error as the remaining bytes to be
 + * transferred is non-zero.
 + *
 + * returns:   IRQ_HANDLED always
 + **/
 +#ifdef LINUX_ONLY_NOT_UBOOT
 +static irqreturn_t xqspips_irq(int irq, void *dev_id)
 +{
 +      struct xqspips *xqspi = dev_id;
 +#else
 +static int xqspips_irq_poll(struct xqspips *xqspi)
 +{
 +      int max_loop;
 +#endif
 +      u32 intr_status;
 +
 +#ifdef DEBUG
 +      printf("xqspips_irq_poll: xqspi: 0x%08x\n",
 +              (u32)xqspi);
 +#endif
 +
 +#ifdef LINUX_ONLY_NOT_UBOOT
 +      intr_status = xqspips_read(xqspi->regs + XQSPIPSS_STATUS_OFFSET);
 +#else
 +      /* u-boot: Poll until any of the interrupt status bits are set */
 +      max_loop = 0;
 +      do {
 +              intr_status = xqspips_read(xqspi->regs +
 +                              XQSPIPSS_STATUS_OFFSET);
 +              max_loop ++;
 +      } while ((intr_status == 0) && (max_loop < 100000));
 +      if (intr_status == 0) {
 +              printf("xqspips_irq_poll: timeout\n");
 +              return 0;
 +      }
 +#endif
 +
 +      xqspips_write(xqspi->regs + XQSPIPSS_STATUS_OFFSET , intr_status);
 +#ifndef LINUX_ONLY_NOT_UBOOT
 +      /* u-boot: Disable all interrupts */
 +      xqspips_write(xqspi->regs + XQSPIPSS_IDIS_OFFSET,
 +                      XQSPIPSS_IXR_ALL_MASK);
 +#endif
 +      if ((intr_status & XQSPIPSS_IXR_TXNFULL_MASK) ||
 +                 (intr_status & XQSPIPSS_IXR_RXNEMTY_MASK)) {
 +              /* This bit is set when Tx FIFO has < THRESHOLD entries. We have
 +                 the THRESHOLD value set to 1, so this bit indicates Tx FIFO
 +                 is empty */
 +              u32 config_reg;
 +
 +              /* Read out the data from the RX FIFO */
 +              while (xqspips_read(xqspi->regs + XQSPIPSS_STATUS_OFFSET) &
 +                      XQSPIPSS_IXR_RXNEMTY_MASK) {
 +                      u32 data;
 +
 +                      data = xqspips_read(xqspi->regs + XQSPIPSS_RXD_OFFSET);
 +
 +                      if ((xqspi->inst_response) &&
 +                              (!((xqspi->curr_inst->opcode ==
 +                                      XQSPIPSS_FLASH_OPCODE_RDSR1) ||
 +                              (xqspi->curr_inst->opcode ==
 +                                      XQSPIPSS_FLASH_OPCODE_RDSR2)))) {
 +                              xqspi->inst_response = 0;
 +                              xqspips_copy_read_data(xqspi, data,
 +                                      xqspi->curr_inst->inst_size);
 +                      } else if (xqspi->bytes_to_receive < 4)
 +                              xqspips_copy_read_data(xqspi, data,
 +                                      xqspi->bytes_to_receive);
 +                      else
 +                              xqspips_copy_read_data(xqspi, data, 4);
 +              }
 +
 +              if (xqspi->bytes_to_transfer) {
 +                      /* There is more data to send */
 +                      xqspips_fill_tx_fifo(xqspi);
 +
 +                      xqspips_write(xqspi->regs + XQSPIPSS_IEN_OFFSET,
 +                                      XQSPIPSS_IXR_ALL_MASK);
 +
 +                      spin_lock(&xqspi->config_reg_lock);
 +                      config_reg = xqspips_read(xqspi->regs +
 +                                              XQSPIPSS_CONFIG_OFFSET);
 +
 +                      config_reg |= XQSPIPSS_CONFIG_MANSRT_MASK;
 +                      xqspips_write(xqspi->regs + XQSPIPSS_CONFIG_OFFSET,
 +                              config_reg);
 +                      spin_unlock(&xqspi->config_reg_lock);
 +              } else {
 +                      /* If transfer and receive is completed then only send
 +                       * complete signal */
 +                      if (!xqspi->bytes_to_receive) {
 +#ifdef LINUX_ONLY_NOT_UBOOT
 +                              complete(&xqspi->done);
 +#else
 +                              /* u-boot: return "operation complete" */
 +                              xqspips_write(xqspi->regs +
 +                                      XQSPIPSS_IDIS_OFFSET,
 +                                      XQSPIPSS_IXR_ALL_MASK);
 +                              return 1;
 +#endif
 +                      }
 +              }
 +      }
 +
 +#ifdef LINUX_ONLY_NOT_UBOOT
 +      return IRQ_HANDLED;
 +#else
 +      /* u-boot: Transfer not complete */
 +      return 0;
 +#endif
 +}
 +
 +/**
 + * xqspips_start_transfer - Initiates the QSPI transfer
 + * @qspi:     Pointer to the spi_device structure
 + * @transfer: Pointer to the spi_transfer structure which provide information
 + *            about next transfer parameters
 + *
 + * This function fills the TX FIFO, starts the QSPI transfer, and waits for the
 + * transfer to be completed.
 + *
 + * returns:   Number of bytes transferred in the last transfer
 + **/
 +static int xqspips_start_transfer(struct spi_device *qspi,
 +                      struct spi_transfer *transfer)
 +{
 +      struct xqspips *xqspi = spi_master_get_devdata(qspi->master);
 +      u32 config_reg;
 +      unsigned long flags;
 +      u32 data = 0;
 +      u8 instruction = 0;
 +      u8 index;
 +#ifdef HACK_WRITE_NO_DELAY
 +      static bool no_delay = 0;
 +#endif
 +
 +#ifdef DEBUG
 +      printf("%s: qspi: 0x%08x transfer: 0x%08x len: %d\n",
 +              __func__, (u32)qspi, (u32)transfer, transfer->len);
 +#endif
 +
 +      xqspi->txbuf = transfer->tx_buf;
 +      xqspi->rxbuf = transfer->rx_buf;
 +      xqspi->bytes_to_transfer = transfer->len;
 +      xqspi->bytes_to_receive = transfer->len;
 +
 +#ifdef HACK_WRITE_NO_DELAY
 +      if (no_delay) {
 +              /* Indicates Page programm command + address is already in Tx
 +               * FIFO. We need to receive extra 4 bytes for command + address
 +               */
 +              xqspi->bytes_to_receive += 4;
 +              no_delay = 0;
 +      }
 +#endif
 +
 +      if (xqspi->txbuf)
 +              instruction = *(u8 *)xqspi->txbuf;
 +
 +      if (instruction && xqspi->is_inst) {
 +              for (index = 0 ; index < ARRAY_SIZE(flash_inst); index++)
 +                      if (instruction == flash_inst[index].opcode)
 +                              break;
 +
 +              /* Instruction might have already been transmitted. This is a
 +               * 'data only' transfer */
 +              if (index == ARRAY_SIZE(flash_inst))
 +                      goto xfer_data;
 +
 +              xqspi->curr_inst = &flash_inst[index];
 +              xqspi->inst_response = 1;
 +
 +              /* In case of dual memories, convert 25 bit address to 24 bit
 +               * address before transmitting to the 2 memories
 +               */
 +              if ((xqspi->is_dual == 1) &&
 +                  ((instruction == XQSPIPSS_FLASH_OPCODE_PP) ||
 +                  (instruction == XQSPIPSS_FLASH_OPCODE_SE) ||
 +                  (instruction == XQSPIPSS_FLASH_OPCODE_BE_32K) ||
 +                  (instruction == XQSPIPSS_FLASH_OPCODE_BE_4K) ||
 +                  (instruction == XQSPIPSS_FLASH_OPCODE_BE) ||
 +                  (instruction == XQSPIPSS_FLASH_OPCODE_NORM_READ) ||
 +                  (instruction == XQSPIPSS_FLASH_OPCODE_FAST_READ) ||
 +                  (instruction == XQSPIPSS_FLASH_OPCODE_DUAL_READ) ||
 +                  (instruction == XQSPIPSS_FLASH_OPCODE_QUAD_READ))) {
 +
 +                      u8 *ptr = (u8*) (xqspi->txbuf);
 +                      data = ((u32) ptr[1] << 24) | ((u32) ptr[2] << 16) |
 +                              ((u32) ptr[3] << 8) | ((u32) ptr[4]);
 +                      data = data/2;
 +                      ptr[1] = (u8) (data >> 16);
 +                      ptr[2] = (u8) (data >> 8);
 +                      ptr[3] = (u8) (data);
 +                      xqspi->bytes_to_transfer -= 1;
 +                      xqspi->bytes_to_receive -= 1;
 +              }
 +
 +              /* Get the instruction */
 +              data = 0;
 +              xqspips_copy_write_data(xqspi, &data,
 +                      xqspi->curr_inst->inst_size);
 +
 +              /* Write the instruction to LSB of the FIFO. The core is
 +               * designed such that it is not necessary to check whether the
 +               * write FIFO is full before writing. However, write would be
 +               * delayed if the user tries to write when write FIFO is full
 +               */
 +              xqspips_write(xqspi->regs + xqspi->curr_inst->offset, data);
 +
 +#ifdef HACK_WRITE_NO_DELAY
 +              if (xqspi->curr_inst->opcode == XQSPIPSS_FLASH_OPCODE_PP) {
 +                      /* Write instruction + address to the Tx FIFO, but do
 +                       * not start transmission yet. Wait for the next
 +                       * spi_message with data, and start transmission after
 +                       * data is filled into the FIFO
 +                       */
 +                      no_delay = 1;
 +                      return (transfer->len);
 +              }
 +#endif
 +
 +              /* Read status register and Read ID instructions don't require
 +               * to ignore the extra bytes in response of instruction as
 +               * response contains the value */
 +              if ((instruction == XQSPIPSS_FLASH_OPCODE_RDSR1) ||
 +                      (instruction == XQSPIPSS_FLASH_OPCODE_RDSR2) ||
 +                      (instruction == XQSPIPSS_FLASH_OPCODE_RDID)) {
 +                      if (xqspi->bytes_to_transfer < 4)
 +                              xqspi->bytes_to_transfer = 0;
 +                      else
 +                              xqspi->bytes_to_transfer -= 3;
 +              }
 +      }
 +
 +xfer_data:
 +      INIT_COMPLETION(xqspi->done);
 +
 +      /* In case of Fast, Dual and Quad reads, transmit the instruction first.
 +       * Address and dummy byte should be transmitted after instruction
 +       * is transmitted */
 +      if (((xqspi->is_inst == 0) && (xqspi->bytes_to_transfer)) ||
 +           ((xqspi->bytes_to_transfer) &&
 +            (instruction != XQSPIPSS_FLASH_OPCODE_FAST_READ) &&
 +            (instruction != XQSPIPSS_FLASH_OPCODE_DUAL_READ) &&
 +            (instruction != XQSPIPSS_FLASH_OPCODE_QUAD_READ)))
 +              xqspips_fill_tx_fifo(xqspi);
 +      xqspips_write(xqspi->regs + XQSPIPSS_IEN_OFFSET,
 +                      XQSPIPSS_IXR_ALL_MASK);
 +      /* Start the transfer by enabling manual start bit */
 +      spin_lock_irqsave(&xqspi->config_reg_lock, flags);
 +      config_reg = xqspips_read(xqspi->regs +
 +                      XQSPIPSS_CONFIG_OFFSET) | XQSPIPSS_CONFIG_MANSRT_MASK;
 +      xqspips_write(xqspi->regs + XQSPIPSS_CONFIG_OFFSET, config_reg);
 +      spin_unlock_irqrestore(&xqspi->config_reg_lock, flags);
 +
 +      wait_for_completion(&xqspi->done);
 +
 +      return (transfer->len) - (xqspi->bytes_to_transfer);
 +}
 +
 +#ifdef LINUX_ONLY_NOT_UBOOT
 +/**
 + * xqspips_work_queue - Get the request from queue to perform transfers
 + * @work:     Pointer to the work_struct structure
 + **/
 +static void xqspips_work_queue(struct work_struct *work)
 +#else
 +int
 +xqspips_transfer(struct spi_device *qspi, struct spi_transfer *transfer)
 +#endif
 +{
 +#ifdef LINUX_ONLY_NOT_UBOOT
 +      struct xqspips *xqspi = container_of(work, struct xqspips, work);
 +#else
 +      struct xqspips *xqspi = spi_master_get_devdata(qspi->master);
 +#endif
 +      unsigned long flags;
 +
 +      spin_lock_irqsave(&xqspi->trans_queue_lock, flags);
 +      xqspi->dev_busy = 1;
 +
 +#ifdef DEBUG
 +      printf("xqspips_transfer\n");
 +#endif
 +
 +#ifdef LINUX_ONLY_NOT_UBOOT
 +      /* Check if list is empty or queue is stoped */
 +      if (list_empty(&xqspi->queue) ||
 +              xqspi->queue_state == XQSPIPSS_QUEUE_STOPPED) {
 +              xqspi->dev_busy = 0;
 +              spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags);
 +              return;
 +      }
 +#endif
 +
 +#ifdef LINUX_ONLY_NOT_UBOOT
 +      /* Keep requesting transfer till list is empty */
 +      while (!list_empty(&xqspi->queue)) {
 +              struct spi_message *msg;
 +              struct spi_device *qspi;
 +              struct spi_transfer *transfer = NULL;
 +              unsigned cs_change = 1;
 +              int status = 0;
 +
 +              msg = container_of(xqspi->queue.next, struct spi_message,
 +                                      queue);
 +              list_del_init(&msg->queue);
 +              spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags);
 +              qspi = msg->spi;
 +              xqspi->is_inst = 1;
 +
 +              list_for_each_entry(transfer, &msg->transfers, transfer_list) {
 +#else
 +      {
 +              unsigned cs_change = 1;
 +              int status = 0;
 +
 +              while (1) {
 +#endif
 +                      if (transfer->bits_per_word || transfer->speed_hz) {
 +                              status =
 +                                      xqspips_setup_transfer(qspi, transfer);
 +                              if (status < 0)
 +                                      break;
 +                      }
 +
 +                      /* Select the chip if required */
 +                      if (cs_change)
 +                              xqspips_chipselect(qspi, 1);
 +
 +                      cs_change = transfer->cs_change;
 +
 +                      if (!transfer->tx_buf && !transfer->rx_buf &&
 +                              transfer->len) {
 +                              status = -EINVAL;
 +                              break;
 +                      }
 +
 +                      /* Request the transfer */
 +                      if (transfer->len) {
 +                              status =
 +                                      xqspips_start_transfer(qspi, transfer);
 +                              xqspi->is_inst = 0;
 +                      }
 +
 +                      if (status != transfer->len) {
 +                              if (status > 0)
 +                                      status = -EMSGSIZE;
 +                              break;
 +                      }
 +#ifdef LINUX_ONLY_NOT_UBOOT
 +                      msg->actual_length += status;
 +#endif
 +                      status = 0;
 +
 +                      if (transfer->delay_usecs)
 +                              udelay(transfer->delay_usecs);
 +
 +                      if (cs_change)
 +                              /* Deselect the chip */
 +                              xqspips_chipselect(qspi, 0);
 +
 +#ifdef LINUX_ONLY_NOT_UBOOT
 +                      if (transfer->transfer_list.next == &msg->transfers)
 +                              break;
 +              }
 +
 +              msg->status = status;
 +              msg->complete(msg->context);
 +#else
 +                      break;
 +              }
 +#endif
 +
 +              xqspips_setup_transfer(qspi, NULL);
 +
 +#ifdef LINUX_ONLY_NOT_UBOOT
 +              if (!(status == 0 && cs_change))
 +                      xqspips_chipselect(qspi, 0);
 +#endif
 +
 +              spin_lock_irqsave(&xqspi->trans_queue_lock, flags);
 +      }
 +
 +      xqspi->dev_busy = 0;
 +      spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags);
 +
 +#ifndef LINUX_ONLY_NOT_UBOOT
 +      return 0;
 +#endif
 +}
 +
 +#ifdef LINUX_ONLY_NOT_UBOOT
 +/**
 + * xqspips_transfer - Add a new transfer request at the tail of work queue
 + * @qspi:     Pointer to the spi_device structure
 + * @message:  Pointer to the spi_transfer structure which provides information
 + *            about next transfer parameters
 + *
 + * returns:   0 on success, -EINVAL on invalid input parameter and
 + *            -ESHUTDOWN if queue is stopped by module unload function
 + **/
 +static int
 +xqspips_transfer(struct spi_device *qspi, struct spi_message *message)
 +{
 +      struct xqspips *xqspi = spi_master_get_devdata(qspi->master);
 +      struct spi_transfer *transfer;
 +      unsigned long flags;
 +
 +      if (xqspi->queue_state == XQSPIPSS_QUEUE_STOPPED)
 +              return -ESHUTDOWN;
 +
 +      message->actual_length = 0;
 +      message->status = -EINPROGRESS;
 +
 +      /* Check each transfer's parameters */
 +      list_for_each_entry(transfer, &message->transfers, transfer_list) {
 +              u8 bits_per_word =
 +                      transfer->bits_per_word ? : qspi->bits_per_word;
 +
 +              bits_per_word = bits_per_word ? : 32;
 +              if (!transfer->tx_buf && !transfer->rx_buf && transfer->len)
 +                      return -EINVAL;
 +              /* QSPI controller supports only 32 bit transfers whereas higher
 +               * layer drivers request 8 bit transfers. Re-visit at a later
 +               * time */
 +              /* if (bits_per_word != 32)
 +                      return -EINVAL; */
 +      }
 +
 +      spin_lock_irqsave(&xqspi->trans_queue_lock, flags);
 +      list_add_tail(&message->queue, &xqspi->queue);
 +      if (!xqspi->dev_busy)
 +              queue_work(xqspi->workqueue, &xqspi->work);
 +      spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags);
 +
 +      return 0;
 +}
 +
 +/**
 + * xqspips_start_queue - Starts the queue of the QSPI driver
 + * @xqspi:    Pointer to the xqspips structure
 + *
 + * returns:   0 on success and -EBUSY if queue is already running or device is
 + *            busy
 + **/
 +static inline int xqspips_start_queue(struct xqspips *xqspi)
 +{
 +      unsigned long flags;
 +
 +      spin_lock_irqsave(&xqspi->trans_queue_lock, flags);
 +
 +      if (xqspi->queue_state == XQSPIPSS_QUEUE_RUNNING || xqspi->dev_busy) {
 +              spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags);
 +              return -EBUSY;
 +      }
 +
 +      xqspi->queue_state = XQSPIPSS_QUEUE_RUNNING;
 +      spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags);
 +
 +      return 0;
 +}
 +
 +/**
 + * xqspips_stop_queue - Stops the queue of the QSPI driver
 + * @xqspi:    Pointer to the xqspips structure
 + *
 + * This function waits till queue is empty and then stops the queue.
 + * Maximum time out is set to 5 seconds.
 + *
 + * returns:   0 on success and -EBUSY if queue is not empty or device is busy
 + **/
 +static inline int xqspips_stop_queue(struct xqspips *xqspi)
 +{
 +      unsigned long flags;
 +      unsigned limit = 500;
 +      int ret = 0;
 +
 +      if (xqspi->queue_state != XQSPIPSS_QUEUE_RUNNING)
 +              return ret;
 +
 +      spin_lock_irqsave(&xqspi->trans_queue_lock, flags);
 +
 +      while ((!list_empty(&xqspi->queue) || xqspi->dev_busy) && limit--) {
 +              spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags);
 +              msleep(10);
 +              spin_lock_irqsave(&xqspi->trans_queue_lock, flags);
 +      }
 +
 +      if (!list_empty(&xqspi->queue) || xqspi->dev_busy)
 +              ret = -EBUSY;
 +
 +      if (ret == 0)
 +              xqspi->queue_state = XQSPIPSS_QUEUE_STOPPED;
 +
 +      spin_unlock_irqrestore(&xqspi->trans_queue_lock, flags);
 +
 +      return ret;
 +}
 +
 +/**
 + * xqspips_destroy_queue - Destroys the queue of the QSPI driver
 + * @xqspi:    Pointer to the xqspips structure
 + *
 + * returns:   0 on success and error value on failure
 + **/
 +static inline int xqspips_destroy_queue(struct xqspips *xqspi)
 +{
 +      int ret;
 +
 +      ret = xqspips_stop_queue(xqspi);
 +      if (ret != 0)
 +              return ret;
 +
 +      destroy_workqueue(xqspi->workqueue);
 +
 +      return 0;
 +}
 +
 +/**
 + * xqspips_probe - Probe method for the QSPI driver
 + * @dev:      Pointer to the platform_device structure
 + *
 + * This function initializes the driver data structures and the hardware.
 + *
 + * returns:   0 on success and error value on failure
 + **/
 +static int __devinit xqspips_probe(struct platform_device *dev)
 +{
 +      int ret = 0;
 +      struct spi_master *master;
 +      struct xqspips *xqspi;
 +      struct resource *r;
 +      struct xspi_platform_data *platform_info;
 +
 +      master = spi_alloc_master(&dev->dev, sizeof(struct xqspips));
 +      if (master == NULL)
 +              return -ENOMEM;
 +
 +      xqspi = spi_master_get_devdata(master);
 +      platform_set_drvdata(dev, master);
 +
 +      platform_info = dev->dev.platform_data;
 +      if (platform_info == NULL) {
 +              ret = -ENODEV;
 +              dev_err(&dev->dev, "platform data not available\n");
 +              goto put_master;
 +      }
 +
 +      r = platform_get_resource(dev, IORESOURCE_MEM, 0);
 +      if (r == NULL) {
 +              ret = -ENODEV;
 +              dev_err(&dev->dev, "platform_get_resource failed\n");
 +              goto put_master;
 +      }
 +
 +      if (!request_mem_region(r->start,
 +                      r->end - r->start + 1, dev->name)) {
 +              ret = -ENXIO;
 +              dev_err(&dev->dev, "request_mem_region failed\n");
 +              goto put_master;
 +      }
 +
 +      xqspi->regs = ioremap(r->start, r->end - r->start + 1);
 +      if (xqspi->regs == NULL) {
 +              ret = -ENOMEM;
 +              dev_err(&dev->dev, "ioremap failed\n");
 +              goto release_mem;
 +      }
 +
 +      xqspi->irq = platform_get_irq(dev, 0);
 +      if (xqspi->irq < 0) {
 +              ret = -ENXIO;
 +              dev_err(&dev->dev, "irq resource not found\n");
 +              goto unmap_io;
 +      }
 +
 +      ret = request_irq(xqspi->irq, xqspips_irq, 0, dev->name, xqspi);
 +      if (ret != 0) {
 +              ret = -ENXIO;
 +              dev_err(&dev->dev, "request_irq failed\n");
 +              goto unmap_io;
 +      }
 +
 +      /* QSPI controller initializations */
 +      xqspips_init_hw(xqspi->regs);
 +
 +      init_completion(&xqspi->done);
 +      master->bus_num = platform_info->bus_num;
 +      master->num_chipselect = platform_info->num_chipselect;
 +      master->setup = xqspips_setup;
 +      master->transfer = xqspips_transfer;
 +      xqspi->input_clk_hz = platform_info->speed_hz;
 +      xqspi->speed_hz = platform_info->speed_hz / 2;
 +      xqspi->dev_busy = 0;
 +
 +      INIT_LIST_HEAD(&xqspi->queue);
 +      spin_lock_init(&xqspi->trans_queue_lock);
 +      spin_lock_init(&xqspi->config_reg_lock);
 +
 +      xqspi->queue_state = XQSPIPSS_QUEUE_STOPPED;
 +      xqspi->dev_busy = 0;
 +
 +      INIT_WORK(&xqspi->work, xqspips_work_queue);
 +      xqspi->workqueue =
 +              create_singlethread_workqueue(dev_name(&master->dev));
 +      if (!xqspi->workqueue) {
 +              ret = -ENOMEM;
 +              dev_err(&dev->dev, "problem initializing queue\n");
 +              goto free_irq;
 +      }
 +
 +      ret = xqspips_start_queue(xqspi);
 +      if (ret != 0) {
 +              dev_err(&dev->dev, "problem starting queue\n");
 +              goto remove_queue;
 +      }
 +
 +      ret = spi_register_master(master);
 +      if (ret) {
 +              dev_err(&dev->dev, "spi_register_master failed\n");
 +              goto remove_queue;
 +      }
 +
 +      dev_info(&dev->dev, "at 0x%08X mapped to 0x%08X, irq=%d\n", r->start,
 +               (u32 __force)xqspi->regs, xqspi->irq);
 +
 +      return ret;
 +
 +remove_queue:
 +      (void)xqspips_destroy_queue(xqspi);
 +free_irq:
 +      free_irq(xqspi->irq, xqspi);
 +unmap_io:
 +      iounmap(xqspi->regs);
 +release_mem:
 +      release_mem_region(r->start, r->end - r->start + 1);
 +put_master:
 +      platform_set_drvdata(dev, NULL);
 +      spi_master_put(master);
 +      return ret;
 +}
 +
 +/**
 + * xqspips_remove - Remove method for the QSPI driver
 + * @dev:      Pointer to the platform_device structure
 + *
 + * This function is called if a device is physically removed from the system or
 + * if the driver module is being unloaded. It frees all resources allocated to
 + * the device.
 + *
 + * returns:   0 on success and error value on failure
 + **/
 +static int __devexit xqspips_remove(struct platform_device *dev)
 +{
 +      struct spi_master *master = platform_get_drvdata(dev);
 +      struct xqspips *xqspi = spi_master_get_devdata(master);
 +      struct resource *r;
 +      int ret = 0;
 +
 +      r = platform_get_resource(dev, IORESOURCE_MEM, 0);
 +      if (r == NULL) {
 +              dev_err(&dev->dev, "platform_get_resource failed\n");
 +              return -ENODEV;
 +      }
 +
 +      ret = xqspips_destroy_queue(xqspi);
 +      if (ret != 0)
 +              return ret;
 +
 +      xqspips_write(xqspi->regs + XQSPIPSS_ENABLE_OFFSET,
 +                      ~XQSPIPSS_ENABLE_ENABLE_MASK);
 +
 +      free_irq(xqspi->irq, xqspi);
 +      iounmap(xqspi->regs);
 +      release_mem_region(r->start, r->end - r->start + 1);
 +
 +      spi_unregister_master(master);
 +      spi_master_put(master);
 +
 +      /* Prevent double remove */
 +      platform_set_drvdata(dev, NULL);
 +
 +      dev_dbg(&dev->dev, "remove succeeded\n");
 +      return 0;
 +}
 +
 +/* Work with hotplug and coldplug */
 +MODULE_ALIAS("platform:" DRIVER_NAME);
 +
 +/*
 + * xqspips_driver - This structure defines the QSPI platform driver
 + */
 +static struct platform_driver xqspips_driver = {
 +      .probe  = xqspips_probe,
 +      .remove = __devexit_p(xqspips_remove),
 +      .suspend = NULL,
 +      .resume = NULL,
 +      .driver = {
 +              .name = DRIVER_NAME,
 +              .owner = THIS_MODULE,
 +      },
 +};
 +
 +/**
 + * xqspips_init - QSPI driver module initialization function
 + *
 + * returns:   0 on success and error value on failure
 + **/
 +static int __init xqspips_init(void)
 +{
 +      return platform_driver_register(&xqspips_driver);
 +}
 +
 +module_init(xqspips_init);
 +
 +/**
 + * xqspips_exit - QSPI driver module exit function
 + **/
 +static void __exit xqspips_exit(void)
 +{
 +      platform_driver_unregister(&xqspips_driver);
 +}
 +
 +module_exit(xqspips_exit);
 +
 +MODULE_AUTHOR("Xilinx, Inc.");
 +MODULE_DESCRIPTION("Xilinx PSS QSPI driver");
 +MODULE_LICENSE("GPL");
 +
 +#endif
 +
 +/**
 + * xqspips_check_is_dual_flash - checking for dual or single qspi
 + *
 + * This function will check the type of the flash whether it supports
 + * single or dual qspi based on the MIO configuration done by FSBL.
 + *
 + * User needs to correctly configure the MIO's based on the
 + * number of qspi flashes present on the board.
 + *
 + * function will return -1, if there is no MIO configuration for
 + * qspi flash.
 + *
 + * @regs_base:        base address of SLCR
 + */
 +
 +int xqspips_check_is_dual_flash(void __iomem *regs_base)
 +{
 +      int is_dual = -1, lower_mio = 0, upper_mio = 0, val;
 +      u16 mask = 3, type = 2;
 +      u32 mio_base, mio_pin_index;
 +
 +#ifdef CONFIG_EP107
 +#ifdef CONFIG_XILINX_PSS_QSPI_USE_DUAL_FLASH
 +      is_dual = 1;
 +#else
 +      is_dual = 0;
 +#endif
 +      return is_dual;
 +#endif
 +
 +      mio_base = regs_base + 0x700;
 +
 +      /* checking single QSPI MIO's */
 +      for (mio_pin_index = 2; mio_pin_index < 7; mio_pin_index++) {
 +              val = xqspips_read(mio_base + 4 * mio_pin_index);
 +              if ((val & mask) == type)
 +                      lower_mio++;
 +      }
 +
 +      /* checking dual QSPI MIO's */
 +      for (mio_pin_index = 8; mio_pin_index < 14; mio_pin_index++) {
 +              val = xqspips_read(mio_base + 4 * mio_pin_index);
 +              if ((val & mask) == type)
 +                      upper_mio++;
 +      }
 +
 +      if ((lower_mio == 5) && (upper_mio == 6))
 +              is_dual = 1;
 +      else if (lower_mio == 5)
 +              is_dual = 0;
 +
 +      return is_dual;
 +}
 +
 +/**
 + * xqspips_write_quad_bit - Write 1 to QUAD bit on flash
 + *
 + * This function will write a 1 to quad bit in flash
 + * using QSPI controller and supports only spansion flash.
 + *
 + * @regs_base:  base address of QSPI controller
 + */
 +void xqspips_write_quad_bit(void __iomem *regs_base)
 +{
 +      u32 config_reg, intr_status;
 +
 +      /* enable the QSPI controller */
 +      xqspips_write(regs_base + XQSPIPSS_ENABLE_OFFSET,
 +                      XQSPIPSS_ENABLE_ENABLE_MASK);
 +
 +      /* Write QUAD bit with 3-byte instruction */
 +      xqspips_write(regs_base + XQSPIPSS_TXD_00_11_OFFSET, 0x20001);
 +
 +      /* Enable manual start command */
 +      config_reg = xqspips_read(regs_base +
 +              XQSPIPSS_CONFIG_OFFSET) | XQSPIPSS_CONFIG_MANSRT_MASK;
 +      xqspips_write(regs_base + XQSPIPSS_CONFIG_OFFSET, config_reg);
 +
 +      /* Wait for the transfer to finish by polling Tx fifo status */
 +      do {
 +              intr_status = xqspips_read(regs_base +
 +                      XQSPIPSS_STATUS_OFFSET);
 +      } while ((intr_status & 0x04) == 0);
 +
 +      /* Read data receive register */
 +      config_reg = xqspips_read(regs_base + XQSPIPSS_RXD_OFFSET);
 +}
Simple merge
index 96fa819f8d177d7cb586751d24b4eba076263e80,f63e04b634d0195313e96801a645653e118ea71c..a6e222108c78653e3cc2e5f34ffa4c92e2029a79
@@@ -205,11 -204,9 +207,8 @@@ typedef enum 
  #define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG))
  #define NAND_HAS_COPYBACK(chip) ((chip->options & NAND_COPYBACK))
  /* Large page NAND with SOFT_ECC should support subpage reads */
 -#define NAND_SUBPAGE_READ(chip) ((chip->ecc.mode == NAND_ECC_SOFT) \
 -                                      && (chip->page_shift > 9))
 +#define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ))
  
- /* Mask to zero out the chip options, which come from the id table */
- #define NAND_CHIPOPTIONS_MSK  (0x0000efff & ~NAND_NO_AUTOINCR)
  /* Non chip related options */
  /*
   * Use a flash based bad block table. OOB identifier is saved in OOB area.