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, ¤t_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