esp_hal/
system.rs

1//! # System Control
2
3use esp_sync::NonReentrantMutex;
4
5use crate::peripherals::SYSTEM;
6
7/// Peripherals which can be enabled via `PeripheralClockControl`.
8///
9/// This enum represents various hardware peripherals that can be enabled
10/// by the system's clock control. Depending on the target device, different
11/// peripherals will be available for enabling.
12// FIXME: This enum needs to be public because it's exposed via a bunch of traits, but it's not
13// useful to users.
14#[doc(hidden)]
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16#[repr(u8)]
17#[cfg_attr(feature = "defmt", derive(defmt::Format))]
18pub enum Peripheral {
19    /// SPI2 peripheral.
20    #[cfg(soc_has_spi2)]
21    Spi2,
22    /// SPI3 peripheral.
23    #[cfg(soc_has_spi3)]
24    Spi3,
25    /// External I2C0 peripheral.
26    #[cfg(soc_has_i2c0)]
27    I2cExt0,
28    /// External I2C1 peripheral.
29    #[cfg(soc_has_i2c1)]
30    I2cExt1,
31    /// RMT peripheral (Remote Control).
32    #[cfg(soc_has_rmt)]
33    Rmt,
34    /// LEDC peripheral (LED PWM Controller).
35    #[cfg(soc_has_ledc)]
36    Ledc,
37    /// MCPWM0 peripheral (Motor Control PWM 0).
38    #[cfg(soc_has_mcpwm0)]
39    Mcpwm0,
40    /// MCPWM1 peripheral (Motor Control PWM 1).
41    #[cfg(soc_has_mcpwm1)]
42    Mcpwm1,
43    /// PCNT peripheral (Pulse Counter).
44    #[cfg(soc_has_pcnt)]
45    Pcnt,
46    /// APB SAR ADC peripheral.
47    #[cfg(soc_has_apb_saradc)]
48    ApbSarAdc,
49    /// General DMA (GDMA) peripheral.
50    #[cfg(gdma)]
51    Gdma,
52    /// Peripheral DMA (PDMA) peripheral.
53    #[cfg(pdma)]
54    Dma,
55    /// I2S0 peripheral (Inter-IC Sound).
56    #[cfg(soc_has_i2s0)]
57    I2s0,
58    /// I2S1 peripheral (Inter-IC Sound).
59    #[cfg(soc_has_i2s1)]
60    I2s1,
61    /// USB0 peripheral.
62    #[cfg(soc_has_usb0)]
63    Usb,
64    /// AES peripheral (Advanced Encryption Standard).
65    #[cfg(soc_has_aes)]
66    Aes,
67    /// TWAI0 peripheral.
68    #[cfg(soc_has_twai0)]
69    Twai0,
70    /// TWAI1 peripheral.
71    #[cfg(soc_has_twai1)]
72    Twai1,
73    /// Timer Group 0 peripheral.
74    #[cfg(soc_has_timg0)]
75    Timg0,
76    /// Timer Group 1 peripheral.
77    #[cfg(soc_has_timg1)]
78    Timg1,
79    /// SHA peripheral (Secure Hash Algorithm).
80    #[cfg(soc_has_sha)]
81    Sha,
82    /// USB Device peripheral.
83    #[cfg(soc_has_usb_device)]
84    UsbDevice,
85    /// UART0 peripheral.
86    #[cfg(soc_has_uart0)]
87    Uart0,
88    /// UART1 peripheral.
89    #[cfg(soc_has_uart1)]
90    Uart1,
91    /// UART2 peripheral.
92    #[cfg(soc_has_uart2)]
93    Uart2,
94    /// RSA peripheral (Rivest-Shamir-Adleman encryption).
95    #[cfg(soc_has_rsa)]
96    Rsa,
97    /// Parallel IO peripheral.
98    #[cfg(soc_has_parl_io)]
99    ParlIo,
100    /// HMAC peripheral (Hash-based Message Authentication Code).
101    #[cfg(soc_has_hmac)]
102    Hmac,
103    /// ECC peripheral (Elliptic Curve Cryptography).
104    #[cfg(soc_has_ecc)]
105    Ecc,
106    /// SOC ETM peripheral (Event Task Manager).
107    #[cfg(soc_has_etm)]
108    Etm,
109    /// TRACE0 peripheral (Debug trace).
110    #[cfg(soc_has_trace0)]
111    Trace0,
112    /// LCD Camera peripheral.
113    #[cfg(soc_has_lcd_cam)]
114    LcdCam,
115    /// Systimer peripheral.
116    #[cfg(soc_has_systimer)]
117    Systimer,
118    /// Temperature sensor peripheral.
119    #[cfg(soc_has_tsens)]
120    Tsens,
121    /// UHCI0
122    #[cfg(soc_has_uhci0)]
123    Uhci0,
124}
125
126impl Peripheral {
127    const KEEP_ENABLED: &[Peripheral] = &[
128        Peripheral::Uart0,
129        #[cfg(soc_has_usb_device)]
130        Peripheral::UsbDevice,
131        #[cfg(soc_has_systimer)]
132        Peripheral::Systimer,
133        #[cfg(soc_has_timg0)]
134        Peripheral::Timg0,
135        #[cfg(esp32c6)] // used by some wifi calibration steps.
136        // TODO: We should probably automatically enable this when needed.
137        Peripheral::ApbSarAdc,
138    ];
139
140    const COUNT: usize = Self::ALL.len();
141
142    const ALL: &[Self] = &[
143        #[cfg(soc_has_spi2)]
144        Self::Spi2,
145        #[cfg(soc_has_spi3)]
146        Self::Spi3,
147        #[cfg(soc_has_i2c0)]
148        Self::I2cExt0,
149        #[cfg(soc_has_i2c1)]
150        Self::I2cExt1,
151        #[cfg(soc_has_rmt)]
152        Self::Rmt,
153        #[cfg(soc_has_ledc)]
154        Self::Ledc,
155        #[cfg(soc_has_mcpwm0)]
156        Self::Mcpwm0,
157        #[cfg(soc_has_mcpwm1)]
158        Self::Mcpwm1,
159        #[cfg(soc_has_pcnt)]
160        Self::Pcnt,
161        #[cfg(soc_has_apb_saradc)]
162        Self::ApbSarAdc,
163        #[cfg(gdma)]
164        Self::Gdma,
165        #[cfg(pdma)]
166        Self::Dma,
167        #[cfg(soc_has_i2s0)]
168        Self::I2s0,
169        #[cfg(soc_has_i2s1)]
170        Self::I2s1,
171        #[cfg(soc_has_usb0)]
172        Self::Usb,
173        #[cfg(soc_has_aes)]
174        Self::Aes,
175        #[cfg(soc_has_twai0)]
176        Self::Twai0,
177        #[cfg(soc_has_twai1)]
178        Self::Twai1,
179        #[cfg(soc_has_timg0)]
180        Self::Timg0,
181        #[cfg(soc_has_timg1)]
182        Self::Timg1,
183        #[cfg(soc_has_sha)]
184        Self::Sha,
185        #[cfg(soc_has_usb_device)]
186        Self::UsbDevice,
187        #[cfg(soc_has_uart0)]
188        Self::Uart0,
189        #[cfg(soc_has_uart1)]
190        Self::Uart1,
191        #[cfg(soc_has_uart2)]
192        Self::Uart2,
193        #[cfg(soc_has_rsa)]
194        Self::Rsa,
195        #[cfg(soc_has_parl_io)]
196        Self::ParlIo,
197        #[cfg(soc_has_hmac)]
198        Self::Hmac,
199        #[cfg(soc_has_ecc)]
200        Self::Ecc,
201        #[cfg(soc_has_etm)]
202        Self::Etm,
203        #[cfg(soc_has_trace0)]
204        Self::Trace0,
205        #[cfg(soc_has_lcd_cam)]
206        Self::LcdCam,
207        #[cfg(soc_has_systimer)]
208        Self::Systimer,
209        #[cfg(soc_has_tsens)]
210        Self::Tsens,
211        #[cfg(soc_has_uhci0)]
212        Self::Uhci0,
213    ];
214}
215
216impl Peripheral {
217    pub fn try_from(value: u8) -> Option<Peripheral> {
218        if value >= Peripheral::COUNT as u8 {
219            return None;
220        }
221
222        Some(unsafe { core::mem::transmute::<u8, Peripheral>(value) })
223    }
224}
225
226struct RefCounts {
227    counts: [usize; Peripheral::COUNT],
228}
229
230impl RefCounts {
231    pub const fn new() -> Self {
232        Self {
233            counts: [0; Peripheral::COUNT],
234        }
235    }
236}
237
238static PERIPHERAL_REF_COUNT: NonReentrantMutex<RefCounts> =
239    NonReentrantMutex::new(RefCounts::new());
240
241/// Disable all peripherals.
242///
243/// Peripherals listed in [KEEP_ENABLED] are NOT disabled.
244#[cfg_attr(not(feature = "rt"), expect(dead_code))]
245pub(crate) fn disable_peripherals() {
246    // Take the critical section up front to avoid taking it multiple times.
247    PERIPHERAL_REF_COUNT.with(|refcounts| {
248        for p in Peripheral::ALL {
249            if Peripheral::KEEP_ENABLED.contains(p) {
250                continue;
251            }
252            PeripheralClockControl::enable_forced_with_counts(*p, false, true, refcounts);
253        }
254    })
255}
256
257#[derive(Debug, PartialEq, Eq)]
258#[cfg_attr(feature = "defmt", derive(defmt::Format))]
259pub(crate) struct PeripheralGuard {
260    peripheral: Peripheral,
261}
262
263impl PeripheralGuard {
264    pub(crate) fn new_with(p: Peripheral, init: fn()) -> Self {
265        if !Peripheral::KEEP_ENABLED.contains(&p) && PeripheralClockControl::enable(p) {
266            PeripheralClockControl::reset(p);
267            init();
268        }
269
270        Self { peripheral: p }
271    }
272
273    pub(crate) fn new(p: Peripheral) -> Self {
274        Self::new_with(p, || {})
275    }
276}
277
278impl Drop for PeripheralGuard {
279    fn drop(&mut self) {
280        if !Peripheral::KEEP_ENABLED.contains(&self.peripheral) {
281            PeripheralClockControl::disable(self.peripheral);
282        }
283    }
284}
285
286#[derive(Debug)]
287#[cfg_attr(feature = "defmt", derive(defmt::Format))]
288pub(crate) struct GenericPeripheralGuard<const P: u8> {}
289
290impl<const P: u8> GenericPeripheralGuard<P> {
291    pub(crate) fn new_with(init: fn()) -> Self {
292        let peripheral = unwrap!(Peripheral::try_from(P));
293        if !Peripheral::KEEP_ENABLED.contains(&peripheral) {
294            PERIPHERAL_REF_COUNT.with(|ref_counts| {
295                if PeripheralClockControl::enable_with_counts(peripheral, ref_counts) {
296                    unsafe { PeripheralClockControl::reset_racey(peripheral) };
297                    init();
298                }
299            });
300        }
301
302        Self {}
303    }
304
305    pub(crate) fn new() -> Self {
306        Self::new_with(|| {})
307    }
308}
309
310impl<const P: u8> Clone for GenericPeripheralGuard<P> {
311    fn clone(&self) -> Self {
312        Self::new()
313    }
314
315    fn clone_from(&mut self, _source: &Self) {
316        // This is a no-op since the ref count for P remains the same.
317    }
318}
319
320impl<const P: u8> Drop for GenericPeripheralGuard<P> {
321    fn drop(&mut self) {
322        let peripheral = unwrap!(Peripheral::try_from(P));
323        if !Peripheral::KEEP_ENABLED.contains(&peripheral) {
324            PeripheralClockControl::disable(peripheral);
325        }
326    }
327}
328
329/// Controls the enablement of peripheral clocks.
330pub(crate) struct PeripheralClockControl;
331
332#[cfg(not(any(esp32c6, esp32h2)))]
333impl PeripheralClockControl {
334    unsafe fn enable_internal_racey(peripheral: Peripheral, enable: bool) {
335        debug!("Enable {:?} {}", peripheral, enable);
336
337        let system = SYSTEM::regs();
338
339        #[cfg(esp32)]
340        let (perip_clk_en0, perip_clk_en1) = { (&system.perip_clk_en(), &system.peri_clk_en()) };
341        #[cfg(not(esp32))]
342        let perip_clk_en0 = &system.perip_clk_en0();
343
344        #[cfg(any(esp32c2, esp32c3, esp32s2, esp32s3))]
345        let perip_clk_en1 = &system.perip_clk_en1();
346
347        match peripheral {
348            #[cfg(soc_has_spi2)]
349            Peripheral::Spi2 => {
350                perip_clk_en0.modify(|_, w| w.spi2_clk_en().bit(enable));
351            }
352            #[cfg(soc_has_spi3)]
353            Peripheral::Spi3 => {
354                perip_clk_en0.modify(|_, w| w.spi3_clk_en().bit(enable));
355            }
356            #[cfg(soc_has_i2c0)]
357            Peripheral::I2cExt0 => {
358                perip_clk_en0.modify(|_, w| w.i2c_ext0_clk_en().bit(enable));
359            }
360            #[cfg(soc_has_i2c1)]
361            Peripheral::I2cExt1 => {
362                perip_clk_en0.modify(|_, w| w.i2c_ext1_clk_en().bit(enable));
363            }
364            #[cfg(soc_has_rmt)]
365            Peripheral::Rmt => {
366                perip_clk_en0.modify(|_, w| w.rmt_clk_en().bit(enable));
367            }
368            #[cfg(soc_has_ledc)]
369            Peripheral::Ledc => {
370                perip_clk_en0.modify(|_, w| w.ledc_clk_en().bit(enable));
371            }
372            #[cfg(soc_has_mcpwm0)]
373            Peripheral::Mcpwm0 => {
374                perip_clk_en0.modify(|_, w| w.pwm0_clk_en().bit(enable));
375            }
376            #[cfg(soc_has_mcpwm1)]
377            Peripheral::Mcpwm1 => {
378                perip_clk_en0.modify(|_, w| w.pwm1_clk_en().bit(enable));
379            }
380            #[cfg(soc_has_pcnt)]
381            Peripheral::Pcnt => {
382                perip_clk_en0.modify(|_, w| w.pcnt_clk_en().bit(enable));
383            }
384            #[cfg(soc_has_apb_saradc)]
385            Peripheral::ApbSarAdc => {
386                perip_clk_en0.modify(|_, w| w.apb_saradc_clk_en().bit(enable));
387            }
388            #[cfg(gdma)]
389            Peripheral::Gdma => {
390                perip_clk_en1.modify(|_, w| w.dma_clk_en().bit(enable));
391            }
392            #[cfg(esp32)]
393            Peripheral::Dma => {
394                perip_clk_en0.modify(|_, w| w.spi_dma_clk_en().bit(enable));
395            }
396            #[cfg(esp32s2)]
397            Peripheral::Dma => {
398                perip_clk_en0.modify(|_, w| w.spi2_dma_clk_en().bit(enable));
399                perip_clk_en0.modify(|_, w| w.spi3_dma_clk_en().bit(enable));
400                perip_clk_en1.modify(|_, w| w.crypto_dma_clk_en().bit(enable));
401            }
402            #[cfg(soc_has_i2s0)]
403            Peripheral::I2s0 => {
404                perip_clk_en0.modify(|_, w| w.i2s0_clk_en().bit(enable));
405            }
406            #[cfg(soc_has_i2s1)]
407            Peripheral::I2s1 => {
408                perip_clk_en0.modify(|_, w| w.i2s1_clk_en().bit(enable));
409            }
410            #[cfg(soc_has_usb0)]
411            Peripheral::Usb => {
412                perip_clk_en0.modify(|_, w| w.usb_clk_en().bit(enable));
413            }
414            #[cfg(soc_has_twai0)]
415            Peripheral::Twai0 => {
416                perip_clk_en0.modify(|_, w| w.twai_clk_en().bit(enable));
417            }
418            #[cfg(soc_has_aes)]
419            Peripheral::Aes => {
420                perip_clk_en1.modify(|_, w| w.crypto_aes_clk_en().bit(enable));
421            }
422            #[cfg(soc_has_timg0)]
423            Peripheral::Timg0 => {
424                #[cfg(any(esp32c3, esp32s2, esp32s3))]
425                perip_clk_en0.modify(|_, w| w.timers_clk_en().bit(enable));
426                perip_clk_en0.modify(|_, w| w.timergroup_clk_en().bit(enable));
427            }
428            #[cfg(soc_has_timg1)]
429            Peripheral::Timg1 => {
430                #[cfg(any(esp32c3, esp32s2, esp32s3))]
431                perip_clk_en0.modify(|_, w| w.timers_clk_en().bit(enable));
432                perip_clk_en0.modify(|_, w| w.timergroup1_clk_en().bit(enable));
433            }
434            #[cfg(soc_has_sha)]
435            Peripheral::Sha => {
436                perip_clk_en1.modify(|_, w| w.crypto_sha_clk_en().bit(enable));
437            }
438            #[cfg(esp32c3)]
439            Peripheral::UsbDevice => {
440                perip_clk_en0.modify(|_, w| w.usb_device_clk_en().bit(enable));
441            }
442            #[cfg(esp32s3)]
443            Peripheral::UsbDevice => {
444                perip_clk_en1.modify(|_, w| w.usb_device_clk_en().bit(enable));
445            }
446            #[cfg(soc_has_uart0)]
447            Peripheral::Uart0 => {
448                perip_clk_en0.modify(|_, w| w.uart_clk_en().bit(enable));
449            }
450            #[cfg(soc_has_uart1)]
451            Peripheral::Uart1 => {
452                perip_clk_en0.modify(|_, w| w.uart1_clk_en().bit(enable));
453            }
454            #[cfg(all(soc_has_uart2, esp32s3))]
455            Peripheral::Uart2 => {
456                perip_clk_en1.modify(|_, w| w.uart2_clk_en().set_bit());
457            }
458            #[cfg(all(soc_has_uart2, esp32))]
459            Peripheral::Uart2 => {
460                perip_clk_en0.modify(|_, w| w.uart2_clk_en().bit(enable));
461            }
462            #[cfg(all(rsa, esp32))]
463            Peripheral::Rsa => {
464                perip_clk_en1.modify(|_, w| w.crypto_rsa_clk_en().bit(enable));
465            }
466            #[cfg(all(rsa, any(esp32c3, esp32s2, esp32s3)))]
467            Peripheral::Rsa => {
468                perip_clk_en1.modify(|_, w| w.crypto_rsa_clk_en().bit(enable));
469                system
470                    .rsa_pd_ctrl()
471                    .modify(|_, w| w.rsa_mem_pd().bit(!enable));
472            }
473            #[cfg(soc_has_hmac)]
474            Peripheral::Hmac => {
475                perip_clk_en1.modify(|_, w| w.crypto_hmac_clk_en().bit(enable));
476            }
477            #[cfg(soc_has_ecc)]
478            Peripheral::Ecc => {
479                perip_clk_en1.modify(|_, w| w.crypto_ecc_clk_en().bit(enable));
480            }
481            #[cfg(soc_has_lcd_cam)]
482            Peripheral::LcdCam => {
483                perip_clk_en1.modify(|_, w| w.lcd_cam_clk_en().bit(enable));
484            }
485            #[cfg(soc_has_systimer)]
486            Peripheral::Systimer => {
487                perip_clk_en0.modify(|_, w| w.systimer_clk_en().bit(enable));
488            }
489            #[cfg(soc_has_tsens)]
490            Peripheral::Tsens => {
491                perip_clk_en1.modify(|_, w| w.tsens_clk_en().bit(enable));
492            }
493            #[cfg(soc_has_uhci0)]
494            Peripheral::Uhci0 => {
495                perip_clk_en0.modify(|_, w| w.uhci0_clk_en().bit(enable));
496            }
497        }
498    }
499}
500
501#[cfg(any(esp32c6, esp32h2))]
502impl PeripheralClockControl {
503    unsafe fn enable_internal_racey(peripheral: Peripheral, enable: bool) {
504        debug!("Enable {:?} {}", peripheral, enable);
505        let system = SYSTEM::regs();
506
507        match peripheral {
508            #[cfg(soc_has_spi2)]
509            Peripheral::Spi2 => {
510                system
511                    .spi2_conf()
512                    .modify(|_, w| w.spi2_clk_en().bit(enable));
513            }
514            #[cfg(soc_has_i2c0)]
515            Peripheral::I2cExt0 => {
516                system
517                    .i2c0_conf()
518                    .modify(|_, w| w.i2c0_clk_en().bit(enable));
519            }
520            #[cfg(soc_has_i2c1)]
521            Peripheral::I2cExt1 => {
522                system
523                    .i2c1_conf()
524                    .modify(|_, w| w.i2c1_clk_en().bit(enable));
525            }
526            #[cfg(soc_has_rmt)]
527            Peripheral::Rmt => {
528                system.rmt_conf().modify(|_, w| w.rmt_clk_en().bit(enable));
529            }
530            #[cfg(soc_has_ledc)]
531            Peripheral::Ledc => {
532                system
533                    .ledc_conf()
534                    .modify(|_, w| w.ledc_clk_en().bit(enable));
535            }
536            #[cfg(soc_has_mcpwm0)]
537            Peripheral::Mcpwm0 => {
538                system.pwm_conf().modify(|_, w| w.pwm_clk_en().bit(enable));
539            }
540            #[cfg(soc_has_mcpwm1)]
541            Peripheral::Mcpwm1 => {
542                system.pwm_conf.modify(|_, w| w.pwm_clk_en().bit(enable));
543            }
544            #[cfg(soc_has_apb_saradc)]
545            Peripheral::ApbSarAdc => {
546                system
547                    .saradc_conf()
548                    .modify(|_, w| w.saradc_reg_clk_en().bit(enable));
549            }
550            #[cfg(gdma)]
551            Peripheral::Gdma => {
552                system
553                    .gdma_conf()
554                    .modify(|_, w| w.gdma_clk_en().bit(enable));
555            }
556            #[cfg(soc_has_i2s0)]
557            Peripheral::I2s0 => {
558                system.i2s_conf().modify(|_, w| w.i2s_clk_en().bit(enable));
559            }
560            #[cfg(soc_has_twai0)]
561            Peripheral::Twai0 => {
562                system
563                    .twai0_conf()
564                    .modify(|_, w| w.twai0_clk_en().bit(enable));
565
566                if enable {
567                    // use Xtal clk-src
568                    system.twai0_func_clk_conf().modify(|_, w| {
569                        w.twai0_func_clk_en().set_bit();
570                        w.twai0_func_clk_sel().variant(false)
571                    });
572                }
573            }
574            #[cfg(soc_has_twai1)]
575            Peripheral::Twai1 => {
576                system
577                    .twai1_conf()
578                    .modify(|_, w| w.twai1_clk_en().bit(enable));
579            }
580            #[cfg(soc_has_aes)]
581            Peripheral::Aes => {
582                system.aes_conf().modify(|_, w| w.aes_clk_en().bit(enable));
583            }
584            #[cfg(soc_has_pcnt)]
585            Peripheral::Pcnt => {
586                system
587                    .pcnt_conf()
588                    .modify(|_, w| w.pcnt_clk_en().bit(enable));
589            }
590            #[cfg(soc_has_timg0)]
591            Peripheral::Timg0 => {
592                system
593                    .timergroup0_timer_clk_conf()
594                    .modify(|_, w| w.tg0_timer_clk_en().bit(enable));
595            }
596            #[cfg(soc_has_timg1)]
597            Peripheral::Timg1 => {
598                system
599                    .timergroup1_timer_clk_conf()
600                    .modify(|_, w| w.tg1_timer_clk_en().bit(enable));
601            }
602            #[cfg(soc_has_sha)]
603            Peripheral::Sha => {
604                system.sha_conf().modify(|_, w| w.sha_clk_en().bit(enable));
605            }
606            #[cfg(soc_has_usb_device)]
607            Peripheral::UsbDevice => {
608                system
609                    .usb_device_conf()
610                    .modify(|_, w| w.usb_device_clk_en().bit(enable));
611            }
612            #[cfg(soc_has_uart0)]
613            Peripheral::Uart0 => {
614                system.uart(0).conf().modify(|_, w| w.clk_en().bit(enable));
615            }
616            #[cfg(soc_has_uart1)]
617            Peripheral::Uart1 => {
618                system.uart(1).conf().modify(|_, w| w.clk_en().bit(enable));
619            }
620            #[cfg(soc_has_rsa)]
621            Peripheral::Rsa => {
622                system.rsa_conf().modify(|_, w| w.rsa_clk_en().bit(enable));
623                system
624                    .rsa_pd_ctrl()
625                    .modify(|_, w| w.rsa_mem_pd().clear_bit());
626            }
627            #[cfg(soc_has_parl_io)]
628            Peripheral::ParlIo => {
629                system
630                    .parl_io_conf()
631                    .modify(|_, w| w.parl_clk_en().bit(enable));
632            }
633            #[cfg(soc_has_hmac)]
634            Peripheral::Hmac => {
635                system
636                    .hmac_conf()
637                    .modify(|_, w| w.hmac_clk_en().bit(enable));
638            }
639            #[cfg(soc_has_ecc)]
640            Peripheral::Ecc => {
641                system.ecc_conf().modify(|_, w| w.ecc_clk_en().bit(enable));
642            }
643            #[cfg(soc_has_etm)]
644            Peripheral::Etm => {
645                system.etm_conf().modify(|_, w| w.etm_clk_en().bit(enable));
646            }
647            #[cfg(soc_has_trace0)]
648            Peripheral::Trace0 => {
649                system
650                    .trace_conf()
651                    .modify(|_, w| w.trace_clk_en().bit(enable));
652            }
653            #[cfg(soc_has_systimer)]
654            Peripheral::Systimer => {
655                system
656                    .systimer_conf()
657                    .modify(|_, w| w.systimer_clk_en().bit(enable));
658            }
659            #[cfg(soc_has_tsens)]
660            Peripheral::Tsens => {
661                system.tsens_clk_conf().modify(|_, w| {
662                    w.tsens_clk_en().bit(enable);
663                    w.tsens_clk_sel().bit(enable)
664                });
665            }
666            #[cfg(soc_has_uhci0)]
667            Peripheral::Uhci0 => {
668                system
669                    .uhci_conf()
670                    .modify(|_, w| w.uhci_clk_en().bit(enable));
671            }
672        }
673    }
674}
675
676#[cfg(not(any(esp32c6, esp32h2)))]
677/// Resets the given peripheral
678unsafe fn assert_peri_reset_racey(peripheral: Peripheral, reset: bool) {
679    let system = SYSTEM::regs();
680
681    #[cfg(esp32)]
682    let (perip_rst_en0, perip_rst_en1) = (system.perip_rst_en(), system.peri_rst_en());
683    #[cfg(not(esp32))]
684    let perip_rst_en0 = system.perip_rst_en0();
685
686    #[cfg(any(esp32c2, esp32c3, esp32s2, esp32s3))]
687    let perip_rst_en1 = system.perip_rst_en1();
688
689    match peripheral {
690        #[cfg(soc_has_spi2)]
691        Peripheral::Spi2 => {
692            perip_rst_en0.modify(|_, w| w.spi2_rst().bit(reset));
693        }
694        #[cfg(soc_has_spi3)]
695        Peripheral::Spi3 => {
696            perip_rst_en0.modify(|_, w| w.spi3_rst().bit(reset));
697        }
698        #[cfg(soc_has_i2c0)]
699        Peripheral::I2cExt0 => {
700            perip_rst_en0.modify(|_, w| w.i2c_ext0_rst().bit(reset));
701        }
702        #[cfg(soc_has_i2c1)]
703        Peripheral::I2cExt1 => {
704            perip_rst_en0.modify(|_, w| w.i2c_ext1_rst().bit(reset));
705        }
706        #[cfg(soc_has_rmt)]
707        Peripheral::Rmt => {
708            perip_rst_en0.modify(|_, w| w.rmt_rst().bit(reset));
709        }
710        #[cfg(soc_has_ledc)]
711        Peripheral::Ledc => {
712            perip_rst_en0.modify(|_, w| w.ledc_rst().bit(reset));
713        }
714        #[cfg(soc_has_mcpwm0)]
715        Peripheral::Mcpwm0 => {
716            perip_rst_en0.modify(|_, w| w.pwm0_rst().bit(reset));
717        }
718        #[cfg(soc_has_mcpwm1)]
719        Peripheral::Mcpwm1 => {
720            perip_rst_en0.modify(|_, w| w.pwm1_rst().bit(reset));
721        }
722        #[cfg(soc_has_pcnt)]
723        Peripheral::Pcnt => {
724            perip_rst_en0.modify(|_, w| w.pcnt_rst().bit(reset));
725        }
726        #[cfg(soc_has_apb_saradc)]
727        Peripheral::ApbSarAdc => {
728            perip_rst_en0.modify(|_, w| w.apb_saradc_rst().bit(reset));
729        }
730        #[cfg(gdma)]
731        Peripheral::Gdma => {
732            perip_rst_en1.modify(|_, w| w.dma_rst().bit(reset));
733        }
734        #[cfg(esp32)]
735        Peripheral::Dma => {
736            perip_rst_en0.modify(|_, w| w.spi_dma_rst().bit(reset));
737        }
738        #[cfg(esp32s2)]
739        Peripheral::Dma => {
740            perip_rst_en0.modify(|_, w| w.spi2_dma_rst().bit(reset));
741            perip_rst_en0.modify(|_, w| w.spi3_dma_rst().bit(reset));
742            perip_rst_en1.modify(|_, w| w.crypto_dma_rst().bit(reset));
743        }
744        #[cfg(soc_has_i2s0)]
745        Peripheral::I2s0 => {
746            perip_rst_en0.modify(|_, w| w.i2s0_rst().bit(reset));
747        }
748        #[cfg(soc_has_i2s1)]
749        Peripheral::I2s1 => {
750            perip_rst_en0.modify(|_, w| w.i2s1_rst().bit(reset));
751        }
752        #[cfg(soc_has_usb0)]
753        Peripheral::Usb => {
754            perip_rst_en0.modify(|_, w| w.usb_rst().bit(reset));
755        }
756        #[cfg(soc_has_twai0)]
757        Peripheral::Twai0 => {
758            perip_rst_en0.modify(|_, w| w.twai_rst().bit(reset));
759        }
760        #[cfg(soc_has_aes)]
761        Peripheral::Aes => {
762            perip_rst_en1.modify(|_, w| w.crypto_aes_rst().bit(reset));
763        }
764        #[cfg(soc_has_timg0)]
765        Peripheral::Timg0 => {
766            #[cfg(any(esp32c3, esp32s2, esp32s3))]
767            perip_rst_en0.modify(|_, w| w.timers_rst().bit(reset));
768            perip_rst_en0.modify(|_, w| w.timergroup_rst().bit(reset));
769        }
770        #[cfg(soc_has_timg1)]
771        Peripheral::Timg1 => {
772            #[cfg(any(esp32c3, esp32s2, esp32s3))]
773            perip_rst_en0.modify(|_, w| w.timers_rst().bit(reset));
774            perip_rst_en0.modify(|_, w| w.timergroup1_rst().bit(reset));
775        }
776        #[cfg(soc_has_sha)]
777        Peripheral::Sha => {
778            perip_rst_en1.modify(|_, w| w.crypto_sha_rst().bit(reset));
779        }
780        #[cfg(soc_has_usb_device)]
781        Peripheral::UsbDevice => {
782            cfg_if::cfg_if! {
783                if #[cfg(esp32c3)] {
784                    perip_rst_en0.modify(|_, w| w.usb_device_rst().bit(reset));
785                } else {
786                    perip_rst_en1.modify(|_, w| w.usb_device_rst().bit(reset));
787                }
788            }
789        }
790        #[cfg(soc_has_uart0)]
791        Peripheral::Uart0 => {
792            perip_rst_en0.modify(|_, w| w.uart_rst().bit(reset));
793        }
794        #[cfg(soc_has_uart1)]
795        Peripheral::Uart1 => {
796            perip_rst_en0.modify(|_, w| w.uart1_rst().bit(reset));
797        }
798        #[cfg(soc_has_uart2)]
799        Peripheral::Uart2 => {
800            cfg_if::cfg_if! {
801                if #[cfg(esp32)] {
802                    perip_rst_en0.modify(|_, w| w.uart2_rst().bit(reset));
803                } else {
804                    perip_rst_en1.modify(|_, w| w.uart2_rst().bit(reset));
805                }
806            }
807        }
808        #[cfg(soc_has_rsa)]
809        Peripheral::Rsa => {
810            perip_rst_en1.modify(|_, w| w.crypto_rsa_rst().bit(reset));
811        }
812        #[cfg(soc_has_hmac)]
813        Peripheral::Hmac => {
814            perip_rst_en1.modify(|_, w| w.crypto_hmac_rst().bit(reset));
815        }
816        #[cfg(soc_has_ecc)]
817        Peripheral::Ecc => {
818            perip_rst_en1.modify(|_, w| w.crypto_ecc_rst().bit(reset));
819        }
820        #[cfg(soc_has_lcd_cam)]
821        Peripheral::LcdCam => {
822            perip_rst_en1.modify(|_, w| w.lcd_cam_rst().bit(reset));
823        }
824        #[cfg(soc_has_systimer)]
825        Peripheral::Systimer => {
826            perip_rst_en0.modify(|_, w| w.systimer_rst().bit(reset));
827        }
828        #[cfg(soc_has_tsens)]
829        Peripheral::Tsens => {
830            cfg_if::cfg_if! {
831                if #[cfg(esp32c3)] {
832                    perip_rst_en1.modify(|_, w| w.tsens_rst().bit(reset));
833                } else {
834                    perip_rst_en0.modify(|_, w| w.tsens_rst().bit(reset));
835                }
836            }
837        }
838        #[cfg(soc_has_uhci0)]
839        Peripheral::Uhci0 => {
840            perip_rst_en0.modify(|_, w| w.uhci0_rst().bit(reset));
841        }
842    }
843}
844
845#[cfg(any(esp32c6, esp32h2))]
846unsafe fn assert_peri_reset_racey(peripheral: Peripheral, reset: bool) {
847    let system = SYSTEM::regs();
848
849    // No need to lock, different peripherals' bits are in separate registers. In theory this may
850    // race with accessing the clk_enable bits, but the peripheral singleton pattern, as well as the
851    // general usage patterns of this code should prevent that.
852
853    match peripheral {
854        #[cfg(soc_has_spi2)]
855        Peripheral::Spi2 => {
856            system.spi2_conf().modify(|_, w| w.spi2_rst_en().bit(reset));
857        }
858        #[cfg(soc_has_i2c0)]
859        Peripheral::I2cExt0 => {
860            system.i2c0_conf().modify(|_, w| w.i2c0_rst_en().bit(reset));
861        }
862        #[cfg(soc_has_i2c1)]
863        Peripheral::I2cExt1 => {
864            system.i2c1_conf().modify(|_, w| w.i2c1_rst_en().bit(reset));
865        }
866        #[cfg(soc_has_rmt)]
867        Peripheral::Rmt => {
868            system.rmt_conf().modify(|_, w| w.rmt_rst_en().bit(reset));
869        }
870        #[cfg(soc_has_ledc)]
871        Peripheral::Ledc => {
872            system.ledc_conf().modify(|_, w| w.ledc_rst_en().bit(reset));
873        }
874        #[cfg(soc_has_mcpwm0)]
875        Peripheral::Mcpwm0 => {
876            system.pwm_conf().modify(|_, w| w.pwm_rst_en().bit(reset));
877        }
878        #[cfg(soc_has_apb_saradc)]
879        Peripheral::ApbSarAdc => {
880            system
881                .saradc_conf()
882                .modify(|_, w| w.saradc_reg_rst_en().bit(reset));
883        }
884        #[cfg(gdma)]
885        Peripheral::Gdma => {
886            system.gdma_conf().modify(|_, w| w.gdma_rst_en().bit(reset));
887        }
888        #[cfg(soc_has_i2s0)]
889        Peripheral::I2s0 => {
890            system.i2s_conf().modify(|_, w| w.i2s_rst_en().bit(reset));
891        }
892        #[cfg(soc_has_twai0)]
893        Peripheral::Twai0 => {
894            system
895                .twai0_conf()
896                .modify(|_, w| w.twai0_rst_en().bit(reset));
897        }
898        #[cfg(soc_has_twai1)]
899        Peripheral::Twai1 => {
900            system
901                .twai1_conf()
902                .modify(|_, w| w.twai1_rst_en().bit(reset));
903        }
904        #[cfg(soc_has_aes)]
905        Peripheral::Aes => {
906            system.aes_conf().modify(|_, w| w.aes_rst_en().bit(reset));
907        }
908        #[cfg(soc_has_pcnt)]
909        Peripheral::Pcnt => {
910            system.pcnt_conf().modify(|_, w| w.pcnt_rst_en().bit(reset));
911        }
912        #[cfg(soc_has_timg0)]
913        Peripheral::Timg0 => {
914            // no reset?
915        }
916        #[cfg(soc_has_timg1)]
917        Peripheral::Timg1 => {
918            // no reset?
919        }
920        #[cfg(soc_has_sha)]
921        Peripheral::Sha => {
922            system.sha_conf().modify(|_, w| w.sha_rst_en().bit(reset));
923        }
924        #[cfg(soc_has_usb_device)]
925        Peripheral::UsbDevice => {
926            system
927                .usb_device_conf()
928                .modify(|_, w| w.usb_device_rst_en().bit(reset));
929        }
930        #[cfg(soc_has_uart0)]
931        Peripheral::Uart0 => {
932            system.uart(0).conf().modify(|_, w| w.rst_en().bit(reset));
933        }
934        #[cfg(soc_has_uart1)]
935        Peripheral::Uart1 => {
936            system.uart(1).conf().modify(|_, w| w.rst_en().bit(reset));
937        }
938        #[cfg(soc_has_rsa)]
939        Peripheral::Rsa => {
940            system.rsa_conf().modify(|_, w| w.rsa_rst_en().bit(reset));
941        }
942        #[cfg(soc_has_parl_io)]
943        Peripheral::ParlIo => {
944            system
945                .parl_io_conf()
946                .modify(|_, w| w.parl_rst_en().bit(reset));
947        }
948        #[cfg(soc_has_hmac)]
949        Peripheral::Hmac => {
950            system.hmac_conf().modify(|_, w| w.hmac_rst_en().bit(reset));
951        }
952        #[cfg(soc_has_ecc)]
953        Peripheral::Ecc => {
954            system.ecc_conf().modify(|_, w| w.ecc_rst_en().bit(reset));
955        }
956        #[cfg(soc_has_etm)]
957        Peripheral::Etm => {
958            system.etm_conf().modify(|_, w| w.etm_rst_en().bit(reset));
959        }
960        #[cfg(soc_has_trace0)]
961        Peripheral::Trace0 => {
962            system
963                .trace_conf()
964                .modify(|_, w| w.trace_rst_en().bit(reset));
965        }
966        #[cfg(soc_has_systimer)]
967        Peripheral::Systimer => {
968            system
969                .systimer_conf()
970                .modify(|_, w| w.systimer_rst_en().bit(reset));
971        }
972        #[cfg(soc_has_tsens)]
973        Peripheral::Tsens => {
974            system
975                .tsens_clk_conf()
976                .modify(|_, w| w.tsens_rst_en().bit(reset));
977        }
978        #[cfg(soc_has_uhci0)]
979        Peripheral::Uhci0 => {
980            system.uhci_conf().modify(|_, w| w.uhci_rst_en().bit(reset));
981        }
982    }
983}
984
985impl PeripheralClockControl {
986    /// Enables the given peripheral.
987    ///
988    /// This keeps track of enabling a peripheral - i.e. a peripheral
989    /// is only enabled with the first call attempt to enable it.
990    ///
991    /// Returns `true` if it actually enabled the peripheral.
992    pub(crate) fn enable(peripheral: Peripheral) -> bool {
993        PERIPHERAL_REF_COUNT.with(|ref_counts| Self::enable_with_counts(peripheral, ref_counts))
994    }
995
996    /// Enables the given peripheral.
997    ///
998    /// This keeps track of enabling a peripheral - i.e. a peripheral
999    /// is only enabled with the first call attempt to enable it.
1000    ///
1001    /// Returns `true` if it actually enabled the peripheral.
1002    fn enable_with_counts(peripheral: Peripheral, ref_counts: &mut RefCounts) -> bool {
1003        Self::enable_forced_with_counts(peripheral, true, false, ref_counts)
1004    }
1005
1006    /// Disables the given peripheral.
1007    ///
1008    /// This keeps track of disabling a peripheral - i.e. it only
1009    /// gets disabled when the number of enable/disable attempts is balanced.
1010    ///
1011    /// Returns `true` if it actually disabled the peripheral.
1012    ///
1013    /// Before disabling a peripheral it will also get reset
1014    pub(crate) fn disable(peripheral: Peripheral) -> bool {
1015        PERIPHERAL_REF_COUNT.with(|ref_counts| {
1016            Self::enable_forced_with_counts(peripheral, false, false, ref_counts)
1017        })
1018    }
1019
1020    fn enable_forced_with_counts(
1021        peripheral: Peripheral,
1022        enable: bool,
1023        force: bool,
1024        ref_counts: &mut RefCounts,
1025    ) -> bool {
1026        let ref_count = &mut ref_counts.counts[peripheral as usize];
1027        if !force {
1028            let prev = *ref_count;
1029            if enable {
1030                *ref_count += 1;
1031                trace!("Enable {:?} {} -> {}", peripheral, prev, *ref_count);
1032                if prev > 0 {
1033                    return false;
1034                }
1035            } else {
1036                assert!(prev != 0);
1037                *ref_count -= 1;
1038                trace!("Disable {:?} {} -> {}", peripheral, prev, *ref_count);
1039                if prev > 1 {
1040                    return false;
1041                }
1042            };
1043        } else if !enable {
1044            assert!(*ref_count == 0);
1045        }
1046
1047        if !enable {
1048            unsafe { Self::reset_racey(peripheral) };
1049        }
1050
1051        unsafe { Self::enable_internal_racey(peripheral, enable) };
1052
1053        true
1054    }
1055
1056    /// Resets the given peripheral
1057    pub(crate) unsafe fn reset_racey(peripheral: Peripheral) {
1058        debug!("Reset {:?}", peripheral);
1059
1060        unsafe {
1061            assert_peri_reset_racey(peripheral, true);
1062            assert_peri_reset_racey(peripheral, false);
1063        }
1064    }
1065
1066    /// Resets the given peripheral
1067    pub(crate) fn reset(peripheral: Peripheral) {
1068        PERIPHERAL_REF_COUNT.with(|_| unsafe { Self::reset_racey(peripheral) })
1069    }
1070}
1071
1072#[cfg(any(esp32, esp32s3))]
1073#[allow(unused_imports)]
1074pub use crate::soc::cpu_control::*;
1075
1076/// Available CPU cores
1077///
1078/// The actual number of available cores depends on the target.
1079#[derive(Debug, Copy, Clone, PartialEq, Eq, strum::FromRepr)]
1080#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1081#[repr(C)]
1082pub enum Cpu {
1083    /// The first core
1084    ProCpu = 0,
1085    /// The second core
1086    #[cfg(multi_core)]
1087    AppCpu = 1,
1088}
1089
1090impl Cpu {
1091    /// The number of available cores.
1092    pub const COUNT: usize = 1 + cfg!(multi_core) as usize;
1093
1094    #[procmacros::doc_replace]
1095    /// Returns the core the application is currently executing on
1096    ///
1097    /// ```rust, no_run
1098    /// # {before_snippet}
1099    /// #
1100    /// use esp_hal::system::Cpu;
1101    /// let current_cpu = Cpu::current();
1102    /// #
1103    /// # {after_snippet}
1104    /// ```
1105    #[inline(always)]
1106    pub fn current() -> Self {
1107        // This works for both RISCV and Xtensa because both
1108        // get_raw_core functions return zero, _or_ something
1109        // greater than zero; 1 in the case of RISCV and 0x2000
1110        // in the case of Xtensa.
1111        match raw_core() {
1112            0 => Cpu::ProCpu,
1113            #[cfg(all(multi_core, riscv))]
1114            1 => Cpu::AppCpu,
1115            #[cfg(all(multi_core, xtensa))]
1116            0x2000 => Cpu::AppCpu,
1117            _ => unreachable!(),
1118        }
1119    }
1120
1121    /// Returns an iterator over the "other" cores.
1122    #[inline(always)]
1123    #[instability::unstable]
1124    pub fn other() -> impl Iterator<Item = Self> {
1125        cfg_if::cfg_if! {
1126            if #[cfg(multi_core)] {
1127                match Self::current() {
1128                    Cpu::ProCpu => [Cpu::AppCpu].into_iter(),
1129                    Cpu::AppCpu => [Cpu::ProCpu].into_iter(),
1130                }
1131            } else {
1132                [].into_iter()
1133            }
1134        }
1135    }
1136
1137    /// Returns an iterator over all cores.
1138    #[inline(always)]
1139    pub(crate) fn all() -> impl Iterator<Item = Self> {
1140        cfg_if::cfg_if! {
1141            if #[cfg(multi_core)] {
1142                [Cpu::ProCpu, Cpu::AppCpu].into_iter()
1143            } else {
1144                [Cpu::ProCpu].into_iter()
1145            }
1146        }
1147    }
1148}
1149
1150/// Returns the raw value of the mhartid register.
1151///
1152/// On RISC-V, this is the hardware thread ID.
1153///
1154/// On Xtensa, this returns the result of reading the PRID register logically
1155/// ANDed with 0x2000, the 13th bit in the register. Espressif Xtensa chips use
1156/// this bit to determine the core id.
1157#[inline(always)]
1158pub(crate) fn raw_core() -> usize {
1159    // This method must never return UNUSED_THREAD_ID_VALUE
1160    cfg_if::cfg_if! {
1161        if #[cfg(all(multi_core, riscv))] {
1162            riscv::register::mhartid::read()
1163        } else if #[cfg(all(multi_core, xtensa))] {
1164            (xtensa_lx::get_processor_id() & 0x2000) as usize
1165        } else {
1166            0
1167        }
1168    }
1169}
1170
1171use crate::rtc_cntl::SocResetReason;
1172
1173/// Source of the wakeup event
1174#[derive(Debug, Copy, Clone)]
1175#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1176#[instability::unstable]
1177pub enum SleepSource {
1178    /// In case of deep sleep, reset was not caused by exit from deep sleep
1179    Undefined = 0,
1180    /// Not a wakeup cause, used to disable all wakeup sources with
1181    /// esp_sleep_disable_wakeup_source
1182    All,
1183    /// Wakeup caused by external signal using RTC_IO
1184    Ext0,
1185    /// Wakeup caused by external signal using RTC_CNTL
1186    Ext1,
1187    /// Wakeup caused by timer
1188    Timer,
1189    /// Wakeup caused by touchpad
1190    TouchPad,
1191    /// Wakeup caused by ULP program
1192    Ulp,
1193    /// Wakeup caused by GPIO (light sleep only on ESP32, S2 and S3)
1194    Gpio,
1195    /// Wakeup caused by UART (light sleep only)
1196    Uart,
1197    /// Wakeup caused by WIFI (light sleep only)
1198    Wifi,
1199    /// Wakeup caused by COCPU int
1200    Cocpu,
1201    /// Wakeup caused by COCPU crash
1202    CocpuTrapTrig,
1203    /// Wakeup caused by BT (light sleep only)
1204    BT,
1205}
1206
1207#[procmacros::doc_replace]
1208/// Performs a software reset on the chip.
1209///
1210/// # Example
1211///
1212/// ```rust, no_run
1213/// # {before_snippet}
1214/// use esp_hal::system::software_reset;
1215/// software_reset();
1216/// # {after_snippet}
1217/// ```
1218#[inline]
1219pub fn software_reset() -> ! {
1220    crate::rom::software_reset()
1221}
1222
1223/// Resets the given CPU, leaving peripherals unchanged.
1224#[instability::unstable]
1225#[inline]
1226pub fn software_reset_cpu(cpu: Cpu) {
1227    crate::rom::software_reset_cpu(cpu as u32)
1228}
1229
1230/// Retrieves the reason for the last reset as a SocResetReason enum value.
1231/// Returns `None` if the reset reason cannot be determined.
1232#[instability::unstable]
1233#[inline]
1234pub fn reset_reason() -> Option<SocResetReason> {
1235    crate::rtc_cntl::reset_reason(Cpu::current())
1236}
1237
1238/// Retrieves the cause of the last wakeup event as a SleepSource enum value.
1239#[instability::unstable]
1240#[inline]
1241pub fn wakeup_cause() -> SleepSource {
1242    crate::rtc_cntl::wakeup_cause()
1243}