Commit 73f907fd authored by Boris Brezillon's avatar Boris Brezillon

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: default avatarBoris Brezillon <boris.brezillon@free-electrons.com>
Fixes: d8e725dd ("mtd: nand: automate NAND timings selection")
Reviewed-by: default avatarSascha Hauer <s.hauer@pengutronix.de>
Tested-by: default avatarMarc Gonzalez <marc_gonzalez@sigmadesigns.com>
parent ce93bedb
...@@ -1095,10 +1095,11 @@ static void nand_release_data_interface(struct nand_chip *chip) ...@@ -1095,10 +1095,11 @@ static void nand_release_data_interface(struct nand_chip *chip)
/** /**
* nand_reset - Reset and initialize a NAND device * nand_reset - Reset and initialize a NAND device
* @chip: The NAND chip * @chip: The NAND chip
* @chipnr: Internal die id
* *
* Returns 0 for success or negative error code otherwise * 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); struct mtd_info *mtd = nand_to_mtd(chip);
int ret; int ret;
...@@ -1107,9 +1108,17 @@ int nand_reset(struct nand_chip *chip) ...@@ -1107,9 +1108,17 @@ int nand_reset(struct nand_chip *chip)
if (ret) if (ret)
return 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->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
chip->select_chip(mtd, -1);
chip->select_chip(mtd, chipnr);
ret = nand_setup_data_interface(chip); ret = nand_setup_data_interface(chip);
chip->select_chip(mtd, -1);
if (ret) if (ret)
return ret; return ret;
...@@ -1185,8 +1194,6 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) ...@@ -1185,8 +1194,6 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
/* Shift to get chip number */ /* Shift to get chip number */
chipnr = ofs >> chip->chip_shift; chipnr = ofs >> chip->chip_shift;
chip->select_chip(mtd, chipnr);
/* /*
* Reset the chip. * Reset the chip.
* If we want to check the WP through READ STATUS and check the bit 7 * 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) ...@@ -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 * some operation can also clear the bit 7 of status register
* eg. erase/program a locked block * eg. erase/program a locked block
*/ */
nand_reset(chip); nand_reset(chip, chipnr);
chip->select_chip(mtd, chipnr);
/* Check, if it is write protected */ /* Check, if it is write protected */
if (nand_check_wp(mtd)) { if (nand_check_wp(mtd)) {
...@@ -1244,8 +1253,6 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) ...@@ -1244,8 +1253,6 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
/* Shift to get chip number */ /* Shift to get chip number */
chipnr = ofs >> chip->chip_shift; chipnr = ofs >> chip->chip_shift;
chip->select_chip(mtd, chipnr);
/* /*
* Reset the chip. * Reset the chip.
* If we want to check the WP through READ STATUS and check the bit 7 * 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) ...@@ -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 * some operation can also clear the bit 7 of status register
* eg. erase/program a locked block * eg. erase/program a locked block
*/ */
nand_reset(chip); nand_reset(chip, chipnr);
chip->select_chip(mtd, chipnr);
/* Check, if it is write protected */ /* Check, if it is write protected */
if (nand_check_wp(mtd)) { if (nand_check_wp(mtd)) {
...@@ -2940,10 +2949,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, ...@@ -2940,10 +2949,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
} }
chipnr = (int)(to >> chip->chip_shift); 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 * 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, ...@@ -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' * 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. * 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 */ /* Check, if it is write protected */
if (nand_check_wp(mtd)) { if (nand_check_wp(mtd)) {
...@@ -3984,14 +3994,14 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, ...@@ -3984,14 +3994,14 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
int i, maf_idx; int i, maf_idx;
u8 id_data[8]; u8 id_data[8];
/* Select the device */
chip->select_chip(mtd, 0);
/* /*
* Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx) * Reset the chip, required by some chips (e.g. Micron MT29FxGxxxxx)
* after power-up. * 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 */ /* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
...@@ -4329,17 +4339,31 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, ...@@ -4329,17 +4339,31 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
return PTR_ERR(type); return PTR_ERR(type);
} }
/* Initialize the ->data_interface field. */
ret = nand_init_data_interface(chip); ret = nand_init_data_interface(chip);
if (ret) if (ret)
return 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); chip->select_chip(mtd, -1);
/* Check for a chip array */ /* Check for a chip array */
for (i = 1; i < maxchips; i++) { for (i = 1; i < maxchips; i++) {
chip->select_chip(mtd, i);
/* See comment in nand_get_flash_type for reset */ /* 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 */ /* Send the command for reading device ID */
chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1); chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
/* Read manufacturer and device IDs */ /* Read manufacturer and device IDs */
......
...@@ -1184,7 +1184,7 @@ int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, ...@@ -1184,7 +1184,7 @@ int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
int page); int page);
/* Reset and initialize a NAND device */ /* 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 */ /* Free resources held by the NAND device */
void nand_cleanup(struct nand_chip *chip); void nand_cleanup(struct nand_chip *chip);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment