esp_hal/clock/clocks_ll/
esp32.rs

1use crate::{
2    clock::{Clock, PllClock, XtalClock},
3    efuse::{Efuse, VOL_LEVEL_HP_INV},
4    peripherals::{APB_CTRL, DPORT, LPWR},
5    soc::regi2c,
6};
7
8const REF_CLK_FREQ: u32 = 1000000;
9
10const MHZ: u32 = 1000000;
11const UINT16_MAX: u32 = 0xffff;
12
13const RTC_CNTL_DBIAS_1V10: u8 = 4;
14const RTC_CNTL_DBIAS_1V25: u8 = 7;
15
16const DIG_DBIAS_80M_160M: u8 = RTC_CNTL_DBIAS_1V10;
17const DIG_DBIAS_XTAL: u8 = RTC_CNTL_DBIAS_1V10;
18
19const BBPLL_IR_CAL_DELAY_VAL: u8 = 0x18;
20const BBPLL_IR_CAL_EXT_CAP_VAL: u8 = 0x20;
21const BBPLL_OC_ENB_FCAL_VAL: u8 = 0x9a;
22const BBPLL_OC_ENB_VCON_VAL: u8 = 0x00;
23const BBPLL_BBADC_CAL_7_0_VAL: u8 = 0x00;
24
25const BBPLL_ENDIV5_VAL_320M: u8 = 0x43;
26const BBPLL_BBADC_DSMP_VAL_320M: u8 = 0x84;
27const BBPLL_ENDIV5_VAL_480M: u8 = 0xc3;
28const BBPLL_BBADC_DSMP_VAL_480M: u8 = 0x74;
29
30pub(crate) fn esp32_rtc_bbpll_configure(xtal_freq: XtalClock, pll_freq: PllClock) {
31    let rtc_cntl_dbias_hp_volt = RTC_CNTL_DBIAS_1V25 - Efuse::read_field_le::<u8>(VOL_LEVEL_HP_INV);
32    let dig_dbias_240_m = rtc_cntl_dbias_hp_volt;
33
34    let div_ref: u8;
35    let div7_0: u8;
36    let div10_8: u8;
37    let lref: u8;
38    let dcur: u8;
39    let bw: u8;
40
41    if matches!(pll_freq, PllClock::Pll320MHz) {
42        // Raise the voltage, if needed
43        LPWR::regs()
44            .reg()
45            .modify(|_, w| unsafe { w.dig_dbias_wak().bits(DIG_DBIAS_80M_160M) });
46
47        // Configure 320M PLL
48        match xtal_freq {
49            XtalClock::_40M => {
50                div_ref = 0;
51                div7_0 = 32;
52                div10_8 = 0;
53                lref = 0;
54                dcur = 6;
55                bw = 3;
56            }
57
58            XtalClock::_26M => {
59                div_ref = 12;
60                div7_0 = 224;
61                div10_8 = 4;
62                lref = 1;
63                dcur = 0;
64                bw = 1;
65            }
66
67            XtalClock::Other(_) => {
68                div_ref = 12;
69                div7_0 = 224;
70                div10_8 = 4;
71                lref = 0;
72                dcur = 0;
73                bw = 0;
74            }
75        }
76
77        regi2c::I2C_BBPLL_ENDIV5.write_reg(BBPLL_ENDIV5_VAL_320M);
78        regi2c::I2C_BBPLL_BBADC_DSMP.write_reg(BBPLL_BBADC_DSMP_VAL_320M);
79    } else {
80        // Raise the voltage
81        LPWR::regs()
82            .reg()
83            .modify(|_, w| unsafe { w.dig_dbias_wak().bits(dig_dbias_240_m) });
84
85        // Configure 480M PLL
86        match xtal_freq {
87            XtalClock::_40M => {
88                div_ref = 0;
89                div7_0 = 28;
90                div10_8 = 0;
91                lref = 0;
92                dcur = 6;
93                bw = 3;
94            }
95
96            XtalClock::_26M => {
97                div_ref = 12;
98                div7_0 = 144;
99                div10_8 = 4;
100                lref = 1;
101                dcur = 0;
102                bw = 1;
103            }
104
105            XtalClock::Other(_) => {
106                div_ref = 12;
107                div7_0 = 224;
108                div10_8 = 4;
109                lref = 0;
110                dcur = 0;
111                bw = 0;
112            }
113        }
114
115        regi2c::I2C_BBPLL_ENDIV5.write_reg(BBPLL_ENDIV5_VAL_480M);
116        regi2c::I2C_BBPLL_BBADC_DSMP.write_reg(BBPLL_BBADC_DSMP_VAL_480M);
117    }
118
119    let i2c_bbpll_lref = (lref << 7) | (div10_8 << 4) | (div_ref);
120    let i2c_bbpll_dcur = (bw << 6) | dcur;
121
122    regi2c::I2C_BBPLL_OC_LREF.write_reg(i2c_bbpll_lref);
123    regi2c::I2C_BBPLL_OC_DIV_REG.write_reg(div7_0);
124    regi2c::I2C_BBPLL_OC_DCUR.write_reg(i2c_bbpll_dcur);
125}
126
127pub(crate) fn esp32_rtc_bbpll_enable() {
128    LPWR::regs().options0().modify(|_, w| {
129        w.bias_i2c_force_pd().clear_bit();
130        w.bb_i2c_force_pd().clear_bit();
131        w.bbpll_force_pd().clear_bit();
132        w.bbpll_i2c_force_pd().clear_bit()
133    });
134
135    // reset BBPLL configuration
136    regi2c::I2C_BBPLL_IR_CAL_DELAY.write_reg(BBPLL_IR_CAL_DELAY_VAL);
137    regi2c::I2C_BBPLL_IR_CAL_EXT_CAP.write_reg(BBPLL_IR_CAL_EXT_CAP_VAL);
138    regi2c::I2C_BBPLL_OC_ENB_FCAL.write_reg(BBPLL_OC_ENB_FCAL_VAL);
139    regi2c::I2C_BBPLL_OC_ENB_VCON.write_reg(BBPLL_OC_ENB_VCON_VAL);
140    regi2c::I2C_BBPLL_BBADC_CAL_REG.write_reg(BBPLL_BBADC_CAL_7_0_VAL);
141}
142
143pub(crate) fn esp32_rtc_update_to_xtal(freq: XtalClock, _div: u32) {
144    let value = ((freq.hz() >> 12) & UINT16_MAX) | (((freq.hz() >> 12) & UINT16_MAX) << 16);
145    esp32_update_cpu_freq(freq.hz());
146
147    // set divider from XTAL to APB clock
148    APB_CTRL::regs().sysclk_conf().modify(|_, w| unsafe {
149        w.pre_div_cnt()
150            .bits(((freq.hz()) / REF_CLK_FREQ - 1) as u16)
151    });
152
153    // adjust ref_tick
154    APB_CTRL::regs().xtal_tick_conf().modify(|_, w| unsafe {
155        w.xtal_tick_num()
156            .bits(((freq.hz()) / REF_CLK_FREQ - 1) as u8)
157    });
158
159    // switch clock source
160    LPWR::regs()
161        .clk_conf()
162        .modify(|_, w| w.soc_clk_sel().xtal());
163    LPWR::regs()
164        .store5()
165        .modify(|_, w| unsafe { w.scratch5().bits(value) });
166
167    // lower the voltage
168    LPWR::regs()
169        .reg()
170        .modify(|_, w| unsafe { w.dig_dbias_wak().bits(DIG_DBIAS_XTAL) });
171}
172
173pub(crate) fn set_cpu_freq(cpu_freq_mhz: crate::clock::CpuClock) {
174    let rtc_cntl_dbias_hp_volt = RTC_CNTL_DBIAS_1V25 - Efuse::read_field_le::<u8>(VOL_LEVEL_HP_INV);
175
176    let dig_dbias_240_m = rtc_cntl_dbias_hp_volt;
177
178    const CPU_80M: u8 = 0;
179    const CPU_160M: u8 = 1;
180    const CPU_240M: u8 = 2;
181
182    let mut dbias = DIG_DBIAS_80M_160M;
183    let per_conf = match cpu_freq_mhz {
184        crate::clock::CpuClock::_160MHz => CPU_160M,
185        crate::clock::CpuClock::_240MHz => {
186            dbias = dig_dbias_240_m;
187            CPU_240M
188        }
189        crate::clock::CpuClock::_80MHz => CPU_80M,
190    };
191
192    let value = (((80 * MHZ) >> 12) & UINT16_MAX) | ((((80 * MHZ) >> 12) & UINT16_MAX) << 16);
193    DPORT::regs()
194        .cpu_per_conf()
195        .write(|w| unsafe { w.cpuperiod_sel().bits(per_conf) });
196    LPWR::regs()
197        .reg()
198        .modify(|_, w| unsafe { w.dig_dbias_wak().bits(dbias) });
199    LPWR::regs().clk_conf().modify(|_, w| w.soc_clk_sel().pll());
200    LPWR::regs()
201        .store5()
202        .modify(|_, w| unsafe { w.scratch5().bits(value) });
203
204    esp32_update_cpu_freq(cpu_freq_mhz.mhz());
205}
206
207/// Pass the CPU clock in MHz so that ets_delay_us
208/// will be accurate. Call this function when CPU frequency is changed.
209fn esp32_update_cpu_freq(mhz: u32) {
210    const G_TICKS_PER_US_PRO: u32 = 0x3ffe01e0;
211    unsafe {
212        // Update scale factors used by esp_rom_delay_us
213        (G_TICKS_PER_US_PRO as *mut u32).write_volatile(mhz);
214    }
215}
216
217const DPORT_WIFI_CLK_WIFI_BT_COMMON_M: u32 = 0x000003c9;
218const DPORT_WIFI_CLK_WIFI_EN_M: u32 = 0x00000406;
219const DPORT_WIFI_CLK_BT_EN_M: u32 = 0x00030800;
220
221pub(super) fn enable_phy(enable: bool) {
222    // `periph_ll_wifi_bt_module_enable_clk_clear_rst`
223    // `periph_ll_wifi_bt_module_disable_clk_set_rst`
224    DPORT::regs().wifi_clk_en().modify(|r, w| unsafe {
225        if enable {
226            w.bits(r.bits() | DPORT_WIFI_CLK_WIFI_BT_COMMON_M)
227        } else {
228            w.bits(r.bits() & !DPORT_WIFI_CLK_WIFI_BT_COMMON_M)
229        }
230    });
231}
232
233pub(super) fn enable_bt(enable: bool) {
234    DPORT::regs().wifi_clk_en().modify(|r, w| unsafe {
235        if enable {
236            w.bits(r.bits() | DPORT_WIFI_CLK_BT_EN_M)
237        } else {
238            w.bits(r.bits() & !DPORT_WIFI_CLK_BT_EN_M)
239        }
240    });
241}
242
243pub(super) fn enable_wifi(enable: bool) {
244    // `periph_ll_wifi_module_enable_clk_clear_rst`
245    // `periph_ll_wifi_module_disable_clk_set_rst`
246    DPORT::regs().wifi_clk_en().modify(|r, w| unsafe {
247        if enable {
248            w.bits(r.bits() | DPORT_WIFI_CLK_WIFI_EN_M)
249        } else {
250            w.bits(r.bits() & !DPORT_WIFI_CLK_WIFI_EN_M)
251        }
252    });
253}
254
255pub(super) fn reset_mac() {
256    DPORT::regs()
257        .wifi_rst_en()
258        .modify(|_, w| w.mac_rst().set_bit());
259    DPORT::regs()
260        .wifi_rst_en()
261        .modify(|_, w| w.mac_rst().clear_bit());
262}
263
264pub(super) fn init_clocks() {
265    // esp-idf assumes all clocks are enabled by default, and disables the following
266    // bits:
267    //
268    // ```
269    // const DPORT_WIFI_CLK_SDIOSLAVE_EN: u32 = 1 << 4;
270    // const DPORT_WIFI_CLK_UNUSED_BIT5: u32 = 1 << 5;
271    // const DPORT_WIFI_CLK_UNUSED_BIT12: u32 = 1 << 12;
272    // const DPORT_WIFI_CLK_SDIO_HOST_EN: u32 = 1 << 13;
273    // const DPORT_WIFI_CLK_EMAC_EN: u32 = 1 << 14;
274    //
275    // const WIFI_BT_SDIO_CLK: u32 = DPORT_WIFI_CLK_WIFI_EN_M
276    //     | DPORT_WIFI_CLK_BT_EN_M
277    //     | DPORT_WIFI_CLK_UNUSED_BIT5
278    //     | DPORT_WIFI_CLK_UNUSED_BIT12
279    //     | DPORT_WIFI_CLK_SDIOSLAVE_EN
280    //     | DPORT_WIFI_CLK_SDIO_HOST_EN
281    //     | DPORT_WIFI_CLK_EMAC_EN;
282    // ```
283    //
284    // However, we can't do this because somehow our initialization process is
285    // different, and disabling some bits, or not enabling them makes the BT
286    // stack crash.
287
288    DPORT::regs()
289        .wifi_clk_en()
290        .write(|w| unsafe { w.bits(u32::MAX) });
291}
292
293pub(super) fn ble_rtc_clk_init() {
294    // nothing for this target
295}
296
297pub(super) fn reset_rpa() {
298    // nothing for this target
299}