]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
mtd: nand: raw: atmel: Respect tAR, tCLR in read setup timing
authorAlexander Sverdlin <alexander.sverdlin@siemens.com>
Sat, 13 Sep 2025 15:08:29 +0000 (11:08 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 19 Sep 2025 14:29:57 +0000 (16:29 +0200)
[ Upstream commit fd779eac2d659668be4d3dbdac0710afd5d6db12 ]

Having setup time 0 violates tAR, tCLR of some chips, for instance
TOSHIBA TC58NVG2S3ETAI0 cannot be detected successfully (first ID byte
being read duplicated, i.e. 98 98 dc 90 15 76 14 03 instead of
98 dc 90 15 76 ...).

Atmel Application Notes postulated 1 cycle NRD_SETUP without explanation
[1], but it looks more appropriate to just calculate setup time properly.

Link: https://ww1.microchip.com/downloads/aemDocuments/documents/MPU32/ApplicationNotes/ApplicationNotes/doc6255.pdf
Cc: stable@vger.kernel.org
Fixes: f9ce2eddf176 ("mtd: nand: atmel: Add ->setup_data_interface() hooks")
Signed-off-by: Alexander Sverdlin <alexander.sverdlin@siemens.com>
Tested-by: Alexander Dahl <ada@thorsis.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/mtd/nand/raw/atmel/nand-controller.c

index 511bd0d1e06729d95b49e37bfcc38da73feaf2ad..78f317ac04afaa7d484cbe88ca946fcd4d2f3443 100644 (file)
@@ -1377,14 +1377,24 @@ static int atmel_smc_nand_prepare_smcconf(struct atmel_nand *nand,
        if (ret)
                return ret;
 
+       /*
+        * Read setup timing depends on the operation done on the NAND:
+        *
+        * NRD_SETUP = max(tAR, tCLR)
+        */
+       timeps = max(conf->timings.sdr.tAR_min, conf->timings.sdr.tCLR_min);
+       ncycles = DIV_ROUND_UP(timeps, mckperiodps);
+       totalcycles += ncycles;
+       ret = atmel_smc_cs_conf_set_setup(smcconf, ATMEL_SMC_NRD_SHIFT, ncycles);
+       if (ret)
+               return ret;
+
        /*
         * The read cycle timing is directly matching tRC, but is also
         * dependent on the setup and hold timings we calculated earlier,
         * which gives:
         *
-        * NRD_CYCLE = max(tRC, NRD_PULSE + NRD_HOLD)
-        *
-        * NRD_SETUP is always 0.
+        * NRD_CYCLE = max(tRC, NRD_SETUP + NRD_PULSE + NRD_HOLD)
         */
        ncycles = DIV_ROUND_UP(conf->timings.sdr.tRC_min, mckperiodps);
        ncycles = max(totalcycles, ncycles);