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    soc::regi2c,
6};
7
8// rtc_clk_bbpll_configure
9pub(crate) fn esp32c6_rtc_bbpll_configure(xtal_freq: XtalClock, pll_freq: PllClock) {
10    esp32c6_rtc_bbpll_configure_raw(xtal_freq.mhz(), pll_freq.mhz())
11}
12
13pub(crate) fn esp32c6_rtc_bbpll_configure_raw(_xtal_freq: u32, pll_freq: u32) {
14    // clk_ll_bbpll_set_freq_mhz
15    // The target SPLL is fixed to 480MHz
16    // Do nothing
17    debug_assert!(pll_freq == 480);
18
19    critical_section::with(|_| {
20        // enable i2c mst clk by force on (temporarily)
21        let was_i2c_mst_en = MODEM_LPCON::regs().clk_conf().read().clk_i2c_mst_en().bit();
22        MODEM_LPCON::regs()
23            .clk_conf()
24            .modify(|_, w| w.clk_i2c_mst_en().set_bit());
25
26        MODEM_LPCON::regs()
27            .i2c_mst_clk_conf()
28            .modify(|_, w| w.clk_i2c_mst_sel_160m().set_bit());
29
30        // BBPLL CALIBRATION START
31        I2C_ANA_MST::regs().ana_conf0().modify(|_, w| {
32            w.bbpll_stop_force_high().clear_bit();
33            w.bbpll_stop_force_low().set_bit()
34        });
35
36        const DIV_REF: u8 = 0;
37        const DCHGP: u8 = 5;
38        const DCUR: u8 = 3;
39
40        const I2C_BBPLL_OC_DCHGP_LSB: u32 = 4;
41        const I2C_BBPLL_OC_DHREF_SEL_LSB: u32 = 4;
42        const I2C_BBPLL_OC_DLREF_SEL_LSB: u32 = 6;
43
44        const I2C_BBPLL_LREF: u8 = (DCHGP << I2C_BBPLL_OC_DCHGP_LSB) | DIV_REF;
45        const I2C_BBPLL_DCUR: u8 =
46            (1 << I2C_BBPLL_OC_DLREF_SEL_LSB) | (3 << I2C_BBPLL_OC_DHREF_SEL_LSB) | DCUR;
47
48        regi2c::I2C_BBPLL_OC_REF.write_reg(I2C_BBPLL_LREF);
49        regi2c::I2C_BBPLL_OC_DIV_REG.write_reg(8);
50        regi2c::I2C_BBPLL_OC_DR1.write_field(0);
51        regi2c::I2C_BBPLL_OC_DR3.write_field(0);
52        regi2c::I2C_BBPLL_REG6.write_reg(I2C_BBPLL_DCUR);
53        regi2c::I2C_BBPLL_OC_VCO_DBIAS.write_field(2);
54
55        // WAIT CALIBRATION DONE
56        while I2C_ANA_MST::regs()
57            .ana_conf0()
58            .read()
59            .cal_done()
60            .bit_is_clear()
61        {}
62
63        // workaround bbpll calibration might stop early
64        crate::rom::ets_delay_us(10);
65
66        // BBPLL CALIBRATION STOP
67        I2C_ANA_MST::regs().ana_conf0().modify(|_, w| {
68            w.bbpll_stop_force_high().set_bit();
69            w.bbpll_stop_force_low().clear_bit()
70        });
71
72        MODEM_LPCON::regs()
73            .clk_conf()
74            .modify(|_, w| w.clk_i2c_mst_en().bit(was_i2c_mst_en));
75    });
76}
77
78pub(crate) fn esp32c6_rtc_bbpll_enable() {
79    PMU::regs().imm_hp_ck_power().modify(|_, w| {
80        w.tie_high_xpd_bb_i2c().set_bit();
81        w.tie_high_xpd_bbpll().set_bit();
82        w.tie_high_xpd_bbpll_i2c().set_bit()
83    });
84
85    PMU::regs()
86        .imm_hp_ck_power()
87        .modify(|_, w| w.tie_high_global_bbpll_icg().set_bit());
88}
89
90pub(crate) fn esp32c6_rtc_update_to_xtal(freq: XtalClock, div: u8) {
91    esp32c6_rtc_update_to_xtal_raw(freq.mhz(), div)
92}
93
94pub(crate) fn esp32c6_rtc_update_to_xtal_raw(freq_mhz: u32, div: u8) {
95    esp32c6_ahb_set_ls_divider(div);
96    esp32c6_cpu_set_ls_divider(div);
97
98    CpuClockSource::Xtal.select();
99
100    crate::rom::ets_update_cpu_frequency_rom(freq_mhz);
101}
102
103pub(crate) fn esp32c6_rtc_update_to_8m() {
104    esp32c6_ahb_set_ls_divider(1);
105    esp32c6_cpu_set_ls_divider(1);
106
107    CpuClockSource::RcFast.select();
108
109    crate::rom::ets_update_cpu_frequency_rom(20);
110}
111
112pub(crate) fn esp32c6_rtc_freq_to_pll_mhz(cpu_clock_speed: CpuClock) {
113    esp32c6_rtc_freq_to_pll_mhz_raw(cpu_clock_speed.mhz());
114}
115
116pub(crate) fn esp32c6_rtc_freq_to_pll_mhz_raw(cpu_clock_speed_mhz: u32) {
117    // On ESP32C6, MSPI source clock's default HS divider leads to 120MHz, which is
118    // unusable before calibration Therefore, before switching SOC_ROOT_CLK to
119    // HS, we need to set MSPI source clock HS divider to make it run at
120    // 80MHz after the switch. PLL = 480MHz, so divider is 6.
121    clk_ll_mspi_fast_set_hs_divider(6);
122
123    PCR::regs().cpu_freq_conf().modify(|_, w| unsafe {
124        w.cpu_hs_div_num()
125            .bits(((480 / cpu_clock_speed_mhz / 3) - 1) as u8);
126        w.cpu_hs_120m_force().clear_bit()
127    });
128
129    PCR::regs()
130        .cpu_freq_conf()
131        .modify(|_, w| w.cpu_hs_120m_force().clear_bit());
132
133    CpuClockSource::Pll.select();
134
135    crate::rom::ets_update_cpu_frequency_rom(cpu_clock_speed_mhz);
136}
137
138pub(crate) fn esp32c6_rtc_apb_freq_update(apb_freq: ApbClock) {
139    let value = ((apb_freq.hz() >> 12) & u16::MAX as u32)
140        | (((apb_freq.hz() >> 12) & u16::MAX as u32) << 16);
141
142    LP_AON::regs()
143        .store5()
144        .modify(|_, w| unsafe { w.lp_aon_store5().bits(value) });
145}
146
147fn clk_ll_mspi_fast_set_hs_divider(divider: u32) {
148    // SOC_ROOT_CLK ------> MSPI_FAST_CLK
149    // HS divider option: 4, 5, 6 (PCR_MSPI_FAST_HS_DIV_NUM=3, 4, 5)
150
151    let div_num = match divider {
152        4..=6 => divider as u8 - 1,
153        _ => panic!("Unsupported HS MSPI_FAST divider"),
154    };
155
156    PCR::regs()
157        .mspi_clk_conf()
158        .modify(|_, w| unsafe { w.mspi_fast_hs_div_num().bits(div_num) });
159}
160
161// clk_ll_ahb_set_ls_divider
162fn esp32c6_ahb_set_ls_divider(div: u8) {
163    PCR::regs()
164        .ahb_freq_conf()
165        .modify(|_, w| unsafe { w.ahb_ls_div_num().bits(div - 1) });
166}
167
168// clk_ll_cpu_set_ls_divider
169fn esp32c6_cpu_set_ls_divider(div: u8) {
170    PCR::regs()
171        .cpu_freq_conf()
172        .modify(|_, w| unsafe { w.cpu_ls_div_num().bits(div - 1) });
173}
174
175// clk_ll_cpu_get_ls_divider
176pub(crate) fn esp32c6_cpu_get_ls_divider() -> u8 {
177    let cpu_ls_div = PCR::regs().cpu_freq_conf().read().cpu_ls_div_num().bits();
178    let hp_root_ls_div = PCR::regs().sysclk_conf().read().ls_div_num().bits();
179    (hp_root_ls_div + 1) * (cpu_ls_div + 1)
180}
181
182// clk_ll_cpu_get_hs_divider
183pub(crate) fn esp32c6_cpu_get_hs_divider() -> u8 {
184    let force_120m = PCR::regs().cpu_freq_conf().read().cpu_hs_120m_force().bit();
185    let cpu_hs_div = PCR::regs().cpu_freq_conf().read().cpu_hs_div_num().bits();
186    if cpu_hs_div == 0 && force_120m {
187        return 4;
188    }
189    let hp_root_hs_div = PCR::regs().sysclk_conf().read().hs_div_num().bits();
190    (hp_root_hs_div + 1) * (cpu_hs_div + 1)
191}
192
193// clk_ll_bbpll_get_freq_mhz
194pub(crate) fn esp32c6_bbpll_get_freq_mhz() -> u32 {
195    // The target has a fixed 480MHz SPLL
196    const CLK_LL_PLL_480M_FREQ_MHZ: u32 = 480;
197
198    CLK_LL_PLL_480M_FREQ_MHZ
199}
200
201pub(super) fn enable_phy(en: bool) {
202    MODEM_LPCON::regs()
203        .clk_conf()
204        .modify(|_, w| w.clk_i2c_mst_en().bit(en));
205    MODEM_LPCON::regs()
206        .i2c_mst_clk_conf()
207        .modify(|_, w| w.clk_i2c_mst_sel_160m().bit(en));
208}
209
210pub(super) fn enable_wifi(en: bool) {
211    MODEM_SYSCON::regs().clk_conf1().modify(|_, w| {
212        w.clk_wifi_apb_en().bit(en);
213        w.clk_wifimac_en().bit(en);
214        w.clk_fe_apb_en().bit(en);
215        w.clk_fe_cal_160m_en().bit(en);
216        w.clk_fe_160m_en().bit(en);
217        w.clk_fe_80m_en().bit(en);
218        w.clk_wifibb_160x1_en().bit(en);
219        w.clk_wifibb_80x1_en().bit(en);
220        w.clk_wifibb_40x1_en().bit(en);
221        w.clk_wifibb_80x_en().bit(en);
222        w.clk_wifibb_40x_en().bit(en);
223        w.clk_wifibb_80m_en().bit(en);
224        w.clk_wifibb_44m_en().bit(en);
225        w.clk_wifibb_40m_en().bit(en);
226        w.clk_wifibb_22m_en().bit(en)
227    });
228
229    MODEM_LPCON::regs().clk_conf().modify(|_, w| {
230        w.clk_wifipwr_en().bit(en);
231        w.clk_coex_en().bit(en)
232    });
233}
234
235pub(super) fn enable_ieee802154(en: bool) {
236    MODEM_SYSCON::regs().clk_conf().modify(|_, w| {
237        w.clk_zb_apb_en().bit(en);
238        w.clk_zb_mac_en().bit(en)
239    });
240
241    MODEM_SYSCON::regs().clk_conf1().modify(|_, w| {
242        w.clk_fe_apb_en().bit(en);
243        w.clk_fe_cal_160m_en().bit(en);
244        w.clk_fe_160m_en().bit(en);
245        w.clk_fe_80m_en().bit(en);
246        w.clk_bt_apb_en().bit(en);
247        w.clk_bt_en().bit(en);
248        w.clk_wifibb_160x1_en().bit(en);
249        w.clk_wifibb_80x1_en().bit(en);
250        w.clk_wifibb_40x1_en().bit(en);
251        w.clk_wifibb_80x_en().bit(en);
252        w.clk_wifibb_40x_en().bit(en);
253        w.clk_wifibb_80m_en().bit(en);
254        w.clk_wifibb_44m_en().bit(en);
255        w.clk_wifibb_40m_en().bit(en);
256        w.clk_wifibb_22m_en().bit(en)
257    });
258
259    MODEM_LPCON::regs()
260        .clk_conf()
261        .modify(|_, w| w.clk_coex_en().set_bit());
262}
263
264pub(super) fn enable_bt(en: bool) {
265    MODEM_SYSCON::regs().clk_conf().modify(|_, w| {
266        w.clk_etm_en().bit(en);
267        w.clk_modem_sec_en().bit(en);
268        w.clk_modem_sec_ecb_en().bit(en);
269        w.clk_modem_sec_ccm_en().bit(en);
270        w.clk_modem_sec_bah_en().bit(en);
271        w.clk_modem_sec_apb_en().bit(en);
272        w.clk_ble_timer_en().bit(en)
273    });
274
275    MODEM_SYSCON::regs().clk_conf1().modify(|_, w| {
276        w.clk_fe_apb_en().bit(en);
277        w.clk_fe_cal_160m_en().bit(en);
278        w.clk_fe_160m_en().bit(en);
279        w.clk_fe_80m_en().bit(en);
280        w.clk_bt_apb_en().bit(en);
281        w.clk_bt_en().bit(en)
282    });
283
284    MODEM_LPCON::regs()
285        .clk_conf()
286        .modify(|_, w| w.clk_coex_en().bit(en));
287}
288
289pub(super) fn reset_mac() {
290    // empty
291}
292
293pub(super) fn init_clocks() {
294    unsafe {
295        PMU::regs()
296            .hp_sleep_icg_modem()
297            .modify(|_, w| w.hp_sleep_dig_icg_modem_code().bits(0));
298        PMU::regs()
299            .hp_modem_icg_modem()
300            .modify(|_, w| w.hp_modem_dig_icg_modem_code().bits(1));
301        PMU::regs()
302            .hp_active_icg_modem()
303            .modify(|_, w| w.hp_active_dig_icg_modem_code().bits(2));
304        PMU::regs()
305            .imm_modem_icg()
306            .write(|w| w.update_dig_icg_modem_en().set_bit());
307        PMU::regs()
308            .imm_sleep_sysclk()
309            .write(|w| w.update_dig_icg_switch().set_bit());
310
311        MODEM_SYSCON::regs().clk_conf_power_st().modify(|_, w| {
312            w.clk_modem_apb_st_map().bits(6);
313            w.clk_modem_peri_st_map().bits(4);
314            w.clk_wifi_st_map().bits(6);
315            w.clk_bt_st_map().bits(6);
316            w.clk_fe_st_map().bits(6);
317            w.clk_zb_st_map().bits(6)
318        });
319
320        MODEM_LPCON::regs().clk_conf_power_st().modify(|_, w| {
321            w.clk_lp_apb_st_map().bits(6);
322            w.clk_i2c_mst_st_map().bits(6);
323            w.clk_coex_st_map().bits(6);
324            w.clk_wifipwr_st_map().bits(6)
325        });
326
327        MODEM_LPCON::regs().wifi_lp_clk_conf().modify(|_, w| {
328            w.clk_wifipwr_lp_sel_osc_slow().set_bit();
329            w.clk_wifipwr_lp_sel_osc_fast().set_bit();
330            w.clk_wifipwr_lp_sel_xtal32k().set_bit();
331            w.clk_wifipwr_lp_sel_xtal().set_bit()
332        });
333
334        MODEM_LPCON::regs()
335            .wifi_lp_clk_conf()
336            .modify(|_, w| w.clk_wifipwr_lp_div_num().bits(0));
337
338        MODEM_LPCON::regs()
339            .clk_conf()
340            .modify(|_, w| w.clk_wifipwr_en().set_bit());
341    }
342}
343
344pub(super) fn ble_rtc_clk_init() {
345    // nothing for this target (yet)
346}
347
348pub(super) fn reset_rpa() {
349    // nothing for this target (yet)
350}