From 929a551ba9da399563dfaa4ae309ee7e1ed8ecee Mon Sep 17 00:00:00 2001 From: Alexander Dahl Date: Tue, 12 Mar 2024 13:41:04 +0100 Subject: [PATCH] mtd: nand: raw: atmel: Port timing fix from at91bootstrap From reading the S34ML02G1 and the SAM9X60 datasheets again, it seems like we have to wait tREA after rising RE# before sampling the data. Thus pulse must be at least tREA. The fix works in bootstrap, u-boot, and Linux, but the explanation might be improved. It probably worked on sam9g20 and sama5d2 before, because those have a slower mck clock rate and thus the resolution of the timings setup is not as tight as with sam9x60. Without the fix we got PMECC errors when reading after switching to ONFI timing mode 3. Link: https://github.com/linux4sam/at91bootstrap/issues/174 Cc: Li Bin --- drivers/mtd/nand/raw/atmel/nand-controller.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/nand/raw/atmel/nand-controller.c b/drivers/mtd/nand/raw/atmel/nand-controller.c index dc75d50d52e84e..d30848e58adba9 100644 --- a/drivers/mtd/nand/raw/atmel/nand-controller.c +++ b/drivers/mtd/nand/raw/atmel/nand-controller.c @@ -1240,7 +1240,7 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand, const struct nand_interface_config *conf, struct atmel_smc_cs_conf *smcconf) { - u32 ncycles, totalcycles, timeps, mckperiodps; + u32 ncycles, totalcycles, timeps, mckperiodps, pulse; struct atmel_nand_controller *nc; int ret; @@ -1366,11 +1366,16 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand, ATMEL_SMC_MODE_TDFMODE_OPTIMIZED; /* - * Read pulse timing directly matches tRP: + * Read pulse timing would directly match tRP, + * but some NAND flash chips (S34ML01G2 and W29N02KVxxAF) + * do not work properly in timing mode 3. + * The workaround is to extend the SMC NRD pulse to meet tREA + * timing. * - * NRD_PULSE = tRP + * NRD_PULSE = max(tRP, tREA) */ - ncycles = DIV_ROUND_UP(conf->timings.sdr.tRP_min, mckperiodps); + pulse = max(conf->timings.sdr.tRP_min, conf->timings.sdr.tREA_max); + ncycles = DIV_ROUND_UP(pulse, mckperiodps); totalcycles += ncycles; ret = atmel_smc_cs_conf_set_pulse(smcconf, ATMEL_SMC_NRD_SHIFT, ncycles);