|
214 | 214 |
|
215 | 215 | #define FSPI_DLLACR 0xC0 |
216 | 216 | #define FSPI_DLLACR_OVRDEN BIT(8) |
| 217 | +#define FSPI_DLLACR_SLVDLY(x) ((x) << 3) |
| 218 | +#define FSPI_DLLACR_DLLRESET BIT(1) |
| 219 | +#define FSPI_DLLACR_DLLEN BIT(0) |
217 | 220 |
|
218 | 221 | #define FSPI_DLLBCR 0xC4 |
219 | 222 | #define FSPI_DLLBCR_OVRDEN BIT(8) |
| 223 | +#define FSPI_DLLBCR_SLVDLY(x) ((x) << 3) |
| 224 | +#define FSPI_DLLBCR_DLLRESET BIT(1) |
| 225 | +#define FSPI_DLLBCR_DLLEN BIT(0) |
220 | 226 |
|
221 | 227 | #define FSPI_STS0 0xE0 |
222 | 228 | #define FSPI_STS0_DLPHB(x) ((x) << 8) |
|
231 | 237 | #define FSPI_STS1_AHB_ERRCD(x) ((x) << 8) |
232 | 238 | #define FSPI_STS1_AHB_ERRID(x) (x) |
233 | 239 |
|
| 240 | +#define FSPI_STS2 0xE8 |
| 241 | +#define FSPI_STS2_BREFLOCK BIT(17) |
| 242 | +#define FSPI_STS2_BSLVLOCK BIT(16) |
| 243 | +#define FSPI_STS2_AREFLOCK BIT(1) |
| 244 | +#define FSPI_STS2_ASLVLOCK BIT(0) |
| 245 | +#define FSPI_STS2_AB_LOCK (FSPI_STS2_BREFLOCK | \ |
| 246 | + FSPI_STS2_BSLVLOCK | \ |
| 247 | + FSPI_STS2_AREFLOCK | \ |
| 248 | + FSPI_STS2_ASLVLOCK) |
| 249 | + |
234 | 250 | #define FSPI_AHBSPNST 0xEC |
235 | 251 | #define FSPI_AHBSPNST_DATLFT(x) ((x) << 16) |
236 | 252 | #define FSPI_AHBSPNST_BUFID(x) ((x) << 1) |
@@ -615,6 +631,35 @@ static int nxp_fspi_clk_disable_unprep(struct nxp_fspi *f) |
615 | 631 | return 0; |
616 | 632 | } |
617 | 633 |
|
| 634 | +static void nxp_fspi_dll_calibration(struct nxp_fspi *f) |
| 635 | +{ |
| 636 | + int ret; |
| 637 | + |
| 638 | + /* Reset the DLL, set the DLLRESET to 1 and then set to 0 */ |
| 639 | + fspi_writel(f, FSPI_DLLACR_DLLRESET, f->iobase + FSPI_DLLACR); |
| 640 | + fspi_writel(f, FSPI_DLLBCR_DLLRESET, f->iobase + FSPI_DLLBCR); |
| 641 | + fspi_writel(f, 0, f->iobase + FSPI_DLLACR); |
| 642 | + fspi_writel(f, 0, f->iobase + FSPI_DLLBCR); |
| 643 | + |
| 644 | + /* |
| 645 | + * Enable the DLL calibration mode. |
| 646 | + * The delay target for slave delay line is: |
| 647 | + * ((SLVDLYTARGET+1) * 1/32 * clock cycle of reference clock. |
| 648 | + * When clock rate > 100MHz, recommend SLVDLYTARGET is 0xF, which |
| 649 | + * means half of clock cycle of reference clock. |
| 650 | + */ |
| 651 | + fspi_writel(f, FSPI_DLLACR_DLLEN | FSPI_DLLACR_SLVDLY(0xF), |
| 652 | + f->iobase + FSPI_DLLACR); |
| 653 | + fspi_writel(f, FSPI_DLLBCR_DLLEN | FSPI_DLLBCR_SLVDLY(0xF), |
| 654 | + f->iobase + FSPI_DLLBCR); |
| 655 | + |
| 656 | + /* Wait to get REF/SLV lock */ |
| 657 | + ret = fspi_readl_poll_tout(f, f->iobase + FSPI_STS2, FSPI_STS2_AB_LOCK, |
| 658 | + 0, POLL_TOUT, true); |
| 659 | + if (ret) |
| 660 | + dev_warn(f->dev, "DLL lock failed, please fix it!\n"); |
| 661 | +} |
| 662 | + |
618 | 663 | /* |
619 | 664 | * In FlexSPI controller, flash access is based on value of FSPI_FLSHXXCR0 |
620 | 665 | * 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) |
690 | 735 | if (ret) |
691 | 736 | return; |
692 | 737 |
|
| 738 | + /* |
| 739 | + * If clock rate > 100MHz, then switch from DLL override mode to |
| 740 | + * DLL calibration mode. |
| 741 | + */ |
| 742 | + if (rate > 100000000) |
| 743 | + nxp_fspi_dll_calibration(f); |
| 744 | + |
693 | 745 | f->selected = spi_get_chipselect(spi, 0); |
694 | 746 | } |
695 | 747 |
|
|
0 commit comments