1 /*
2  * Copyright 2022-2023 NXP
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #include <zephyr/init.h>
7 #include "fsl_power.h"
8 #include "fsl_inputmux.h"
9 #include <zephyr/pm/policy.h>
10 #include "board.h"
11 
12 #ifdef CONFIG_FLASH_MCUX_FLEXSPI_XIP
13 #include "flash_clock_setup.h"
14 #endif
15 
16 /* OTP fuse index. */
17 #define FRO_192MHZ_SC_TRIM 0x2C
18 #define FRO_192MHZ_RD_TRIM 0x2B
19 #define FRO_96MHZ_SC_TRIM  0x2E
20 #define FRO_96MHZ_RD_TRIM  0x2D
21 
22 #define OTP_FUSE_READ_API ((void (*)(uint32_t addr, uint32_t *data))0x1300805D)
23 
24 #define PMIC_MODE_BOOT			0U
25 #define PMIC_MODE_DEEP_SLEEP		1U
26 #define PMIC_MODE_FRO192M_900MV		2U
27 #define PMIC_MODE_FRO96M_800MV		3U
28 
29 #define PMIC_SETTLING_TIME		2000U	/* in micro-seconds */
30 
31 static uint32_t sc_trim_192, rd_trim_192, sc_trim_96, rd_trim_96;
32 
33 #if CONFIG_REGULATOR
34 #include <zephyr/drivers/regulator.h>
35 
36 #define NODE_PCA9420	DT_NODELABEL(pca9420)
37 #define NODE_SW1	DT_NODELABEL(pca9420_sw1)
38 #define NODE_SW2	DT_NODELABEL(pca9420_sw2)
39 #define NODE_LDO1	DT_NODELABEL(pca9420_ldo1)
40 #define NODE_LDO2	DT_NODELABEL(pca9420_ldo2)
41 static const struct device *pca9420 = DEVICE_DT_GET(NODE_PCA9420);
42 static const struct device *sw1 = DEVICE_DT_GET(NODE_SW1);
43 static const struct device *sw2 = DEVICE_DT_GET(NODE_SW2);
44 static const struct device *ldo1 = DEVICE_DT_GET(NODE_LDO1);
45 static const struct device *ldo2 = DEVICE_DT_GET(NODE_LDO2);
46 
47 static int current_power_profile;
48 
49 #define MEGA (1000000U)
50 
51 /* Core frequency levels number. */
52 #define POWER_FREQ_LEVELS_NUM (5U)
53 
54 /* Invalid voltage level. */
55 #define POWER_INVALID_VOLT_LEVEL (0xFFFFFFFFU)
56 
57 static const uint32_t power_freq_level[POWER_FREQ_LEVELS_NUM] = {
58 	275U * MEGA,
59 	230U * MEGA,
60 	192U * MEGA,
61 	100U * MEGA,
62 	60U * MEGA
63 };
64 
65 /* System clock frequency. */
66 extern uint32_t SystemCoreClock;
67 
68 static const int32_t sw1_volt[] = {1100000, 1000000, 900000, 800000, 700000};
69 
board_calc_volt_level(void)70 static int32_t board_calc_volt_level(void)
71 {
72 	uint32_t i;
73 	uint32_t volt;
74 
75 	for (i = 0U; i < POWER_FREQ_LEVELS_NUM; i++) {
76 		if (SystemCoreClock > power_freq_level[i]) {
77 			break;
78 		}
79 	}
80 
81 	/* Frequency exceed max supported */
82 	if (i == 0U) {
83 		volt = POWER_INVALID_VOLT_LEVEL;
84 	} else {
85 		volt = sw1_volt[i - 1U];
86 	}
87 
88 	return volt;
89 }
90 
board_config_pmic(void)91 static int board_config_pmic(void)
92 {
93 	uint32_t volt;
94 	int ret = 0;
95 
96 	volt = board_calc_volt_level();
97 
98 	ret = regulator_set_voltage(sw1, volt, volt);
99 	if (ret != 0) {
100 		return ret;
101 	}
102 
103 	ret = regulator_set_voltage(sw2, 1800000, 1800000);
104 	if (ret != 0) {
105 		return ret;
106 	}
107 
108 	ret = regulator_set_voltage(ldo1, 1800000, 1800000);
109 	if (ret != 0) {
110 		return ret;
111 	}
112 
113 	ret = regulator_set_voltage(ldo2, 3300000, 3300000);
114 	if (ret != 0) {
115 		return ret;
116 	}
117 
118 	/* We can enter deep low power modes */
119 	pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
120 
121 	return ret;
122 }
123 
board_pmic_change_mode(uint8_t pmic_mode)124 static int board_pmic_change_mode(uint8_t pmic_mode)
125 {
126 	int ret;
127 
128 	if (pmic_mode >= 4) {
129 		return -ERANGE;
130 	}
131 
132 	ret = regulator_parent_dvs_state_set(pca9420, pmic_mode);
133 	if (ret != -EPERM) {
134 		return ret;
135 	}
136 
137 	POWER_SetPmicMode(pmic_mode, kCfg_Run);
138 	k_busy_wait(PMIC_SETTLING_TIME);
139 
140 	return 0;
141 }
142 
143 /* Changes power-related config to preset profiles, like clocks and VDDCORE voltage */
power_manager_set_profile(uint32_t power_profile)144 __ramfunc int32_t power_manager_set_profile(uint32_t power_profile)
145 {
146 	bool voltage_changed = false;
147 	int32_t current_uv, future_uv;
148 	int ret;
149 
150 	if (power_profile == current_power_profile) {
151 		return 0;
152 	}
153 
154 	/* Confirm valid power_profile, and read the new VDDCORE voltage */
155 	switch (power_profile) {
156 	case POWER_PROFILE_AFTER_BOOT:
157 		future_uv = DT_PROP(NODE_SW1, nxp_mode0_microvolt);
158 		break;
159 
160 	case POWER_PROFILE_FRO192M_900MV:
161 		future_uv = DT_PROP(NODE_SW1, nxp_mode2_microvolt);
162 		break;
163 
164 	case POWER_PROFILE_FRO96M_800MV:
165 		future_uv = DT_PROP(NODE_SW1, nxp_mode3_microvolt);
166 		break;
167 
168 	default:
169 		return -EINVAL;
170 	}
171 
172 	if (current_power_profile == POWER_PROFILE_AFTER_BOOT) {
173 		/* One-Time optimization after boot */
174 
175 		POWER_DisableLVD();
176 
177 		CLOCK_AttachClk(kFRO_DIV1_to_MAIN_CLK);
178 		/* Set SYSCPUAHBCLKDIV divider to value 1 */
179 		CLOCK_SetClkDiv(kCLOCK_DivSysCpuAhbClk, 1U);
180 
181 		/* Other clock optimizations */
182 	#ifdef CONFIG_FLASH_MCUX_FLEXSPI_XIP
183 		flexspi_setup_clock(FLEXSPI0, 0U, 1U);	/* main_clk div by 1 */
184 	#endif
185 		/* Disable the PFDs of SYSPLL */
186 		CLKCTL0->SYSPLL0PFD |=	CLKCTL0_SYSPLL0PFD_PFD0_CLKGATE_MASK |
187 					CLKCTL0_SYSPLL0PFD_PFD1_CLKGATE_MASK |
188 					CLKCTL0_SYSPLL0PFD_PFD2_CLKGATE_MASK;
189 
190 		POWER_EnablePD(kPDRUNCFG_PD_SYSPLL_LDO);
191 		POWER_EnablePD(kPDRUNCFG_PD_SYSPLL_ANA);
192 		POWER_EnablePD(kPDRUNCFG_PD_AUDPLL_LDO);
193 		POWER_EnablePD(kPDRUNCFG_PD_AUDPLL_ANA);
194 		POWER_EnablePD(kPDRUNCFG_PD_SYSXTAL);
195 
196 		/* Configure MCU that PMIC supplies will be powered in all
197 		 * PMIC modes
198 		 */
199 		PMC->PMICCFG = 0xFF;
200 
201 	}
202 
203 	/* Get current and future PMIC voltages to determine DVFS sequence */
204 	ret = regulator_get_voltage(sw1, &current_uv);
205 	if (ret) {
206 		return ret;
207 	}
208 
209 	if (power_profile == POWER_PROFILE_FRO192M_900MV) {
210 		/* check if voltage or frequency change is first */
211 		if (future_uv > current_uv) {
212 			/* Increase voltage first before frequencies */
213 			ret = board_pmic_change_mode(PMIC_MODE_FRO192M_900MV);
214 			if (ret) {
215 				return ret;
216 			}
217 
218 			voltage_changed = true;
219 		}
220 
221 		/* Trim FRO to 192MHz */
222 		CLKCTL0->FRO_SCTRIM = sc_trim_192;
223 		CLKCTL0->FRO_RDTRIM = rd_trim_192;
224 		/* Reset the EXP_COUNT. */
225 		CLKCTL0->FRO_CONTROL &= ~CLKCTL0_FRO_CONTROL_EXP_COUNT_MASK;
226 
227 		CLOCK_AttachClk(kFRO_DIV1_to_MAIN_CLK);
228 		/* Set SYSCPUAHBCLKDIV divider to value 1 */
229 		CLOCK_SetClkDiv(kCLOCK_DivSysCpuAhbClk, 1U);
230 
231 		if (voltage_changed == false) {
232 			ret = board_pmic_change_mode(PMIC_MODE_FRO192M_900MV);
233 			if (ret) {
234 				return ret;
235 			}
236 		}
237 
238 	} else if (power_profile == POWER_PROFILE_FRO96M_800MV) {
239 		/* This PMIC mode is the lowest voltage used for DVFS,
240 		 * Reduce frequency first, and then reduce voltage
241 		 */
242 
243 		/* Trim the FRO to 96MHz */
244 		CLKCTL0->FRO_SCTRIM = sc_trim_96;
245 		CLKCTL0->FRO_RDTRIM = rd_trim_96;
246 		/* Reset the EXP_COUNT. */
247 		CLKCTL0->FRO_CONTROL &= ~CLKCTL0_FRO_CONTROL_EXP_COUNT_MASK;
248 
249 		CLOCK_AttachClk(kFRO_DIV1_to_MAIN_CLK);
250 		/* Set SYSCPUAHBCLKDIV divider to value 1 */
251 		CLOCK_SetClkDiv(kCLOCK_DivSysCpuAhbClk, 1U);
252 
253 		ret = board_pmic_change_mode(PMIC_MODE_FRO96M_800MV);
254 		if (ret) {
255 			return ret;
256 		}
257 	}
258 
259 	current_power_profile = power_profile;
260 
261 	return 0;
262 }
263 
264 #endif /* CONFIG_REGULATOR */
265 
board_early_init_hook(void)266 void board_early_init_hook(void)
267 {
268 	/* Set the correct voltage range according to the board. */
269 	power_pad_vrange_t vrange = {
270 		.Vdde0Range = kPadVol_171_198,
271 		.Vdde1Range = kPadVol_171_198,
272 		.Vdde2Range = kPadVol_171_198,
273 		.Vdde3Range = kPadVol_300_360,
274 		.Vdde4Range = kPadVol_171_198
275 	};
276 
277 	POWER_SetPadVolRange(&vrange);
278 
279 	/* Do not enter deep low power modes until the PMIC modes have been initialized */
280 	pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
281 
282 #ifdef CONFIG_I2S
283 #ifdef CONFIG_I2S_TEST_SEPARATE_DEVICES
284 	/* Set shared signal set 0 SCK, WS from Transmit I2S - Flexcomm3 */
285 	SYSCTL1->SHAREDCTRLSET[0] = SYSCTL1_SHAREDCTRLSET_SHAREDSCKSEL(3) |
286 				SYSCTL1_SHAREDCTRLSET_SHAREDWSSEL(3);
287 	/* Select Data in from Transmit I2S - Flexcomm 3 */
288 	SYSCTL1->SHAREDCTRLSET[0] |= SYSCTL1_SHAREDCTRLSET_SHAREDDATASEL(3);
289 	/* Enable Transmit I2S - Flexcomm 3 for Shared Data Out */
290 	SYSCTL1->SHAREDCTRLSET[0] |= SYSCTL1_SHAREDCTRLSET_FC3DATAOUTEN(1);
291 #else
292 	/* Set shared signal set 0: SCK, WS from Flexcomm1 */
293 	SYSCTL1->SHAREDCTRLSET[0] = SYSCTL1_SHAREDCTRLSET_SHAREDSCKSEL(1) |
294 				SYSCTL1_SHAREDCTRLSET_SHAREDWSSEL(1);
295 #endif
296 	/* Set Receive I2S - Flexcomm 1 SCK, WS from shared signal set 0 */
297 	SYSCTL1->FCCTRLSEL[1] = SYSCTL1_FCCTRLSEL_SCKINSEL(1) |
298 				SYSCTL1_FCCTRLSEL_WSINSEL(1);
299 	/* Set Transmit I2S - Flexcomm 3 SCK, WS from shared signal set 0 */
300 	SYSCTL1->FCCTRLSEL[3] = SYSCTL1_FCCTRLSEL_SCKINSEL(1) |
301 				SYSCTL1_FCCTRLSEL_WSINSEL(1);
302 #ifdef CONFIG_I2S_TEST_SEPARATE_DEVICES
303 	/* Select Receive I2S - Flexcomm 1 Data in from shared signal set 0 */
304 	SYSCTL1->FCCTRLSEL[1] |= SYSCTL1_FCCTRLSEL_DATAINSEL(1);
305 	/* Select Transmit I2S - Flexcomm 3 Data out to shared signal set 0 */
306 	SYSCTL1->FCCTRLSEL[3] |= SYSCTL1_FCCTRLSEL_DATAOUTSEL(1);
307 #endif /* CONFIG_I2S_TEST_SEPARATE_DEVICES */
308 #endif /* CONFIG_I2S */
309 
310 	/* Configure the DMA requests in the INPUTMUX */
311 	INPUTMUX_Init(INPUTMUX);
312 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(dma0))
313 	/* Enable the DMA requests with only 1 mux option.  The other request
314 	 * choices should be configured for the application
315 	 */
316 	INPUTMUX_EnableSignal(INPUTMUX,
317 			kINPUTMUX_Flexcomm11RxToDmac0Ch32RequestEna, true);
318 	INPUTMUX_EnableSignal(INPUTMUX,
319 			kINPUTMUX_Flexcomm11TxToDmac0Ch33RequestEna, true);
320 	INPUTMUX_EnableSignal(INPUTMUX,
321 			kINPUTMUX_Flexcomm12RxToDmac0Ch34RequestEna, true);
322 	INPUTMUX_EnableSignal(INPUTMUX,
323 			kINPUTMUX_Flexcomm12TxToDmac0Ch35RequestEna, true);
324 	INPUTMUX_EnableSignal(INPUTMUX,
325 			kINPUTMUX_Flexcomm16RxToDmac0Ch28RequestEna, true);
326 	INPUTMUX_EnableSignal(INPUTMUX,
327 			kINPUTMUX_Flexcomm16TxToDmac0Ch29RequestEna, true);
328 	INPUTMUX_EnableSignal(INPUTMUX,
329 			kINPUTMUX_I3c1RxToDmac0Ch30RequestEna, true);
330 	INPUTMUX_EnableSignal(INPUTMUX,
331 			kINPUTMUX_I3c1TxToDmac0Ch31RequestEna, true);
332 #endif /* dma0 */
333 
334 #if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(dma1))
335 	/* Enable the DMA requests with only 1 mux option.  The other request
336 	 * choices should be configured for the application
337 	 */
338 	INPUTMUX_EnableSignal(INPUTMUX,
339 			kINPUTMUX_Flexcomm11RxToDmac1Ch32RequestEna, true);
340 	INPUTMUX_EnableSignal(INPUTMUX,
341 			kINPUTMUX_Flexcomm11TxToDmac1Ch33RequestEna, true);
342 	INPUTMUX_EnableSignal(INPUTMUX,
343 			kINPUTMUX_Flexcomm12RxToDmac1Ch34RequestEna, true);
344 	INPUTMUX_EnableSignal(INPUTMUX,
345 			kINPUTMUX_Flexcomm12TxToDmac1Ch35RequestEna, true);
346 	INPUTMUX_EnableSignal(INPUTMUX,
347 			kINPUTMUX_Flexcomm16RxToDmac1Ch28RequestEna, true);
348 	INPUTMUX_EnableSignal(INPUTMUX,
349 			kINPUTMUX_Flexcomm16TxToDmac1Ch29RequestEna, true);
350 	INPUTMUX_EnableSignal(INPUTMUX,
351 			kINPUTMUX_I3c1RxToDmac1Ch30RequestEna, true);
352 	INPUTMUX_EnableSignal(INPUTMUX,
353 			kINPUTMUX_I3c1TxToDmac1Ch31RequestEna, true);
354 #endif /* dma1 */
355 
356 #ifdef CONFIG_REBOOT
357 	/*
358 	 * The sys_reboot API calls NVIC_SystemReset. On the RT595, the warm
359 	 * reset will not complete correctly unless the ROM toggles the
360 	 * flash reset pin. We can control this behavior using the OTP shadow
361 	 * register for OPT word BOOT_CFG1
362 	 *
363 	 * Set FLEXSPI_RESET_PIN_ENABLE=1, FLEXSPI_RESET_PIN= PIO4_5
364 	 */
365 	 OCOTP0->OTP_SHADOW[97] = 0x164000;
366 #endif /* CONFIG_REBOOT */
367 
368 	/* Read 192M FRO clock Trim settings from fuses.
369 	 * NOTE: Reading OTP fuses requires a VDDCORE voltage of at least 1.0V
370 	 */
371 	OTP_FUSE_READ_API(FRO_192MHZ_SC_TRIM, &sc_trim_192);
372 	OTP_FUSE_READ_API(FRO_192MHZ_RD_TRIM, &rd_trim_192);
373 
374 	/* Read 96M FRO clock Trim settings from fuses. */
375 	OTP_FUSE_READ_API(FRO_96MHZ_SC_TRIM, &sc_trim_96);
376 	OTP_FUSE_READ_API(FRO_96MHZ_RD_TRIM, &rd_trim_96);
377 
378 	/* Check if the 96MHz fuses have been programmed.
379 	 * Production devices have 96M trim values programmed in OTP fuses.
380 	 * However, older EVKs may have pre-production silicon.
381 	 */
382 	if ((rd_trim_96 == 0) && (sc_trim_96 == 0)) {
383 		/* If not programmed then use software to calculate the trim values */
384 		CLOCK_FroTuneToFreq(96000000u);
385 		rd_trim_96 = CLKCTL0->FRO_RDTRIM;
386 		sc_trim_96 = sc_trim_192;
387 	}
388 }
389 
390 
391 #ifdef CONFIG_LV_Z_VDB_CUSTOM_SECTION
392 extern char __flexspi2_start[];
393 extern char __flexspi2_end[];
394 
init_psram_framebufs(void)395 static int init_psram_framebufs(void)
396 {
397 	/*
398 	 * Framebuffers will be stored in PSRAM, within FlexSPI2 linker
399 	 * section. Zero out BSS section.
400 	 */
401 	memset(__flexspi2_start, 0, __flexspi2_end - __flexspi2_start);
402 	return 0;
403 }
404 
405 #endif /* CONFIG_LV_Z_VDB_CUSTOM_SECTION */
406 
407 #if CONFIG_REGULATOR
408 /* PMIC setup is dependent on the regulator API */
409 SYS_INIT(board_config_pmic, POST_KERNEL, CONFIG_APPLICATION_INIT_PRIORITY);
410 #endif
411 
412 #ifdef CONFIG_LV_Z_VDB_CUSTOM_SECTION
413 /* Framebuffers should be setup after PSRAM is initialized but before
414  * Graphics framework init
415  */
416 SYS_INIT(init_psram_framebufs, POST_KERNEL, CONFIG_APPLICATION_INIT_PRIORITY);
417 #endif
418