Skip to main content

esp_hal/rtc_cntl/rtc/
esp32p4.rs

1use strum::FromRepr;
2
3use crate::{
4    peripherals::PMU,
5    soc::{clocks::ClockConfig, regi2c},
6};
7
8// `dig_sysclk_sel` codes (SOC_CPU_CLK_SRC_*).
9const HP_SYSCLK_XTAL: u8 = 0;
10
11/// SOC Reset Reason.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, FromRepr)]
13#[repr(usize)]
14#[cfg_attr(feature = "defmt", derive(defmt::Format))]
15pub enum SocResetReason {
16    /// Powers on reset.
17    ChipPowerOn   = 0x01,
18    /// Software resets the digital core
19    CoreSw        = 0x03,
20    /// Deep sleep reset the digital core
21    CoreDeepSleep = 0x05,
22    /// SDIO Core reset
23    CoreSDIO      = 0x06,
24    /// Main watch dog 0 resets digital core
25    CoreMwdt0     = 0x07,
26    /// Main watch dog 1 resets digital core
27    CoreMwdt1     = 0x08,
28    /// RTC watch dog resets digital core
29    CoreRtcWdt    = 0x09,
30    /// Main watch dog 0 resets CPU 0
31    Cpu0Mwdt0     = 0x0B,
32    /// Software resets CPU 0
33    Cpu0Sw        = 0x0C,
34    /// RTC watch dog resets CPU 0
35    Cpu0RtcWdt    = 0x0D,
36    /// VDD voltage is not stable and resets the digital core.
37    SysBrownOut   = 0x0F,
38    /// RTC watch dog resets digital core and rtc module
39    SysRtcWdt     = 0x10,
40    /// Main watch dog 1 resets CPU 0
41    Cpu0Mwdt1     = 0x11,
42    /// Super watch dog resets the digital core and rtc module
43    SysSuperWdt   = 0x12,
44    /// eFuse CRC error resets the digital core
45    CoreEfuseCrc  = 0x14,
46    /// USB UART resets the digital core
47    CoreUsbUart   = 0x15,
48    /// USB JTAG resets the digital core
49    CoreUsbJtag   = 0x16,
50    /// JTAG resets CPU
51    Cpu0JtagCpu   = 0x18,
52}
53
54/// Clears all force flags on PMU power domains to allow normal power management.
55///
56/// eco5 power domains (verified against PAC):
57///   - TOP: power_pd_top_cntl (system top-level)
58///   - CNNT: power_pd_cnnt_cntl (connectivity, eco5 new -- replaces hpaon/hpcpu/hpwifi)
59///   - HPMEM: power_pd_hpmem_cntl (HP memory)
60///   - CPU: power_pd_hp_cpu_cntl (the CPU that a light sleep with retention powers down)
61///   - LPPERI: power_pd_lpperi_cntl (LP peripherals, eco5 new)
62///
63/// esp-idf clears the same flags for TOP, CNNT, HPMEM and CPU (`esp32p4/pmu_init.c:142-160`).
64fn pmu_power_domain_force_default() {
65    let pmu = PMU::regs();
66
67    // PMU_HP_PD_TOP
68    pmu.power_pd_top_cntl().modify(|_, w| {
69        w.force_top_reset().bit(false);
70        w.force_top_iso().bit(false);
71        w.force_top_pu().bit(false);
72        w.force_top_no_reset().bit(false);
73        w.force_top_no_iso().bit(false);
74        w.force_top_pd().bit(false)
75    });
76
77    // PMU_HP_PD_CNNT (eco5: replaces hpaon + hpcpu + hpwifi from eco4)
78    pmu.power_pd_cnnt_cntl().modify(|_, w| {
79        w.force_cnnt_reset().bit(false);
80        w.force_cnnt_iso().bit(false);
81        w.force_cnnt_pu().bit(false);
82        w.force_cnnt_no_reset().bit(false);
83        w.force_cnnt_no_iso().bit(false);
84        w.force_cnnt_pd().bit(false)
85    });
86
87    // PMU_HP_PD_HPMEM
88    pmu.power_pd_hpmem_cntl().modify(|_, w| {
89        w.force_hp_mem_reset().bit(false);
90        w.force_hp_mem_iso().bit(false);
91        w.force_hp_mem_pu().bit(false);
92        w.force_hp_mem_no_reset().bit(false);
93        w.force_hp_mem_no_iso().bit(false);
94        w.force_hp_mem_pd().bit(false)
95    });
96
97    // PMU_HP_PD_CPU. A force flag here keeps the CPU domain powered through a sleep that asks for
98    // the power-down, so a light sleep with CPU retention needs this clear.
99    pmu.power_pd_hp_cpu_cntl().modify(|_, w| {
100        w.force_hp_cpu_reset().bit(false);
101        w.force_hp_cpu_iso().bit(false);
102        w.force_hp_cpu_pu().bit(false);
103        w.force_hp_cpu_no_reset().bit(false);
104        w.force_hp_cpu_no_iso().bit(false);
105        w.force_hp_cpu_pd().bit(false)
106    });
107
108    // PMU_LP_PD_LPPERI (eco5 new)
109    pmu.power_pd_lpperi_cntl().modify(|_, w| {
110        w.force_lp_peri_reset().bit(false);
111        w.force_lp_peri_iso().bit(false);
112        w.force_lp_peri_pu().bit(false);
113        w.force_lp_peri_no_reset().bit(false);
114        w.force_lp_peri_no_iso().bit(false);
115        w.force_lp_peri_pd().bit(false)
116    });
117}
118
119// ---------------------------------------------------------------------------
120// PMU register data structures.
121//
122// These mirror the `pmu_*_t` structs in esp-idf. The bit positions match the
123// ESP32-P4 PMU PAC register layouts so that the power configs can be written as
124// raw `u32` values, while the analog/syscntl configs are written field-by-field
125// from the sleep driver.
126// ---------------------------------------------------------------------------
127
128bitfield::bitfield! {
129    #[derive(Clone, Copy, Default)]
130    // pmu_hp_power_t.0 (hp_*_dig_power)
131    pub struct HpDigPower(u32);
132
133    pub bool, dcdc_switch_pd_en, set_dcdc_switch_pd_en: 21;
134    pub bool, mem_dslp          , set_mem_dslp          : 22;
135    pub bool, mem_pd_en         , set_mem_pd_en         : 23;
136    pub bool, cpu_pd_en         , set_cpu_pd_en         : 29;
137    pub bool, cnnt_pd_en        , set_cnnt_pd_en        : 30;
138    pub bool, top_pd_en         , set_top_pd_en         : 31;
139}
140
141bitfield::bitfield! {
142    #[derive(Clone, Copy, Default)]
143    // pmu_hp_power_t.1 (hp_*_hp_ck_power)
144    pub struct HpClkPower(u32);
145
146    pub bool, i2c_iso_en   , set_i2c_iso_en   : 21;
147    pub bool, i2c_retention, set_i2c_retention: 22;
148    pub u8,   xpd_pll_i2c  , set_xpd_pll_i2c  : 26, 23;
149    pub u8,   xpd_pll      , set_xpd_pll      : 30, 27;
150}
151
152bitfield::bitfield! {
153    #[derive(Clone, Copy, Default)]
154    // pmu_hp_power_t.2 (hp_*_xtal)
155    pub struct HpXtalPower(u32);
156
157    pub bool, xpd_xtal, set_xpd_xtal: 31;
158}
159
160#[derive(Clone, Copy, Default)]
161// pmu_sleep_power_config_t.0
162pub struct HpSysPower {
163    pub dig_power: HpDigPower,
164    pub clk: HpClkPower,
165    pub xtal: HpXtalPower,
166}
167
168bitfield::bitfield! {
169    #[derive(Clone, Copy, Default)]
170    // pmu_hp_sys_cntl_reg_t (hp_*_hp_sys_cntl)
171    pub struct HpSysCntlReg(u32);
172
173    pub bool, uart_wakeup_en , set_uart_wakeup_en : 24;
174    pub bool, lp_pad_hold_all, set_lp_pad_hold_all: 25;
175    pub bool, hp_pad_hold_all, set_hp_pad_hold_all: 26;
176    pub bool, dig_pad_slp_sel, set_dig_pad_slp_sel: 27;
177    pub bool, dig_pause_wdt  , set_dig_pause_wdt  : 28;
178    pub bool, dig_cpu_stall  , set_dig_cpu_stall  : 29;
179}
180
181bitfield::bitfield! {
182    #[derive(Clone, Copy, Default)]
183    // pmu_hp_sysclk_reg_t (hp_*_sysclk)
184    pub struct HpSysclk(u32);
185
186    pub bool, dig_sysclk_nodiv, set_dig_sysclk_nodiv: 26;
187    pub bool, icg_sysclk_en   , set_icg_sysclk_en   : 27;
188    pub bool, sysclk_slp_sel  , set_sysclk_slp_sel  : 28;
189    pub bool, icg_slp_sel     , set_icg_slp_sel     : 29;
190    pub u8,   dig_sysclk_sel  , set_dig_sysclk_sel  : 31, 30;
191}
192
193bitfield::bitfield! {
194    #[derive(Clone, Copy, Default)]
195    // pmu_hp_analog_t.0 (hp_*_bias) -- note P4-only dcm fields.
196    pub struct HpAnalogBias(u32);
197
198    pub u8,   dcm_vset  , set_dcm_vset  : 22, 18;
199    pub u8,   dcm_mode  , set_dcm_mode  : 24, 23;
200    pub bool, xpd_bias  , set_xpd_bias  : 25;
201    pub u8,   dbg_atten , set_dbg_atten : 29, 26;
202    pub bool, pd_cur    , set_pd_cur    : 30;
203    pub bool, bias_sleep, set_bias_sleep: 31;
204}
205
206bitfield::bitfield! {
207    #[derive(Clone, Copy, Default)]
208    // pmu_hp_analog_t.1 (hp_*_hp_regulator0)
209    pub struct HpAnalogRegulator0(u32);
210
211    pub bool, slp_mem_xpd    , set_slp_mem_xpd    : 16;
212    pub bool, slp_logic_xpd  , set_slp_logic_xpd  : 17;
213    pub bool, xpd            , set_xpd            : 18;
214    pub u8,   slp_mem_dbias  , set_slp_mem_dbias  : 22, 19;
215    pub u8,   slp_logic_dbias, set_slp_logic_dbias: 26, 23;
216    pub u8,   dbias          , set_dbias          : 31, 27;
217}
218
219bitfield::bitfield! {
220    #[derive(Clone, Copy, Default)]
221    // pmu_hp_analog_t.2 (hp_*_hp_regulator1)
222    pub struct HpAnalogRegulator1(u32);
223
224    pub u8, drv_b, set_drv_b: 31, 26;
225}
226
227#[derive(Clone, Copy, Default)]
228// pmu_hp_analog_t
229pub struct HpAnalog {
230    pub bias: HpAnalogBias,
231    pub regulator0: HpAnalogRegulator0,
232    pub regulator1: HpAnalogRegulator1,
233}
234
235bitfield::bitfield! {
236    #[derive(Clone, Copy, Default)]
237    // pmu_lp_power_t.0 (lp dig_power)
238    pub struct LpDigPower(u32);
239
240    pub bool, lp_pad_slp_sel, set_lp_pad_slp_sel: 26;
241    pub bool, bod_source_sel, set_bod_source_sel: 27;
242    pub u8,   vddbat_mode   , set_vddbat_mode   : 29, 28;
243    pub bool, mem_dslp      , set_mem_dslp      : 30;
244    pub bool, peri_pd_en    , set_peri_pd_en    : 31;
245}
246
247bitfield::bitfield! {
248    #[derive(Clone, Copy, Default)]
249    // pmu_lp_power_t.1 (lp clk_power)
250    pub struct LpClkPower(u32);
251
252    pub bool, xpd_lppll  , set_xpd_lppll  : 27;
253    pub bool, xpd_xtal32k, set_xpd_xtal32k: 28;
254    pub bool, xpd_rc32k  , set_xpd_rc32k  : 29;
255    pub bool, xpd_fosc   , set_xpd_fosc   : 30;
256    pub bool, pd_osc     , set_pd_osc     : 31;
257}
258
259bitfield::bitfield! {
260    #[derive(Clone, Copy, Default)]
261    // pmu_lp_power_t.2 (lp xtal)
262    pub struct LpXtalPower(u32);
263
264    pub bool, xpd_xtal, set_xpd_xtal: 31;
265}
266
267#[derive(Clone, Copy, Default)]
268// pmu_sleep_power_config_t.1
269pub struct LpSysPower {
270    pub dig_power: LpDigPower,
271    pub clk_power: LpClkPower,
272    pub xtal: LpXtalPower,
273}
274
275bitfield::bitfield! {
276    #[derive(Clone, Copy, Default)]
277    // pmu_lp_analog_t.0 (lp_*_bias)
278    pub struct LpAnalogBias(u32);
279
280    pub bool, xpd_bias  , set_xpd_bias  : 25;
281    pub u8,   dbg_atten , set_dbg_atten : 29, 26;
282    pub bool, pd_cur    , set_pd_cur    : 30;
283    pub bool, bias_sleep, set_bias_sleep: 31;
284}
285
286bitfield::bitfield! {
287    #[derive(Clone, Copy, Default)]
288    // pmu_lp_analog_t.1 (lp_*_lp_regulator0)
289    pub struct LpAnalogRegulator0(u32);
290
291    pub bool, slp_xpd  , set_slp_xpd  : 21;
292    pub bool, xpd      , set_xpd      : 22;
293    pub u8,   slp_dbias, set_slp_dbias: 26, 23;
294    pub u8,   dbias    , set_dbias    : 31, 27;
295}
296
297bitfield::bitfield! {
298    #[derive(Clone, Copy, Default)]
299    // pmu_lp_analog_t.2 (lp_*_lp_regulator1)
300    pub struct LpAnalogRegulator1(u32);
301
302    pub u8, drv_b, set_drv_b: 31, 26;
303}
304
305#[derive(Clone, Copy, Default)]
306// pmu_lp_analog_t
307pub struct LpAnalog {
308    pub bias: LpAnalogBias,
309    pub regulator0: LpAnalogRegulator0,
310    pub regulator1: LpAnalogRegulator1,
311}
312
313/// Configures the default per-mode HP system PMU registers (HP_ACTIVE and
314/// HP_SLEEP). Mirrors `pmu_hp_system_init()` in esp-idf. The HP_MODEM mode is
315/// skipped (P4 has no wireless modem).
316fn pmu_hp_system_init() {
317    let pmu = PMU::regs();
318
319    // ---- HP_ACTIVE ----
320    pmu.hp_active_dig_power().write(|w| unsafe { w.bits(0) });
321    pmu.hp_active_hp_ck_power().write(|w| unsafe {
322        w.hp_active_i2c_iso_en().bit(false);
323        w.hp_active_i2c_retention().bit(false);
324        w.hp_active_xpd_pll_i2c().bits(0xf);
325        w.hp_active_xpd_pll().bits(0xf)
326    });
327    pmu.hp_active_xtal()
328        .modify(|_, w| w.hp_active_xpd_xtal().bit(true));
329
330    pmu.hp_active_icg_hp_func()
331        .write(|w| unsafe { w.bits(0xffff_ffff) });
332    pmu.hp_active_icg_hp_apb()
333        .write(|w| unsafe { w.bits(0xffff_ffff) });
334    pmu.hp_active_icg_modem()
335        .write(|w| unsafe { w.hp_active_dig_icg_modem_code().bits(0) });
336    pmu.hp_active_sysclk().modify(|_, w| unsafe {
337        w.hp_active_dig_sys_clk_no_div().bit(false);
338        w.hp_active_icg_sys_clock_en().bit(true);
339        w.hp_active_sys_clk_slp_sel().bit(false);
340        w.hp_active_icg_slp_sel().bit(false);
341        w.hp_active_dig_sys_clk_sel().bits(HP_SYSCLK_XTAL)
342    });
343    pmu.hp_active_hp_sys_cntl().modify(|_, w| {
344        w.hp_active_uart_wakeup_en().bit(false);
345        w.hp_active_lp_pad_hold_all().bit(false);
346        w.hp_active_hp_pad_hold_all().bit(false);
347        w.hp_active_dig_pad_slp_sel().bit(false);
348        w.hp_active_dig_pause_wdt().bit(false);
349        w.hp_active_dig_cpu_stall().bit(false)
350    });
351    pmu.hp_active_bias().modify(|_, w| unsafe {
352        w.hp_active_dcm_vset().bits(27);
353        w.hp_active_dcm_mode().bits(1);
354        w.hp_active_xpd_bias().bit(true);
355        w.hp_active_dbg_atten().bits(0);
356        w.hp_active_pd_cur().bit(false);
357        w.sleep().bit(false)
358    });
359    // NOTE: do NOT reprogram the HP active regulator xpd/dbias here. The
360    // bootloader already applied the efuse-calibrated active voltage
361    // (get_act_hp_dbias()); overriding it with a fixed default under-volts the
362    // HP domain and hangs the running CPU. IDF's pmu_hp_system_init() only
363    // touches the sleep-related regulator sub-fields (pmu_init.c).
364    pmu.hp_active_hp_regulator0().modify(|_, w| unsafe {
365        w.hp_active_hp_regulator_slp_mem_xpd().bit(false);
366        w.hp_active_hp_regulator_slp_logic_xpd().bit(false);
367        w.hp_active_hp_regulator_slp_logic_dbias().bits(0)
368    });
369    pmu.hp_active_backup().write(|w| unsafe { w.bits(0) });
370    pmu.hp_active_backup_clk()
371        .write(|w| unsafe { w.bits(0xffff_ffff) });
372
373    // ---- HP_SLEEP ----
374    pmu.hp_sleep_dig_power()
375        .write(|w| w.hp_sleep_dcdc_switch_pd_en().bit(true));
376    pmu.hp_sleep_hp_ck_power().write(|w| unsafe {
377        w.hp_sleep_i2c_iso_en().bit(true);
378        w.hp_sleep_i2c_retention().bit(true);
379        w.hp_sleep_xpd_pll_i2c().bits(1);
380        w.hp_sleep_xpd_pll().bits(0)
381    });
382    pmu.hp_sleep_xtal()
383        .modify(|_, w| w.hp_sleep_xpd_xtal().bit(false));
384
385    pmu.hp_sleep_icg_hp_func().write(|w| unsafe { w.bits(0) });
386    pmu.hp_sleep_icg_hp_apb().write(|w| unsafe { w.bits(0) });
387    pmu.hp_sleep_icg_modem()
388        .write(|w| unsafe { w.hp_sleep_dig_icg_modem_code().bits(0) });
389    pmu.hp_sleep_sysclk().modify(|_, w| unsafe {
390        w.hp_sleep_dig_sys_clk_no_div().bit(false);
391        w.hp_sleep_icg_sys_clock_en().bit(false);
392        w.hp_sleep_sys_clk_slp_sel().bit(true);
393        w.hp_sleep_icg_slp_sel().bit(true);
394        w.hp_sleep_dig_sys_clk_sel().bits(HP_SYSCLK_XTAL)
395    });
396    pmu.hp_sleep_hp_sys_cntl().modify(|_, w| {
397        w.hp_sleep_uart_wakeup_en().bit(true);
398        w.hp_sleep_lp_pad_hold_all().bit(false);
399        w.hp_sleep_hp_pad_hold_all().bit(false);
400        w.hp_sleep_dig_pad_slp_sel().bit(false);
401        w.hp_sleep_dig_pause_wdt().bit(true);
402        w.hp_sleep_dig_cpu_stall().bit(true)
403    });
404    pmu.hp_sleep_bias().modify(|_, w| unsafe {
405        w.hp_sleep_dcm_vset().bits(0);
406        w.hp_sleep_dcm_mode().bits(1);
407        w.hp_sleep_xpd_bias().bit(false);
408        w.hp_sleep_dbg_atten().bits(0);
409        w.hp_sleep_pd_cur().bit(true);
410        w.sleep().bit(true)
411    });
412    pmu.hp_sleep_hp_regulator0().modify(|_, w| unsafe {
413        w.hp_sleep_hp_regulator_slp_mem_xpd().bit(false);
414        w.hp_sleep_hp_regulator_slp_logic_xpd().bit(false);
415        w.hp_sleep_hp_regulator_xpd().bit(true);
416        w.hp_sleep_hp_regulator_slp_mem_dbias().bits(1);
417        w.hp_sleep_hp_regulator_slp_logic_dbias().bits(0)
418    });
419    pmu.hp_sleep_backup().write(|w| unsafe { w.bits(0) });
420    pmu.hp_sleep_backup_clk()
421        .write(|w| unsafe { w.bits(0xffff_ffff) });
422
423    // Some PMU initial parameter configuration (force update ICG/sysclk).
424    pmu.imm_modem_icg()
425        .write(|w| w.update_dig_icg_modem_en().bit(true));
426    pmu.imm_sleep_sysclk()
427        .write(|w| w.update_dig_icg_switch().bit(true));
428
429    // PMU_SLEEP_PROTECT_HP_LP_SLEEP
430    const PMU_SLEEP_PROTECT_HP_LP_SLEEP: u8 = 2;
431    pmu.slp_wakeup_cntl3()
432        .modify(|_, w| unsafe { w.sleep_prt_sel().bits(PMU_SLEEP_PROTECT_HP_LP_SLEEP) });
433}
434
435/// Configures the default per-mode LP system PMU registers (LP_ACTIVE which
436/// lives in the `hp_sleep_lp_*` group, and LP_SLEEP in the `lp_sleep_*` group).
437/// Mirrors `pmu_lp_system_init()` in esp-idf.
438fn pmu_lp_system_init() {
439    let pmu = PMU::regs();
440
441    // ---- LP_ACTIVE (hp_sleep_lp_*) ----
442    pmu.hp_sleep_lp_dig_power().write(|w| unsafe { w.bits(0) });
443    pmu.hp_sleep_lp_ck_power().write(|w| {
444        w.hp_sleep_xpd_lppll().bit(false);
445        w.hp_sleep_xpd_xtal32k().bit(true);
446        w.hp_sleep_xpd_rc32k().bit(true);
447        w.hp_sleep_xpd_fosc_clk().bit(true);
448        w.hp_sleep_pd_osc_clk().bit(false)
449    });
450    // Likewise, leave the LP active regulator voltage (xpd/dbias) as the
451    // bootloader calibrated it (get_act_lp_dbias()); IDF's pmu_lp_system_init()
452    // only defaults the sleep sub-fields here.
453    pmu.hp_sleep_lp_regulator0().modify(|_, w| unsafe {
454        w.hp_sleep_lp_regulator_slp_xpd().bit(false);
455        w.hp_sleep_lp_regulator_slp_dbias().bits(0)
456    });
457    pmu.hp_sleep_lp_regulator1()
458        .modify(|_, w| unsafe { w.hp_sleep_lp_regulator_drv_b().bits(0) });
459
460    // ---- LP_SLEEP (lp_sleep_*) ----
461    pmu.lp_sleep_lp_dig_power().write(|w| unsafe { w.bits(0) });
462    pmu.lp_sleep_lp_ck_power().write(|w| unsafe { w.bits(0) });
463    pmu.lp_sleep_xtal()
464        .modify(|_, w| w.lp_sleep_xpd_xtal().bit(false));
465    pmu.lp_sleep_bias().modify(|_, w| unsafe {
466        w.lp_sleep_xpd_bias().bit(false);
467        w.lp_sleep_dbg_atten().bits(0);
468        w.lp_sleep_pd_cur().bit(true);
469        w.sleep().bit(true)
470    });
471    pmu.lp_sleep_lp_regulator0().modify(|_, w| unsafe {
472        w.lp_sleep_lp_regulator_slp_xpd().bit(false);
473        w.lp_sleep_lp_regulator_xpd().bit(true);
474        w.lp_sleep_lp_regulator_slp_dbias().bits(0);
475        w.lp_sleep_lp_regulator_dbias().bits(12)
476    });
477    pmu.lp_sleep_lp_regulator1()
478        .modify(|_, w| unsafe { w.lp_sleep_lp_regulator_drv_b().bits(0) });
479}
480
481/// Minimal init for bare-metal boot.
482pub(crate) fn init(_config: &ClockConfig) {
483    pmu_power_domain_force_default();
484
485    // Force the analog dig regulators on via regi2c (XPD off => regulated by
486    // PMU) and configure the default per-mode PMU system state (HP/LP active +
487    // sleep). Required before the PMU can perform a clean sleep/wake transition.
488    // Ref: IDF rtc_clk_init.c (esp32p4).
489    regi2c::I2C_DIG_REG_FORCE_RTC_DREG.write_field(1);
490    regi2c::I2C_DIG_REG_FORCE_DIG_DREG.write_field(1);
491    regi2c::I2C_DIG_REG_XPD_RTC_REG.write_field(0);
492    regi2c::I2C_DIG_REG_XPD_DIG_REG.write_field(0);
493    pmu_hp_system_init();
494    pmu_lp_system_init();
495
496    // Clear DCDC switch force flags PMU_POWER_DCDC_SWITCH_REG (offset 0x10c)
497    PMU::regs().power_dcdc_switch().modify(|_, w| {
498        w.force_dcdc_switch_pu().bit(false);
499        w.force_dcdc_switch_pd().bit(false)
500    });
501
502    // PAC: tie_high_xpd_pll is 4-bit field (one bit per PLL: CPLL/SPLL/MPLL/PLLA).
503    // Set all bits to enable all PLLs. Same for pll_i2c.
504    PMU::regs().imm_hp_ck_power().write(|w| unsafe {
505        w.tie_high_xpd_pll().bits(0xF);
506        w.tie_high_xpd_pll_i2c().bits(0xF)
507    });
508}