summaryrefslogtreecommitdiff
path: root/drivers/mtd
diff options
context:
space:
mode:
authorHan Xu <han.xu@nxp.com>2019-02-22 10:34:21 -0600
committerHan Xu <han.xu@nxp.com>2019-02-22 11:33:48 -0600
commit87016bd6f17bd3a53232c1a20b6ad0c4f3fa7f31 (patch)
tree2a86c076802cafe8c7fc8bf83befa33ef7a35962 /drivers/mtd
parent1f388533326f03a2bee44973dbcb47e54422db0c (diff)
MLK-20970: mtd: flexspi: add delay cell support for fspi
Add delay cell support for fspi to set calibrated value to DLL register for different clock frequency. Signed-off-by: Han Xu <han.xu@nxp.com> (cherry picked from commit 5b608b98697668bd11563febba89bd0eea1c1b26)
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/spi-nor/fsl-flexspi.c104
1 files changed, 99 insertions, 5 deletions
diff --git a/drivers/mtd/spi-nor/fsl-flexspi.c b/drivers/mtd/spi-nor/fsl-flexspi.c
index b0b23a3b2452..ccdb3c5a2189 100644
--- a/drivers/mtd/spi-nor/fsl-flexspi.c
+++ b/drivers/mtd/spi-nor/fsl-flexspi.c
@@ -35,10 +35,17 @@
/* Board only enabled up to Quad mode, not Octal*/
#define FLEXSPI_QUIRK_QUAD_ONLY (1 << 0)
/* Maximum clock limitation */
-#define FLEXSPI_QUIRK_FREQ_LIMIT (1 << 0)
+#define FLEXSPI_QUIRK_FREQ_LIMIT (1 << 1)
+/* Config DLL register */
+#define FLEXSPI_QUIRK_CONFIG_DLL (1 << 2)
/* runtime pm timeout */
#define FSL_FLEXSPI_RPM_TIMEOUT 50 /* 50ms */
+#define FREQ_1MHz 1000000 /* 1MHz */
+
+/* delay cell range */
+#define FLEXSPI_DLL_MIN 75 /* 75ps */
+#define FLEXSPI_DLL_MAX 225 /* 225ps */
/* The registers */
#define FLEXSPI_MCR0 0x00
@@ -271,6 +278,34 @@
#define FLEXSPI_IPTXFCR_WMRK_SHIFT 2
#define FLEXSPI_IPTXFCR_WMRK_MASK (0x1F << FLEXSPI_IPTXFCR_WMRK_SHIFT)
+#define FLEXSPI_DLLACR 0xC0
+#define FLEXSPI_DLLACR_REFUPDINT_SHIFT 28
+#define FLEXSPI_DLLACR_REFUPDINT_MASK (0xF << FLEXSPI_DLLACR_REFUPDINT_SHIFT)
+#define FLEXSPI_DLLACR_OVRDVAL_SHIFT 9
+#define FLEXSPI_DLLACR_OVRDVAL_MASK (0x3F << FLEXSPI_DLLACR_OVRDVAL_SHIFT)
+#define FLEXSPI_DLLACR_OVRDEN_SHIFT 8
+#define FLEXSPI_DLLACR_OVRDEN_MASK (1 << FLEXSPI_DLLACR_OVRDEN_SHIFT)
+#define FLEXSPI_DLLACR_SLVDLYTGT_SHIFT 3
+#define FLEXSPI_DLLACR_SLVDLYTGT_MASK (0xF << FLEXSPI_DLLACR_SLVDLYTGT_SHIFT)
+#define FLEXSPI_DLLACR_DLLRST_SHIFT 1
+#define FLEXSPI_DLLACR_DLLRST_MASK (1 << FLEXSPI_DLLACR_DLLRST_SHIFT)
+#define FLEXSPI_DLLACR_DLLEN_SHIFT 0
+#define FLEXSPI_DLLACR_DLLEN_MASK (1 << FLEXSPI_DLLACR_DLLEN_SHIFT)
+
+#define FLEXSPI_DLLBCR 0xC4
+#define FLEXSPI_DLLBCR_REFUPDINT_SHIFT 28
+#define FLEXSPI_DLLBCR_REFUPDINT_MASK (0xF << FLEXSPI_DLLBCR_REFUPDINT_SHIFT)
+#define FLEXSPI_DLLBCR_OVRDVAL_SHIFT 9
+#define FLEXSPI_DLLBCR_OVRDVAL_MASK (0x3F << FLEXSPI_DLLBCR_OVRDVAL_SHIFT)
+#define FLEXSPI_DLLBCR_OVRDEN_SHIFT 8
+#define FLEXSPI_DLLBCR_OVRDEN_MASK (1 << FLEXSPI_DLLBCR_OVRDEN_SHIFT)
+#define FLEXSPI_DLLBCR_SLVDLYTGT_SHIFT 3
+#define FLEXSPI_DLLBCR_SLVDLYTGT_MASK (0xF << FLEXSPI_DLLBCR_SLVDLYTGT_SHIFT)
+#define FLEXSPI_DLLBCR_DLLRST_SHIFT 1
+#define FLEXSPI_DLLBCR_DLLRST_MASK (1 << FLEXSPI_DLLBCR_DLLRST_SHIFT)
+#define FLEXSPI_DLLBCR_DLLEN_SHIFT 0
+#define FLEXSPI_DLLBCR_DLLEN_MASK (1 << FLEXSPI_DLLBCR_DLLEN_SHIFT)
+
#define FLEXSPI_STS0 0xE0
#define FLEXSPI_STS0_DLPHA_SHIFT 9
#define FLEXSPI_STS0_DLPHA_MASK (0x1F << FLEXSPI_STS0_DLPHA_SHIFT)
@@ -425,6 +460,7 @@ struct fsl_flexspi_devtype_data {
int txfifo;
int ahb_buf_size;
int driver_data;
+ int dllvalue;
};
static struct fsl_flexspi_devtype_data imx8qm_data = {
@@ -432,7 +468,8 @@ static struct fsl_flexspi_devtype_data imx8qm_data = {
.rxfifo = 1024,
.txfifo = 1024,
.ahb_buf_size = 2048,
- .driver_data = 0,
+ .driver_data = FLEXSPI_QUIRK_CONFIG_DLL,
+ .dllvalue = 80, /* unit is 0.1 ns, this is 8ns */
};
static struct fsl_flexspi_devtype_data imx8qxp_data = {
@@ -440,7 +477,8 @@ static struct fsl_flexspi_devtype_data imx8qxp_data = {
.rxfifo = 1024,
.txfifo = 1024,
.ahb_buf_size = 2048,
- .driver_data = 0,
+ .driver_data = FLEXSPI_QUIRK_CONFIG_DLL,
+ .dllvalue = 80, /* unit is 0.1 ns, this is 8ns */
};
static struct fsl_flexspi_devtype_data imx8mm_data = {
@@ -449,6 +487,7 @@ static struct fsl_flexspi_devtype_data imx8mm_data = {
.txfifo = 1024,
.ahb_buf_size = 2048,
.driver_data = FLEXSPI_QUIRK_QUAD_ONLY | FLEXSPI_QUIRK_FREQ_LIMIT,
+ .dllvalue = 0,
};
#define FSL_FLEXSPI_MAX_CHIP 4
@@ -477,6 +516,11 @@ struct fsl_flexspi {
int flags;
};
+static inline int fsl_flexspi_need_config_dll(struct fsl_flexspi *flex)
+{
+ return flex->devtype_data->driver_data & FLEXSPI_QUIRK_CONFIG_DLL;
+}
+
static inline int fsl_flexspi_freq_limit(struct fsl_flexspi *flex)
{
return flex->devtype_data->driver_data & FLEXSPI_QUIRK_FREQ_LIMIT;
@@ -964,6 +1008,53 @@ static int fsl_flexspi_init_rpm(struct fsl_flexspi *flex)
return 0;
}
+static void fsl_flexspi_config_dll(struct fsl_flexspi *flex, int rate)
+{
+ int tmp, dll;
+ u32 reg;
+
+ if (!fsl_flexspi_need_config_dll(flex))
+ return;
+
+ if (rate >= 100 * FREQ_1MHz) {
+ writel(FLEXSPI_DLLACR_DLLEN_MASK | FLEXSPI_DLLACR_SLVDLYTGT_MASK,
+ flex->iobase + FLEXSPI_DLLACR);
+ writel(FLEXSPI_DLLBCR_DLLEN_MASK | FLEXSPI_DLLBCR_SLVDLYTGT_MASK,
+ flex->iobase + FLEXSPI_DLLBCR);
+ } else {
+ /*
+ * If Serial root closk is lower than 100MHz, DLL is unable to lock on
+ * half cycle of serial root clock because the dealy cell number is limited
+ * in delay chain, Then DLL should be configured as following instead:
+ * OVRDEN = 0x01
+ * OVRDVAL=N; each dealy cell in DLL is about 75ps - 225ps.
+ * The delay of DLL delay chain ( N * delay_cell_delay) should be larger
+ * than device output data valid time (from SCK edge to data valid).
+ */
+
+ /* 0.1 ns to ps */
+ tmp = flex->devtype_data->dllvalue * 100;
+ dll = tmp / FLEXSPI_DLL_MIN;
+
+ if (dll >= FLEXSPI_DLLACR_OVRDVAL_MASK)
+ dll = FLEXSPI_DLLACR_OVRDVAL_MASK;
+ else if (dll * FLEXSPI_DLL_MIN < tmp)
+ dll++;
+
+ writel(FLEXSPI_DLLACR_OVRDEN_MASK | (dll << FLEXSPI_DLLACR_OVRDVAL_SHIFT) |
+ FLEXSPI_DLLACR_DLLRST_MASK, flex->iobase + FLEXSPI_DLLACR);
+ udelay(1);
+ reg = readl(flex->iobase + FLEXSPI_DLLACR);
+ writel(reg & ~FLEXSPI_DLLACR_DLLRST_MASK, flex->iobase + FLEXSPI_DLLACR);
+
+ writel(FLEXSPI_DLLBCR_OVRDEN_MASK | (dll << FLEXSPI_DLLBCR_OVRDVAL_SHIFT) |
+ FLEXSPI_DLLBCR_DLLRST_MASK, flex->iobase + FLEXSPI_DLLBCR);
+ udelay(1);
+ reg = readl(flex->iobase + FLEXSPI_DLLBCR);
+ writel(reg & ~FLEXSPI_DLLBCR_DLLRST_MASK, flex->iobase + FLEXSPI_DLLBCR);
+ }
+}
+
/* We use this function to do some basic init for spi_nor_scan(). */
static int fsl_flexspi_nor_setup(struct fsl_flexspi *flex)
{
@@ -974,7 +1065,7 @@ static int fsl_flexspi_nor_setup(struct fsl_flexspi *flex)
fsl_flexspi_clk_disable_unprep(flex);
/* set rate to 24Mhz as safe clock rate to probe */
- ret = clk_set_rate(flex->clk, 24000000);
+ ret = clk_set_rate(flex->clk, 24 * FREQ_1MHz);
if (ret)
return ret;
@@ -1020,7 +1111,7 @@ static int fsl_flexspi_nor_setup_last(struct fsl_flexspi *flex)
/* clock limitation for i.MX8MM, no more than 160Mhz */
if (fsl_flexspi_freq_limit(flex))
- rate = rate > 160000000 ? 160000000 : rate;
+ rate = rate > 160 * FREQ_1MHz ? 160 * FREQ_1MHz : rate;
ret = clk_set_rate(flex->clk, rate);
if (ret)
@@ -1030,6 +1121,9 @@ static int fsl_flexspi_nor_setup_last(struct fsl_flexspi *flex)
if (ret)
return ret;
+ /* setup the DLL value */
+ fsl_flexspi_config_dll(flex, rate);
+
/* Init the LUT table again. */
fsl_flexspi_init_lut(flex);