From 99d822b3adc4f9af59cefdc6619cb3f64182efed Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Wed, 22 Mar 2023 17:04:51 +0800 Subject: spi: spi-nxp-fspi: use DLL calibration when clock rate > 100MHz 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 Link: https://lore.kernel.org/r/20230322090451.3179431-2-haibo.chen@nxp.com Signed-off-by: Mark Brown --- drivers/spi/spi-nxp-fspi.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/drivers/spi/spi-nxp-fspi.c b/drivers/spi/spi-nxp-fspi.c index 6735c22b9137..544017655787 100644 --- a/drivers/spi/spi-nxp-fspi.c +++ b/drivers/spi/spi-nxp-fspi.c @@ -214,9 +214,15 @@ #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) @@ -231,6 +237,16 @@ #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); } -- cgit v1.2.3