1#![allow(dead_code)]
4
5use esp_sync::NonReentrantMutex;
6
7cfg_select! {
8 all(soc_multi_core_enabled, feature = "unstable") => {
9 pub(crate) mod multi_core;
10 pub use multi_core::*;
11 }
12 _ => {}
13}
14
15implement_peripheral_clocks!();
17
18impl Peripheral {
19 pub const fn try_from(value: u8) -> Option<Peripheral> {
20 if value >= Peripheral::COUNT as u8 {
21 return None;
22 }
23
24 Some(unsafe { core::mem::transmute::<u8, Peripheral>(value) })
25 }
26}
27
28struct RefCounts {
29 counts: [usize; Peripheral::COUNT],
30}
31
32impl RefCounts {
33 pub const fn new() -> Self {
34 Self {
35 counts: [0; Peripheral::COUNT],
36 }
37 }
38}
39
40static PERIPHERAL_REF_COUNT: NonReentrantMutex<RefCounts> =
41 NonReentrantMutex::new(RefCounts::new());
42
43#[cfg_attr(not(feature = "rt"), expect(dead_code))]
47pub(crate) fn disable_peripherals() {
48 PERIPHERAL_REF_COUNT.with(|refcounts| {
50 for p in Peripheral::KEEP_ENABLED {
51 refcounts.counts[*p as usize] += 1;
52 }
53 for p in Peripheral::ALL {
54 let ref_count = refcounts.counts[*p as usize];
55 if ref_count == 0 {
56 PeripheralClockControl::enable_forced_with_counts(*p, false, true, refcounts);
57 }
58 }
59 })
60}
61
62#[derive(Debug, PartialEq, Eq)]
63#[cfg_attr(feature = "defmt", derive(defmt::Format))]
64pub(crate) struct PeripheralGuard {
65 peripheral: Peripheral,
66}
67
68impl PeripheralGuard {
69 pub(crate) fn new_with(p: Peripheral, init: fn()) -> Self {
70 PeripheralClockControl::request_peripheral(p, init);
71
72 Self { peripheral: p }
73 }
74
75 pub(crate) fn new(p: Peripheral) -> Self {
76 Self::new_with(p, || {})
77 }
78}
79
80impl Clone for PeripheralGuard {
81 fn clone(&self) -> Self {
82 Self::new(self.peripheral)
83 }
84
85 fn clone_from(&mut self, _source: &Self) {
86 }
88}
89
90impl Drop for PeripheralGuard {
91 fn drop(&mut self) {
92 PeripheralClockControl::disable(self.peripheral);
93 }
94}
95
96#[derive(Debug)]
97#[cfg_attr(feature = "defmt", derive(defmt::Format))]
98pub(crate) struct GenericPeripheralGuard<const P: u8> {}
99
100impl<const P: u8> GenericPeripheralGuard<P> {
101 pub(crate) fn new_with(init: fn()) -> Self {
102 let p = const { Peripheral::try_from(P).unwrap() };
103 PeripheralClockControl::request_peripheral(p, init);
104
105 Self {}
106 }
107
108 #[cfg_attr(esp32p4, allow(unused))]
109 #[cfg_attr(not(feature = "unstable"), allow(unused))]
110 pub(crate) fn new() -> Self {
111 Self::new_with(|| {})
112 }
113}
114
115impl<const P: u8> Clone for GenericPeripheralGuard<P> {
116 fn clone(&self) -> Self {
117 Self::new()
118 }
119
120 fn clone_from(&mut self, _source: &Self) {
121 }
123}
124
125impl<const P: u8> Drop for GenericPeripheralGuard<P> {
126 fn drop(&mut self) {
127 let peripheral = const { Peripheral::try_from(P).unwrap() };
128 PeripheralClockControl::disable(peripheral);
129 }
130}
131
132pub(crate) struct PeripheralClockControl;
134
135impl PeripheralClockControl {
136 fn request_peripheral(p: Peripheral, init: fn()) {
137 PERIPHERAL_REF_COUNT.with(|ref_counts| {
138 if Self::enable_with_counts(p, ref_counts) {
139 unsafe { Self::reset_racey(p) };
140 init();
141 }
142 });
143 }
144
145 pub(crate) fn enable(peripheral: Peripheral) -> bool {
152 PERIPHERAL_REF_COUNT.with(|ref_counts| Self::enable_with_counts(peripheral, ref_counts))
153 }
154
155 fn enable_with_counts(peripheral: Peripheral, ref_counts: &mut RefCounts) -> bool {
162 Self::enable_forced_with_counts(peripheral, true, false, ref_counts)
163 }
164
165 pub(crate) fn disable(peripheral: Peripheral) -> bool {
172 PERIPHERAL_REF_COUNT.with(|ref_counts| {
173 Self::enable_forced_with_counts(peripheral, false, false, ref_counts)
174 })
175 }
176
177 fn enable_forced_with_counts(
178 peripheral: Peripheral,
179 enable: bool,
180 force: bool,
181 ref_counts: &mut RefCounts,
182 ) -> bool {
183 let ref_count = &mut ref_counts.counts[peripheral as usize];
184 if !force {
185 let prev = *ref_count;
186 if enable {
187 *ref_count += 1;
188 trace!("Enable {:?} {} -> {}", peripheral, prev, *ref_count);
189 if prev > 0 {
190 return false;
191 }
192 } else {
193 assert!(prev != 0);
194 *ref_count -= 1;
195 trace!("Disable {:?} {} -> {}", peripheral, prev, *ref_count);
196 if prev > 1 {
197 return false;
198 }
199 };
200 } else if !enable {
201 assert!(*ref_count == 0);
202 }
203
204 debug!("Enable {:?} {}", peripheral, enable);
205 unsafe { enable_internal_racey(peripheral, enable) };
206
207 true
208 }
209
210 pub(crate) unsafe fn reset_racey(peripheral: Peripheral) {
212 debug!("Reset {:?}", peripheral);
213
214 unsafe {
215 assert_peri_reset_racey(peripheral, true);
216 assert_peri_reset_racey(peripheral, false);
217 }
218 }
219
220 pub(crate) fn reset(peripheral: Peripheral) {
222 PERIPHERAL_REF_COUNT.with(|_| unsafe { Self::reset_racey(peripheral) })
223 }
224}
225
226#[derive(Debug, Copy, Clone, PartialEq, Eq, strum::FromRepr)]
230#[cfg_attr(feature = "defmt", derive(defmt::Format))]
231#[repr(C)]
232pub enum Cpu {
233 ProCpu = 0,
235 #[cfg(multi_core)]
237 AppCpu = 1,
238}
239
240impl Cpu {
241 pub const COUNT: usize = 1 + cfg!(multi_core) as usize;
243
244 #[procmacros::doc_replace]
245 #[inline(always)]
256 pub fn current() -> Self {
257 match raw_core() {
262 0 => Cpu::ProCpu,
263
264 #[cfg(all(multi_core, riscv))]
265 1 => Cpu::AppCpu,
266
267 #[cfg(all(multi_core, xtensa))]
268 0x2000 => Cpu::AppCpu,
269
270 other => unreachable!("unknown core id: {}", other),
271 }
272 }
273
274 #[inline(always)]
276 #[instability::unstable]
277 pub fn other() -> impl Iterator<Item = Self> {
278 cfg_select! {
279 multi_core => match Self::current() {
280 Cpu::ProCpu => [Cpu::AppCpu].into_iter(),
281 Cpu::AppCpu => [Cpu::ProCpu].into_iter(),
282 },
283 _ => [].into_iter(),
284 }
285 }
286
287 #[inline(always)]
289 pub fn all() -> impl Iterator<Item = Self> {
290 cfg_select! {
291 multi_core => [Cpu::ProCpu, Cpu::AppCpu].into_iter(),
292 _ => [Cpu::ProCpu].into_iter(),
293 }
294 }
295}
296
297#[inline(always)]
305pub(crate) fn raw_core() -> usize {
306 cfg_select! {
307 all(multi_core, riscv) => riscv::register::mhartid::read(),
308 all(multi_core, xtensa) => (xtensa_lx::get_processor_id() & 0x2000) as usize,
309 _ => 0,
310 }
311}
312
313use crate::rtc_cntl::SocResetReason;
314
315#[procmacros::doc_replace]
316#[inline]
327pub fn software_reset() -> ! {
328 let _uart0_sclk_guard = ensure_uart0_sclk_enabled();
329 #[cfg(any(esp32h4, esp32p4, esp32s31))]
330 crate::soc::cpu_control::pre_system_reset();
331 crate::rom::software_reset()
332}
333
334#[instability::unstable]
336#[inline]
337pub fn software_reset_cpu(cpu: Cpu) {
338 let _uart0_sclk_guard = ensure_uart0_sclk_enabled();
339 crate::rom::software_reset_cpu(cpu as u32)
340}
341
342#[must_use = "dropping the guard releases the UART0 source clock"]
346pub(crate) struct Uart0SclkGuard {
347 release: bool,
348}
349
350impl Drop for Uart0SclkGuard {
351 fn drop(&mut self) {
352 if self.release {
353 release_uart0_sclk();
354 }
355 }
356}
357
358#[inline(always)]
365pub(crate) fn ensure_uart0_sclk_enabled() -> Uart0SclkGuard {
366 Uart0SclkGuard {
367 release: request_uart0_sclk(),
368 }
369}
370
371#[cfg(soc_has_clock_node_uart_function_clock)]
372fn request_uart0_sclk() -> bool {
373 crate::soc::clocks::ClockTree::with(|clocks| {
374 let uart = crate::soc::clocks::UartInstance::Uart0;
375 if uart.function_clock_config(clocks).is_some() {
376 uart.request_function_clock(clocks);
377 true
378 } else {
379 false
380 }
381 })
382}
383
384#[cfg(not(soc_has_clock_node_uart_function_clock))]
385fn request_uart0_sclk() -> bool {
386 false
387}
388
389#[cfg(soc_has_clock_node_uart_function_clock)]
390fn release_uart0_sclk() {
391 crate::soc::clocks::ClockTree::with(|clocks| {
392 crate::soc::clocks::UartInstance::Uart0.release_function_clock(clocks);
393 });
394}
395
396#[cfg(not(soc_has_clock_node_uart_function_clock))]
397fn release_uart0_sclk() {}
398
399#[cfg(feature = "unstable")]
401#[must_use = "dropping the guard releases the crypto clock"]
402pub(crate) struct CryptoClockGuard;
403
404#[cfg(feature = "unstable")]
405impl CryptoClockGuard {
406 #[inline(always)]
411 pub(crate) fn new() -> Self {
412 Self::request();
413 Self
414 }
415
416 fn request() {
417 cfg_select! {
418 soc_has_clock_node_crypto_clk => {
419 crate::soc::clocks::ClockTree::with(|clocks| {
420 crate::soc::clocks::request_crypto_clk(clocks);
421 });
422 }
423 soc_has_clock_node_crypto_pwm_clk => {
424 crate::soc::clocks::ClockTree::with(|clocks| {
425 crate::soc::clocks::request_crypto_pwm_clk(clocks);
426 });
427 }
428 _ => {}
429 }
430 }
431
432 fn release() {
433 cfg_select! {
434 soc_has_clock_node_crypto_clk => {
435 crate::soc::clocks::ClockTree::with(|clocks| {
436 crate::soc::clocks::release_crypto_clk(clocks);
437 });
438 }
439 soc_has_clock_node_crypto_pwm_clk => {
440 crate::soc::clocks::ClockTree::with(|clocks| {
441 crate::soc::clocks::release_crypto_pwm_clk(clocks);
442 });
443 }
444 _ => {}
445 }
446 }
447}
448
449#[cfg(feature = "unstable")]
450impl Drop for CryptoClockGuard {
451 fn drop(&mut self) {
452 Self::release();
453 }
454}
455
456#[instability::unstable]
459#[inline]
460pub fn reset_reason() -> Option<SocResetReason> {
461 crate::rtc_cntl::reset_reason(Cpu::current())
462}
463
464#[cfg(sleep_driver_supported)]
469#[instability::unstable]
470#[inline]
471pub fn wakeup_cause() -> crate::rtc_cntl::WakeupReason {
472 crate::rtc_cntl::wakeup_cause()
473}