aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiquel Raynal <miquel.raynal@bootlin.com>2018-03-19 09:47:24 -0400
committerBoris Brezillon <boris.brezillon@bootlin.com>2018-03-20 04:49:41 -0400
commit415ae78ffb5d97343ada8e4c2d4bda5f6416b5ef (patch)
treec96826801c39c69cf2c881ea3c8dda2c552226bd
parent29714d6bd72b2de163a89240a70550f23d25c324 (diff)
mtd: rawnand: check ONFI timings have been acked by the chip
Choosing ONFI timings when ->set/get_features() calls are supported by the NAND chip is a matter of reading the chip's ONFI parameter page and telling the chip the chosen mode (between all of the supported ones) with ->set_feature(). Add a check on whether the chip "acked" the timing mode or not. This can be a problem for NAND chips that do not follow entirely the ONFI specification. These chips actually support other modes than "mode 0", but either: 1/ do not update the timing mode register once a timing mode has been selected. or 2/ do not support the TIMING_MODE featured and thus do not require users to change the timing mode at all. These issues will be addressed in another patch that will add the feature to overwrite NAND chips features within the parameter page, from the NAND chip driver. Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> Tested-by: Han Xu <han.xu@nxp.com> Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
-rw-r--r--drivers/mtd/nand/raw/nand_base.c36
1 files changed, 35 insertions, 1 deletions
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 9d5c2739fe6d..837ea698af08 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -1283,7 +1283,41 @@ static int nand_setup_data_interface(struct nand_chip *chip, int chipnr)
1283 } 1283 }
1284 1284
1285 /* Change the mode on the controller side */ 1285 /* Change the mode on the controller side */
1286 return chip->setup_data_interface(mtd, chipnr, &chip->data_interface); 1286 ret = chip->setup_data_interface(mtd, chipnr, &chip->data_interface);
1287 if (ret)
1288 return ret;
1289
1290 /* Check the mode has been accepted by the chip, if supported */
1291 if (!nand_supports_set_get_features(chip))
1292 return 0;
1293
1294 memset(tmode_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
1295 chip->select_chip(mtd, chipnr);
1296 ret = nand_get_features(chip, ONFI_FEATURE_ADDR_TIMING_MODE,
1297 tmode_param);
1298 chip->select_chip(mtd, -1);
1299 if (ret)
1300 goto err_reset_chip;
1301
1302 if (tmode_param[0] != chip->onfi_timing_mode_default) {
1303 pr_warn("timing mode %d not acknowledged by the NAND chip\n",
1304 chip->onfi_timing_mode_default);
1305 goto err_reset_chip;
1306 }
1307
1308 return 0;
1309
1310err_reset_chip:
1311 /*
1312 * Fallback to mode 0 if the chip explicitly did not ack the chosen
1313 * timing mode.
1314 */
1315 nand_reset_data_interface(chip, chipnr);
1316 chip->select_chip(mtd, chipnr);
1317 nand_reset_op(chip);
1318 chip->select_chip(mtd, -1);
1319
1320 return ret;
1287} 1321}
1288 1322
1289/** 1323/**