[PATCH 4/4] mtd: rawnand: fsmc: Fix timing computation

From: Herve Codina
Date: Fri Nov 12 2021 - 09:39:50 EST


The timing setting were incorrect on some nands leading to a
fallback to mode 0 timing on some Micron nand or to incorrect
data reads on some Winbond NAND.

The timing computation did not take into account the following
constraint given in SPEAr3xx reference manual:
twait >= tCEA - tset*TCLK + TOUTDEL + TINDEL

This patch adds this constraint and fixes the issues on both
nands having the both nands working at mode 3 timing.
The change has no impact on slower timing mode such as mode 0.
Indeed, on mode 0 timing, computed values are the same with and
without the patch.

Signed-off-by: Herve Codina <herve.codina@xxxxxxxxxxx>
---
drivers/mtd/nand/raw/fsmc_nand.c | 27 +++++++++++++++++++--------
1 file changed, 19 insertions(+), 8 deletions(-)

diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c
index bff09219ce3a..a3aa66f30869 100644
--- a/drivers/mtd/nand/raw/fsmc_nand.c
+++ b/drivers/mtd/nand/raw/fsmc_nand.c
@@ -278,7 +278,7 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host,
{
unsigned long hclk = clk_get_rate(host->clk);
unsigned long hclkn = NSEC_PER_SEC / hclk;
- u32 thiz, thold, twait, tset;
+ u32 thiz, thold, twait, tset, tmp;

if (sdrt->tRC_min < 30000)
return -EOPNOTSUPP;
@@ -310,13 +310,6 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host,
else if (tims->thold > FSMC_THOLD_MASK)
tims->thold = FSMC_THOLD_MASK;

- twait = max(sdrt->tRP_min, sdrt->tWP_min);
- tims->twait = DIV_ROUND_UP(twait / 1000, hclkn) - 1;
- if (tims->twait == 0)
- tims->twait = 1;
- else if (tims->twait > FSMC_TWAIT_MASK)
- tims->twait = FSMC_TWAIT_MASK;
-
tset = max(sdrt->tCS_min - sdrt->tWP_min,
sdrt->tCEA_max - sdrt->tREA_max);
tims->tset = DIV_ROUND_UP(tset / 1000, hclkn) - 1;
@@ -325,6 +318,24 @@ static int fsmc_calc_timings(struct fsmc_nand_data *host,
else if (tims->tset > FSMC_TSET_MASK)
tims->tset = FSMC_TSET_MASK;

+ twait = max(sdrt->tRP_min, sdrt->tWP_min);
+
+ /* According to SPEAr300 Reference Manual (RM0082) which gives more
+ * information related to FSMSC timings than the SPEAr600 one (RM0305),
+ * twait >= tCEA - tset*TCLK + TOUTDEL + TINDEL
+ * With TOUTDEL = 7ns (Output delay from the flip-flops to the board)
+ * and TINDEL = 5ns (Input delay from the board to the flipflop)
+ */
+ tmp = sdrt->tCEA_max - (tims->tset + 1)*hclkn*1000 + 7000 + 5000;
+ if (twait < tmp)
+ twait = tmp;
+
+ tims->twait = DIV_ROUND_UP(twait / 1000, hclkn) - 1;
+ if (tims->twait == 0)
+ tims->twait = 1;
+ else if (tims->twait > FSMC_TWAIT_MASK)
+ tims->twait = FSMC_TWAIT_MASK;
+
return 0;
}

--
2.31.1