esp_hal/clock/clocks_ll/
esp32c6.rs

1use crate::{
2    clock::{ApbClock, Clock, CpuClock, PllClock, XtalClock},
3    peripherals::{I2C_ANA_MST, LP_AON, MODEM_LPCON, MODEM_SYSCON, PCR, PMU},
4    rtc_cntl::rtc::CpuClockSource,
5};
6
7const I2C_BBPLL: u8 = 0x66;
8const I2C_BBPLL_HOSTID: u8 = 0;
9
10const I2C_BBPLL_OC_REF_DIV: u8 = 2;
11const I2C_BBPLL_OC_DCHGP_LSB: u32 = 4;
12
13const I2C_BBPLL_OC_DIV_7_0: u8 = 3;
14
15const I2C_BBPLL_OC_DR1: u8 = 5;
16const I2C_BBPLL_OC_DR1_MSB: u8 = 2;
17const I2C_BBPLL_OC_DR1_LSB: u8 = 0;
18
19const I2C_BBPLL_OC_DR3: u8 = 5;
20const I2C_BBPLL_OC_DR3_MSB: u8 = 6;
21const I2C_BBPLL_OC_DR3_LSB: u8 = 4;
22
23const I2C_BBPLL_OC_DCUR: u8 = 6;
24
25const I2C_BBPLL_OC_DHREF_SEL_LSB: u32 = 4;
26
27const I2C_BBPLL_OC_DLREF_SEL_LSB: u32 = 6;
28
29const I2C_BBPLL_OC_VCO_DBIAS: u8 = 9;
30const I2C_BBPLL_OC_VCO_DBIAS_MSB: u8 = 1;
31const I2C_BBPLL_OC_VCO_DBIAS_LSB: u8 = 0;
32
33// rtc_clk_bbpll_configure
34pub(crate) fn esp32c6_rtc_bbpll_configure(xtal_freq: XtalClock, pll_freq: PllClock) {
35    esp32c6_rtc_bbpll_configure_raw(xtal_freq.mhz(), pll_freq.mhz())
36}
37
38pub(crate) fn esp32c6_rtc_bbpll_configure_raw(_xtal_freq: u32, pll_freq: u32) {
39    // clk_ll_bbpll_set_freq_mhz
40    // The target SPLL is fixed to 480MHz
41    // Do nothing
42    debug_assert!(pll_freq == 480);
43
44    critical_section::with(|_| {
45        // enable i2c mst clk by force on (temporarily)
46        let was_i2c_mst_en = MODEM_LPCON::regs().clk_conf().read().clk_i2c_mst_en().bit();
47        MODEM_LPCON::regs()
48            .clk_conf()
49            .modify(|_, w| w.clk_i2c_mst_en().set_bit());
50
51        MODEM_LPCON::regs()
52            .i2c_mst_clk_conf()
53            .modify(|_, w| w.clk_i2c_mst_sel_160m().set_bit());
54
55        // BBPLL CALIBRATION START
56        I2C_ANA_MST::regs().ana_conf0().modify(|_, w| {
57            w.bbpll_stop_force_high().clear_bit();
58            w.bbpll_stop_force_low().set_bit()
59        });
60
61        let div_ref = 0;
62        let div7_0 = 8;
63        let dr1 = 0;
64        let dr3 = 0;
65        let dchgp = 5;
66        let dcur = 3;
67        let dbias = 2;
68
69        let i2c_bbpll_lref = (dchgp << I2C_BBPLL_OC_DCHGP_LSB) | div_ref;
70        let i2c_bbpll_div_7_0 = div7_0;
71        let i2c_bbpll_dcur =
72            (1 << I2C_BBPLL_OC_DLREF_SEL_LSB) | (3 << I2C_BBPLL_OC_DHREF_SEL_LSB) | dcur;
73
74        regi2c_write(
75            I2C_BBPLL,
76            I2C_BBPLL_HOSTID,
77            I2C_BBPLL_OC_REF_DIV,
78            i2c_bbpll_lref,
79        );
80        regi2c_write(
81            I2C_BBPLL,
82            I2C_BBPLL_HOSTID,
83            I2C_BBPLL_OC_DIV_7_0,
84            i2c_bbpll_div_7_0,
85        );
86        regi2c_write_mask(
87            I2C_BBPLL,
88            I2C_BBPLL_HOSTID,
89            I2C_BBPLL_OC_DR1,
90            I2C_BBPLL_OC_DR1_MSB,
91            I2C_BBPLL_OC_DR1_LSB,
92            dr1,
93        );
94        regi2c_write_mask(
95            I2C_BBPLL,
96            I2C_BBPLL_HOSTID,
97            I2C_BBPLL_OC_DR3,
98            I2C_BBPLL_OC_DR3_MSB,
99            I2C_BBPLL_OC_DR3_LSB,
100            dr3,
101        );
102        regi2c_write(
103            I2C_BBPLL,
104            I2C_BBPLL_HOSTID,
105            I2C_BBPLL_OC_DCUR,
106            i2c_bbpll_dcur,
107        );
108        regi2c_write_mask(
109            I2C_BBPLL,
110            I2C_BBPLL_HOSTID,
111            I2C_BBPLL_OC_VCO_DBIAS,
112            I2C_BBPLL_OC_VCO_DBIAS_MSB,
113            I2C_BBPLL_OC_VCO_DBIAS_LSB,
114            dbias,
115        );
116
117        // WAIT CALIBRATION DONE
118        while I2C_ANA_MST::regs()
119            .ana_conf0()
120            .read()
121            .cal_done()
122            .bit_is_clear()
123        {}
124
125        // workaround bbpll calibration might stop early
126        crate::rom::ets_delay_us(10);
127
128        // BBPLL CALIBRATION STOP
129        I2C_ANA_MST::regs().ana_conf0().modify(|_, w| {
130            w.bbpll_stop_force_high().set_bit();
131            w.bbpll_stop_force_low().clear_bit()
132        });
133
134        MODEM_LPCON::regs()
135            .clk_conf()
136            .modify(|_, w| w.clk_i2c_mst_en().bit(was_i2c_mst_en));
137    });
138}
139
140pub(crate) fn esp32c6_rtc_bbpll_enable() {
141    PMU::regs().imm_hp_ck_power().modify(|_, w| {
142        w.tie_high_xpd_bb_i2c().set_bit();
143        w.tie_high_xpd_bbpll().set_bit();
144        w.tie_high_xpd_bbpll_i2c().set_bit()
145    });
146
147    PMU::regs()
148        .imm_hp_ck_power()
149        .modify(|_, w| w.tie_high_global_bbpll_icg().set_bit());
150}
151
152pub(crate) fn esp32c6_rtc_update_to_xtal(freq: XtalClock, div: u8) {
153    esp32c6_rtc_update_to_xtal_raw(freq.mhz(), div)
154}
155
156pub(crate) fn esp32c6_rtc_update_to_xtal_raw(freq_mhz: u32, div: u8) {
157    esp32c6_ahb_set_ls_divider(div);
158    esp32c6_cpu_set_ls_divider(div);
159
160    CpuClockSource::Xtal.select();
161
162    crate::rom::ets_update_cpu_frequency_rom(freq_mhz);
163}
164
165pub(crate) fn esp32c6_rtc_update_to_8m() {
166    esp32c6_ahb_set_ls_divider(1);
167    esp32c6_cpu_set_ls_divider(1);
168
169    CpuClockSource::RcFast.select();
170
171    crate::rom::ets_update_cpu_frequency_rom(20);
172}
173
174pub(crate) fn esp32c6_rtc_freq_to_pll_mhz(cpu_clock_speed: CpuClock) {
175    esp32c6_rtc_freq_to_pll_mhz_raw(cpu_clock_speed.mhz());
176}
177
178pub(crate) fn esp32c6_rtc_freq_to_pll_mhz_raw(cpu_clock_speed_mhz: u32) {
179    // On ESP32C6, MSPI source clock's default HS divider leads to 120MHz, which is
180    // unusable before calibration Therefore, before switching SOC_ROOT_CLK to
181    // HS, we need to set MSPI source clock HS divider to make it run at
182    // 80MHz after the switch. PLL = 480MHz, so divider is 6.
183    clk_ll_mspi_fast_set_hs_divider(6);
184
185    PCR::regs().cpu_freq_conf().modify(|_, w| unsafe {
186        w.cpu_hs_div_num()
187            .bits(((480 / cpu_clock_speed_mhz / 3) - 1) as u8);
188        w.cpu_hs_120m_force().clear_bit()
189    });
190
191    PCR::regs()
192        .cpu_freq_conf()
193        .modify(|_, w| w.cpu_hs_120m_force().clear_bit());
194
195    CpuClockSource::Pll.select();
196
197    crate::rom::ets_update_cpu_frequency_rom(cpu_clock_speed_mhz);
198}
199
200pub(crate) fn esp32c6_rtc_apb_freq_update(apb_freq: ApbClock) {
201    let value = ((apb_freq.hz() >> 12) & u16::MAX as u32)
202        | (((apb_freq.hz() >> 12) & u16::MAX as u32) << 16);
203
204    LP_AON::regs()
205        .store5()
206        .modify(|_, w| unsafe { w.lp_aon_store5().bits(value) });
207}
208
209fn clk_ll_mspi_fast_set_hs_divider(divider: u32) {
210    // SOC_ROOT_CLK ------> MSPI_FAST_CLK
211    // HS divider option: 4, 5, 6 (PCR_MSPI_FAST_HS_DIV_NUM=3, 4, 5)
212
213    let div_num = match divider {
214        4..=6 => divider as u8 - 1,
215        _ => panic!("Unsupported HS MSPI_FAST divider"),
216    };
217
218    PCR::regs()
219        .mspi_clk_conf()
220        .modify(|_, w| unsafe { w.mspi_fast_hs_div_num().bits(div_num) });
221}
222
223const REGI2C_BBPLL: u8 = 0x66;
224const REGI2C_BIAS: u8 = 0x6a;
225const REGI2C_DIG_REG: u8 = 0x6d;
226const REGI2C_ULP_CAL: u8 = 0x61;
227const REGI2C_SAR_I2C: u8 = 0x69;
228
229const I2C_MST_ANA_CONF1_M: u32 = 0x00FFFFFF;
230
231fn regi2c_enable_block(block: u8) -> usize {
232    MODEM_LPCON::regs()
233        .clk_conf()
234        .modify(|_, w| w.clk_i2c_mst_en().set_bit());
235
236    // Before config I2C register, enable corresponding slave.
237    let i2c_sel_bits = I2C_ANA_MST::regs().ana_conf2().read();
238    let i2c_sel = match block {
239        v if v == REGI2C_BBPLL => i2c_sel_bits.bbpll_mst_sel().bit_is_set(),
240        v if v == REGI2C_BIAS => i2c_sel_bits.bias_mst_sel().bit_is_set(),
241        v if v == REGI2C_DIG_REG => i2c_sel_bits.dig_reg_mst_sel().bit_is_set(),
242        v if v == REGI2C_ULP_CAL => i2c_sel_bits.ulp_cal_mst_sel().bit_is_set(),
243        v if v == REGI2C_SAR_I2C => i2c_sel_bits.sar_i2c_mst_sel().bit_is_set(),
244        _ => unreachable!(),
245    };
246    I2C_ANA_MST::regs().ana_conf1().write(|w| unsafe {
247        w.bits(I2C_MST_ANA_CONF1_M);
248        match block {
249            v if v == REGI2C_BBPLL => w.bbpll_rd().clear_bit(),
250            v if v == REGI2C_BIAS => w.bias_rd().clear_bit(),
251            v if v == REGI2C_DIG_REG => w.dig_reg_rd().clear_bit(),
252            v if v == REGI2C_ULP_CAL => w.ulp_cal_rd().clear_bit(),
253            v if v == REGI2C_SAR_I2C => w.sar_i2c_rd().clear_bit(),
254            _ => unreachable!(),
255        }
256    });
257
258    if i2c_sel {
259        0
260    } else {
261        1
262    }
263}
264
265pub(crate) fn regi2c_write(block: u8, _host_id: u8, reg_add: u8, data: u8) {
266    let master = regi2c_enable_block(block);
267
268    I2C_ANA_MST::regs().i2c_ctrl(master).write(|w| unsafe {
269        w.slave_addr().bits(block);
270        w.slave_reg_addr().bits(reg_add);
271        w.read_write().set_bit();
272        w.data().bits(data)
273    });
274
275    while I2C_ANA_MST::regs().i2c_ctrl(master).read().busy().bit() {}
276}
277
278pub(crate) fn regi2c_write_mask(block: u8, _host_id: u8, reg_add: u8, msb: u8, lsb: u8, data: u8) {
279    assert!(msb < 8 + lsb);
280    let master = regi2c_enable_block(block);
281
282    // Read the i2c bus register
283    I2C_ANA_MST::regs().i2c_ctrl(master).write(|w| unsafe {
284        w.slave_addr().bits(block);
285        w.slave_reg_addr().bits(reg_add)
286    });
287
288    while I2C_ANA_MST::regs().i2c_ctrl(master).read().busy().bit() {}
289
290    // Example: LSB=2, MSB = 5
291    // unwritten_bits = 1100 0011
292    // data_mask      = 0000 1111
293    // data_bits      = 00xx xx00
294    let unwritten_bits = (!(u32::MAX << lsb) | (u32::MAX << (msb + 1))) as u8;
295    let data_mask = !(u32::MAX << (msb - lsb + 1)) as u8;
296    let data_bits = (data & data_mask) << lsb;
297
298    I2C_ANA_MST::regs().i2c_ctrl(master).modify(|r, w| unsafe {
299        w.slave_addr().bits(block);
300        w.slave_reg_addr().bits(reg_add);
301        w.read_write().set_bit();
302        w.data()
303            .bits((r.data().bits() & unwritten_bits) | data_bits)
304    });
305
306    while I2C_ANA_MST::regs().i2c_ctrl(master).read().busy().bit() {}
307}
308
309// clk_ll_ahb_set_ls_divider
310fn esp32c6_ahb_set_ls_divider(div: u8) {
311    PCR::regs()
312        .ahb_freq_conf()
313        .modify(|_, w| unsafe { w.ahb_ls_div_num().bits(div - 1) });
314}
315
316// clk_ll_cpu_set_ls_divider
317fn esp32c6_cpu_set_ls_divider(div: u8) {
318    PCR::regs()
319        .cpu_freq_conf()
320        .modify(|_, w| unsafe { w.cpu_ls_div_num().bits(div - 1) });
321}
322
323// clk_ll_cpu_get_ls_divider
324pub(crate) fn esp32c6_cpu_get_ls_divider() -> u8 {
325    let cpu_ls_div = PCR::regs().cpu_freq_conf().read().cpu_ls_div_num().bits();
326    let hp_root_ls_div = PCR::regs().sysclk_conf().read().ls_div_num().bits();
327    (hp_root_ls_div + 1) * (cpu_ls_div + 1)
328}
329
330// clk_ll_cpu_get_hs_divider
331pub(crate) fn esp32c6_cpu_get_hs_divider() -> u8 {
332    let force_120m = PCR::regs().cpu_freq_conf().read().cpu_hs_120m_force().bit();
333    let cpu_hs_div = PCR::regs().cpu_freq_conf().read().cpu_hs_div_num().bits();
334    if cpu_hs_div == 0 && force_120m {
335        return 4;
336    }
337    let hp_root_hs_div = PCR::regs().sysclk_conf().read().hs_div_num().bits();
338    (hp_root_hs_div + 1) * (cpu_hs_div + 1)
339}
340
341// clk_ll_bbpll_get_freq_mhz
342pub(crate) fn esp32c6_bbpll_get_freq_mhz() -> u32 {
343    // The target has a fixed 480MHz SPLL
344    const CLK_LL_PLL_480M_FREQ_MHZ: u32 = 480;
345
346    CLK_LL_PLL_480M_FREQ_MHZ
347}
348
349pub(super) fn enable_phy(en: bool) {
350    MODEM_LPCON::regs()
351        .clk_conf()
352        .modify(|_, w| w.clk_i2c_mst_en().bit(en));
353    MODEM_LPCON::regs()
354        .i2c_mst_clk_conf()
355        .modify(|_, w| w.clk_i2c_mst_sel_160m().bit(en));
356}
357
358pub(super) fn enable_wifi(en: bool) {
359    MODEM_SYSCON::regs().clk_conf1().modify(|_, w| {
360        w.clk_wifi_apb_en().bit(en);
361        w.clk_wifimac_en().bit(en);
362        w.clk_fe_apb_en().bit(en);
363        w.clk_fe_cal_160m_en().bit(en);
364        w.clk_fe_160m_en().bit(en);
365        w.clk_fe_80m_en().bit(en);
366        w.clk_wifibb_160x1_en().bit(en);
367        w.clk_wifibb_80x1_en().bit(en);
368        w.clk_wifibb_40x1_en().bit(en);
369        w.clk_wifibb_80x_en().bit(en);
370        w.clk_wifibb_40x_en().bit(en);
371        w.clk_wifibb_80m_en().bit(en);
372        w.clk_wifibb_44m_en().bit(en);
373        w.clk_wifibb_40m_en().bit(en);
374        w.clk_wifibb_22m_en().bit(en)
375    });
376
377    MODEM_LPCON::regs().clk_conf().modify(|_, w| {
378        w.clk_wifipwr_en().bit(en);
379        w.clk_coex_en().bit(en)
380    });
381}
382
383pub(super) fn enable_ieee802154(en: bool) {
384    MODEM_SYSCON::regs().clk_conf().modify(|_, w| {
385        w.clk_zb_apb_en().bit(en);
386        w.clk_zb_mac_en().bit(en)
387    });
388
389    MODEM_SYSCON::regs().clk_conf1().modify(|_, w| {
390        w.clk_fe_apb_en().bit(en);
391        w.clk_fe_cal_160m_en().bit(en);
392        w.clk_fe_160m_en().bit(en);
393        w.clk_fe_80m_en().bit(en);
394        w.clk_bt_apb_en().bit(en);
395        w.clk_bt_en().bit(en);
396        w.clk_wifibb_160x1_en().bit(en);
397        w.clk_wifibb_80x1_en().bit(en);
398        w.clk_wifibb_40x1_en().bit(en);
399        w.clk_wifibb_80x_en().bit(en);
400        w.clk_wifibb_40x_en().bit(en);
401        w.clk_wifibb_80m_en().bit(en);
402        w.clk_wifibb_44m_en().bit(en);
403        w.clk_wifibb_40m_en().bit(en);
404        w.clk_wifibb_22m_en().bit(en)
405    });
406
407    MODEM_LPCON::regs()
408        .clk_conf()
409        .modify(|_, w| w.clk_coex_en().set_bit());
410}
411
412pub(super) fn enable_bt(en: bool) {
413    MODEM_SYSCON::regs().clk_conf().modify(|_, w| {
414        w.clk_etm_en().bit(en);
415        w.clk_modem_sec_en().bit(en);
416        w.clk_modem_sec_ecb_en().bit(en);
417        w.clk_modem_sec_ccm_en().bit(en);
418        w.clk_modem_sec_bah_en().bit(en);
419        w.clk_modem_sec_apb_en().bit(en);
420        w.clk_ble_timer_en().bit(en)
421    });
422
423    MODEM_SYSCON::regs().clk_conf1().modify(|_, w| {
424        w.clk_fe_apb_en().bit(en);
425        w.clk_fe_cal_160m_en().bit(en);
426        w.clk_fe_160m_en().bit(en);
427        w.clk_fe_80m_en().bit(en);
428        w.clk_bt_apb_en().bit(en);
429        w.clk_bt_en().bit(en)
430    });
431
432    MODEM_LPCON::regs()
433        .clk_conf()
434        .modify(|_, w| w.clk_coex_en().bit(en));
435}
436
437pub(super) fn reset_mac() {
438    // empty
439}
440
441pub(super) fn init_clocks() {
442    unsafe {
443        PMU::regs()
444            .hp_sleep_icg_modem()
445            .modify(|_, w| w.hp_sleep_dig_icg_modem_code().bits(0));
446        PMU::regs()
447            .hp_modem_icg_modem()
448            .modify(|_, w| w.hp_modem_dig_icg_modem_code().bits(1));
449        PMU::regs()
450            .hp_active_icg_modem()
451            .modify(|_, w| w.hp_active_dig_icg_modem_code().bits(2));
452        PMU::regs()
453            .imm_modem_icg()
454            .write(|w| w.update_dig_icg_modem_en().set_bit());
455        PMU::regs()
456            .imm_sleep_sysclk()
457            .write(|w| w.update_dig_icg_switch().set_bit());
458
459        MODEM_SYSCON::regs().clk_conf_power_st().modify(|_, w| {
460            w.clk_modem_apb_st_map().bits(6);
461            w.clk_modem_peri_st_map().bits(4);
462            w.clk_wifi_st_map().bits(6);
463            w.clk_bt_st_map().bits(6);
464            w.clk_fe_st_map().bits(6);
465            w.clk_zb_st_map().bits(6)
466        });
467
468        MODEM_LPCON::regs().clk_conf_power_st().modify(|_, w| {
469            w.clk_lp_apb_st_map().bits(6);
470            w.clk_i2c_mst_st_map().bits(6);
471            w.clk_coex_st_map().bits(6);
472            w.clk_wifipwr_st_map().bits(6)
473        });
474
475        MODEM_LPCON::regs().wifi_lp_clk_conf().modify(|_, w| {
476            w.clk_wifipwr_lp_sel_osc_slow().set_bit();
477            w.clk_wifipwr_lp_sel_osc_fast().set_bit();
478            w.clk_wifipwr_lp_sel_xtal32k().set_bit();
479            w.clk_wifipwr_lp_sel_xtal().set_bit()
480        });
481
482        MODEM_LPCON::regs()
483            .wifi_lp_clk_conf()
484            .modify(|_, w| w.clk_wifipwr_lp_div_num().bits(0));
485
486        MODEM_LPCON::regs()
487            .clk_conf()
488            .modify(|_, w| w.clk_wifipwr_en().set_bit());
489    }
490}
491
492pub(super) fn ble_rtc_clk_init() {
493    // nothing for this target (yet)
494}
495
496pub(super) fn reset_rpa() {
497    // nothing for this target (yet)
498}