1 /*
2  * Copyright (c) 2021, NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Note: this file is linked to RAM. Any functions called while changing clocks
7  * to the flexspi modules must be linked to RAM, or within this file
8  */
9 
10 #include <zephyr/init.h>
11 #include <power.h>
12 #include <zephyr/kernel.h>
13 #include <fsl_clock.h>
14 
15 /*
16  * Clock configuration structures populated at boot time. These structures are
17  * used to reinitialize the PLLs after exiting low power mode.
18  */
19 #ifdef CONFIG_INIT_ARM_PLL
20 static clock_arm_pll_config_t arm_pll_config;
21 #endif
22 #ifdef CONFIG_INIT_VIDEO_PLL
23 static clock_video_pll_config_t video_pll_config;
24 #endif
25 #ifdef CONFIG_INIT_ENET_PLL
26 static clock_enet_pll_config_t enet_pll_config;
27 #endif
28 static clock_sys_pll_config_t sys_pll_config;
29 static clock_usb_pll_config_t usb1_pll_config;
30 
31 #define IMX_RT_SYS_PFD_FRAC(reg, pfd_num) \
32 	(((reg) >> (8U * pfd_num)) &\
33 	CCM_ANALOG_PFD_528_PFD0_FRAC_MASK)
34 #define IMX_RT_USB1_PFD_FRAC(reg, pfd_num) \
35 	(((reg) >> (8U * pfd_num)) &\
36 	CCM_ANALOG_PFD_480_PFD0_FRAC_MASK)
37 
38 uint8_t sys_pll_pfd0_frac;
39 uint8_t sys_pll_pfd1_frac;
40 uint8_t sys_pll_pfd2_frac;
41 uint8_t sys_pll_pfd3_frac;
42 
43 uint8_t usb1_pll_pfd1_frac;
44 uint8_t usb1_pll_pfd2_frac;
45 uint8_t usb1_pll_pfd3_frac;
46 
47 uint32_t flexspi_div;
48 
49 /*
50  * Duplicate implementation of CLOCK_SetMux() provided by SDK. This function
51  * must be linked to ITCM, as it will be used to change the clocks of the
52  * FLEXSPI and SEMC peripherals.
53  * Any function called from this function must also reside in ITCM
54  */
clock_set_mux(clock_mux_t mux,uint32_t value)55 static void clock_set_mux(clock_mux_t mux, uint32_t value)
56 {
57 	uint32_t busy_shift;
58 
59 	busy_shift = (uint32_t)CCM_TUPLE_BUSY_SHIFT(mux);
60 	CCM_TUPLE_REG(CCM, mux) = (CCM_TUPLE_REG(CCM, mux) & (~CCM_TUPLE_MASK(mux))) |
61 		  (((uint32_t)((value) << CCM_TUPLE_SHIFT(mux))) & CCM_TUPLE_MASK(mux));
62 
63 	/* Clock switch need Handshake? */
64 	if (busy_shift != CCM_NO_BUSY_WAIT) {
65 		/* Wait until CCM internal handshake finish. */
66 		while ((CCM->CDHIPR & ((1UL << busy_shift))) != 0UL) {
67 		}
68 	}
69 }
70 
71 /*
72  * Duplicate implementation of CLOCK_SetDiv() provided by SDK. This function
73  * must be linked to ITCM, as it will be used to change the clocks of the
74  * FLEXSPI and SEMC peripherals.
75  * Any function called from this function must also reside in ITCM
76  */
clock_set_div(clock_div_t divider,uint32_t value)77 static void clock_set_div(clock_div_t divider, uint32_t value)
78 {
79 	uint32_t busy_shift;
80 
81 	busy_shift = CCM_TUPLE_BUSY_SHIFT(divider);
82 	CCM_TUPLE_REG(CCM, divider) = (CCM_TUPLE_REG(CCM, divider) & (~CCM_TUPLE_MASK(divider))) |
83 		(((uint32_t)((value) << CCM_TUPLE_SHIFT(divider))) & CCM_TUPLE_MASK(divider));
84 
85 	/* Clock switch need Handshake? */
86 	if (busy_shift != CCM_NO_BUSY_WAIT) {
87 		/* Wait until CCM internal handshake finish. */
88 		while ((CCM->CDHIPR & ((uint32_t)(1UL << busy_shift))) != 0UL) {
89 		}
90 	}
91 }
92 
93 /*
94  * Duplicate implementation of CLOCK_InitUsb1Pll() provided by SDK. This function
95  * must be linked to ITCM, as it will be used to change the clocks of the
96  * FLEXSPI and SEMC peripherals.
97  * Any function called from this function must also reside in ITCM
98  */
clock_init_usb1_pll(const clock_usb_pll_config_t * config)99 static void clock_init_usb1_pll(const clock_usb_pll_config_t *config)
100 {
101 	/* Bypass PLL first */
102 	CCM_ANALOG->PLL_USB1 = (CCM_ANALOG->PLL_USB1 & (~CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_MASK)) |
103 		CCM_ANALOG_PLL_USB1_BYPASS_MASK | CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC(config->src);
104 
105 	CCM_ANALOG->PLL_USB1 = (CCM_ANALOG->PLL_USB1 & (~CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK)) |
106 		CCM_ANALOG_PLL_USB1_ENABLE_MASK | CCM_ANALOG_PLL_USB1_POWER_MASK |
107 		CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK |
108 		CCM_ANALOG_PLL_USB1_DIV_SELECT(config->loopDivider);
109 
110 	while ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_LOCK_MASK) == 0UL) {
111 		;
112 	}
113 
114 	/* Disable Bypass */
115 	CCM_ANALOG->PLL_USB1 &= ~CCM_ANALOG_PLL_USB1_BYPASS_MASK;
116 }
117 
flexspi_enter_critical(void)118 static void flexspi_enter_critical(void)
119 {
120 #if DT_SAME_NODE(DT_NODELABEL(flexspi2), DT_PARENT(DT_CHOSEN(zephyr_flash)))
121 	/* Wait for flexspi to be inactive, and gate the clock */
122 	while (!((FLEXSPI2->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) &&
123 			(FLEXSPI2->STS0 & FLEXSPI_STS0_SEQIDLE_MASK))) {
124 	}
125 	FLEXSPI2->MCR0 |= FLEXSPI_MCR0_MDIS_MASK;
126 
127 	/* Disable clock gate of flexspi2. */
128 	CCM->CCGR7 &= (~CCM_CCGR7_CG1_MASK);
129 #endif
130 
131 #if DT_SAME_NODE(DT_NODELABEL(flexspi), DT_PARENT(DT_CHOSEN(zephyr_flash)))
132 	/* Wait for flexspi to be inactive, and gate the clock */
133 	while (!((FLEXSPI->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) &&
134 			(FLEXSPI->STS0 & FLEXSPI_STS0_SEQIDLE_MASK))) {
135 	}
136 	FLEXSPI->MCR0 |= FLEXSPI_MCR0_MDIS_MASK;
137 
138 	/* Disable clock of flexspi. */
139 	CCM->CCGR6 &= (~CCM_CCGR6_CG5_MASK);
140 #endif
141 }
142 
flexspi_exit_critical(void)143 static void flexspi_exit_critical(void)
144 {
145 #if DT_SAME_NODE(DT_NODELABEL(flexspi2), DT_PARENT(DT_CHOSEN(zephyr_flash)))
146 	/* Enable clock gate of flexspi2. */
147 	CCM->CCGR7 |= (CCM_CCGR7_CG1_MASK);
148 
149 	FLEXSPI2->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;
150 	FLEXSPI2->MCR0 |= FLEXSPI_MCR0_SWRESET_MASK;
151 	while (FLEXSPI2->MCR0 & FLEXSPI_MCR0_SWRESET_MASK) {
152 	}
153 	while (!((FLEXSPI2->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) &&
154 		(FLEXSPI2->STS0 & FLEXSPI_STS0_SEQIDLE_MASK))) {
155 	}
156 #elif DT_SAME_NODE(DT_NODELABEL(flexspi), DT_PARENT(DT_CHOSEN(zephyr_flash)))
157 	/* Enable clock of flexspi. */
158 	CCM->CCGR6 |= CCM_CCGR6_CG5_MASK;
159 
160 	FLEXSPI->MCR0 &= ~FLEXSPI_MCR0_MDIS_MASK;
161 	FLEXSPI->MCR0 |= FLEXSPI_MCR0_SWRESET_MASK;
162 	while (FLEXSPI->MCR0 & FLEXSPI_MCR0_SWRESET_MASK) {
163 	}
164 	while (!((FLEXSPI->STS0 & FLEXSPI_STS0_ARBIDLE_MASK) &&
165 		(FLEXSPI->STS0 & FLEXSPI_STS0_SEQIDLE_MASK))) {
166 	}
167 #endif
168 	/* Invalidate I-cache after flexspi clock changed. */
169 	if (SCB_CCR_IC_Msk == (SCB_CCR_IC_Msk & SCB->CCR)) {
170 		SCB_InvalidateICache();
171 	}
172 }
173 
174 
clock_full_power(void)175 void clock_full_power(void)
176 {
177 	/* Power up PLLS */
178 	/* Set arm PLL div to divide by 2*/
179 	clock_set_div(kCLOCK_ArmDiv, 1);
180 #ifdef CONFIG_INIT_ARM_PLL
181 	/* Reinit arm pll based on saved configuration */
182 	CLOCK_InitArmPll(&arm_pll_config);
183 #endif
184 
185 #ifdef CONFIG_INIT_VIDEO_PLL
186 	/* Reinit video pll */
187 	CLOCK_InitVideoPll(&video_pll_config);
188 #endif
189 
190 #ifdef CONFIG_INIT_ENET_PLL
191 	/* Reinit enet pll */
192 	CLOCK_InitEnetPll(&enet_pll_config);
193 #endif
194 	/* Init SYS PLL */
195 	CLOCK_InitSysPll(&sys_pll_config);
196 
197 	/* Enable USB PLL PFD 1 2 3 */
198 	CLOCK_InitUsb1Pfd(kCLOCK_Pfd1, usb1_pll_pfd1_frac);
199 	CLOCK_InitUsb1Pfd(kCLOCK_Pfd2, usb1_pll_pfd2_frac);
200 	CLOCK_InitUsb1Pfd(kCLOCK_Pfd3, usb1_pll_pfd3_frac);
201 
202 	/* Enable SYS PLL PFD0 1 2 3 */
203 	CLOCK_InitSysPfd(kCLOCK_Pfd0, sys_pll_pfd0_frac);
204 	CLOCK_InitSysPfd(kCLOCK_Pfd1, sys_pll_pfd1_frac);
205 	CLOCK_InitSysPfd(kCLOCK_Pfd2, sys_pll_pfd2_frac);
206 	CLOCK_InitSysPfd(kCLOCK_Pfd3, sys_pll_pfd3_frac);
207 
208 	/* Switch to full speed clocks */
209 #if (defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1))
210 	flexspi_enter_critical();
211 #endif
212 
213 	/* Set Flexspi divider before increasing frequency of PLL3 PDF0. */
214 #if DT_SAME_NODE(DT_NODELABEL(flexspi), DT_PARENT(DT_CHOSEN(zephyr_flash)))
215 	clock_set_div(kCLOCK_FlexspiDiv, flexspi_div);
216 	clock_set_mux(kCLOCK_FlexspiMux, 3);
217 #endif
218 #if DT_SAME_NODE(DT_NODELABEL(flexspi2), DT_PARENT(DT_CHOSEN(zephyr_flash)))
219 	clock_set_div(kCLOCK_Flexspi2Div, flexspi_div);
220 	clock_set_mux(kCLOCK_Flexspi2Mux, 1);
221 #endif
222 	/* Init USB1 PLL. This will disable the PLL3 bypass. */
223 	clock_init_usb1_pll(&usb1_pll_config);
224 
225 	/* Switch SEMC clock to PLL2_PFD2 clock */
226 	clock_set_mux(kCLOCK_SemcMux, 1);
227 
228 	/* CORE CLK to 600MHz, AHB, IPG to 150MHz, PERCLK to 75MHz */
229 	clock_set_div(kCLOCK_PerclkDiv, 1);
230 	clock_set_div(kCLOCK_IpgDiv, 3);
231 	clock_set_div(kCLOCK_AhbDiv, 0);
232 	/* PERCLK mux to IPG CLK */
233 	clock_set_mux(kCLOCK_PerclkMux, 0);
234 	/* MUX to ENET_500M (RT1010-1024) / ARM_PODF (RT1050-1064) */
235 	clock_set_mux(kCLOCK_PrePeriphMux, 3);
236 	/* PERIPH mux to periph clock 2 output */
237 	clock_set_mux(kCLOCK_PeriphMux, 0);
238 
239 #if (defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1))
240 	flexspi_exit_critical();
241 #endif
242 
243 }
244 
clock_low_power(void)245 void clock_low_power(void)
246 {
247 #if (defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1))
248 	flexspi_enter_critical();
249 #endif
250 	/* Switch to 24MHz core clock, so ARM PLL can power down */
251 	clock_set_div(kCLOCK_PeriphClk2Div, 0);
252 	/* Switch to OSC clock */
253 	clock_set_mux(kCLOCK_PeriphClk2Mux, 1);
254 	/* Switch peripheral mux to 24MHz source */
255 	clock_set_mux(kCLOCK_PeriphMux, 1);
256 	/* Set PLL3 to bypass mode, output 24M clock */
257 	CCM_ANALOG->PLL_USB1_SET = CCM_ANALOG_PLL_USB1_BYPASS_MASK;
258 	CCM_ANALOG->PLL_USB1_SET = CCM_ANALOG_PLL_USB1_ENABLE_MASK;
259 	CCM_ANALOG->PFD_480_CLR = CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK;
260 	/* Change flexspi to use PLL3 PFD0 with no divisor (24M flexspi clock) */
261 #if DT_SAME_NODE(DT_NODELABEL(flexspi), DT_PARENT(DT_CHOSEN(zephyr_flash)))
262 	clock_set_div(kCLOCK_FlexspiDiv, 0);
263 	/* FLEXSPI1 mux to PLL3 PFD0 BYPASS */
264 	clock_set_mux(kCLOCK_FlexspiMux, 3);
265 #endif
266 #if DT_SAME_NODE(DT_NODELABEL(flexspi2), DT_PARENT(DT_CHOSEN(zephyr_flash)))
267 	clock_set_div(kCLOCK_Flexspi2Div, 0);
268 	/* FLEXSPI2 mux to PLL3 PFD0 BYPASS */
269 	clock_set_mux(kCLOCK_Flexspi2Mux, 1);
270 #endif
271 	/* CORE CLK to 24MHz and AHB, IPG, PERCLK to 12MHz */
272 	clock_set_div(kCLOCK_PerclkDiv, 0);
273 	clock_set_div(kCLOCK_IpgDiv, 1);
274 	clock_set_div(kCLOCK_AhbDiv, 0);
275 	/* PERCLK mux to IPG CLK */
276 	clock_set_mux(kCLOCK_PerclkMux, 0);
277 	/* Switch SEMC clock to peripheral clock */
278 	clock_set_mux(kCLOCK_SemcMux, 0);
279 #if (defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1))
280 	flexspi_exit_critical();
281 #endif
282 	/* After switching clocks, it is safe to power down the PLLs */
283 #ifdef CONFIG_INIT_ARM_PLL
284 	/* Deinit ARM PLL */
285 	CLOCK_DeinitArmPll();
286 #endif
287 	/* Deinit SYS PLL */
288 	CLOCK_DeinitSysPll();
289 
290 	/* Deinit SYS PLL PFD 0 1 2 3 */
291 	CLOCK_DeinitSysPfd(kCLOCK_Pfd0);
292 	CLOCK_DeinitSysPfd(kCLOCK_Pfd1);
293 	CLOCK_DeinitSysPfd(kCLOCK_Pfd2);
294 	CLOCK_DeinitSysPfd(kCLOCK_Pfd3);
295 
296 
297 	/* Deinit USB1 PLL PFD 1 2 3 */
298 	CLOCK_DeinitUsb1Pfd(kCLOCK_Pfd1);
299 	CLOCK_DeinitUsb1Pfd(kCLOCK_Pfd2);
300 	CLOCK_DeinitUsb1Pfd(kCLOCK_Pfd3);
301 
302 	/* Deinit VIDEO PLL */
303 	CLOCK_DeinitVideoPll();
304 
305 	/* Deinit ENET PLL */
306 	CLOCK_DeinitEnetPll();
307 }
308 
clock_lpm_init(void)309 void clock_lpm_init(void)
310 {
311 	uint32_t tmp_reg = 0;
312 
313 	CLOCK_SetMode(kCLOCK_ModeRun);
314 	/* Enable RC OSC. It needs at least 4ms to be stable, so self tuning need to be enabled. */
315 	XTALOSC24M->LOWPWR_CTRL |= XTALOSC24M_LOWPWR_CTRL_RC_OSC_EN_MASK;
316 	/* Configure RC OSC */
317 	XTALOSC24M->OSC_CONFIG0 = XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG_CUR(0x4) |
318 					XTALOSC24M_OSC_CONFIG0_SET_HYST_MINUS(0x2) |
319 					XTALOSC24M_OSC_CONFIG0_RC_OSC_PROG(0xA7) |
320 					XTALOSC24M_OSC_CONFIG0_START_MASK |
321 					XTALOSC24M_OSC_CONFIG0_ENABLE_MASK;
322 	XTALOSC24M->OSC_CONFIG1 = XTALOSC24M_OSC_CONFIG1_COUNT_RC_CUR(0x40) |
323 		XTALOSC24M_OSC_CONFIG1_COUNT_RC_TRG(0x2DC);
324 	/* Take some delay */
325 	SDK_DelayAtLeastUs(4000, SDK_DEVICE_MAXIMUM_CPU_CLOCK_FREQUENCY);
326 	/* Add some hysteresis */
327 	tmp_reg = XTALOSC24M->OSC_CONFIG0;
328 	tmp_reg &= ~(XTALOSC24M_OSC_CONFIG0_HYST_PLUS_MASK |
329 				XTALOSC24M_OSC_CONFIG0_HYST_MINUS_MASK);
330 	tmp_reg |= XTALOSC24M_OSC_CONFIG0_HYST_PLUS(3) | XTALOSC24M_OSC_CONFIG0_HYST_MINUS(3);
331 	XTALOSC24M->OSC_CONFIG0 = tmp_reg;
332 	/* Set COUNT_1M_TRG */
333 	tmp_reg = XTALOSC24M->OSC_CONFIG2;
334 	tmp_reg &= ~XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG_MASK;
335 	tmp_reg |= XTALOSC24M_OSC_CONFIG2_COUNT_1M_TRG(0x2d7);
336 	XTALOSC24M->OSC_CONFIG2 = tmp_reg;
337 	/* Hardware requires to read OSC_CONFIG0 or OSC_CONFIG1 to make OSC_CONFIG2 write work */
338 	tmp_reg = XTALOSC24M->OSC_CONFIG1;
339 	XTALOSC24M->OSC_CONFIG1 = tmp_reg;
340 }
341 
imxrt_lpm_init(void)342 static int imxrt_lpm_init(void)
343 {
344 
345 	struct clock_callbacks callbacks;
346 	uint32_t usb1_pll_pfd0_frac;
347 
348 	callbacks.clock_set_run = clock_full_power;
349 	callbacks.clock_set_low_power = clock_low_power;
350 	callbacks.clock_lpm_init = clock_lpm_init;
351 
352 	/*
353 	 * Read the boot time configuration of all PLLs.
354 	 * This is required because not all PLLs preserve register state
355 	 * when powered down. Additionally, populating these configuration
356 	 * structures enables the rest of the code to use the fsl_clock HAL api.
357 	 */
358 #ifdef CONFIG_INIT_ARM_PLL
359 	/* Read configuration values for arm pll */
360 	arm_pll_config.src = ((CCM_ANALOG->PLL_ARM &
361 		CCM_ANALOG_PLL_ARM_BYPASS_CLK_SRC_MASK) >>
362 		CCM_ANALOG_PLL_ARM_BYPASS_CLK_SRC_SHIFT);
363 	arm_pll_config.loopDivider = ((CCM_ANALOG->PLL_ARM &
364 		CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK) >>
365 		CCM_ANALOG_PLL_ARM_DIV_SELECT_SHIFT);
366 #endif
367 	/* Read configuration values for sys pll */
368 	sys_pll_config.src = ((CCM_ANALOG->PLL_SYS &
369 		CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC_MASK) >>
370 		CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC_SHIFT);
371 	sys_pll_config.loopDivider = ((CCM_ANALOG->PLL_SYS &
372 		CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK) >>
373 		CCM_ANALOG_PLL_SYS_DIV_SELECT_SHIFT);
374 	sys_pll_config.numerator = CCM_ANALOG->PLL_SYS_NUM;
375 	sys_pll_config.denominator = CCM_ANALOG->PLL_SYS_DENOM;
376 	sys_pll_config.ss_step = ((CCM_ANALOG->PLL_SYS_SS &
377 			CCM_ANALOG_PLL_SYS_SS_STEP_MASK) >>
378 			CCM_ANALOG_PLL_SYS_SS_STEP_SHIFT);
379 	sys_pll_config.ss_enable = ((CCM_ANALOG->PLL_SYS_SS &
380 			CCM_ANALOG_PLL_SYS_SS_ENABLE_MASK) >>
381 			CCM_ANALOG_PLL_SYS_SS_ENABLE_SHIFT);
382 	sys_pll_config.ss_stop = ((CCM_ANALOG->PLL_SYS_SS &
383 			CCM_ANALOG_PLL_SYS_SS_STOP_MASK) >>
384 			CCM_ANALOG_PLL_SYS_SS_STOP_SHIFT);
385 
386 	/* Read configuration values for usb1 pll */
387 	usb1_pll_config.src = ((CCM_ANALOG->PLL_USB1 &
388 		CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_MASK) >>
389 		CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_SHIFT);
390 	usb1_pll_config.loopDivider = ((CCM_ANALOG->PLL_USB1 &
391 		CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK) >>
392 		CCM_ANALOG_PLL_USB1_DIV_SELECT_SHIFT);
393 #ifdef CONFIG_INIT_VIDEO_PLL
394 	/* Read configuration values for video pll */
395 	video_pll_config.src = ((CCM_ANALOG->PLL_VIDEO &
396 		CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC_MASK) >>
397 		CCM_ANALOG_PLL_VIDEO_BYPASS_CLK_SRC_SHIFT);
398 	video_pll_config.loopDivider = ((CCM_ANALOG->PLL_VIDEO &
399 		CCM_ANALOG_PLL_VIDEO_DIV_SELECT_MASK) >>
400 		CCM_ANALOG_PLL_VIDEO_DIV_SELECT_SHIFT);
401 	video_pll_config.numerator = CCM_ANALOG->PLL_VIDEO_NUM;
402 	video_pll_config.denominator = CCM_ANALOG->PLL_VIDEO_DENOM;
403 	switch ((CCM_ANALOG->PLL_VIDEO &
404 		CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_MASK) >>
405 		CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_SHIFT) {
406 		case 0:
407 			video_pll_config.postDivider = 16;
408 			break;
409 		case 1:
410 			if (CCM_ANALOG->MISC2 & CCM_ANALOG_MISC2_VIDEO_DIV(3)) {
411 				video_pll_config.postDivider = 8;
412 			} else {
413 				video_pll_config.postDivider = 2;
414 			}
415 			break;
416 		case 2:
417 			if (CCM_ANALOG->MISC2 & CCM_ANALOG_MISC2_VIDEO_DIV(3)) {
418 				video_pll_config.postDivider = 4;
419 			} else {
420 				video_pll_config.postDivider = 1;
421 			}
422 			break;
423 		default:
424 			video_pll_config.postDivider = 1;
425 	}
426 #endif
427 #if CONFIG_INIT_ENET_PLL
428 	enet_pll_config.src = ((CCM_ANALOG->PLL_ENET &
429 		CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC_MASK) >>
430 		CCM_ANALOG_PLL_ENET_BYPASS_CLK_SRC_SHIFT);
431 	enet_pll_config.loopDivider = ((CCM_ANALOG->PLL_ENET &
432 		CCM_ANALOG_PLL_ENET_DIV_SELECT_MASK) >>
433 		CCM_ANALOG_PLL_ENET_DIV_SELECT_SHIFT);
434 	enet_pll_config.loopDivider1 = ((CCM_ANALOG->PLL_ENET &
435 		CCM_ANALOG_PLL_ENET_ENET2_DIV_SELECT_MASK) >>
436 		CCM_ANALOG_PLL_ENET_ENET2_DIV_SELECT_SHIFT);
437 	enet_pll_config.enableClkOutput = (CCM_ANALOG->PLL_ENET &
438 		CCM_ANALOG_PLL_ENET_ENABLE_MASK);
439 	enet_pll_config.enableClkOutput1 = (CCM_ANALOG->PLL_ENET &
440 		CCM_ANALOG_PLL_ENET_ENET2_REF_EN_MASK);
441 	enet_pll_config.enableClkOutput25M = (CCM_ANALOG->PLL_ENET &
442 		CCM_ANALOG_PLL_ENET_ENET_25M_REF_EN_MASK);
443 #endif
444 
445 	/* Record all pll PFD values that we intend to disable in low power mode */
446 	sys_pll_pfd0_frac = IMX_RT_SYS_PFD_FRAC(CCM_ANALOG->PFD_528, kCLOCK_Pfd0);
447 	sys_pll_pfd1_frac = IMX_RT_SYS_PFD_FRAC(CCM_ANALOG->PFD_528, kCLOCK_Pfd1);
448 	sys_pll_pfd2_frac = IMX_RT_SYS_PFD_FRAC(CCM_ANALOG->PFD_528, kCLOCK_Pfd2);
449 	sys_pll_pfd3_frac = IMX_RT_SYS_PFD_FRAC(CCM_ANALOG->PFD_528, kCLOCK_Pfd3);
450 
451 	usb1_pll_pfd0_frac = IMX_RT_USB1_PFD_FRAC(CCM_ANALOG->PFD_480, kCLOCK_Pfd0);
452 	/* The target full power frequency for the flexspi clock is ~100MHz.
453 	 * Use the PFD0 value currently set to calculate the div we should use for
454 	 * the full power flexspi div
455 	 * PFD output frequency formula = (480 * 18) / pfd0_frac
456 	 * flexspi div formula = FLOOR((480*18) / (pfd0_frac * target_full_power_freq))
457 	 */
458 	flexspi_div = (480 * 18) / (usb1_pll_pfd0_frac * 100);
459 
460 
461 	usb1_pll_pfd1_frac = IMX_RT_USB1_PFD_FRAC(CCM_ANALOG->PFD_480, kCLOCK_Pfd1);
462 	usb1_pll_pfd2_frac = IMX_RT_USB1_PFD_FRAC(CCM_ANALOG->PFD_480, kCLOCK_Pfd2);
463 	usb1_pll_pfd3_frac = IMX_RT_USB1_PFD_FRAC(CCM_ANALOG->PFD_480, kCLOCK_Pfd3);
464 
465 	/* Install LPM callbacks */
466 	imxrt_clock_pm_callbacks_register(&callbacks);
467 	return 0;
468 }
469 
470 
471 SYS_INIT(imxrt_lpm_init, PRE_KERNEL_1, 0);
472