From: Michal Simek Date: Mon, 24 Sep 2012 06:54:02 +0000 (+0200) Subject: Merge branch 'v2012.10-rc1' into master X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4180b5cf1d2c17388b42be4e9f49343d335408ed;p=thirdparty%2Fu-boot.git Merge branch 'v2012.10-rc1' into master --- 4180b5cf1d2c17388b42be4e9f49343d335408ed diff --cc Makefile index eb37ea19fad,e3a27c62493..e3a27c62493 mode 100755,100644..100755 --- a/Makefile +++ b/Makefile diff --cc drivers/mtd/nand/Makefile index 4d2caccdf73,beb99cacb66..6e932024db8 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@@ -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) diff --cc drivers/mtd/nand/zynq_nand.c index c78f140933a,00000000000..bd801673749 mode 100644,000000..100644 --- a/drivers/mtd/nand/zynq_nand.c +++ b/drivers/mtd/nand/zynq_nand.c @@@ -1,1203 -1,0 +1,1203 @@@ +/* + * 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 +#include + +#include +#include - #include ++//#include +#include +#include +#include +#include +#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; +} diff --cc drivers/mtd/spi/spansion.c index b23e04f2fb0,32b76e0e907..335b5140def --- a/drivers/mtd/spi/spansion.c +++ b/drivers/mtd/spi/spansion.c @@@ -31,23 -31,6 +31,12 @@@ #include "spi_flash_internal.h" +/* 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 */ + - #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 - 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; } diff --cc drivers/mtd/spi/stmicro.c index 7c10d4e426f,30b626a39f8..81d2f8583fd --- a/drivers/mtd/spi/stmicro.c +++ b/drivers/mtd/spi/stmicro.c @@@ -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; } diff --cc drivers/mtd/spi/winbond.c index d1d2cdf984d,f6aab3d32f4..3ddd057009b --- a/drivers/mtd/spi/winbond.c +++ b/drivers/mtd/spi/winbond.c @@@ -95,24 -62,13 +62,18 @@@ static const struct winbond_spi_flash_p .nr_blocks = 256, .name = "W25Q128", }, + { + .id = 0x5014, + .nr_blocks = 128, + .name = "W25Q80", + }, + { + .id = 0x6017, - .l2_page_size = 8, - .pages_per_sector = 16, - .sectors_per_block = 16, + .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; @@@ -141,27 -96,12 +101,20 @@@ 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; } diff --cc drivers/spi/Makefile index 4c21efa3f21,f0b82c67f5b..2fd98df6b5b --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@@ -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) diff --cc drivers/spi/zynq_qspi.c index 77bc9b7f229,00000000000..408caa99581 mode 100755,000000..100755 --- a/drivers/spi/zynq_qspi.c +++ b/drivers/spi/zynq_qspi.c @@@ -1,1454 -1,0 +1,1454 @@@ +/* + * (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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#else + +#include "xbasic_types.h" +#include +#include + - #include ++//#include +#include +#include + +#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); +} diff --cc include/linux/mtd/nand.h index 96fa819f8d1,f63e04b634d..a6e222108c7 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@@ -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.