1 /*
2  * Copyright 2022 NXP
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 /*
7  * To be explicitly clear, the following set of functions
8  * cannot execute in place from flash and are instead
9  * relocated into internal SRAM.
10  */
11 
12 #include "fsl_power.h"
13 #include "flash_clock_setup.h"
14 
15 #define FLEXSPI_DLL_LOCK_RETRY (10)
16 
flash_deinit(FLEXSPI_Type * base)17 static void flash_deinit(FLEXSPI_Type *base)
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 	uint32_t mask = 0;
33 
34 	/* Enable FLEXSPI module */
35 	base->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;
36 
37 	base->MCR0 |= FLEXSPI_MCR0_SWRESET_MASK;
38 	while (base->MCR0 & FLEXSPI_MCR0_SWRESET_MASK) {
39 	}
40 
41 	/* Need to wait DLL locked if DLL enabled */
42 	if (0U != (base->DLLCR[0] & FLEXSPI_DLLCR_DLLEN_MASK)) {
43 		lastStatus = base->STS2;
44 		retry      = FLEXSPI_DLL_LOCK_RETRY;
45 		/* Flash on port A */
46 		if (((base->FLSHCR0[0] & FLEXSPI_FLSHCR0_FLSHSZ_MASK) > 0) ||
47 		    ((base->FLSHCR0[1] & FLEXSPI_FLSHCR0_FLSHSZ_MASK) > 0)) {
48 			mask |= FLEXSPI_STS2_AREFLOCK_MASK | FLEXSPI_STS2_ASLVLOCK_MASK;
49 		}
50 		/* Flash on port B */
51 		if (((base->FLSHCR0[2] & FLEXSPI_FLSHCR0_FLSHSZ_MASK) > 0) ||
52 		    ((base->FLSHCR0[3] & FLEXSPI_FLSHCR0_FLSHSZ_MASK) > 0)) {
53 			mask |= FLEXSPI_STS2_BREFLOCK_MASK | FLEXSPI_STS2_BSLVLOCK_MASK;
54 		}
55 		/* Wait slave delay line locked and slave reference delay line locked. */
56 		do {
57 			status = base->STS2;
58 			if ((status & mask) == mask) {
59 				/* Locked */
60 				retry = 100;
61 				break;
62 			} else if (status == lastStatus) {
63 				/* Same delay cell number in calibration */
64 				retry--;
65 			} else {
66 				retry = FLEXSPI_DLL_LOCK_RETRY;
67 				lastStatus = status;
68 			}
69 		} while (retry > 0);
70 		/* According to ERR011377, need to delay at least 100 NOPs
71 		 * to ensure the DLL is locked.
72 		 */
73 		for (; retry > 0U; retry--) {
74 			__NOP();
75 		}
76 	}
77 }
78 
flexspi_setup_clock(FLEXSPI_Type * base,uint32_t src,uint32_t divider)79 void flexspi_setup_clock(FLEXSPI_Type *base, uint32_t src, uint32_t divider)
80 {
81 	if (base == FLEXSPI) {
82 		if ((CLKCTL0->FLEXSPIFCLKSEL != CLKCTL0_FLEXSPIFCLKSEL_SEL(src)) ||
83 		   ((CLKCTL0->FLEXSPIFCLKDIV & CLKCTL0_FLEXSPIFCLKDIV_DIV_MASK) !=
84 		    (divider - 1))) {
85 			/* Always deinit FLEXSPI and init FLEXSPI for the flash to make sure the
86 			 * flash works correctly after the FLEXSPI root clock changed as the
87 			 * default FLEXSPI configuration may does not work for the new root
88 			 * clock frequency.
89 			 */
90 			flash_deinit(base);
91 
92 			/* Disable clock before changing clock source */
93 			CLKCTL0->PSCCTL0_CLR = CLKCTL0_PSCCTL0_CLR_FLEXSPI_OTFAD_CLK_MASK;
94 			/* Update flexspi clock */
95 			CLKCTL0->FLEXSPIFCLKSEL = CLKCTL0_FLEXSPIFCLKSEL_SEL(src);
96 			/* Reset the divider counter */
97 			CLKCTL0->FLEXSPIFCLKDIV |= CLKCTL0_FLEXSPIFCLKDIV_RESET_MASK;
98 			CLKCTL0->FLEXSPIFCLKDIV = CLKCTL0_FLEXSPIFCLKDIV_DIV(divider - 1);
99 			while ((CLKCTL0->FLEXSPIFCLKDIV) & CLKCTL0_FLEXSPIFCLKDIV_REQFLAG_MASK) {
100 			}
101 			/* Enable FLEXSPI clock again */
102 			CLKCTL0->PSCCTL0_SET = CLKCTL0_PSCCTL0_SET_FLEXSPI_OTFAD_CLK_MASK;
103 
104 			flash_init(base);
105 		}
106 	} else {
107 		return;
108 	}
109 }
110 
111 /* This function is used to change FlexSPI clock to a stable source before clock
112  * sources(Such as PLL and Main clock) updating in case XIP (execute code on
113  * FLEXSPI memory.)
114  */
flexspi_clock_safe_config(void)115 void flexspi_clock_safe_config(void)
116 {
117 	/* Move FLEXSPI clock source from main clock to FRO192M / 2 to avoid instruction/data
118 	 * fetch issue in XIP when updating PLL and main clock.
119 	 */
120 	flexspi_setup_clock(FLEXSPI, 3U, 1U);
121 }
122