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)
--- /dev/null
- #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;
+}
#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;
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;
}
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;
}
.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;
}
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)
--- /dev/null
- #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);
+}
#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.