diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-22 12:00:44 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-22 12:00:44 -0700 |
commit | a62d016cece2fce1d5e4eedf36b17f03a7a5c78e (patch) | |
tree | ac37b4835be5f4fe0e04611fdb40c85abb98ec78 /drivers/mtd/nand | |
parent | 7c034dfd58bbc056280262887acf5b7a98944d0a (diff) | |
parent | 3e550d2396d9deef77328237ed992e19dcfefca5 (diff) | |
download | op-kernel-dev-a62d016cece2fce1d5e4eedf36b17f03a7a5c78e.zip op-kernel-dev-a62d016cece2fce1d5e4eedf36b17f03a7a5c78e.tar.gz |
Merge tag 'for-linus-20150422' of git://git.infradead.org/linux-mtd
Pull MTD updates from Brian Norris:
"Common MTD:
- Add Kconfig option for keeping both the 'master' and 'partition'
MTDs registered as devices. This would really make a better
default if we could do it over, as it allows a lot more flexibility
in (1) determining the flash topology of the system from user-space
and (2) adding temporary partitions at runtime (ioctl(BLKPG)).
Unfortunately, this would possibly cause user-space breakage, as it
will cause renumbering of the /dev/mtdX devices. We'll see if we
can change this in the future, as there have already been a few
people looking for this feature, and I know others have just been
working around our current limitations instead of fixing them this
way.
- Along with the previous change, add some additional information to
sysfs, so user-space can read the offset of each partition within
its master device
SPI NOR:
- add new device tree compatible binding to represent the
mostly-compatible class of SPI NOR flash which can be detected by
their extended JEDEC ID bytes, cutting down the duplication of our
ID tables
- misc. new IDs
Various other miscellaneous fixes and changes"
* tag 'for-linus-20150422' of git://git.infradead.org/linux-mtd: (53 commits)
mtd: spi-nor: Add support for Macronix mx25u6435f serial flash
mtd: spi-nor: Add support for Winbond w25q64dw serial flash
mtd: spi-nor: add support for the Winbond W25X05 flash
mtd: spi-nor: support en25s64 device
mtd: m25p80: bind to "nor-jedec" ID, for auto-detection
Documentation: devicetree: m25p80: add "nor-jedec" binding
mtd: Make MTD tests cancelable
mtd: mtd_oobtest: Fix bitflip_limit usage in test case 3
mtd: docg3: remove invalid __exit annotations
mtd: fsl_ifc_nand: use msecs_to_jiffies for time conversion
mtd: atmel_nand: don't map the ROM table if no pmecc table offset in DT
mtd: atmel_nand: add a definition for the oob reserved bytes
mtd: part: Remove partition overlap checks
mtd: part: Add sysfs variable for offset of partition
mtd: part: Create the master device node when partitioned
mtd: ts5500_flash: Fix typo in MODULE_DESCRIPTION in ts5500_flash.c
mtd: denali: Disable sub-page writes in Denali NAND driver
mtd: pxa3xx_nand: cleanup wait_for_completion handling
mtd: nand: gpmi: Check for scan_bbt() error
mtd: nand: gpmi: fixup return type of wait_for_completion_timeout
...
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r-- | drivers/mtd/nand/atmel_nand.c | 26 | ||||
-rw-r--r-- | drivers/mtd/nand/atmel_nand_ecc.h | 3 | ||||
-rw-r--r-- | drivers/mtd/nand/atmel_nand_nfc.h | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/denali.c | 6 | ||||
-rw-r--r-- | drivers/mtd/nand/fsl_ifc_nand.c | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/fsmc_nand.c | 7 | ||||
-rw-r--r-- | drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 16 | ||||
-rw-r--r-- | drivers/mtd/nand/mxc_nand.c | 146 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 41 | ||||
-rw-r--r-- | drivers/mtd/nand/pxa3xx_nand.c | 48 | ||||
-rw-r--r-- | drivers/mtd/nand/s3c2410.c | 3 |
11 files changed, 191 insertions, 110 deletions
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index d93c849..46010bd 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -485,7 +485,7 @@ static void pmecc_config_ecc_layout(struct nand_ecclayout *layout, for (i = 0; i < ecc_len; i++) layout->eccpos[i] = oobsize - ecc_len + i; - layout->oobfree[0].offset = 2; + layout->oobfree[0].offset = PMECC_OOB_RESERVED_BYTES; layout->oobfree[0].length = oobsize - ecc_len - layout->oobfree[0].offset; } @@ -1204,14 +1204,14 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, goto err; } - regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); - host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom); - if (IS_ERR(host->pmecc_rom_base)) { - if (!host->has_no_lookup_table) - /* Don't display the information again */ + if (!host->has_no_lookup_table) { + regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); + host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, + regs_rom); + if (IS_ERR(host->pmecc_rom_base)) { dev_err(host->dev, "Can not get I/O resource for ROM, will build a lookup table in runtime!\n"); - - host->has_no_lookup_table = true; + host->has_no_lookup_table = true; + } } if (host->has_no_lookup_table) { @@ -1254,7 +1254,8 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, nand_chip->ecc.steps = mtd->writesize / sector_size; nand_chip->ecc.total = nand_chip->ecc.bytes * nand_chip->ecc.steps; - if (nand_chip->ecc.total > mtd->oobsize - 2) { + if (nand_chip->ecc.total > + mtd->oobsize - PMECC_OOB_RESERVED_BYTES) { dev_err(host->dev, "No room for ECC bytes\n"); err_no = -EINVAL; goto err; @@ -1719,7 +1720,7 @@ static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag) comp[index++] = &host->nfc->comp_cmd_done; if (index == 0) { - dev_err(host->dev, "Unkown interrupt flag: 0x%08x\n", flag); + dev_err(host->dev, "Unknown interrupt flag: 0x%08x\n", flag); return -EINVAL; } @@ -1752,11 +1753,10 @@ static int nfc_send_command(struct atmel_nand_host *host, cmd, addr, cycle0); timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS); - while (nfc_cmd_readl(NFCADDR_CMD_NFCBUSY, host->nfc->base_cmd_regs) - & NFCADDR_CMD_NFCBUSY) { + while (nfc_readl(host->nfc->hsmc_regs, SR) & NFC_SR_BUSY) { if (time_after(jiffies, timeout)) { dev_err(host->dev, - "Time out to wait CMD_NFCBUSY ready!\n"); + "Time out to wait for NFC ready!\n"); return -ETIMEDOUT; } } diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h index d4035e3..668e735 100644 --- a/drivers/mtd/nand/atmel_nand_ecc.h +++ b/drivers/mtd/nand/atmel_nand_ecc.h @@ -152,4 +152,7 @@ /* Time out value for reading PMECC status register */ #define PMECC_MAX_TIMEOUT_MS 100 +/* Reserved bytes in oob area */ +#define PMECC_OOB_RESERVED_BYTES 2 + #endif diff --git a/drivers/mtd/nand/atmel_nand_nfc.h b/drivers/mtd/nand/atmel_nand_nfc.h index 85b8ca6..4d5d262 100644 --- a/drivers/mtd/nand/atmel_nand_nfc.h +++ b/drivers/mtd/nand/atmel_nand_nfc.h @@ -35,6 +35,7 @@ #define NFC_CTRL_DISABLE (1 << 1) #define ATMEL_HSMC_NFC_SR 0x08 /* NFC Status Register */ +#define NFC_SR_BUSY (1 << 8) #define NFC_SR_XFR_DONE (1 << 16) #define NFC_SR_CMD_DONE (1 << 17) #define NFC_SR_DTOE (1 << 20) diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index f44c606..870c7fc 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -225,7 +225,6 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, uint16_t Twhr[6] = {120, 80, 80, 60, 60, 60}; uint16_t Tcs[6] = {70, 35, 25, 25, 20, 15}; - uint16_t TclsRising = 1; uint16_t data_invalid_rhoh, data_invalid_rloh, data_invalid; uint16_t dv_window = 0; uint16_t en_lo, en_hi; @@ -276,8 +275,6 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, re_2_re = CEIL_DIV(Trhz[mode], CLK_X); we_2_re = CEIL_DIV(Twhr[mode], CLK_X); cs_cnt = CEIL_DIV((Tcs[mode] - Trp[mode]), CLK_X); - if (!TclsRising) - cs_cnt = CEIL_DIV(Tcs[mode], CLK_X); if (cs_cnt == 0) cs_cnt = 1; @@ -1536,6 +1533,9 @@ int denali_init(struct denali_nand_info *denali) denali->nand.options |= NAND_SKIP_BBTSCAN; denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME; + /* no subpage writes on denali */ + denali->nand.options |= NAND_NO_SUBPAGE_WRITE; + /* * Denali Controller only support 15bit and 8bit ECC in MRST, * so just let controller do 15bit ECC for MLC and 8bit ECC for diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 4c05f4f..51394e5 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -317,7 +317,7 @@ static void fsl_ifc_run_command(struct mtd_info *mtd) /* wait for command complete flag or timeout */ wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat, - IFC_TIMEOUT_MSECS * HZ/1000); + msecs_to_jiffies(IFC_TIMEOUT_MSECS)); /* ctrl->nand_stat will be updated from IRQ context */ if (!ctrl->nand_stat) @@ -860,7 +860,7 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv) /* wait for command complete flag or timeout */ wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat, - IFC_TIMEOUT_MSECS * HZ/1000); + msecs_to_jiffies(IFC_TIMEOUT_MSECS)); if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) printk(KERN_ERR "fsl-ifc: Failed to Initialise SRAM\n"); diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index edfaa21..e58af4b 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -873,6 +873,7 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev, { struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); u32 val; + int ret; /* Set default NAND width to 8 bits */ pdata->width = 8; @@ -891,8 +892,12 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev, sizeof(*pdata->nand_timings), GFP_KERNEL); if (!pdata->nand_timings) return -ENOMEM; - of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings, + ret = of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings, sizeof(*pdata->nand_timings)); + if (ret) { + dev_info(&pdev->dev, "No timings in dts specified, using default timings!\n"); + pdata->nand_timings = NULL; + } /* Set default NAND bank to 0 */ pdata->bank = 0; diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 33f3c3c..1b8f350 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -446,7 +446,7 @@ int start_dma_without_bch_irq(struct gpmi_nand_data *this, struct dma_async_tx_descriptor *desc) { struct completion *dma_c = &this->dma_done; - int err; + unsigned long timeout; init_completion(dma_c); @@ -456,8 +456,8 @@ int start_dma_without_bch_irq(struct gpmi_nand_data *this, dma_async_issue_pending(get_dma_chan(this)); /* Wait for the interrupt from the DMA block. */ - err = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000)); - if (!err) { + timeout = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000)); + if (!timeout) { dev_err(this->dev, "DMA timeout, last DMA :%d\n", this->last_dma_type); gpmi_dump_info(this); @@ -477,7 +477,7 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *this, struct dma_async_tx_descriptor *desc) { struct completion *bch_c = &this->bch_done; - int err; + unsigned long timeout; /* Prepare to receive an interrupt from the BCH block. */ init_completion(bch_c); @@ -486,8 +486,8 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *this, start_dma_without_bch_irq(this, desc); /* Wait for the interrupt from the BCH block. */ - err = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000)); - if (!err) { + timeout = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000)); + if (!timeout) { dev_err(this->dev, "BCH timeout, last DMA :%d\n", this->last_dma_type); gpmi_dump_info(this); @@ -1950,7 +1950,9 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) ret = nand_boot_init(this); if (ret) goto err_out; - chip->scan_bbt(mtd); + ret = chip->scan_bbt(mtd); + if (ret) + goto err_out; ppdata.of_node = this->pdev->dev.of_node; ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index a8f550f..372e0e3 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -386,26 +386,51 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) /* This function polls the NANDFC to wait for the basic operation to * complete by checking the INT bit of config2 register. */ -static void wait_op_done(struct mxc_nand_host *host, int useirq) +static int wait_op_done(struct mxc_nand_host *host, int useirq) { - int max_retries = 8000; + int ret = 0; + + /* + * If operation is already complete, don't bother to setup an irq or a + * loop. + */ + if (host->devtype_data->check_int(host)) + return 0; if (useirq) { - if (!host->devtype_data->check_int(host)) { - reinit_completion(&host->op_completion); - irq_control(host, 1); - wait_for_completion(&host->op_completion); + unsigned long timeout; + + reinit_completion(&host->op_completion); + + irq_control(host, 1); + + timeout = wait_for_completion_timeout(&host->op_completion, HZ); + if (!timeout && !host->devtype_data->check_int(host)) { + dev_dbg(host->dev, "timeout waiting for irq\n"); + ret = -ETIMEDOUT; } } else { - while (max_retries-- > 0) { - if (host->devtype_data->check_int(host)) - break; + int max_retries = 8000; + int done; + do { udelay(1); + + done = host->devtype_data->check_int(host); + if (done) + break; + + } while (--max_retries); + + if (!done) { + dev_dbg(host->dev, "timeout polling for completion\n"); + ret = -ETIMEDOUT; } - if (max_retries < 0) - pr_debug("%s: INT not set\n", __func__); } + + WARN_ONCE(ret < 0, "timeout! useirq=%d\n", useirq); + + return ret; } static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq) @@ -527,30 +552,17 @@ static void send_page_v1(struct mtd_info *mtd, unsigned int ops) static void send_read_id_v3(struct mxc_nand_host *host) { - struct nand_chip *this = &host->nand; - /* Read ID into main buffer */ writel(NFC_ID, NFC_V3_LAUNCH); wait_op_done(host, true); memcpy32_fromio(host->data_buf, host->main_area0, 16); - - if (this->options & NAND_BUSWIDTH_16) { - /* compress the ID info */ - host->data_buf[1] = host->data_buf[2]; - host->data_buf[2] = host->data_buf[4]; - host->data_buf[3] = host->data_buf[6]; - host->data_buf[4] = host->data_buf[8]; - host->data_buf[5] = host->data_buf[10]; - } } /* Request the NANDFC to perform a read of the NAND device ID. */ static void send_read_id_v1_v2(struct mxc_nand_host *host) { - struct nand_chip *this = &host->nand; - /* NANDFC buffer 0 is used for device ID output */ writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR); @@ -560,15 +572,6 @@ static void send_read_id_v1_v2(struct mxc_nand_host *host) wait_op_done(host, true); memcpy32_fromio(host->data_buf, host->main_area0, 16); - - if (this->options & NAND_BUSWIDTH_16) { - /* compress the ID info */ - host->data_buf[1] = host->data_buf[2]; - host->data_buf[2] = host->data_buf[4]; - host->data_buf[3] = host->data_buf[6]; - host->data_buf[4] = host->data_buf[8]; - host->data_buf[5] = host->data_buf[10]; - } } static uint16_t get_dev_status_v3(struct mxc_nand_host *host) @@ -694,9 +697,17 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd) if (host->status_request) return host->devtype_data->get_dev_status(host) & 0xFF; - ret = *(uint8_t *)(host->data_buf + host->buf_start); - host->buf_start++; + if (nand_chip->options & NAND_BUSWIDTH_16) { + /* only take the lower byte of each word */ + ret = *(uint16_t *)(host->data_buf + host->buf_start); + + host->buf_start += 2; + } else { + ret = *(uint8_t *)(host->data_buf + host->buf_start); + host->buf_start++; + } + pr_debug("%s: ret=0x%hhx (start=%u)\n", __func__, ret, host->buf_start); return ret; } @@ -825,6 +836,12 @@ static void copy_spare(struct mtd_info *mtd, bool bfrom) } } +/* + * MXC NANDFC can only perform full page+spare or spare-only read/write. When + * the upper layers perform a read/write buf operation, the saved column address + * is used to index into the full page. So usually this function is called with + * column == 0 (unless no column cycle is needed indicated by column == -1) + */ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) { struct nand_chip *nand_chip = mtd->priv; @@ -832,16 +849,13 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) /* Write out column address, if necessary */ if (column != -1) { - /* - * MXC NANDFC can only perform full page+spare or - * spare-only read/write. When the upper layers - * perform a read/write buf operation, the saved column - * address is used to index into the full page. - */ - host->devtype_data->send_addr(host, 0, page_addr == -1); + host->devtype_data->send_addr(host, column & 0xff, + page_addr == -1); if (mtd->writesize > 512) /* another col addr cycle for 2k page */ - host->devtype_data->send_addr(host, 0, false); + host->devtype_data->send_addr(host, + (column >> 8) & 0xff, + false); } /* Write out page address, if necessary */ @@ -903,7 +917,7 @@ static void preset_v1(struct mtd_info *mtd) struct mxc_nand_host *host = nand_chip->priv; uint16_t config1 = 0; - if (nand_chip->ecc.mode == NAND_ECC_HW) + if (nand_chip->ecc.mode == NAND_ECC_HW && mtd->writesize) config1 |= NFC_V1_V2_CONFIG1_ECC_EN; if (!host->devtype_data->irqpending_quirk) @@ -931,9 +945,6 @@ static void preset_v2(struct mtd_info *mtd) struct mxc_nand_host *host = nand_chip->priv; uint16_t config1 = 0; - if (nand_chip->ecc.mode == NAND_ECC_HW) - config1 |= NFC_V1_V2_CONFIG1_ECC_EN; - config1 |= NFC_V2_CONFIG1_FP_INT; if (!host->devtype_data->irqpending_quirk) @@ -942,6 +953,9 @@ static void preset_v2(struct mtd_info *mtd) if (mtd->writesize) { uint16_t pages_per_block = mtd->erasesize / mtd->writesize; + if (nand_chip->ecc.mode == NAND_ECC_HW) + config1 |= NFC_V1_V2_CONFIG1_ECC_EN; + host->eccsize = get_eccsize(mtd); if (host->eccsize == 4) config1 |= NFC_V2_CONFIG1_ECC_MODE_4; @@ -999,9 +1013,6 @@ static void preset_v3(struct mtd_info *mtd) NFC_V3_CONFIG2_INT_MSK | NFC_V3_CONFIG2_NUM_ADDR_PHASE0; - if (chip->ecc.mode == NAND_ECC_HW) - config2 |= NFC_V3_CONFIG2_ECC_EN; - addr_phases = fls(chip->pagemask) >> 3; if (mtd->writesize == 2048) { @@ -1016,6 +1027,9 @@ static void preset_v3(struct mtd_info *mtd) } if (mtd->writesize) { + if (chip->ecc.mode == NAND_ECC_HW) + config2 |= NFC_V3_CONFIG2_ECC_EN; + config2 |= NFC_V3_CONFIG2_PPB( ffs(mtd->erasesize / mtd->writesize) - 6, host->devtype_data->ppb_shift); @@ -1066,6 +1080,9 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, host->status_request = true; host->devtype_data->send_cmd(host, command, true); + WARN_ONCE(column != -1 || page_addr != -1, + "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", + command, column, page_addr); mxc_do_addr_cycle(mtd, column, page_addr); break; @@ -1079,7 +1096,10 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, command = NAND_CMD_READ0; /* only READ0 is valid */ host->devtype_data->send_cmd(host, command, false); - mxc_do_addr_cycle(mtd, column, page_addr); + WARN_ONCE(column < 0, + "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", + command, column, page_addr); + mxc_do_addr_cycle(mtd, 0, page_addr); if (mtd->writesize > 512) host->devtype_data->send_cmd(host, @@ -1100,7 +1120,10 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, host->buf_start = column; host->devtype_data->send_cmd(host, command, false); - mxc_do_addr_cycle(mtd, column, page_addr); + WARN_ONCE(column < -1, + "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", + command, column, page_addr); + mxc_do_addr_cycle(mtd, 0, page_addr); break; case NAND_CMD_PAGEPROG: @@ -1108,6 +1131,9 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, copy_spare(mtd, false); host->devtype_data->send_page(mtd, NFC_INPUT); host->devtype_data->send_cmd(host, command, true); + WARN_ONCE(column != -1 || page_addr != -1, + "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", + command, column, page_addr); mxc_do_addr_cycle(mtd, column, page_addr); break; @@ -1115,15 +1141,29 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, host->devtype_data->send_cmd(host, command, true); mxc_do_addr_cycle(mtd, column, page_addr); host->devtype_data->send_read_id(host); - host->buf_start = column; + host->buf_start = 0; break; case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: host->devtype_data->send_cmd(host, command, false); + WARN_ONCE(column != -1, + "Unexpected column value (cmd=%u, col=%d)\n", + command, column); mxc_do_addr_cycle(mtd, column, page_addr); break; + case NAND_CMD_PARAM: + host->devtype_data->send_cmd(host, command, false); + mxc_do_addr_cycle(mtd, column, page_addr); + host->devtype_data->send_page(mtd, NFC_OUTPUT); + memcpy32_fromio(host->data_buf, host->main_area0, 512); + host->buf_start = 0; + break; + default: + WARN_ONCE(1, "Unimplemented command (cmd=%u)\n", + command); + break; } } diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index df7eb4f..c2e1232 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -386,7 +386,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) uint8_t buf[2] = { 0, 0 }; int ret = 0, res, i = 0; - ops.datbuf = NULL; + memset(&ops, 0, sizeof(ops)); ops.oobbuf = buf; ops.ooboffs = chip->badblockpos; if (chip->options & NAND_BUSWIDTH_16) { @@ -566,6 +566,25 @@ void nand_wait_ready(struct mtd_info *mtd) EXPORT_SYMBOL_GPL(nand_wait_ready); /** + * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands. + * @mtd: MTD device structure + * @timeo: Timeout in ms + * + * Wait for status ready (i.e. command done) or timeout. + */ +static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo) +{ + register struct nand_chip *chip = mtd->priv; + + timeo = jiffies + msecs_to_jiffies(timeo); + do { + if ((chip->read_byte(mtd) & NAND_STATUS_READY)) + break; + touch_softlockup_watchdog(); + } while (time_before(jiffies, timeo)); +}; + +/** * nand_command - [DEFAULT] Send command to NAND device * @mtd: MTD device structure * @command: the command to be sent @@ -643,8 +662,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, NAND_CTRL_CLE | NAND_CTRL_CHANGE); chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) - ; + /* EZ-NAND can take upto 250ms as per ONFi v4.0 */ + nand_wait_status_ready(mtd, 250); return; /* This applies to read commands */ @@ -740,8 +759,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) - ; + /* EZ-NAND can take upto 250ms as per ONFi v4.0 */ + nand_wait_status_ready(mtd, 250); return; case NAND_CMD_RNDOUT: @@ -968,7 +987,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) __func__, (unsigned long long)ofs, len); if (check_offs_len(mtd, ofs, len)) - ret = -EINVAL; + return -EINVAL; /* Align to last block address if size addresses end of the device */ if (ofs + len == mtd->size) @@ -1031,7 +1050,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) __func__, (unsigned long long)ofs, len); if (check_offs_len(mtd, ofs, len)) - ret = -EINVAL; + return -EINVAL; nand_get_device(mtd, FL_LOCKING); @@ -1716,9 +1735,9 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, int ret; nand_get_device(mtd, FL_READING); + memset(&ops, 0, sizeof(ops)); ops.len = len; ops.datbuf = buf; - ops.oobbuf = NULL; ops.mode = MTD_OPS_PLACE_OOB; ret = nand_do_read_ops(mtd, from, &ops); *retlen = ops.retlen; @@ -2124,7 +2143,7 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, /** - * nand_write_subpage_hwecc - [REPLACABLE] hardware ECC based subpage write + * nand_write_subpage_hwecc - [REPLACEABLE] hardware ECC based subpage write * @mtd: mtd info structure * @chip: nand chip info structure * @offset: column address of subpage within the page @@ -2508,9 +2527,9 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, /* Grab the device */ panic_nand_get_device(chip, mtd, FL_WRITING); + memset(&ops, 0, sizeof(ops)); ops.len = len; ops.datbuf = (uint8_t *)buf; - ops.oobbuf = NULL; ops.mode = MTD_OPS_PLACE_OOB; ret = nand_do_write_ops(mtd, to, &ops); @@ -2536,9 +2555,9 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, int ret; nand_get_device(mtd, FL_WRITING); + memset(&ops, 0, sizeof(ops)); ops.len = len; ops.datbuf = (uint8_t *)buf; - ops.oobbuf = NULL; ops.mode = MTD_OPS_PLACE_OOB; ret = nand_do_write_ops(mtd, to, &ops); *retlen = ops.retlen; diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 10b1f7a..a4615fc 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -38,8 +38,8 @@ #include <linux/platform_data/mtd-nand-pxa3xx.h> -#define CHIP_DELAY_TIMEOUT (2 * HZ/10) -#define NAND_STOP_DELAY (2 * HZ/50) +#define CHIP_DELAY_TIMEOUT msecs_to_jiffies(200) +#define NAND_STOP_DELAY msecs_to_jiffies(40) #define PAGE_CHUNK_SIZE (2048) /* @@ -605,11 +605,24 @@ static void start_data_dma(struct pxa3xx_nand_info *info) {} #endif +static irqreturn_t pxa3xx_nand_irq_thread(int irq, void *data) +{ + struct pxa3xx_nand_info *info = data; + + handle_data_pio(info); + + info->state = STATE_CMD_DONE; + nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ); + + return IRQ_HANDLED; +} + static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) { struct pxa3xx_nand_info *info = devid; unsigned int status, is_completed = 0, is_ready = 0; unsigned int ready, cmd_done; + irqreturn_t ret = IRQ_HANDLED; if (info->cs == 0) { ready = NDSR_FLASH_RDY; @@ -651,7 +664,8 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) } else { info->state = (status & NDSR_RDDREQ) ? STATE_PIO_READING : STATE_PIO_WRITING; - handle_data_pio(info); + ret = IRQ_WAKE_THREAD; + goto NORMAL_IRQ_EXIT; } } if (status & cmd_done) { @@ -692,7 +706,7 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) if (is_ready) complete(&info->dev_ready); NORMAL_IRQ_EXIT: - return IRQ_HANDLED; + return ret; } static inline int is_buf_blank(uint8_t *buf, size_t len) @@ -951,7 +965,7 @@ static void nand_cmdfunc(struct mtd_info *mtd, unsigned command, { struct pxa3xx_nand_host *host = mtd->priv; struct pxa3xx_nand_info *info = host->info_data; - int ret, exec_cmd; + int exec_cmd; /* * if this is a x16 device ,then convert the input @@ -983,9 +997,8 @@ static void nand_cmdfunc(struct mtd_info *mtd, unsigned command, info->need_wait = 1; pxa3xx_nand_start(info); - ret = wait_for_completion_timeout(&info->cmd_complete, - CHIP_DELAY_TIMEOUT); - if (!ret) { + if (!wait_for_completion_timeout(&info->cmd_complete, + CHIP_DELAY_TIMEOUT)) { dev_err(&info->pdev->dev, "Wait time out!!!\n"); /* Stop State Machine for next command cycle */ pxa3xx_nand_stop(info); @@ -1000,7 +1013,7 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd, { struct pxa3xx_nand_host *host = mtd->priv; struct pxa3xx_nand_info *info = host->info_data; - int ret, exec_cmd, ext_cmd_type; + int exec_cmd, ext_cmd_type; /* * if this is a x16 device then convert the input @@ -1063,9 +1076,8 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd, init_completion(&info->cmd_complete); pxa3xx_nand_start(info); - ret = wait_for_completion_timeout(&info->cmd_complete, - CHIP_DELAY_TIMEOUT); - if (!ret) { + if (!wait_for_completion_timeout(&info->cmd_complete, + CHIP_DELAY_TIMEOUT)) { dev_err(&info->pdev->dev, "Wait time out!!!\n"); /* Stop State Machine for next command cycle */ pxa3xx_nand_stop(info); @@ -1198,13 +1210,11 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) { struct pxa3xx_nand_host *host = mtd->priv; struct pxa3xx_nand_info *info = host->info_data; - int ret; if (info->need_wait) { - ret = wait_for_completion_timeout(&info->dev_ready, - CHIP_DELAY_TIMEOUT); info->need_wait = 0; - if (!ret) { + if (!wait_for_completion_timeout(&info->dev_ready, + CHIP_DELAY_TIMEOUT)) { dev_err(&info->pdev->dev, "Ready time out!!!\n"); return NAND_STATUS_FAIL; } @@ -1508,6 +1518,8 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) return ret; } + memset(pxa3xx_flash_ids, 0, sizeof(pxa3xx_flash_ids)); + pxa3xx_flash_ids[0].name = f->name; pxa3xx_flash_ids[0].dev_id = (f->chip_id >> 8) & 0xffff; pxa3xx_flash_ids[0].pagesize = f->page_size; @@ -1710,7 +1722,9 @@ static int alloc_nand_resource(struct platform_device *pdev) /* initialize all interrupts to be disabled */ disable_int(info, NDSR_MASK); - ret = request_irq(irq, pxa3xx_nand_irq, 0, pdev->name, info); + ret = request_threaded_irq(irq, pxa3xx_nand_irq, + pxa3xx_nand_irq_thread, IRQF_ONESHOT, + pdev->name, info); if (ret < 0) { dev_err(&pdev->dev, "failed to request IRQ\n"); goto fail_free_buf; diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 35aef5e..0e02be4 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -948,8 +948,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) cpu_type = platform_get_device_id(pdev)->driver_data; - pr_debug("s3c2410_nand_probe(%p)\n", pdev); - info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (info == NULL) { err = -ENOMEM; @@ -1045,7 +1043,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND); } - pr_debug("initialised ok\n"); return 0; exit_error: |