1
use strum::FromRepr;
2

            
3
use crate::{
4
    peripherals::{APB_CTRL, EXTMEM, LPWR, SPI0, SPI1, SYSTEM},
5
    soc::{clocks::ClockConfig, regi2c},
6
};
7

            
8
pub(crate) fn init(_config: &ClockConfig) {
9
    let rtc_cntl = LPWR::regs();
10

            
11
325
    regi2c::I2C_DIG_REG_XPD_DIG_REG.write_field(0);
12
325
    regi2c::I2C_DIG_REG_XPD_RTC_REG.write_field(0);
13

            
14
    rtc_cntl.ana_conf().modify(|_, w| w.pvtmon_pu().clear_bit());
15

            
16
    unsafe {
17
        rtc_cntl
18
            .timer1()
19
            .modify(|_, w| w.pll_buf_wait().bits(20u8).ck8m_wait().bits(20u8));
20
        rtc_cntl.timer5().modify(|_, w| w.min_slp_val().bits(2u8));
21

            
22
        // Set default powerup & wait time
23
        rtc_cntl.timer3().modify(|_, w| {
24
            w.wifi_powerup_timer().bits(1u8);
25
            w.wifi_wait_timer().bits(1u16);
26
            w.bt_powerup_timer().bits(1u8);
27
            w.bt_wait_timer().bits(1u16)
28
        });
29
        rtc_cntl.timer4().modify(|_, w| {
30
            w.cpu_top_powerup_timer().bits(1u8);
31
            w.cpu_top_wait_timer().bits(1u16);
32
            w.dg_wrap_powerup_timer().bits(1u8);
33
            w.dg_wrap_wait_timer().bits(1u16)
34
        });
35
        rtc_cntl.timer6().modify(|_, w| {
36
            w.dg_peri_powerup_timer().bits(1u8);
37
            w.dg_peri_wait_timer().bits(1u16)
38
        });
39
    }
40

            
41
    calibrate_ocode();
42

            
43
    set_rtc_dig_dbias();
44

            
45
    clock_control_init();
46

            
47
    power_control_init();
48

            
49
    unsafe {
50
        rtc_cntl.int_ena().write(|w| w.bits(0));
51
        rtc_cntl.int_clr().write(|w| w.bits(u32::MAX));
52
    }
53

            
54
325
    regi2c::I2C_ULP_IR_FORCE_XPD_CK.write_field(0);
55
}
56

            
57
// Trims the RTC bandgap using eFuse calibration data.
58
//
59
// See `set_ocode_by_efuse` in
60
// <https://github.com/espressif/esp-idf/blob/v6.1/components/esp_hw_support/port/esp32c3/rtc_init.c>
61
fn calibrate_ocode() {
62
    super::calibrate_ocode(|| {
63
325
        (crate::efuse::block_version().0 == 1)
64
            .then(|| crate::efuse::read_field_le::<u8>(crate::efuse::OCODE))
65
    });
66
}
67

            
68
fn set_rtc_dig_dbias() {}
69

            
70
/// Performs clock control related initialization.
71
fn clock_control_init() {
72
    let extmem = EXTMEM::regs();
73
    let spi_mem_0 = SPI0::regs();
74
    let spi_mem_1 = SPI1::regs();
75

            
76
    // Clear CMMU clock force on
77
    extmem
78
        .cache_mmu_power_ctrl()
79
        .modify(|_, w| w.cache_mmu_mem_force_on().clear_bit());
80

            
81
    // Clear tag clock force on
82
    extmem
83
        .icache_tag_power_ctrl()
84
        .modify(|_, w| w.icache_tag_mem_force_on().clear_bit());
85

            
86
    // Clear register clock force on
87
    spi_mem_0.clock_gate().modify(|_, w| w.clk_en().clear_bit());
88
    spi_mem_1.clock_gate().modify(|_, w| w.clk_en().clear_bit());
89
}
90

            
91
/// Performs power control related initialization.
92
fn power_control_init() {
93
    let rtc_cntl = LPWR::regs();
94
    let system = SYSTEM::regs();
95
    rtc_cntl
96
        .clk_conf()
97
        .modify(|_, w| w.ck8m_force_pu().clear_bit());
98

            
99
    // Cancel XTAL force PU if no need to force power up
100
    // Cannot cancel XTAL force PU if PLL is force power on
101
    rtc_cntl
102
        .options0()
103
        .modify(|_, w| w.xtl_force_pu().clear_bit());
104

            
105
    // Force PD APLL
106
    rtc_cntl.ana_conf().modify(|_, w| {
107
        w.plla_force_pu().clear_bit();
108
        w.plla_force_pd().set_bit();
109
        // Open SAR_I2C protect function to avoid SAR_I2C
110
        // Reset when rtc_ldo is low.
111
        w.reset_por_force_pd().clear_bit()
112
    });
113

            
114
    // Cancel BBPLL force PU if setting no force power up
115
    rtc_cntl.options0().modify(|_, w| {
116
        w.bbpll_force_pu().clear_bit();
117
        w.bbpll_i2c_force_pu().clear_bit();
118
        w.bb_i2c_force_pu().clear_bit()
119
    });
120
    rtc_cntl.rtc_cntl().modify(|_, w| {
121
        w.regulator_force_pu().clear_bit();
122
        w.dboost_force_pu().clear_bit();
123
        w.dboost_force_pd().set_bit()
124
    });
125

            
126
    // If this mask is enabled, all soc memories cannot enter power down mode.
127
    // We should control soc memory power down mode from RTC,
128
    // so we will not touch this register any more.
129
    system
130
        .mem_pd_mask()
131
        .modify(|_, w| w.lslp_mem_pd_mask().clear_bit());
132

            
133
    rtc_sleep_pu();
134

            
135
    rtc_cntl.dig_pwc().modify(|_, w| {
136
        w.dg_wrap_force_pu().clear_bit();
137
        w.wifi_force_pu().clear_bit();
138
        w.bt_force_pu().clear_bit();
139
        w.cpu_top_force_pu().clear_bit();
140
        w.dg_peri_force_pu().clear_bit()
141
    });
142
    rtc_cntl.dig_iso().modify(|_, w| {
143
        w.dg_wrap_force_noiso().clear_bit();
144
        w.wifi_force_noiso().clear_bit();
145
        w.bt_force_noiso().clear_bit();
146
        w.cpu_top_force_noiso().clear_bit();
147
        w.dg_peri_force_noiso().clear_bit()
148
    });
149

            
150
    // Cancel digital PADS force no iso
151
    system
152
        .cpu_per_conf()
153
        .modify(|_, w| w.cpu_wait_mode_force_on().clear_bit());
154

            
155
    // If SYSTEM_CPU_WAIT_MODE_FORCE_ON == 0,
156
    // the CPU clock will be closed when CPU enter WAITI mode.
157
    rtc_cntl.dig_iso().modify(|_, w| {
158
        w.dg_pad_force_unhold().clear_bit();
159
        w.dg_pad_force_noiso().clear_bit()
160
    });
161
}
162

            
163
/// Configures whether certain peripherals are powered down in deep sleep.
164
fn rtc_sleep_pu() {
165
    let rtc_cntl = LPWR::regs();
166
    let apb_ctrl = APB_CTRL::regs();
167

            
168
    rtc_cntl.dig_pwc().modify(|_, w| {
169
        w.lslp_mem_force_pu().clear_bit();
170
        w.fastmem_force_lpu().clear_bit()
171
    });
172

            
173
    apb_ctrl.front_end_mem_pd().modify(|_, w| {
174
        w.dc_mem_force_pu().clear_bit();
175
        w.pbus_mem_force_pu().clear_bit();
176
        w.agc_mem_force_pu().clear_bit()
177
    });
178
    apb_ctrl.mem_power_up().modify(|_, w| unsafe {
179
        w.sram_power_up().bits(0u8);
180
        w.rom_power_up().bits(0u8)
181
    });
182
}
183

            
184
// Terminology:
185
//
186
// CPU Reset:    Reset CPU core only, once reset done, CPU will execute from
187
//               reset vector
188
// Core Reset:   Reset the whole digital system except RTC sub-system
189
// System Reset: Reset the whole digital system, including RTC sub-system
190
// Chip Reset:   Reset the whole chip, including the analog part
191

            
192
/// SOC Reset Reason.
193
325
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromRepr)]
194
pub enum SocResetReason {
195
    /// Powers on reset.
196
    ///
197
    /// In ESP-IDF this value (0x01) can *also* be `ChipBrownOut` or
198
    /// `ChipSuperWdt`, however that is not really compatible with Rust-style
199
    /// enums.
200
    ChipPowerOn   = 0x01,
201
    /// Software resets the digital core by RTC_CNTL_SW_SYS_RST
202
    CoreSw        = 0x03,
203
    /// Deep sleep reset the digital core
204
    CoreDeepSleep = 0x05,
205
    /// Main watch dog 0 resets digital core
206
    CoreMwdt0     = 0x07,
207
    /// Main watch dog 1 resets digital core
208
    CoreMwdt1     = 0x08,
209
    /// RTC watch dog resets digital core
210
    CoreRtcWdt    = 0x09,
211
    /// Main watch dog 0 resets CPU 0
212
    Cpu0Mwdt0     = 0x0B,
213
    /// Software resets CPU 0 by RTC_CNTL_SW_PROCPU_RST
214
    Cpu0Sw        = 0x0C,
215
    /// RTC watch dog resets CPU 0
216
    Cpu0RtcWdt    = 0x0D,
217
    /// VDD voltage is not stable and resets the digital core.
218
    SysBrownOut   = 0x0F,
219
    /// RTC watch dog resets digital core and rtc module
220
    SysRtcWdt     = 0x10,
221
    /// Main watch dog 1 resets CPU 0
222
    Cpu0Mwdt1     = 0x11,
223
    /// Super watch dog resets the digital core and rtc module
224
    SysSuperWdt   = 0x12,
225
    /// Glitch on clock resets the digital core and rtc module
226
    SysClkGlitch  = 0x13,
227
    /// eFuse CRC error resets the digital core
228
    CoreEfuseCrc  = 0x14,
229
    /// USB UART resets the digital core
230
    CoreUsbUart   = 0x15,
231
    /// USB JTAG resets the digital core
232
    CoreUsbJtag   = 0x16,
233
    /// Glitch on power resets the digital core
234
    CorePwrGlitch = 0x17,
235
}