1use esp_sync::NonReentrantMutex;
4
5implement_peripheral_clocks!();
7
8impl Peripheral {
9 pub const fn try_from(value: u8) -> Option<Peripheral> {
10 if value >= Peripheral::COUNT as u8 {
11 return None;
12 }
13
14 Some(unsafe { core::mem::transmute::<u8, Peripheral>(value) })
15 }
16}
17
18struct RefCounts {
19 counts: [usize; Peripheral::COUNT],
20}
21
22impl RefCounts {
23 pub const fn new() -> Self {
24 Self {
25 counts: [0; Peripheral::COUNT],
26 }
27 }
28}
29
30static PERIPHERAL_REF_COUNT: NonReentrantMutex<RefCounts> =
31 NonReentrantMutex::new(RefCounts::new());
32
33#[cfg_attr(not(feature = "rt"), expect(dead_code))]
37pub(crate) fn disable_peripherals() {
38 PERIPHERAL_REF_COUNT.with(|refcounts| {
40 for p in Peripheral::KEEP_ENABLED {
41 refcounts.counts[*p as usize] += 1;
42 }
43 for p in Peripheral::ALL {
44 let ref_count = refcounts.counts[*p as usize];
45 if ref_count == 0 {
46 PeripheralClockControl::enable_forced_with_counts(*p, false, true, refcounts);
47 }
48 }
49 })
50}
51
52#[derive(Debug, PartialEq, Eq)]
53#[cfg_attr(feature = "defmt", derive(defmt::Format))]
54pub(crate) struct PeripheralGuard {
55 peripheral: Peripheral,
56}
57
58impl PeripheralGuard {
59 pub(crate) fn new_with(p: Peripheral, init: fn()) -> Self {
60 if PeripheralClockControl::enable(p) {
61 PeripheralClockControl::reset(p);
62 init();
63 }
64
65 Self { peripheral: p }
66 }
67
68 pub(crate) fn new(p: Peripheral) -> Self {
69 Self::new_with(p, || {})
70 }
71}
72
73impl Drop for PeripheralGuard {
74 fn drop(&mut self) {
75 PeripheralClockControl::disable(self.peripheral);
76 }
77}
78
79#[derive(Debug)]
80#[cfg_attr(feature = "defmt", derive(defmt::Format))]
81pub(crate) struct GenericPeripheralGuard<const P: u8> {}
82
83impl<const P: u8> GenericPeripheralGuard<P> {
84 pub(crate) fn new_with(init: fn()) -> Self {
85 let peripheral = const { Peripheral::try_from(P).unwrap() };
86
87 PERIPHERAL_REF_COUNT.with(|ref_counts| {
88 if PeripheralClockControl::enable_with_counts(peripheral, ref_counts) {
89 unsafe { PeripheralClockControl::reset_racey(peripheral) };
90 init();
91 }
92 });
93
94 Self {}
95 }
96
97 #[cfg_attr(not(feature = "unstable"), allow(unused))]
98 pub(crate) fn new() -> Self {
99 Self::new_with(|| {})
100 }
101}
102
103impl<const P: u8> Clone for GenericPeripheralGuard<P> {
104 fn clone(&self) -> Self {
105 Self::new()
106 }
107
108 fn clone_from(&mut self, _source: &Self) {
109 }
111}
112
113impl<const P: u8> Drop for GenericPeripheralGuard<P> {
114 fn drop(&mut self) {
115 let peripheral = const { Peripheral::try_from(P).unwrap() };
116 PeripheralClockControl::disable(peripheral);
117 }
118}
119
120pub(crate) struct PeripheralClockControl;
122
123impl PeripheralClockControl {
124 pub(crate) fn enable(peripheral: Peripheral) -> bool {
131 PERIPHERAL_REF_COUNT.with(|ref_counts| Self::enable_with_counts(peripheral, ref_counts))
132 }
133
134 fn enable_with_counts(peripheral: Peripheral, ref_counts: &mut RefCounts) -> bool {
141 Self::enable_forced_with_counts(peripheral, true, false, ref_counts)
142 }
143
144 pub(crate) fn disable(peripheral: Peripheral) -> bool {
153 PERIPHERAL_REF_COUNT.with(|ref_counts| {
154 Self::enable_forced_with_counts(peripheral, false, false, ref_counts)
155 })
156 }
157
158 fn enable_forced_with_counts(
159 peripheral: Peripheral,
160 enable: bool,
161 force: bool,
162 ref_counts: &mut RefCounts,
163 ) -> bool {
164 let ref_count = &mut ref_counts.counts[peripheral as usize];
165 if !force {
166 let prev = *ref_count;
167 if enable {
168 *ref_count += 1;
169 trace!("Enable {:?} {} -> {}", peripheral, prev, *ref_count);
170 if prev > 0 {
171 return false;
172 }
173 } else {
174 assert!(prev != 0);
175 *ref_count -= 1;
176 trace!("Disable {:?} {} -> {}", peripheral, prev, *ref_count);
177 if prev > 1 {
178 return false;
179 }
180 };
181 } else if !enable {
182 assert!(*ref_count == 0);
183 }
184
185 if !enable {
186 unsafe { Self::reset_racey(peripheral) };
187 }
188
189 debug!("Enable {:?} {}", peripheral, enable);
190 unsafe { enable_internal_racey(peripheral, enable) };
191
192 true
193 }
194
195 pub(crate) unsafe fn reset_racey(peripheral: Peripheral) {
197 debug!("Reset {:?}", peripheral);
198
199 unsafe {
200 assert_peri_reset_racey(peripheral, true);
201 assert_peri_reset_racey(peripheral, false);
202 }
203 }
204
205 pub(crate) fn reset(peripheral: Peripheral) {
207 PERIPHERAL_REF_COUNT.with(|_| unsafe { Self::reset_racey(peripheral) })
208 }
209}
210
211#[cfg(any(esp32, esp32s3))]
212#[allow(unused_imports)]
213pub use crate::soc::cpu_control::*;
214
215#[derive(Debug, Copy, Clone, PartialEq, Eq, strum::FromRepr)]
219#[cfg_attr(feature = "defmt", derive(defmt::Format))]
220#[repr(C)]
221pub enum Cpu {
222 ProCpu = 0,
224 #[cfg(multi_core)]
226 AppCpu = 1,
227}
228
229impl Cpu {
230 pub const COUNT: usize = 1 + cfg!(multi_core) as usize;
232
233 #[procmacros::doc_replace]
234 #[inline(always)]
245 pub fn current() -> Self {
246 match raw_core() {
251 0 => Cpu::ProCpu,
252 #[cfg(all(multi_core, riscv))]
253 1 => Cpu::AppCpu,
254 #[cfg(all(multi_core, xtensa))]
255 0x2000 => Cpu::AppCpu,
256 _ => unreachable!(),
257 }
258 }
259
260 #[inline(always)]
262 #[instability::unstable]
263 pub fn other() -> impl Iterator<Item = Self> {
264 cfg_if::cfg_if! {
265 if #[cfg(multi_core)] {
266 match Self::current() {
267 Cpu::ProCpu => [Cpu::AppCpu].into_iter(),
268 Cpu::AppCpu => [Cpu::ProCpu].into_iter(),
269 }
270 } else {
271 [].into_iter()
272 }
273 }
274 }
275
276 #[inline(always)]
278 pub(crate) fn all() -> impl Iterator<Item = Self> {
279 cfg_if::cfg_if! {
280 if #[cfg(multi_core)] {
281 [Cpu::ProCpu, Cpu::AppCpu].into_iter()
282 } else {
283 [Cpu::ProCpu].into_iter()
284 }
285 }
286 }
287}
288
289#[inline(always)]
297pub(crate) fn raw_core() -> usize {
298 cfg_if::cfg_if! {
300 if #[cfg(all(multi_core, riscv))] {
301 riscv::register::mhartid::read()
302 } else if #[cfg(all(multi_core, xtensa))] {
303 (xtensa_lx::get_processor_id() & 0x2000) as usize
304 } else {
305 0
306 }
307 }
308}
309
310use crate::rtc_cntl::SocResetReason;
311
312#[derive(Debug, Copy, Clone)]
314#[cfg_attr(feature = "defmt", derive(defmt::Format))]
315#[instability::unstable]
316pub enum SleepSource {
317 Undefined = 0,
319 All,
322 Ext0,
324 Ext1,
326 Timer,
328 TouchPad,
330 Ulp,
332 Gpio,
334 Uart,
336 Wifi,
338 Cocpu,
340 CocpuTrapTrig,
342 BT,
344}
345
346#[procmacros::doc_replace]
347#[inline]
358pub fn software_reset() -> ! {
359 crate::rom::software_reset()
360}
361
362#[instability::unstable]
364#[inline]
365pub fn software_reset_cpu(cpu: Cpu) {
366 crate::rom::software_reset_cpu(cpu as u32)
367}
368
369#[instability::unstable]
372#[inline]
373pub fn reset_reason() -> Option<SocResetReason> {
374 crate::rtc_cntl::reset_reason(Cpu::current())
375}
376
377#[instability::unstable]
379#[inline]
380pub fn wakeup_cause() -> SleepSource {
381 crate::rtc_cntl::wakeup_cause()
382}