1 /*
2 * Copyright (c) 2022, NXP
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6 #include "fsl_power.h"
7 #include "flash_clock_setup.h"
8
9 #define FLEXSPI_DLL_LOCK_RETRY (10)
10
flash_deinit(FLEXSPI_Type * base)11 static void flash_deinit(FLEXSPI_Type *base)
12 {
13 /* Enable FLEXSPI clock again */
14 CLKCTL0->PSCCTL0_SET = CLKCTL0_PSCCTL0_SET_FLEXSPI0_OTFAD_CLK_MASK;
15
16 /* Enable FLEXSPI module */
17 base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;
18
19 /* Wait until FLEXSPI is not busy */
20 while (!((base->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) &&
21 (base->STS0 & FLEXSPI_STS0_SEQIDLE_MASK))) {
22 }
23 /* Disable module during the reset procedure */
24 base->MCR0 |= FLEXSPI_MCR0_MDIS_MASK;
25 }
26
flash_init(FLEXSPI_Type * base)27 static void flash_init(FLEXSPI_Type *base)
28 {
29 uint32_t status;
30 uint32_t lastStatus;
31 uint32_t retry;
32
33 /* If serial root clock is >= 100 MHz, DLLEN set to 1, OVRDEN set to 0,
34 * then SLVDLYTARGET setting of 0x0 is recommended.
35 */
36 base->DLLCR[0] = 0x1U;
37
38 /* Enable FLEXSPI module */
39 base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;
40
41 base->MCR0 |= FLEXSPI_MCR0_SWRESET_MASK;
42 while (base->MCR0 & FLEXSPI_MCR0_SWRESET_MASK) {
43 }
44
45 /* Need to wait DLL locked if DLL enabled */
46 if (0U != (base->DLLCR[0] & FLEXSPI_DLLCR_DLLEN_MASK)) {
47 lastStatus = base->STS2;
48 retry = FLEXSPI_DLL_LOCK_RETRY;
49 /* Wait slave delay line locked and slave reference delay line locked. */
50 do {
51 status = base->STS2;
52 if ((status & (FLEXSPI_STS2_AREFLOCK_MASK | FLEXSPI_STS2_ASLVLOCK_MASK)) ==
53 (FLEXSPI_STS2_AREFLOCK_MASK | FLEXSPI_STS2_ASLVLOCK_MASK)) {
54 /* Locked */
55 retry = 100;
56 break;
57 } else if (status == lastStatus) {
58 /* Same delay cell number in calibration */
59 retry--;
60 } else {
61 retry = FLEXSPI_DLL_LOCK_RETRY;
62 lastStatus = status;
63 }
64 } while (retry > 0);
65 /* According to ERR011377, need to delay at least 100 NOPs to ensure
66 * the DLL is locked.
67 */
68 for (; retry > 0U; retry--) {
69 __NOP();
70 }
71 }
72 }
73
74 /*
75 * flexspi_set_clock run in RAM used to configure FlexSPI clock source and divider
76 * when XIP.
77 */
flexspi_setup_clock(FLEXSPI_Type * base,uint32_t src,uint32_t divider)78 void flexspi_setup_clock(FLEXSPI_Type *base, uint32_t src, uint32_t divider)
79 {
80 if (base == FLEXSPI0) {
81 if ((CLKCTL0->FLEXSPI0FCLKSEL != CLKCTL0_FLEXSPI0FCLKSEL_SEL(src)) ||
82 ((CLKCTL0->FLEXSPI0FCLKDIV & CLKCTL0_FLEXSPI0FCLKDIV_DIV_MASK) !=
83 (divider - 1))) {
84 /* Always deinit FLEXSPI and init FLEXSPI for the flash to make sure the
85 * flash works correctly after the FLEXSPI root clock changed as the
86 * default FLEXSPI configuration may does not work for the new root
87 * clock frequency.
88 */
89 flash_deinit(base);
90
91 /* Disable clock before changing clock source */
92 CLKCTL0->PSCCTL0_CLR = CLKCTL0_PSCCTL0_CLR_FLEXSPI0_OTFAD_CLK_MASK;
93 /* Update flexspi clock. */
94 CLKCTL0->FLEXSPI0FCLKSEL = CLKCTL0_FLEXSPI0FCLKSEL_SEL(src);
95 /* Reset the divider counter */
96 CLKCTL0->FLEXSPI0FCLKDIV |= CLKCTL0_FLEXSPI0FCLKDIV_RESET_MASK;
97 CLKCTL0->FLEXSPI0FCLKDIV = CLKCTL0_FLEXSPI0FCLKDIV_DIV(divider - 1);
98 while ((CLKCTL0->FLEXSPI0FCLKDIV) & CLKCTL0_FLEXSPI0FCLKDIV_REQFLAG_MASK) {
99 }
100 /* Enable FLEXSPI clock again */
101 CLKCTL0->PSCCTL0_SET = CLKCTL0_PSCCTL0_SET_FLEXSPI0_OTFAD_CLK_MASK;
102
103 flash_init(base);
104 }
105 } else if (base == FLEXSPI1) {
106 if ((CLKCTL0->FLEXSPI1FCLKSEL != CLKCTL0_FLEXSPI1FCLKSEL_SEL(src)) ||
107 ((CLKCTL0->FLEXSPI1FCLKDIV & CLKCTL0_FLEXSPI1FCLKDIV_DIV_MASK) !=
108 (divider - 1))) {
109 /* Always deinit FLEXSPI and init FLEXSPI for the flash to make sure the
110 * flash works correctly after the FLEXSPI root clock changed as the
111 * default FLEXSPI configuration may does not work for the new root
112 * clock frequency.
113 */
114 flash_deinit(base);
115
116 /* Disable clock before changing clock source */
117 CLKCTL0->PSCCTL0_CLR = CLKCTL0_PSCCTL0_CLR_FLEXSPI1_CLK_MASK;
118 /* Update flexspi clock. */
119 CLKCTL0->FLEXSPI1FCLKSEL = CLKCTL0_FLEXSPI1FCLKSEL_SEL(src);
120 /* Reset the divider counter */
121 CLKCTL0->FLEXSPI1FCLKDIV |= CLKCTL0_FLEXSPI1FCLKDIV_RESET_MASK;
122 CLKCTL0->FLEXSPI1FCLKDIV = CLKCTL0_FLEXSPI1FCLKDIV_DIV(divider - 1);
123 while ((CLKCTL0->FLEXSPI1FCLKDIV) & CLKCTL0_FLEXSPI1FCLKDIV_REQFLAG_MASK) {
124 }
125 /* Enable FLEXSPI clock again */
126 CLKCTL0->PSCCTL0_SET = CLKCTL0_PSCCTL0_SET_FLEXSPI1_CLK_MASK;
127
128 flash_init(base);
129 }
130 } else {
131 return;
132 }
133 }
134
135 /* This function is used to change FlexSPI clock to a stable source before clock
136 * sources(Such as PLL and Main clock) updating in case XIP (execute code on
137 * FLEXSPI memory.)
138 */
flexspi_clock_safe_config(void)139 void flexspi_clock_safe_config(void)
140 {
141 /* Move FLEXSPI clock source from main clock to FRO192M / 2 to avoid instruction/data
142 * fetch issue in XIP when updating PLL and main clock.
143 */
144 flexspi_setup_clock(FLEXSPI0, 3U, 2U);
145 }
146