spi: spi-nxp-fspi: use DLL calibration when clock rate > 100MHz
authorHaibo Chen <haibo.chen@nxp.com>
Wed, 22 Mar 2023 09:04:51 +0000 (17:04 +0800)
committerMark Brown <broonie@kernel.org>
Wed, 22 Mar 2023 13:17:43 +0000 (13:17 +0000)
When clock rate > 100MHz, use the DLL calibration mode, and finally
add the suggested half of the current clock cycle to sample the data.

Signed-off-by: Haibo Chen <haibo.chen@nxp.com>
Link: https://lore.kernel.org/r/20230322090451.3179431-2-haibo.chen@nxp.com
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi-nxp-fspi.c

index 6735c22..5440176 100644 (file)
 
 #define FSPI_DLLACR                    0xC0
 #define FSPI_DLLACR_OVRDEN             BIT(8)
+#define FSPI_DLLACR_SLVDLY(x)          ((x) << 3)
+#define FSPI_DLLACR_DLLRESET           BIT(1)
+#define FSPI_DLLACR_DLLEN              BIT(0)
 
 #define FSPI_DLLBCR                    0xC4
 #define FSPI_DLLBCR_OVRDEN             BIT(8)
+#define FSPI_DLLBCR_SLVDLY(x)          ((x) << 3)
+#define FSPI_DLLBCR_DLLRESET           BIT(1)
+#define FSPI_DLLBCR_DLLEN              BIT(0)
 
 #define FSPI_STS0                      0xE0
 #define FSPI_STS0_DLPHB(x)             ((x) << 8)
 #define FSPI_STS1_AHB_ERRCD(x)         ((x) << 8)
 #define FSPI_STS1_AHB_ERRID(x)         (x)
 
+#define FSPI_STS2                      0xE8
+#define FSPI_STS2_BREFLOCK             BIT(17)
+#define FSPI_STS2_BSLVLOCK             BIT(16)
+#define FSPI_STS2_AREFLOCK             BIT(1)
+#define FSPI_STS2_ASLVLOCK             BIT(0)
+#define FSPI_STS2_AB_LOCK              (FSPI_STS2_BREFLOCK | \
+                                        FSPI_STS2_BSLVLOCK | \
+                                        FSPI_STS2_AREFLOCK | \
+                                        FSPI_STS2_ASLVLOCK)
+
 #define FSPI_AHBSPNST                  0xEC
 #define FSPI_AHBSPNST_DATLFT(x)                ((x) << 16)
 #define FSPI_AHBSPNST_BUFID(x)         ((x) << 1)
@@ -615,6 +631,35 @@ static int nxp_fspi_clk_disable_unprep(struct nxp_fspi *f)
        return 0;
 }
 
+static void nxp_fspi_dll_calibration(struct nxp_fspi *f)
+{
+       int ret;
+
+       /* Reset the DLL, set the DLLRESET to 1 and then set to 0 */
+       fspi_writel(f, FSPI_DLLACR_DLLRESET, f->iobase + FSPI_DLLACR);
+       fspi_writel(f, FSPI_DLLBCR_DLLRESET, f->iobase + FSPI_DLLBCR);
+       fspi_writel(f, 0, f->iobase + FSPI_DLLACR);
+       fspi_writel(f, 0, f->iobase + FSPI_DLLBCR);
+
+       /*
+        * Enable the DLL calibration mode.
+        * The delay target for slave delay line is:
+        *   ((SLVDLYTARGET+1) * 1/32 * clock cycle of reference clock.
+        * When clock rate > 100MHz, recommend SLVDLYTARGET is 0xF, which
+        * means half of clock cycle of reference clock.
+        */
+       fspi_writel(f, FSPI_DLLACR_DLLEN | FSPI_DLLACR_SLVDLY(0xF),
+                   f->iobase + FSPI_DLLACR);
+       fspi_writel(f, FSPI_DLLBCR_DLLEN | FSPI_DLLBCR_SLVDLY(0xF),
+                   f->iobase + FSPI_DLLBCR);
+
+       /* Wait to get REF/SLV lock */
+       ret = fspi_readl_poll_tout(f, f->iobase + FSPI_STS2, FSPI_STS2_AB_LOCK,
+                                  0, POLL_TOUT, true);
+       if (ret)
+               dev_warn(f->dev, "DLL lock failed, please fix it!\n");
+}
+
 /*
  * In FlexSPI controller, flash access is based on value of FSPI_FLSHXXCR0
  * register and start base address of the slave device.
@@ -690,6 +735,13 @@ static void nxp_fspi_select_mem(struct nxp_fspi *f, struct spi_device *spi)
        if (ret)
                return;
 
+       /*
+        * If clock rate > 100MHz, then switch from DLL override mode to
+        * DLL calibration mode.
+        */
+       if (rate > 100000000)
+               nxp_fspi_dll_calibration(f);
+
        f->selected = spi_get_chipselect(spi, 0);
 }