Skip to main content

esp_hal/rtc_cntl/rtc/
esp32s31.rs

1use strum::FromRepr;
2
3use crate::{
4    peripherals::{MODEM_LPCON, MODEM_SYSCON, PMU},
5    soc::{
6        clocks::{ClockConfig, LpSlowClkConfig},
7        regi2c,
8    },
9};
10
11const HP_CALI_DBIAS: u32 = 26;
12const LP_CALI_DBIAS: u32 = 26;
13
14const ICG_NOGATING_MODEM: u8 = 1 << 1;
15const ICG_NOGATING_ACTIVE: u8 = 1 << 2;
16const ICG_NOGATING_ACTIVE_MODEM: u8 = ICG_NOGATING_ACTIVE | ICG_NOGATING_MODEM;
17
18const fn hp_retention_regdma_config(dir: u32, entry: u32) -> u32 {
19    ((dir << 4) | (entry & 0xf)) & 0x1f
20}
21
22bitfield::bitfield! {
23    #[derive(Clone, Copy, Default)]
24    pub struct HpDigPower(u32);
25
26    pub bool, vdd_spi_pd_en, set_vdd_spi_pd_en: 20;
27    pub bool, hp_alive_pd_en, set_hp_alive_pd_en: 21;
28    pub bool, hp_mem_dslp, set_hp_mem_dslp: 22;
29    pub u8, hp_mem_pd_en, set_hp_mem_pd_en: 26, 23;
30    pub bool, modem_top_pd_en, set_modem_top_pd_en: 27;
31    pub bool, hp_cnnt_pd_en, set_hp_cnnt_pd_en: 28;
32    pub bool, hp_cpu_pd_en, set_hp_cpu_pd_en: 29;
33    pub bool, modem_pwr_pd_en, set_modem_pwr_pd_en: 30;
34    pub bool, top_pd_en, set_top_pd_en: 31;
35}
36
37bitfield::bitfield! {
38    #[derive(Clone, Copy, Default)]
39    pub struct HpClkPower(u32);
40
41    pub bool, xpd_xtalx2, set_xpd_xtalx2: 19;
42    pub bool, i2c_iso_en, set_i2c_iso_en: 20;
43    pub bool, i2c_retention, set_i2c_retention: 21;
44    pub bool, xpd_bb_i2c, set_xpd_bb_i2c: 22;
45    pub bool, xpd_cpll_i2c, set_xpd_cpll_i2c: 23;
46    pub bool, xpd_bbpll_i2c, set_xpd_bbpll_i2c: 24;
47    pub bool, xpd_apll_i2c, set_xpd_apll_i2c: 25;
48    pub bool, xpd_mpll_i2c, set_xpd_mpll_i2c: 26;
49    pub bool, xpd_cpll, set_xpd_cpll: 27;
50    pub bool, xpd_bbpll, set_xpd_bbpll: 28;
51    pub bool, xpd_apll, set_xpd_apll: 29;
52    pub bool, xpd_mpll, set_xpd_mpll: 30;
53}
54
55bitfield::bitfield! {
56    #[derive(Clone, Copy, Default)]
57    pub struct XtalPower(u32);
58
59    pub bool, xpd_xtal, set_xpd_xtal: 31;
60}
61
62bitfield::bitfield! {
63    #[derive(Clone, Copy, Default)]
64    pub struct HpIcgModem(u32);
65
66    pub u8, code, set_code: 31, 30;
67}
68
69bitfield::bitfield! {
70    #[derive(Clone, Copy, Default)]
71    pub struct HpSysclk(u32);
72
73    pub bool, dig_sysclk_nodiv, set_dig_sysclk_nodiv: 26;
74    pub bool, icg_sysclk_en, set_icg_sysclk_en: 27;
75    pub bool, sysclk_slp_sel, set_sysclk_slp_sel: 28;
76    pub bool, icg_slp_sel, set_icg_slp_sel: 29;
77    pub u8, dig_sysclk_sel, set_dig_sysclk_sel: 31, 30;
78}
79
80bitfield::bitfield! {
81    #[derive(Clone, Copy, Default)]
82    pub struct HpSysCntl(u32);
83
84    pub bool, c_channel, set_c_channel: 23;
85    pub bool, uart_wakeup_en, set_uart_wakeup_en: 24;
86    pub bool, lp_pad_hold_all, set_lp_pad_hold_all: 25;
87    pub bool, hp_pad_hold_all, set_hp_pad_hold_all: 26;
88    pub bool, dig_pad_slp_sel, set_dig_pad_slp_sel: 27;
89    pub bool, dig_pause_wdt, set_dig_pause_wdt: 28;
90    pub bool, dig_cpu_stall, set_dig_cpu_stall: 29;
91}
92
93bitfield::bitfield! {
94    #[derive(Clone, Copy, Default)]
95    pub struct AnalogBias(u32);
96
97    pub bool, xpd_bias, set_xpd_bias: 25;
98    pub u8, dbg_atten, set_dbg_atten: 29, 26;
99    pub bool, pd_cur, set_pd_cur: 30;
100    pub bool, bias_sleep, set_bias_sleep: 31;
101}
102
103bitfield::bitfield! {
104    #[derive(Clone, Copy, Default)]
105    pub struct HpRegulator0(u32);
106
107    pub bool, dig_dbias_init, set_dig_dbias_init: 3;
108    pub u8, lp_dbias_vol, set_lp_dbias_vol: 8, 4;
109    pub u8, hp_dbias_vol, set_hp_dbias_vol: 13, 9;
110    pub bool, dbias_sel, set_dbias_sel: 14;
111    pub bool, slp_connect_en, set_slp_connect_en: 15;
112    pub bool, slp_mem_xpd, set_slp_mem_xpd: 16;
113    pub bool, slp_logic_xpd, set_slp_logic_xpd: 17;
114    pub bool, xpd, set_xpd: 18;
115    pub u8, slp_mem_dbias, set_slp_mem_dbias: 22, 19;
116    pub u8, slp_logic_dbias, set_slp_logic_dbias: 26, 23;
117    pub u8, dbias, set_dbias: 31, 27;
118}
119
120bitfield::bitfield! {
121    #[derive(Clone, Copy, Default)]
122    pub struct HpRegulator1(u32);
123
124    pub u32, drv_b, set_drv_b: 31, 8;
125}
126
127/// Analog settings of the high-power system during sleep.
128#[derive(Clone, Copy, Default)]
129pub struct HpAnalog {
130    pub bias: AnalogBias,
131    pub regulator0: HpRegulator0,
132    pub regulator1: HpRegulator1,
133}
134
135/// Power settings of the high-power system during sleep.
136#[derive(Clone, Copy, Default)]
137pub struct HpSysPower {
138    pub dig_power: HpDigPower,
139    pub clk: HpClkPower,
140    pub xtal: XtalPower,
141}
142
143pub type HpSysCntlReg = HpSysCntl;
144
145bitfield::bitfield! {
146    #[derive(Clone, Copy, Default)]
147    pub struct HpBackup(u32);
148
149    pub u8, sleep2active_modem_clk_code, set_sleep2active_modem_clk_code: 5, 4;
150    pub u8, modem2active_modem_clk_code, set_modem2active_modem_clk_code: 7, 6;
151    pub bool, active_retention_mode, set_active_retention_mode: 10;
152    pub bool, sleep2active_retention_en, set_sleep2active_retention_en: 11;
153    pub bool, modem2active_retention_en, set_modem2active_retention_en: 12;
154    pub u8, sleep2active_backup_clk_sel, set_sleep2active_backup_clk_sel: 15, 14;
155    pub u8, modem2active_backup_clk_sel, set_modem2active_backup_clk_sel: 17, 16;
156    pub u8, sleep2active_backup_mode, set_sleep2active_backup_mode: 22, 18;
157    pub u8, modem2active_backup_mode, set_modem2active_backup_mode: 27, 23;
158    pub bool, sleep2active_backup_en, set_sleep2active_backup_en: 29;
159    pub bool, modem2active_backup_en, set_modem2active_backup_en: 30;
160
161    pub u8, sleep2modem_modem_clk_code, set_sleep2modem_modem_clk_code: 5, 4;
162    pub bool, modem_retention_mode, set_modem_retention_mode: 10;
163    pub bool, sleep2modem_retention_en, set_sleep2modem_retention_en: 11;
164    pub u8, sleep2modem_backup_clk_sel, set_sleep2modem_backup_clk_sel: 15, 14;
165    pub u8, sleep2modem_backup_mode, set_sleep2modem_backup_mode: 24, 20;
166    pub bool, sleep2modem_backup_en, set_sleep2modem_backup_en: 29;
167
168    pub u8, modem2sleep_modem_clk_code, set_modem2sleep_modem_clk_code: 7, 6;
169    pub u8, active2sleep_modem_clk_code, set_active2sleep_modem_clk_code: 9, 8;
170    pub bool, sleep_retention_mode, set_sleep_retention_mode: 10;
171    pub bool, modem2sleep_retention_en, set_modem2sleep_retention_en: 12;
172    pub bool, active2sleep_retention_en, set_active2sleep_retention_en: 13;
173    pub u8, modem2sleep_backup_clk_sel, set_modem2sleep_backup_clk_sel: 17, 16;
174    pub u8, active2sleep_backup_clk_sel, set_active2sleep_backup_clk_sel: 19, 18;
175    pub u8, modem2sleep_backup_mode, set_modem2sleep_backup_mode: 24, 20;
176    pub u8, active2sleep_backup_mode, set_active2sleep_backup_mode: 29, 25;
177    pub bool, modem2sleep_backup_en, set_modem2sleep_backup_en: 30;
178    pub bool, active2sleep_backup_en, set_active2sleep_backup_en: 31;
179}
180
181#[derive(Clone, Copy, Default)]
182struct HpSystemPower {
183    dig_power: HpDigPower,
184    clk_power: HpClkPower,
185    xtal: XtalPower,
186}
187
188#[derive(Clone, Copy)]
189struct HpSystemClock {
190    icg_func: [u32; 2],
191    icg_apb: [u32; 2],
192    icg_modem: HpIcgModem,
193    sysclk: HpSysclk,
194}
195
196#[derive(Clone, Copy)]
197struct HpSystemDigital {
198    syscntl: HpSysCntl,
199}
200
201#[derive(Clone, Copy)]
202struct HpSystemAnalog {
203    bias: AnalogBias,
204    regulator0: HpRegulator0,
205    regulator1: HpRegulator1,
206}
207
208#[derive(Clone, Copy)]
209struct HpSystemRetention {
210    retention: HpBackup,
211    backup_clk: [u32; 2],
212}
213
214#[derive(Clone, Copy)]
215struct HpSystemInit {
216    power: HpSystemPower,
217    clock: HpSystemClock,
218    digital: HpSystemDigital,
219    analog: HpSystemAnalog,
220    retention: HpSystemRetention,
221}
222
223impl HpSystemInit {
224    // PMU_HP_ACTIVE_*_CONFIG_DEFAULT
225    fn active() -> Self {
226        let mut power = HpSystemPower::default();
227        power.clk_power.set_xpd_bb_i2c(true);
228        power.clk_power.set_xpd_cpll_i2c(true);
229        power.clk_power.set_xpd_bbpll_i2c(true);
230        power.clk_power.set_xpd_cpll(true);
231        power.clk_power.set_xpd_bbpll(true);
232        power.xtal.set_xpd_xtal(true);
233
234        let mut icg_modem = HpIcgModem::default();
235        icg_modem.set_code(2);
236        let mut sysclk = HpSysclk::default();
237        sysclk.set_icg_sysclk_en(true);
238        let mut syscntl = HpSysCntl::default();
239        syscntl.set_c_channel(true);
240
241        let mut bias = AnalogBias::default();
242        bias.set_xpd_bias(true);
243        let mut regulator0 = HpRegulator0::default();
244        regulator0.set_dig_dbias_init(true);
245        regulator0.set_lp_dbias_vol(0xd);
246        regulator0.set_hp_dbias_vol(0x1c);
247        regulator0.set_dbias_sel(true);
248        regulator0.set_xpd(true);
249        regulator0.set_dbias(HP_CALI_DBIAS as u8);
250
251        let mut retention = HpBackup::default();
252        retention.set_sleep2active_modem_clk_code(2);
253        retention.set_modem2active_modem_clk_code(2);
254        retention.set_sleep2active_backup_mode(hp_retention_regdma_config(0, 0) as u8);
255        retention.set_modem2active_backup_mode(hp_retention_regdma_config(0, 2) as u8);
256
257        Self {
258            power,
259            clock: HpSystemClock {
260                icg_func: [u32::MAX; 2],
261                icg_apb: [u32::MAX; 2],
262                icg_modem,
263                sysclk,
264            },
265            digital: HpSystemDigital { syscntl },
266            analog: HpSystemAnalog {
267                bias,
268                regulator0,
269                regulator1: HpRegulator1::default(),
270            },
271            retention: HpSystemRetention {
272                retention,
273                backup_clk: [u32::MAX; 2],
274            },
275        }
276    }
277
278    // PMU_HP_MODEM_*_CONFIG_DEFAULT
279    fn modem() -> Self {
280        let mut power = HpSystemPower::default();
281        power.clk_power.set_i2c_iso_en(true);
282        power.clk_power.set_i2c_retention(true);
283        power.clk_power.set_xpd_bb_i2c(true);
284        power.clk_power.set_xpd_cpll_i2c(true);
285        power.clk_power.set_xpd_bbpll_i2c(true);
286        power.clk_power.set_xpd_cpll(true);
287        power.clk_power.set_xpd_bbpll(true);
288        power.xtal.set_xpd_xtal(true);
289
290        let mut icg_modem = HpIcgModem::default();
291        icg_modem.set_code(1);
292        let mut sysclk = HpSysclk::default();
293        sysclk.set_icg_sysclk_en(true);
294        sysclk.set_sysclk_slp_sel(true);
295        sysclk.set_icg_slp_sel(true);
296        let mut syscntl = HpSysCntl::default();
297        syscntl.set_c_channel(true);
298        syscntl.set_lp_pad_hold_all(true);
299        syscntl.set_hp_pad_hold_all(true);
300        syscntl.set_dig_pause_wdt(true);
301        syscntl.set_dig_cpu_stall(true);
302
303        let mut regulator0 = HpRegulator0::default();
304        regulator0.set_xpd(true);
305        regulator0.set_dbias(HP_CALI_DBIAS as u8);
306
307        let mut retention = HpBackup::default();
308        retention.set_sleep2modem_modem_clk_code(1);
309        retention.set_sleep2modem_backup_mode(hp_retention_regdma_config(0, 1) as u8);
310
311        Self {
312            power,
313            clock: HpSystemClock {
314                // PMU_ICG_FUNC_ENA_ETM=40 and PMU_ICG_FUNC_ENA_BUS=47.
315                icg_func: [0, (1 << (40 - 32)) | (1 << (47 - 32))],
316                icg_apb: [0; 2],
317                icg_modem,
318                // The S31 IDF deliberately keeps the modem-state system clock on XTAL.
319                sysclk,
320            },
321            digital: HpSystemDigital { syscntl },
322            analog: HpSystemAnalog {
323                bias: AnalogBias::default(),
324                regulator0,
325                regulator1: HpRegulator1::default(),
326            },
327            retention: HpSystemRetention {
328                retention,
329                backup_clk: [u32::MAX; 2],
330            },
331        }
332    }
333
334    // PMU_HP_SLEEP_*_CONFIG_DEFAULT
335    fn sleep() -> Self {
336        let mut power = HpSystemPower::default();
337        power.clk_power.set_i2c_iso_en(true);
338        power.clk_power.set_i2c_retention(true);
339
340        let mut sysclk = HpSysclk::default();
341        sysclk.set_sysclk_slp_sel(true);
342        sysclk.set_icg_slp_sel(true);
343        let mut syscntl = HpSysCntl::default();
344        syscntl.set_uart_wakeup_en(true);
345        syscntl.set_lp_pad_hold_all(true);
346        syscntl.set_hp_pad_hold_all(true);
347        syscntl.set_dig_pause_wdt(true);
348        syscntl.set_dig_cpu_stall(true);
349
350        let mut bias = AnalogBias::default();
351        bias.set_pd_cur(true);
352        bias.set_bias_sleep(true);
353        let mut regulator0 = HpRegulator0::default();
354        regulator0.set_xpd(true);
355
356        let mut retention = HpBackup::default();
357        retention.set_active2sleep_modem_clk_code(2);
358        retention.set_modem2sleep_backup_mode(hp_retention_regdma_config(1, 1) as u8);
359        retention.set_active2sleep_backup_mode(hp_retention_regdma_config(1, 0) as u8);
360
361        Self {
362            power,
363            clock: HpSystemClock {
364                icg_func: [0; 2],
365                icg_apb: [0; 2],
366                icg_modem: HpIcgModem::default(),
367                sysclk,
368            },
369            digital: HpSystemDigital { syscntl },
370            analog: HpSystemAnalog {
371                bias,
372                regulator0,
373                regulator1: HpRegulator1::default(),
374            },
375            retention: HpSystemRetention {
376                retention,
377                backup_clk: [u32::MAX; 2],
378            },
379        }
380    }
381}
382
383macro_rules! hp_system_init {
384    ($state:ident, $param:expr) => {{
385        let param = $param;
386        let pmu = PMU::regs();
387        paste::paste! {
388            unsafe {
389                pmu.[<$state _dig_power>]().write(|w| w.bits(param.power.dig_power.0));
390                pmu.[<$state _hp_ck_power>]().write(|w| w.bits(param.power.clk_power.0));
391                pmu.[<$state _xtal>]().write(|w| w.bits(param.power.xtal.0));
392
393                pmu.[<$state _icg_hp_func>]().write(|w| w.bits(param.clock.icg_func[0]));
394                pmu.[<$state _icg_hp_apb>]().write(|w| w.bits(param.clock.icg_apb[0]));
395                pmu.[<$state _icg_hp_func1>]().write(|w| w.bits(param.clock.icg_func[1]));
396                pmu.[<$state _icg_hp_apb1>]().write(|w| w.bits(param.clock.icg_apb[1]));
397                pmu.[<$state _icg_modem>]().write(|w| w.bits(param.clock.icg_modem.0));
398                pmu.[<$state _sysclk>]().write(|w| w.bits(param.clock.sysclk.0));
399
400                pmu.[<$state _hp_sys_cntl>]().write(|w| w.bits(param.digital.syscntl.0));
401
402                pmu.[<$state _bias>]().write(|w| w.bits(param.analog.bias.0));
403                pmu.[<$state _hp_regulator0>]().write(|w| w.bits(param.analog.regulator0.0));
404                pmu.[<$state _hp_regulator1>]().write(|w| w.bits(param.analog.regulator1.0));
405
406                pmu.[<$state _backup>]().write(|w| w.bits(param.retention.retention.0));
407                pmu.[<$state _backup_clk>]().write(|w| w.bits(param.retention.backup_clk[0]));
408                pmu.[<$state _backup1_clk>]().write(|w| w.bits(param.retention.backup_clk[1]));
409            }
410        }
411    }};
412}
413
414fn update_hp_system_config() {
415    PMU::regs()
416        .imm_modem_icg()
417        .write(|w| w.update_dig_icg_modem_en().set_bit());
418    PMU::regs()
419        .imm_sleep_sysclk()
420        .write(|w| w.update_dig_icg_switch().set_bit());
421}
422
423impl HpSystemInit {
424    fn init_default() {
425        hp_system_init!(hp_active, Self::active());
426        update_hp_system_config();
427        hp_system_init!(hp_modem, Self::modem());
428        update_hp_system_config();
429        hp_system_init!(hp_sleep, Self::sleep());
430        update_hp_system_config();
431        PMU::regs()
432            .slp_wakeup_cntl3()
433            .modify(|_, w| unsafe { w.sleep_prt_sel().bits(2) });
434    }
435}
436
437bitfield::bitfield! {
438    #[derive(Clone, Copy, Default)]
439    pub struct LpDigPower(u32);
440
441    pub bool, mem_dslp, set_mem_dslp: 30;
442    pub bool, peri_pd_en, set_peri_pd_en: 31;
443}
444
445bitfield::bitfield! {
446    #[derive(Clone, Copy, Default)]
447    pub struct LpClkPower(u32);
448
449    pub bool, xpd_xtal32k, set_xpd_xtal32k: 28;
450    pub bool, xpd_rc32k, set_xpd_rc32k: 29;
451    pub bool, xpd_fosc, set_xpd_fosc: 30;
452    pub bool, pd_osc, set_pd_osc: 31;
453}
454
455bitfield::bitfield! {
456    #[derive(Clone, Copy, Default)]
457    pub struct LpRegulator0(u32);
458
459    pub bool, slp_xpd, set_slp_xpd: 21;
460    pub bool, xpd, set_xpd: 22;
461    pub u8, slp_dbias, set_slp_dbias: 26, 23;
462    pub u8, dbias, set_dbias: 31, 27;
463}
464
465bitfield::bitfield! {
466    #[derive(Clone, Copy, Default)]
467    pub struct LpRegulator1(u32);
468
469    pub u8, drv_b, set_drv_b: 31, 28;
470}
471
472/// Power settings of the low-power system during sleep.
473#[derive(Clone, Copy, Default)]
474pub struct LpSysPower {
475    pub dig_power: LpDigPower,
476    pub clk_power: LpClkPower,
477    pub xtal: XtalPower,
478}
479
480/// Analog settings of the low-power system during sleep.
481#[derive(Clone, Copy, Default)]
482pub struct LpAnalog {
483    pub bias: AnalogBias,
484    pub regulator0: LpRegulator0,
485    pub regulator1: LpRegulator1,
486}
487
488#[derive(Clone, Copy, Default)]
489struct LpSystemPower {
490    dig_power: LpDigPower,
491    clk_power: LpClkPower,
492    xtal: XtalPower,
493}
494
495#[derive(Clone, Copy, Default)]
496struct LpSystemAnalog {
497    bias: AnalogBias,
498    regulator0: LpRegulator0,
499    regulator1: LpRegulator1,
500}
501
502#[derive(Clone, Copy)]
503struct LpSystemInit {
504    power: LpSystemPower,
505    analog: LpSystemAnalog,
506}
507
508impl LpSystemInit {
509    // PMU_LP_ACTIVE_*_CONFIG_DEFAULT
510    fn active() -> Self {
511        let mut clk_power = LpClkPower::default();
512        clk_power.set_xpd_fosc(true);
513        let mut regulator0 = LpRegulator0::default();
514        regulator0.set_xpd(true);
515        regulator0.set_dbias(LP_CALI_DBIAS as u8);
516
517        Self {
518            power: LpSystemPower {
519                dig_power: LpDigPower::default(),
520                clk_power,
521                xtal: XtalPower::default(),
522            },
523            analog: LpSystemAnalog {
524                bias: AnalogBias::default(),
525                regulator0,
526                regulator1: LpRegulator1::default(),
527            },
528        }
529    }
530
531    // PMU_LP_SLEEP_*_CONFIG_DEFAULT
532    fn sleep() -> Self {
533        let mut bias = AnalogBias::default();
534        bias.set_pd_cur(true);
535        bias.set_bias_sleep(true);
536        let mut regulator0 = LpRegulator0::default();
537        regulator0.set_xpd(true);
538
539        Self {
540            power: LpSystemPower::default(),
541            analog: LpSystemAnalog {
542                bias,
543                regulator0,
544                regulator1: LpRegulator1::default(),
545            },
546        }
547    }
548}
549
550impl LpSystemInit {
551    fn init_default() {
552        let active = Self::active();
553        let sleep = Self::sleep();
554        let pmu = PMU::regs();
555
556        unsafe {
557            // PMU_MODE_LP_ACTIVE is represented by the HP-sleep LP register group.
558            pmu.hp_sleep_lp_dig_power()
559                .write(|w| w.bits(active.power.dig_power.0));
560            pmu.hp_sleep_lp_ck_power()
561                .write(|w| w.bits(active.power.clk_power.0));
562            pmu.hp_sleep_lp_regulator0()
563                .write(|w| w.bits(active.analog.regulator0.0));
564            pmu.hp_sleep_lp_regulator1()
565                .write(|w| w.bits(active.analog.regulator1.0));
566
567            pmu.lp_sleep_lp_dig_power()
568                .write(|w| w.bits(sleep.power.dig_power.0));
569            pmu.lp_sleep_lp_ck_power()
570                .write(|w| w.bits(sleep.power.clk_power.0));
571            pmu.lp_sleep_bias().write(|w| w.bits(sleep.analog.bias.0));
572            pmu.lp_sleep_lp_regulator0()
573                .write(|w| w.bits(sleep.analog.regulator0.0));
574            pmu.lp_sleep_lp_regulator1()
575                .write(|w| w.bits(sleep.analog.regulator1.0));
576            pmu.lp_sleep_xtal().write(|w| w.bits(sleep.power.xtal.0));
577        }
578    }
579}
580
581fn power_domain_force_default() {
582    let pmu = PMU::regs();
583
584    // Clear the six force-control bits for every S31 HP power domain while
585    // preserving the domain mask fields.
586    macro_rules! clear_force_control {
587        ($reg:expr) => {
588            $reg.modify(|r, w| unsafe { w.bits(r.bits() & !0x3f) })
589        };
590    }
591    clear_force_control!(pmu.power_pd_top_cntl());
592    clear_force_control!(pmu.power_pd_hp_alive_cntl());
593    clear_force_control!(pmu.power_pd_modem_pwr_cntl());
594    clear_force_control!(pmu.power_pd_hpcpu_cntl());
595    clear_force_control!(pmu.power_pd_hpcnnt_cntl());
596    clear_force_control!(pmu.power_pd_modem_top_cntl());
597
598    // Isolate all HP memory banks in sleep and disable force-power-up.
599    pmu.power_pd_mem_cntl()
600        .modify(|r, w| unsafe { w.bits(r.bits() & !0xff00_0000) });
601    pmu.power_pd_lpperi_cntl()
602        .modify(|r, w| unsafe { w.bits(r.bits() & !0x3f) });
603}
604
605fn modem_clock_domain_power_state_icg_map_init() {
606    // OR in the defaults from esp32s31/modem_clock_impl.c. Other users may
607    // already own additional state-map bits, so do not replace whole fields.
608    MODEM_SYSCON::regs()
609        .clk_conf_power_st()
610        .modify(|r, w| unsafe {
611            w.clk_modem_apb_st_map()
612                .bits(r.clk_modem_apb_st_map().bits() | ICG_NOGATING_ACTIVE_MODEM);
613            w.clk_modem_peri_st_map()
614                .bits(r.clk_modem_peri_st_map().bits() | ICG_NOGATING_ACTIVE);
615            w.clk_wifi_st_map()
616                .bits(r.clk_wifi_st_map().bits() | ICG_NOGATING_ACTIVE_MODEM);
617            w.clk_bt_st_map()
618                .bits(r.clk_bt_st_map().bits() | ICG_NOGATING_ACTIVE);
619            w.clk_fe_st_map()
620                .bits(r.clk_fe_st_map().bits() | ICG_NOGATING_ACTIVE_MODEM);
621            w.clk_zb_st_map()
622                .bits(r.clk_zb_st_map().bits() | ICG_NOGATING_ACTIVE)
623        });
624    MODEM_LPCON::regs()
625        .clk_conf_power_st()
626        .modify(|r, w| unsafe {
627            w.clk_lp_apb_st_map()
628                .bits(r.clk_lp_apb_st_map().bits() | ICG_NOGATING_ACTIVE_MODEM);
629            w.clk_i2c_mst_st_map()
630                .bits(r.clk_i2c_mst_st_map().bits() | ICG_NOGATING_ACTIVE_MODEM);
631            w.clk_coex_st_map()
632                .bits(r.clk_coex_st_map().bits() | ICG_NOGATING_ACTIVE_MODEM);
633            w.clk_wifipwr_st_map()
634                .bits(r.clk_wifipwr_st_map().bits() | ICG_NOGATING_ACTIVE_MODEM)
635        });
636}
637
638/// Selects the WiFi LP clock after `ClockConfig::configure` has applied and
639/// acquired the configured LP clock source.
640pub(crate) fn configure_wifi_lp_clock(config: &ClockConfig) {
641    let lpcon = MODEM_LPCON::regs();
642    let source = config.lp_slow_clk.unwrap_or(LpSlowClkConfig::RcSlow);
643
644    lpcon.wifi_lp_clk_conf().modify(|_, w| {
645        w.clk_wifipwr_lp_sel_osc_slow().clear_bit();
646        w.clk_wifipwr_lp_sel_osc_fast().clear_bit();
647        w.clk_wifipwr_lp_sel_xtal().clear_bit();
648        w.clk_wifipwr_lp_sel_xtal32k().clear_bit();
649        match source {
650            LpSlowClkConfig::RcSlow => w.clk_wifipwr_lp_sel_osc_slow().set_bit(),
651            #[cfg(use_xtal32k)]
652            LpSlowClkConfig::Xtal32k => w.clk_wifipwr_lp_sel_xtal32k().set_bit(),
653        }
654    });
655    if cfg_select! {
656        use_xtal32k => source == LpSlowClkConfig::Xtal32k,
657        _ => false,
658    } {
659        // The WiFi 32 kHz selector feeds from the shared modem 32 kHz mux.
660        // MODEM_CLOCK_XTAL32K_CODE is 0 on S31.
661        lpcon
662            .modem_32k_clk_conf()
663            .modify(|_, w| unsafe { w.clk_modem_32k_sel().bits(0) });
664    }
665    lpcon
666        .wifi_lp_clk_conf()
667        .modify(|_, w| unsafe { w.clk_wifipwr_lp_div_num().bits(0) });
668    lpcon.clk_conf().modify(|_, w| w.clk_wifipwr_en().set_bit());
669}
670
671pub(crate) fn init(_config: &ClockConfig) {
672    // pmu_init: power up and release reset for the analog peripheral I2C.
673    PMU::regs()
674        .ana_peri_pwr_ctrl()
675        .modify(|_, w| w.rstb_perif_i2c().clear_bit());
676    crate::rom::ets_delay_us(1);
677    PMU::regs().ana_peri_pwr_ctrl().modify(|_, w| {
678        w.xpd_perif_i2c().set_bit();
679        w.rstb_perif_i2c().set_bit()
680    });
681
682    HpSystemInit::init_default();
683    LpSystemInit::init_default();
684    power_domain_force_default();
685
686    // rtc_clk_init: S31 only applies RC_SLOW tuning and regulator force bits
687    // here, it has no PCR/FOSC/RC32K tuning sequence.
688    regi2c::I2C_DIG_REG_SCK_DCAP.write_field(128);
689    regi2c::I2C_DIG_REG_ENIF_RTC_DREG.write_field(1);
690    regi2c::I2C_DIG_REG_ENIF_DIG_DREG.write_field(1);
691    regi2c::I2C_DIG_REG_XPD_RTC_REG.write_field(0);
692    regi2c::I2C_DIG_REG_XPD_DIG_REG.write_field(0);
693
694    modem_clock_domain_power_state_icg_map_init();
695}
696
697/// SOC Reset Reason.
698#[derive(Debug, Clone, Copy, PartialEq, Eq, FromRepr)]
699pub enum SocResetReason {
700    /// Powers on reset.
701    ///
702    /// In ESP-IDF this value (0x01) can *also* be `ChipBrownOut` or
703    /// `ChipSuperWdt`, however that is not really compatible with Rust-style
704    /// enums.
705    ChipPowerOn   = 0x01,
706    /// Software resets the digital core
707    CoreSw        = 0x03,
708    /// Deep sleep reset the digital core (also: PMU HP power down core reset)
709    CoreDeepSleep = 0x05,
710    /// PMU HP CPU power down reset
711    CpuPmuPwrDown = 0x06,
712    /// Main watch dog 0 resets digital core
713    CoreMwdt0     = 0x07,
714    /// Main watch dog 1 resets digital core
715    CoreMwdt1     = 0x08,
716    /// RWDT core reset
717    CoreRwdt      = 0x09,
718    /// MWDT HP CPU reset
719    CpuMwdt       = 0x0B,
720    /// Software resets HP CPU
721    CpuSw         = 0x0C,
722    /// RWDT resets digital core
723    CpuRwdt       = 0x0D,
724    /// VDD voltage is not stable and resets the digital core.
725    SysBrownOut   = 0x0F,
726    /// RWDT system reset
727    SysRwdt       = 0x10,
728    /// Super watch dog resets the digital core and rtc module
729    SysSuperWdt   = 0x12,
730    /// Glitch on power resets the digital core and rtc module
731    CorePwrGlitch = 0x13,
732    /// eFuse CRC error resets the digital core
733    CoreEfuseCrc  = 0x14,
734    /// USB Serial/JTAG controller's JTAG resets the digital core
735    CoreUsbJtag   = 0x16,
736    /// USB Serial/JTAG controller's UART resets the digital core
737    CoreUsbUart   = 0x17,
738    /// JTAG resets the CPU
739    CpuJtag       = 0x18,
740    /// CPU lockup (exception inside exception handler)
741    CpuLockup     = 0x1A,
742}