1
#![cfg_attr(docsrs, procmacros::doc_replace)]
2
//! # CPU Clock Control
3
//!
4
//! ## Overview
5
//!
6
//! Clocks are mainly sourced from oscillator (OSC), RC, and PLL circuits, and
7
//! then processed by the dividers or selectors, which allows most functional
8
//! modules to select their working clock according to their power consumption
9
//! and performance requirements.
10
//!
11
//! The clock subsystem  is used to source and distribute system/module clocks
12
//! from a range of root clocks. The clock tree driver maintains the basic
13
//! functionality of the system clock and the intricate relationship among
14
//! module clocks.
15
//!
16
//! ## Configuration
17
//!
18
//! During HAL initialization, specify a CPU clock speed to configure the
19
//! desired clock frequencies.
20
//!
21
//! The `CPU clock` is responsible for defining the speed at which the central
22
//! processing unit (CPU) operates. This driver provides predefined options for
23
//! different CPU clock speeds, such as
24
#![cfg_attr(not(esp32h2), doc = "* 80 MHz")]
25
#![cfg_attr(esp32h2, doc = "* 96 MHz")]
26
#![cfg_attr(esp32c2, doc = "* 120 MHz")]
27
#![cfg_attr(not(any(esp32c2, esp32h2)), doc = "* 160 MHz")]
28
#![cfg_attr(any(esp32c5, xtensa), doc = "* 240 MHz")]
29
//! ### Frozen Clock Frequencies
30
//!
31
//! Once the clock configuration is applied, the clock frequencies become
32
//! `frozen` and cannot be changed.
33
//!
34
//! ## Examples
35
//!
36
//! ### Initialize With Different Clock Frequencies
37
//! ```rust, no_run
38
//! # {before_snippet}
39
//! use esp_hal::clock::CpuClock;
40
//!
41
//! // Initialize with the highest possible frequency for this chip
42
//! let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
43
//! let peripherals = esp_hal::init(config);
44
//! # {after_snippet}
45
//! ```
46
#![cfg_attr(not(feature = "rt"), expect(unused))]
47

            
48
#[cfg(soc_has_clock_node_lp_slow_clk)]
49
use clocks::LpSlowClkConfig;
50
#[cfg(soc_has_clock_node_rtc_slow_clk)]
51
use clocks::RtcSlowClkConfig;
52
#[cfg(soc_has_clock_node_timg_function_clock)]
53
use clocks::TimgFunctionClockConfig;
54

            
55
pub(crate) mod dividers;
56

            
57
/// # Low-level clock control
58
///
59
/// <section class="warning">
60
/// This module provides experimental low-level clock control functionality. These functions
61
/// can render the device temporarily unusable. Use with caution.
62
/// </section>
63
#[doc = ""]
64
#[instability::unstable]
65
pub mod ll {
66
    #[instability::unstable]
67
    pub use crate::soc::clocks::*;
68
}
69

            
70
#[cfg(timergroup_rc_fast_calibration_divider)]
71
use crate::efuse::ChipRevision;
72
#[cfg(all(
73
    soc_has_clock_node_timg_calibration_clock,
74
    timergroup_rc_fast_calibration_tick_enable
