From ce93bedb5ed2b16c08c6df4c797865f9ead600a3 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 22 Oct 2016 14:15:22 -0200 Subject: mtd: nand: gpmi: disable the clocks on errors We should disable the previously enabled GPMI clocks in the error paths. Also, when gpmi_enable_clk() fails simply return the error code immediately rather than jumping to to the 'err_out' label. Signed-off-by: Fabio Estevam Reviewed-by: Marek Vasut Acked-by: Han Xu Signed-off-by: Boris Brezillon --- drivers/mtd/nand/gpmi-nand/gpmi-lib.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c index 0f68a99fc4ad..141bd70a49c2 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-lib.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-lib.c @@ -161,7 +161,7 @@ int gpmi_init(struct gpmi_nand_data *this) ret = gpmi_enable_clk(this); if (ret) - goto err_out; + return ret; ret = gpmi_reset_block(r->gpmi_regs, false); if (ret) goto err_out; @@ -197,6 +197,7 @@ int gpmi_init(struct gpmi_nand_data *this) gpmi_disable_clk(this); return 0; err_out: + gpmi_disable_clk(this); return ret; } @@ -270,7 +271,7 @@ int bch_set_geometry(struct gpmi_nand_data *this) ret = gpmi_enable_clk(this); if (ret) - goto err_out; + return ret; /* * Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this @@ -308,6 +309,7 @@ int bch_set_geometry(struct gpmi_nand_data *this) gpmi_disable_clk(this); return 0; err_out: + gpmi_disable_clk(this); return ret; } -- cgit v1.2.3 From 73f907fd5fa56b0066d199bdd7126bbd04f6cd7b Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 24 Oct 2016 16:46:20 +0200 Subject: mtd: nand: Fix data interface configuration logic When changing from one data interface setting to another, one has to ensure a specific sequence which is described in the ONFI spec. One of these constraints is that the CE line has go high after a reset before a command can be sent with the new data interface setting, which is not guaranteed by the current implementation. Rework the nand_reset() function and all the call sites to make sure the CE line is asserted and released when required. Also make sure to actually apply the new data interface setting on the first die. Signed-off-by: Boris Brezillon Fixes: d8e725dd8311 ("mtd: nand: automate NAND timings selection") Reviewed-by: Sascha Hauer Tested-by: Marc Gonzalez --- drivers/mtd/nand/nand_base.c | 60 +++++++++++++++++++++++++++++++------------- include/linux/mtd/nand.h | 2 +- 2 files changed, 43 insertions(+), 19 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index e5718e5ecf92..3bde96a3f7bf 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1095,10 +1095,11 @@ static void nand_release_data_interface(struct nand_chip *chip) /** * nand_reset - Reset and initialize a NAND device * @chip: The NAND chip + * @chipnr: Internal die id * * Returns 0 for success or negative error code otherwise */ -int nand_reset(struct nand_chip *chip) +int nand_reset(struct nand_chip *chip, int chipnr) { struct mtd_info *mtd = nand_to_mtd(chip); int ret; @@ -1107,9 +1108,17 @@ int nand_reset(struct nand_chip *chip) if (ret) return ret; + /* + * The CS line has to be released before we can apply the new NAND + * interface settings, hence this weird ->select_chip() dance. + */ + chip->select_chip(mtd, chipnr); chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + chip->select_chip(mtd, -1); + chip->select_chip(mtd, chipnr); ret = nand_setup_data_interface(chip); + chip->select_chip(mtd, -1); if (ret) return ret; @@ -1185,8 +1194,6 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) /* Shift to get chip number */ chipnr = ofs >> chip->chip_shift; - chip->select_chip(mtd, chipnr); - /* * Reset the chip. * If we want to check the WP through READ STATUS and check the bit 7 @@ -1194,7 +1201,9 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) * some operation can also clear the bit 7 of status register * eg. erase/program a locked block */ - nand_reset(chip); + nand_reset(chip, chipnr); + + chip->select_chip(mtd, chipnr); /* Check, if it is write protected */ if (nand_check_wp(mtd)) { @@ -1244,8 +1253,6 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) /* Shift to get chip number */ chipnr = ofs >> chip->chip_shift; - chip->select_chip(mtd, chipnr); - /* * Reset the chip. * If we want to check the WP through READ STATUS and check the bit 7 @@ -1253,7 +1260,9 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) * some operation can also clear the bit 7 of status register * eg. erase/program a locked block */ - nand_reset(chip); + nand_reset(chip, chipnr); + + chip->select_chip(mtd, chipnr); /* Check, if it is write protected */ if (nand_check_wp(mtd)) { @@ -2940,10 +2949,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, } chipnr = (int)(to >> chip->chip_shift); - chip->select_chip(mtd, chipnr); - - /* Shift to get page */ - page = (int)(to >> chip->page_shift); /* * Reset the chip. Some chips (like the Toshiba TC5832DC found in one @@ -2951,7 +2956,12 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, * if we don't do this. I have no clue why, but I seem to have 'fixed' * it in the doc2000 driver in August 1999. dwmw2. */ - nand_reset(chip); + nand_reset(chip, chipnr); + + chip->select_chip(mtd, chipnr); + + /* Shift to get page */ + page = (int)(to >> chip->page_shift); /* Check, if it is write protected */ if (nand_check_wp(mtd)) { @@ -3984,14 +3994,14 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, int i, maf_idx; u8 id_data[8]; - /* Select the device */ - chip->select_chip(mtd, 0); - /* * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) * after power-up. */ - nand_reset(chip); + nand_reset(chip, 0); + + /* Select the device */ + chip->select_chip(mtd, 0); /* Send the command for reading device ID */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); @@ -4329,17 +4339,31 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, return PTR_ERR(type); } + /* Initialize the ->data_interface field. */ ret = nand_init_data_interface(chip); if (ret) return ret; + /* + * Setup the data interface correctly on the chip and controller side. + * This explicit call to nand_setup_data_interface() is only required + * for the first die, because nand_reset() has been called before + * ->data_interface and ->default_onfi_timing_mode were set. + * For the other dies, nand_reset() will automatically switch to the + * best mode for us. + */ + ret = nand_setup_data_interface(chip); + if (ret) + return ret; + chip->select_chip(mtd, -1); /* Check for a chip array */ for (i = 1; i < maxchips; i++) { - chip->select_chip(mtd, i); /* See comment in nand_get_flash_type for reset */ - nand_reset(chip); + nand_reset(chip, i); + + chip->select_chip(mtd, i); /* Send the command for reading device ID */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index c5d3d5024fc8..d8905a229f34 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -1184,7 +1184,7 @@ int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, int page); /* Reset and initialize a NAND device */ -int nand_reset(struct nand_chip *chip); +int nand_reset(struct nand_chip *chip, int chipnr); /* Free resources held by the NAND device */ void nand_cleanup(struct nand_chip *chip); -- cgit v1.2.3 From 8ff0513bdcdd71e84aa561cce216675d43fb41b8 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 18 Oct 2016 00:05:31 +0200 Subject: mtd: mtk: avoid warning in mtk_ecc_encode When building with -Wmaybe-uninitialized, gcc produces a silly false positive warning for the mtk_ecc_encode function: drivers/mtd/nand/mtk_ecc.c: In function 'mtk_ecc_encode': drivers/mtd/nand/mtk_ecc.c:402:15: error: 'val' may be used uninitialized in this function [-Werror=maybe-uninitialized] The function for some reason contains a double byte swap on big-endian builds to get the OOB data into the correct order again, and is written in a slightly confusing way. Using a simple memcpy32_fromio() to read the data simplifies it a lot so it becomes more readable and produces no warning. However, the output might not have 32-bit alignment, so we have to use another memcpy to avoid taking alignment faults or writing beyond the end of the array. Signed-off-by: Arnd Bergmann Tested-by: RogerCC Lin Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mtk_ecc.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers/mtd') diff --git a/drivers/mtd/nand/mtk_ecc.c b/drivers/mtd/nand/mtk_ecc.c index d54f666417e1..dbf256217b3e 100644 --- a/drivers/mtd/nand/mtk_ecc.c +++ b/drivers/mtd/nand/mtk_ecc.c @@ -86,6 +86,8 @@ struct mtk_ecc { struct completion done; struct mutex lock; u32 sectors; + + u8 eccdata[112]; }; static inline void mtk_ecc_wait_idle(struct mtk_ecc *ecc, @@ -366,9 +368,8 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config, u8 *data, u32 bytes) { dma_addr_t addr; - u8 *p; - u32 len, i, val; - int ret = 0; + u32 len; + int ret; addr = dma_map_single(ecc->dev, data, bytes, DMA_TO_DEVICE); ret = dma_mapping_error(ecc->dev, addr); @@ -393,14 +394,12 @@ int mtk_ecc_encode(struct mtk_ecc *ecc, struct mtk_ecc_config *config, /* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */ len = (config->strength * ECC_PARITY_BITS + 7) >> 3; - p = data + bytes; - /* write the parity bytes generated by the ECC back to the OOB region */ - for (i = 0; i < len; i++) { - if ((i % 4) == 0) - val = readl(ecc->regs + ECC_ENCPAR(i / 4)); - p[i] = (val >> ((i % 4) * 8)) & 0xff; - } + /* write the parity bytes generated by the ECC back to temp buffer */ + __ioread32_copy(ecc->eccdata, ecc->regs + ECC_ENCPAR(0), round_up(len, 4)); + + /* copy into possibly unaligned OOB region with actual length */ + memcpy(data + bytes, ecc->eccdata, len); timeout: dma_unmap_single(ecc->dev, addr, bytes, DMA_TO_DEVICE); -- cgit v1.2.3