diff options
-rw-r--r-- | drivers/mtd/nand/raw/mtk_nand.c | 46 |
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 * ------------------------------------- |