75
))]
76
use crate::peripherals::PCR;
77
#[cfg(soc_has_clock_node_timg_calibration_clock)]
78
use crate::peripherals::TIMG0;
79
#[instability::unstable]
80
pub use crate::soc::clocks::ClockConfig;
81
pub use crate::soc::clocks::CpuClock;
82
use crate::{
83
    soc::{clocks, clocks::ClockTree},
84
    time::Rate,
85
};
86

            
87
cfg_select! {
88
    esp32s31 => {
89
        use crate::peripherals::LP_SYS as LP_AON;
90
    }
91
    soc_has_lp_aon => {
92
        use crate::peripherals::LP_AON;
93
    }
94
    _ => {
95
        use crate::peripherals::LPWR as LP_AON;
96
    }
97
}
98

            
99
impl CpuClock {
100
    #[procmacros::doc_replace]
101
    /// Returns the highest possible CPU clock frequency for this chip.
102
    ///
103
    /// # Examples
104
    ///
105
    /// ```rust, no_run
106
    /// # {before_snippet}
107
    /// use esp_hal::clock::CpuClock;
108
    /// let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
109
    /// let peripherals = esp_hal::init(config);
110
    /// # {after_snippet}
111
    /// ```
112
    pub const fn max() -> Self {
113
        cfg_select! {
114
            esp32c2 => Self::_120MHz,
115
            any(esp32c3, esp32c6, esp32c61) => Self::_160MHz,
116
            any(esp32h2, esp32h4) => Self::_96MHz,
117
            esp32p4 => Self::_400MHz,
118
            esp32s31 => Self::_320MHz,
119
            _ => Self::_240MHz,
120
        }
121
    }
122
}
123

            
124
/// RTC Clocks.
125
#[instability::unstable]
126
pub struct RtcClock;
127

            
128
#[cfg(soc_has_clock_node_timg_calibration_clock)]
129
use crate::soc::clocks::TimgCalibrationClockConfig;
130

            
131
/// RTC Watchdog Timer driver.
132
impl RtcClock {
133
    pub(crate) const CAL_FRACT: u32 = 19;
134

            
135
    /// Returns the nominal value of the RTC_SLOW_CLK source.
136
    #[instability::unstable]
137
    #[cfg(any(soc_has_clock_node_lp_slow_clk, soc_has_clock_node_rtc_slow_clk))]
138
    pub fn slow_freq() -> Rate {
139
        let freq = cfg_select! {
140
            soc_has_clock_node_rtc_slow_clk => clocks::rtc_slow_clk_frequency(),
141
            _ => clocks::lp_slow_clk_frequency(),
142
        };
143

            
144
        Rate::from_hz(freq)
145
    }
146

            
147
    /// Measures the frequency of one of the TIMG0 calibration clocks,
148
    /// using XTAL_CLK as the reference clock.
149
    ///
150
    /// Times out and returns 0 if the time for the given number of cycles to be
151
    /// counted exceeds the expected time twice. This may happen if 32k XTAL is
152
    /// being calibrated, but the oscillator has not started up (due to incorrect
153
    /// loading capacitance, board design issue, or lack of 32 XTAL on board).
154
    #[cfg(soc_has_clock_node_timg_calibration_clock)]
155
    pub(crate) fn calibrate(cal_clk: TimgCalibrationClockConfig, slowclk_cycles: u32) -> u32 {
156
        #[cfg(use_xtal32k)]
157
        if cal_clk == TimgCalibrationClockConfig::Xtal32kClk {
158
            debug!("Assuming Xtal32k has precisely 32.768kHz instead of calibrating");
159
            let freq_hz: u64 = 32_768;
160
            let period_64 = (1_000_000u64 << RtcClock::CAL_FRACT) / freq_hz;
161
            return period_64 as u32;
162
        }
163

            
164
        ClockTree::with(|clocks| {
165
            let xtal_freq = Rate::from_hz(clocks::xtal_clk_frequency());
166

            
167
325
            let (xtal_cycles, _) = RtcClock::measure_rtc_clock(
168
                clocks,
169
                cal_clk,
170
                #[cfg(soc_has_clock_node_timg_function_clock)]
171
                TimgFunctionClockConfig::XtalClk,
172
                slowclk_cycles,
173
            );
174

            
175
325
            if xtal_cycles == 0 {
176
                warn!("{:?} calibration failed", cal_clk);
177
            } else {
178
                debug!("Counted {} XTAL cycles", xtal_cycles);
179

            
180
                debug!(
181
                    "{:?} frequency: {}",
182
                    cal_clk,
183
                    (xtal_freq / xtal_cycles) * slowclk_cycles
184
                );
185
            }
186

            
187
325
            let divider = xtal_freq.as_mhz() as u64 * slowclk_cycles as u64;
188

            
189
            let period_64 =
190
325
                (((xtal_cycles as u64) << RtcClock::CAL_FRACT) + divider / 2u64 - 1u64) / divider;
191

            
192
            (period_64 & u32::MAX as u64) as u32
193
        })
194
    }
195
}
196

            
197
pub(crate) fn init(cpu_clock_config: ClockConfig) {
198
    ClockTree::with(|clocks| {
199
        crate::rtc_cntl::rtc::init(&cpu_clock_config);
200

            
201
        cpu_clock_config.configure(clocks);
202
        #[cfg(esp32s31)]
203
        crate::rtc_cntl::rtc::configure_wifi_lp_clock(&cpu_clock_config);
204

            
205
        // FIXME: MCPWM clock configuration needs to know about the active clock source
206
        // frequency. In the future, we should turn the MCPWM config structs into
207
        // plain old data structures and remove this pre-configuration, otherwise we will not be
208
        // able to select a different clock source.
209
        #[cfg(soc_clock_node_mcpwm_function_clock_is_configurable)]
210
        {
211
            clocks::McpwmInstance::Mcpwm0.configure_function_clock(clocks, Default::default());
212
            #[cfg(soc_has_mcpwm1)]
213
            clocks::McpwmInstance::Mcpwm1.configure_function_clock(clocks, Default::default());
214
        }
215
        // Until we have every clock consumer modelled, we should manually keep clocks alive
216
        #[cfg(soc_has_clock_node_rc_fast_clk)]
217
        clocks::request_rc_fast_clk(clocks);
218
        #[cfg(soc_has_clock_node_rc_slow_clk)]
219
        clocks::request_rc_slow_clk(clocks);
220
        #[cfg(soc_has_clock_node_pll_clk)]
221
        clocks::request_pll_clk(clocks);
222
        #[cfg(soc_has_clock_node_pll_f96m_clk)]
223
        clocks::request_pll_f96m_clk(clocks);
224
        #[cfg(soc_has_clock_node_pll_f120m)]
225
        clocks::request_pll_f120m(clocks);
226
        #[cfg(soc_has_clock_node_pll_f160m)]
227
        clocks::request_pll_f160m(clocks);
228
        #[cfg(soc_has_clock_node_pll_f240m)]
229
        clocks::request_pll_f240m(clocks);
230
        #[cfg(soc_has_clock_node_rc_fast_div_clk)]
231
        clocks::request_rc_fast_div_clk(clocks);
232
        #[cfg(soc_has_clock_node_rtc_slow_clk)]
233
325
        clocks::request_rtc_slow_clk(clocks);
234
    });
235

            
236
    calibrate_rtc_slow_clock();
237
    calibrate_rtc_fast_clock();
238
}
239

            
240
impl RtcClock {
241
    /// Counts clock cycles of a high-frequency clock for a period of time measured
242
    /// by a low-frequency clock. Calibrates two clocks to each other, e.g. to
243
    /// determine a rough value of the XTAL clock, or to determine the current
244
    /// frequency of a low-precision RC oscillator.
245
    #[cfg(soc_has_clock_node_timg_calibration_clock)]
246
650
    pub(crate) fn measure_rtc_clock(
247
        clocks: &mut ClockTree,
248
        rtc_clock: TimgCalibrationClockConfig,
249
        // TODO: verify function clock is used, C6 TRM suggests fixed XTAL_CLK
250
        #[cfg(soc_has_clock_node_timg_function_clock)] function_clock: TimgFunctionClockConfig,
251
        slow_cycles: u32,
252
    ) -> (u32, Rate) {
253
        // There may already be another calibration process running when we call this function,
254
        // so we should wait until the previous process is finished.
255
        #[cfg(not(esp32))]
256
650
        if TIMG0::regs()
257
            .rtccalicfg()
258
            .read()
259
            .rtc_cali_start_cycling()
260
            .bit()
261
        {
262
            // Set a small timeout threshold to speed up timeout occurrence.
263
            // The internal circuit will be reset when the timeout occurs and will not affect
264
            // the next calibration.
265
            TIMG0::regs()
266
                .rtccalicfg2()
267
                .modify(|_, w| unsafe { w.rtc_cali_timeout_thres().bits(1) });
268

            
269
            loop {
270
                if TIMG0::regs()
271
                    .rtccalicfg()
272
                    .read()
273
                    .rtc_cali_rdy()
274
                    .bit_is_set()
275
                    || TIMG0::regs()
276
                        .rtccalicfg2()
277
                        .read()
278
                        .rtc_cali_timeout()
279
                        .bit_is_set()
280
                {
281
                    break;
282
                }
283
            }
284
        }
285
        TIMG0::regs()
286
            .rtccalicfg()
287
            .modify(|_, w| w.rtc_cali_start_cycling().clear_bit());
288

            
289
        use esp_rom_sys::rom::ets_delay_us;
290

            
291
        #[cfg(timergroup_rc_fast_calibration_divider)]
292
        let calibration_divider = if rtc_clock == TimgCalibrationClockConfig::RcFastDivClk
293
            && crate::soc::chip_revision_above(ChipRevision::from_combined(property!(
294
                "timergroup.rc_fast_calibration_divider_min_rev"
295
            ))) {
296
            property!("timergroup.rc_fast_calibration_divider")
297
        } else {
298
            1
299
        };
300
        #[cfg(not(timergroup_rc_fast_calibration_divider))]
301
        let calibration_divider = 1;
302

            
303
        #[cfg(timergroup_rc_fast_calibration_tick_enable)]
304
        let use_rc_fast_calibration_divider = rtc_clock == TimgCalibrationClockConfig::RcFastDivClk
305
            && crate::soc::chip_revision_above(ChipRevision::from_combined(property!(
306
                "timergroup.rc_fast_calibration_divider_min_rev"
307
            )));
308

            
309
        // On some revisions calibration uses a divided RC_FAST tick.
310
        let calibration_cycles = (slow_cycles / calibration_divider).max(1);
311

            
312
        // By default the TIMG0 bus clock is running. Do not create a peripheral guard as dropping
313
        // it would reset the timer, and it would enable its WDT.
314

            
315
        // Make sure the process doesn't time out due to some spooky configuration.
316
        #[cfg(not(esp32))]
317
        TIMG0::regs().rtccalicfg2().reset();
318

            
319
        TIMG0::regs()
320
            .rtccalicfg()
321
            .modify(|_, w| w.rtc_cali_start().clear_bit());
322

            
323
        // Make sure we measure the crystal.
324
        cfg_select! {
325
            soc_has_clock_node_timg_function_clock => {
326
                let current_function_clock =
327
                    clocks::TimgInstance::Timg0.function_clock_config(clocks);
328
                clocks::TimgInstance::Timg0.configure_function_clock(clocks, function_clock);
329
650
                clocks::TimgInstance::Timg0.request_function_clock(clocks);
330
            }
331
            _ => {}
332
        }
333

            
334
        let current_calib_clock = clocks::timg_calibration_clock_config(clocks);
335
650
        clocks::configure_timg_calibration_clock(clocks, rtc_clock);
336
650
        clocks::request_timg_calibration_clock(clocks);
337

            
338
        // Align with IDF ECO2+ RC_FAST calibration flow.
339
        #[cfg(timergroup_rc_fast_calibration_tick_enable)]
340
        if use_rc_fast_calibration_divider {
341
            PCR::regs()
342
                .ctrl_tick_conf()
343
                .modify(|_, w| w.tick_enable().set_bit());
344
        }
345

            
346
        let calibration_clock_frequency = clocks::timg_calibration_clock_frequency();
347

            
348
        let effective_calibration_clock_frequency =
349
            calibration_clock_frequency / calibration_divider;
350

            
351
        // Set up timeout based on the calibration clock frequency. This is counted in XTAL_CLK
352
        // cycles.
353
        #[cfg(not(esp32))]
354
        {
355
            let function_clk_freq = clocks::TimgInstance::Timg0.function_clock_frequency() as u64;
356
650
            let expected_function_clock_cycles = (function_clk_freq * slow_cycles as u64
357
                / effective_calibration_clock_frequency as u64)
358
                as u32;
359

            
360
            TIMG0::regs().rtccalicfg2().modify(|_, w| unsafe {
361
                let writer = w.rtc_cali_timeout_thres();
362
                let mask = (1 << writer.width()) - 1;
363
650
                writer.bits((expected_function_clock_cycles * 2).min(mask));
364
                w
365
            });
366
        }
367

            
368
        TIMG0::regs().rtccalicfg().modify(|_, w| unsafe {
369
            w.rtc_cali_max().bits(calibration_cycles as u16);
370
            w.rtc_cali_start_cycling().clear_bit();
371
            w.rtc_cali_start().set_bit()
372
        });
373

            
374
        // Delay, otherwise the CPU may read back the previous state of the completion flag and skip
375
        // waiting.
376
650
        let us_time_estimate = slow_cycles * 1_000_000 / effective_calibration_clock_frequency;
377
        ets_delay_us(us_time_estimate);
378

            
379
        #[cfg(esp32)]
380
        let mut timeout_us = us_time_estimate;
381

            
382
        // Wait for the calibration to finish
383
        let cali_value = loop {
384
650
            if TIMG0::regs()
385
                .rtccalicfg()
386
                .read()
387
                .rtc_cali_rdy()
388
                .bit_is_set()
389
            {
390
                break TIMG0::regs().rtccalicfg1().read().rtc_cali_value().bits();
391
            }
392

            
393
            #[cfg(not(esp32))]
394
            if TIMG0::regs()
395
                .rtccalicfg2()
396
                .read()
397
                .rtc_cali_timeout()
398
                .bit_is_set()
399
            {
400
                // Timed out waiting for calibration
401
                break 0;
402
            }
403

            
404
            #[cfg(esp32)]
405
            if timeout_us > 0 {
406
                timeout_us -= 1;
407
                ets_delay_us(1);
408
            } else {
409
                // Timed out waiting for calibration
410
                break 0;
411
            }
412
        };
413

            
414
        #[cfg(esp32h4)]
415
        let cali_value = if rtc_clock == TimgCalibrationClockConfig::RcSlowClk {
416
            cali_value * property!("timergroup.rc_slow_calibration_multiplier")
417
        } else {
418
            cali_value
419
        };
420

            
421
        TIMG0::regs()
422
            .rtccalicfg()
423
            .modify(|_, w| w.rtc_cali_start().clear_bit());
424

            
425
        // Align with IDF ECO2+ RC_FAST calibration flow.
426
        #[cfg(timergroup_rc_fast_calibration_tick_enable)]
427
        if use_rc_fast_calibration_divider {
428
            PCR::regs()
429
                .ctrl_tick_conf()
430
                .modify(|_, w| w.tick_enable().clear_bit());
431
        }
432

            
433
650
        if let Some(calib_clock) = current_calib_clock
434
            && calib_clock != rtc_clock
435
        {
436
325
            clocks::configure_timg_calibration_clock(clocks, calib_clock);
437
        }
438
325
        clocks::release_timg_calibration_clock(clocks);
439

            
440
        #[cfg(soc_has_clock_node_timg_function_clock)]
441
        {
442
325
            if let Some(func_clock) = current_function_clock
443
                && func_clock != function_clock
444
            {
445
                clocks::TimgInstance::Timg0.configure_function_clock(clocks, func_clock);
446
            }
447
            clocks::TimgInstance::Timg0.release_function_clock(clocks);
448
        }
449

            
450
        (cali_value, Rate::from_hz(calibration_clock_frequency))
451
650
    }
452
}
453

            
454
#[cfg(not(soc_has_clock_node_timg_calibration_clock))]
455
fn calibrate_rtc_slow_clock() {
456
    // Do nothing until TIMG_CALIBRATION_CLOCK is added to device metadata.
457
}
458

            
459
#[cfg(soc_has_clock_node_timg_calibration_clock)]
460
pub(crate) fn calibrate_rtc_slow_clock() {
461
    // Unfortunate device specific mapping.
462
    // TODO: fix it by generating cfgs for each mux input?
463
    cfg_select! {
464
        esp32s2 => {
465
            // Can directly measure output of the RTC_SLOW mux
466
            let slow_clk = TimgCalibrationClockConfig::RtcClk;
467
            let rc_slow_selected =
468
                unwrap!(ClockTree::with(clocks::rtc_slow_clk_config)) == RtcSlowClkConfig::RcSlow;
469
        }
470
        soc_has_clock_node_rtc_slow_clk => {
471
            let slow_clk_config = unwrap!(ClockTree::with(clocks::rtc_slow_clk_config));
472
            let rc_slow_selected = slow_clk_config == RtcSlowClkConfig::RcSlow;
473
            let slow_clk = match slow_clk_config {
474
                RtcSlowClkConfig::RcFast => TimgCalibrationClockConfig::RcFastDivClk,
475
                RtcSlowClkConfig::RcSlow => TimgCalibrationClockConfig::RcSlowClk,
476
                #[cfg(use_xtal32k)]
477
                RtcSlowClkConfig::Xtal32k => TimgCalibrationClockConfig::Xtal32kClk,
478
                #[cfg(esp32c2)]
479
                RtcSlowClkConfig::OscSlow => TimgCalibrationClockConfig::Osc32kClk,
480
            };
481
        }
482
        soc_has_clock_node_lp_slow_clk => {
483
            let slow_clk_config = unwrap!(ClockTree::with(clocks::lp_slow_clk_config));
484
            let rc_slow_selected = slow_clk_config == LpSlowClkConfig::RcSlow;
485
            let slow_clk = match slow_clk_config {
486
                // on S31, clock can not be calibrated to get OSC_SLOW actual frequency
487
                #[cfg(all(not(esp32s31), use_xtal32k))]
488
                LpSlowClkConfig::OscSlow => TimgCalibrationClockConfig::Xtal32kClk, //?
489
                #[cfg(all(not(esp32s31), not(use_xtal32k)))]
490
                LpSlowClkConfig::OscSlow => TimgCalibrationClockConfig::RcSlowClk,
491
                #[cfg(use_xtal32k)]
492
                LpSlowClkConfig::Xtal32k => TimgCalibrationClockConfig::Xtal32kClk,
493
                LpSlowClkConfig::RcSlow => TimgCalibrationClockConfig::RcSlowClk,
494
            };
495
        }
496
        _ => {}
497
    }
498

            
499
    // Clock is in order of 30-150kHz.
500
    const SLOW_CLK_SRC_CAL_CYCLES: u32 = 16;
501
    let cal_val = RtcClock::calibrate(slow_clk, SLOW_CLK_SRC_CAL_CYCLES);
502

            
503
325
    if cal_val == 0 {
504
        panic!("{:?} calibration failed.", slow_clk);
505
    }
506

            
507
    let reg = cfg_select! {
508
        esp32s31 => LP_AON::regs().lp_store(1),
509
        esp32p4 => LP_AON::regs().lp_store1(),
510
        _ => LP_AON::regs().store1(),
511
    };
512

            
513
    reg.write(|w| unsafe { w.bits(cal_val) });
514

            
515
325
    if rc_slow_selected {
516
325
        let frequency = ((1_000_000u64 << RtcClock::CAL_FRACT) / cal_val as u64) as u32;
517

            
518
        // On some chips, the calibrated clock is RC_SLOW_CLK divided down.
519
325
        let divider = clocks::rc_slow_clk_frequency()
520
325
            / clocks::timg_calibration_clock_source_frequency(slow_clk);
521

            
522
325
        ClockTree::with(|clocks| clocks::set_rc_slow_clk_frequency(clocks, frequency * divider));
523
    }
524
}
525

            
526
#[cfg(soc_has_clock_node_timg_calibration_clock)]
527
pub(crate) fn calibrate_rtc_fast_clock() {
528
    // Clock is in order of 10 MHz
529
    const FAST_CLK_SRC_CAL_CYCLES: u32 = 128;
530

            
531
    ClockTree::with(|clocks| {
532
325
        let (xtal_cycles, calibration_clock_frequency) = RtcClock::measure_rtc_clock(
533
            clocks,
534
            TimgCalibrationClockConfig::RcFastDivClk,
535
            #[cfg(soc_has_clock_node_timg_function_clock)]
536
            TimgFunctionClockConfig::XtalClk,
537
            FAST_CLK_SRC_CAL_CYCLES,
538
        );
539

            
540
325
        if xtal_cycles == 0 {
541
            warn!("RC_FAST_CLK calibration failed");
542
            return;
543
        }
544

            
545
        // On some chips, the calibration input is RC_FAST_CLK divided by 256.
546
325
        let divider = clocks::rc_fast_clk_frequency() / calibration_clock_frequency.as_hz();
547
        let frequency =
548
325
            (clocks::xtal_clk_frequency() as u64 * FAST_CLK_SRC_CAL_CYCLES as u64 * divider as u64
549
                / xtal_cycles as u64) as u32;
550

            
551
325
        clocks::set_rc_fast_clk_frequency(clocks, frequency);
552
    });
553
}
554

            
555
#[cfg(not(soc_has_clock_node_timg_calibration_clock))]
556
fn calibrate_rtc_fast_clock() {
557
    // Do nothing until TIMG_CALIBRATION_CLOCK is added to device metadata.
558
}
559

            
560
/// The CPU clock frequency.
561
9
pub fn cpu_clock() -> Rate {
562
    Rate::from_hz(ll::cpu_clk_frequency())
563
9
}
564

            
565
/// The XTAL clock frequency.
566
pub fn xtal_clock() -> Rate {
567
    Rate::from_hz(ll::xtal_clk_frequency())
568
}
569

            
570
/// Reads the calibrated RTC slow clock period from the STORE1 register.
571
///
572
/// The period is in unit of microseconds, represented as a fixed-point number
573
/// with `RtcClock::CAL_FRACT` fractional bits.
574
///
575
/// Written by [`calibrate_rtc_slow_clock`] during clock initialization.
576
pub(crate) fn rtc_slow_cal_period() -> u32 {
577
    let reg = cfg_select! {
578
        esp32s31 => LP_AON::regs().lp_store(1),
579
        esp32p4 => LP_AON::regs().lp_store1(),
580
        _ => LP_AON::regs().store1(),
581
    };
582

            
583
    reg.read().bits()
584
}
585

            
586
/// Converts RTC slow clock ticks to microseconds using the calibrated period.
587
#[cfg(lp_timer_driver_supported)]
588
pub(crate) fn rtc_ticks_to_us(ticks: u64) -> u64 {
589
    let period = rtc_slow_cal_period() as u64;
590

            
591
    // The LP timer is a 48-bit counter running from RTC_SLOW_CLK.
592
    // `period` is a fixed point number with 19 fractional bits, it may be a 24-bit value if
593
    // RTC_SLOW_CLK is as low as 32768 Hz. Just multiplying the two may cause an overflow on 64
594
    // bits. We use a calculation that prevents overflow unconditionally because the counter reaches
595
    // 2^19 pretty quickly. We could use a larger mask (up to 40 bits), but that would make the
596
    // calculation slower and more complex for perhaps too little benefit.
597

            
598
    const MASK: u64 = (1 << RtcClock::CAL_FRACT) - 1;
599
2
    let upper = (ticks & !MASK) >> RtcClock::CAL_FRACT;
600
2
    let lower = ticks & MASK;
601

            
602
2
    upper * period + ((lower * period) >> RtcClock::CAL_FRACT)
603
}
604

            
605
/// Converts microseconds to RTC slow clock ticks using the calibrated period.
606
pub(crate) fn us_to_rtc_ticks(time_in_us: u64) -> u64 {
607
    let period = rtc_slow_cal_period() as u64;
608

            
609
1
    if time_in_us > (u64::MAX >> RtcClock::CAL_FRACT) {
610
        ((time_in_us / period) << RtcClock::CAL_FRACT)
611
            + ((time_in_us % period) << RtcClock::CAL_FRACT) / period
612
    } else {
613
1
        (time_in_us << RtcClock::CAL_FRACT) / period
614
    }
615
}