summaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/nand/raw/mtk_nand.c46
1 files changed, 36 insertions, 10 deletions
diff --git a/drivers/mtd/nand/raw/mtk_nand.c b/drivers/mtd/nand/raw/mtk_nand.c
index 23fe19397315..03aff7e9bea5 100644
--- a/drivers/mtd/nand/raw/mtk_nand.c
+++ b/drivers/mtd/nand/raw/mtk_nand.c
@@ -79,6 +79,10 @@
#define NFI_FDMM(x) (0xA4 + (x) * sizeof(u32) * 2)
#define NFI_FDM_MAX_SIZE (8)
#define NFI_FDM_MIN_SIZE (1)
+#define NFI_DEBUG_CON1 (0x220)
+#define STROBE_MASK GENMASK(4, 3)
+#define STROBE_SHIFT (3)
+#define MAX_STROBE_DLY (3)
#define NFI_MASTER_STA (0x224)
#define MASTER_STA_MASK (0x0FFF)
#define NFI_EMPTY_THRESH (0x23C)
@@ -501,7 +505,7 @@ static int mtk_nfc_setup_data_interface(struct nand_chip *chip, int csline,
struct mtk_nfc *nfc = nand_get_controller_data(chip);
const struct nand_sdr_timings *timings;
u32 rate, tpoecs, tprecs, tc2r, tw2r, twh, twst = 0, trlt = 0;
- u32 thold;
+ u32 temp, tsel = 0;
timings = nand_get_sdr_timings(conf);
if (IS_ERR(timings))
@@ -538,30 +542,52 @@ static int mtk_nfc_setup_data_interface(struct nand_chip *chip, int csline,
twh &= 0xf;
/* Calculate real WE#/RE# hold time in nanosecond */
- thold = (twh + 1) * 1000000 / rate;
+ temp = (twh + 1) * 1000000 / rate;
/* nanosecond to picosecond */
- thold *= 1000;
+ temp *= 1000;
/*
* WE# low level time should be expaned to meet WE# pulse time
* and WE# cycle time at the same time.
*/
- if (thold < timings->tWC_min)
- twst = timings->tWC_min - thold;
+ if (temp < timings->tWC_min)
+ twst = timings->tWC_min - temp;
twst = max(timings->tWP_min, twst) / 1000;
twst = DIV_ROUND_UP(twst * rate, 1000000) - 1;
twst &= 0xf;
/*
- * RE# low level time should be expaned to meet RE# pulse time,
- * RE# access time and RE# cycle time at the same time.
+ * RE# low level time should be expaned to meet RE# pulse time
+ * and RE# cycle time at the same time.
*/
- if (thold < timings->tRC_min)
- trlt = timings->tRC_min - thold;
- trlt = max3(trlt, timings->tREA_max, timings->tRP_min) / 1000;
+ if (temp < timings->tRC_min)
+ trlt = timings->tRC_min - temp;
+ trlt = max(trlt, timings->tRP_min) / 1000;
trlt = DIV_ROUND_UP(trlt * rate, 1000000) - 1;
trlt &= 0xf;
+ /* Calculate RE# pulse time in nanosecond. */
+ temp = (trlt + 1) * 1000000 / rate;
+ /* nanosecond to picosecond */
+ temp *= 1000;
+ /*
+ * If RE# access time is bigger than RE# pulse time,
+ * delay sampling data timing.
+ */
+ if (temp < timings->tREA_max) {
+ tsel = timings->tREA_max / 1000;
+ tsel = DIV_ROUND_UP(tsel * rate, 1000000);
+ tsel -= (trlt + 1);
+ if (tsel > MAX_STROBE_DLY) {
+ trlt += tsel - MAX_STROBE_DLY;
+ tsel = MAX_STROBE_DLY;
+ }
+ }
+ temp = nfi_readl(nfc, NFI_DEBUG_CON1);
+ temp &= ~STROBE_MASK;
+ temp |= tsel << STROBE_SHIFT;
+ nfi_writel(nfc, temp, NFI_DEBUG_CON1);
+
/*
* ACCON: access timing control register
* -------------------------------------