1use esp_sync::NonReentrantMutex;
4
5cfg_if::cfg_if! {
6 if #[cfg(all(soc_multi_core_enabled, feature = "unstable"))] {
7 pub(crate) mod multi_core;
8 #[cfg(feature = "unstable")]
9 pub use multi_core::*;
10 }
11}
12
13implement_peripheral_clocks!();
15
16impl Peripheral {
17 pub const fn try_from(value: u8) -> Option<Peripheral> {
18 if value >= Peripheral::COUNT as u8 {
19 return None;
20 }
21
22 Some(unsafe { core::mem::transmute::<u8, Peripheral>(value) })
23 }
24}
25
26struct RefCounts {
27 counts: [usize; Peripheral::COUNT],
28}
29
30impl RefCounts {
31 pub const fn new() -> Self {
32 Self {
33 counts: [0; Peripheral::COUNT],
34 }
35 }
36}
37
38static PERIPHERAL_REF_COUNT: NonReentrantMutex<RefCounts> =
39 NonReentrantMutex::new(RefCounts::new());
40
41#[cfg_attr(not(feature = "rt"), expect(dead_code))]
45pub(crate) fn disable_peripherals() {
46 PERIPHERAL_REF_COUNT.with(|refcounts| {
48 for p in Peripheral::KEEP_ENABLED {
49 refcounts.counts[*p as usize] += 1;
50 }
51 for p in Peripheral::ALL {
52 let ref_count = refcounts.counts[*p as usize];
53 if ref_count == 0 {
54 PeripheralClockControl::enable_forced_with_counts(*p, false, true, refcounts);
55 }
56 }
57 })
58}
59
60#[derive(Debug, PartialEq, Eq)]
61#[cfg_attr(feature = "defmt", derive(defmt::Format))]
62pub(crate) struct PeripheralGuard {
63 peripheral: Peripheral,
64}
65
66impl PeripheralGuard {
67 pub(crate) fn new_with(p: Peripheral, init: fn()) -> Self {
68 PeripheralClockControl::request_peripheral(p, init);
69
70 Self { peripheral: p }
71 }
72
73 pub(crate) fn new(p: Peripheral) -> Self {
74 Self::new_with(p, || {})
75 }
76}
77
78impl Clone for PeripheralGuard {
79 fn clone(&self) -> Self {
80 Self::new(self.peripheral)
81 }
82
83 fn clone_from(&mut self, _source: &Self) {
84 }
86}
87
88impl Drop for PeripheralGuard {
89 fn drop(&mut self) {
90 PeripheralClockControl::disable(self.peripheral);
91 }
92}
93
94#[derive(Debug)]
95#[cfg_attr(feature = "defmt", derive(defmt::Format))]
96pub(crate) struct GenericPeripheralGuard<const P: u8> {}
97
98impl<const P: u8> GenericPeripheralGuard<P> {
99 pub(crate) fn new_with(init: fn()) -> Self {
100 let p = const { Peripheral::try_from(P).unwrap() };
101 PeripheralClockControl::request_peripheral(p, init);
102
103 Self {}
104 }
105
106 #[cfg_attr(not(feature = "unstable"), allow(unused))]
107 pub(crate) fn new() -> Self {
108 Self::new_with(|| {})
109 }
110}
111
112impl<const P: u8> Clone for GenericPeripheralGuard<P> {
113 fn clone(&self) -> Self {
114 Self::new()
115 }
116
117 fn clone_from(&mut self, _source: &Self) {
118 }
120}
121
122impl<const P: u8> Drop for GenericPeripheralGuard<P> {
123 fn drop(&mut self) {
124 let peripheral = const { Peripheral::try_from(P).unwrap() };
125 PeripheralClockControl::disable(peripheral);
126 }
127}
128
129pub(crate) struct PeripheralClockControl;
131
132impl PeripheralClockControl {
133 fn request_peripheral(p: Peripheral, init: fn()) {
134 PERIPHERAL_REF_COUNT.with(|ref_counts| {
135 if Self::enable_with_counts(p, ref_counts) {
136 unsafe { Self::reset_racey(p) };
137 init();
138 }
139 });
140 }
141
142 pub(crate) fn enable(peripheral: Peripheral) -> bool {
149 PERIPHERAL_REF_COUNT.with(|ref_counts| Self::enable_with_counts(peripheral, ref_counts))
150 }
151
152 fn enable_with_counts(peripheral: Peripheral, ref_counts: &mut RefCounts) -> bool {
159 Self::enable_forced_with_counts(peripheral, true, false, ref_counts)
160 }
161
162 pub(crate) fn disable(peripheral: Peripheral) -> bool {
169 PERIPHERAL_REF_COUNT.with(|ref_counts| {
170 Self::enable_forced_with_counts(peripheral, false, false, ref_counts)
171 })
172 }
173
174 fn enable_forced_with_counts(
175 peripheral: Peripheral,
176 enable: bool,
177 force: bool,
178 ref_counts: &mut RefCounts,
179 ) -> bool {
180 let ref_count = &mut ref_counts.counts[peripheral as usize];
181 if !force {
182 let prev = *ref_count;
183 if enable {
184 *ref_count += 1;
185 trace!("Enable {:?} {} -> {}", peripheral, prev, *ref_count);
186 if prev > 0 {
187 return false;
188 }
189 } else {
190 assert!(prev != 0);
191 *ref_count -= 1;
192 trace!("Disable {:?} {} -> {}", peripheral, prev, *ref_count);
193 if prev > 1 {
194 return false;
195 }
196 };
197 } else if !enable {
198 assert!(*ref_count == 0);
199 }
200
201 debug!("Enable {:?} {}", peripheral, enable);
202 unsafe { enable_internal_racey(peripheral, enable) };
203
204 true
205 }
206
207 pub(crate) unsafe fn reset_racey(peripheral: Peripheral) {
209 debug!("Reset {:?}", peripheral);
210
211 unsafe {
212 assert_peri_reset_racey(peripheral, true);
213 assert_peri_reset_racey(peripheral, false);
214 }
215 }
216
217 pub(crate) fn reset(peripheral: Peripheral) {
219 PERIPHERAL_REF_COUNT.with(|_| unsafe { Self::reset_racey(peripheral) })
220 }
221}
222
223#[derive(Debug, Copy, Clone, PartialEq, Eq, strum::FromRepr)]
227#[cfg_attr(feature = "defmt", derive(defmt::Format))]
228#[repr(C)]
229pub enum Cpu {
230 ProCpu = 0,
232 #[cfg(multi_core)]
234 AppCpu = 1,
235}
236
237impl Cpu {
238 pub const COUNT: usize = 1 + cfg!(multi_core) as usize;
240
241 #[procmacros::doc_replace]
242 #[inline(always)]
253 pub fn current() -> Self {
254 match raw_core() {
259 0 => Cpu::ProCpu,
260 #[cfg(all(multi_core, riscv))]
261 1 => Cpu::AppCpu,
262 #[cfg(all(multi_core, xtensa))]
263 0x2000 => Cpu::AppCpu,
264 _ => unreachable!(),
265 }
266 }
267
268 #[inline(always)]
270 #[instability::unstable]
271 pub fn other() -> impl Iterator<Item = Self> {
272 cfg_if::cfg_if! {
273 if #[cfg(multi_core)] {
274 match Self::current() {
275 Cpu::ProCpu => [Cpu::AppCpu].into_iter(),
276 Cpu::AppCpu => [Cpu::ProCpu].into_iter(),
277 }
278 } else {
279 [].into_iter()
280 }
281 }
282 }
283
284 #[inline(always)]
286 pub fn all() -> impl Iterator<Item = Self> {
287 cfg_if::cfg_if! {
288 if #[cfg(multi_core)] {
289 [Cpu::ProCpu, Cpu::AppCpu].into_iter()
290 } else {
291 [Cpu::ProCpu].into_iter()
292 }
293 }
294 }
295}
296
297#[inline(always)]
305pub(crate) fn raw_core() -> usize {
306 cfg_if::cfg_if! {
308 if #[cfg(all(multi_core, riscv))] {
309 riscv::register::mhartid::read()
310 } else if #[cfg(all(multi_core, xtensa))] {
311 (xtensa_lx::get_processor_id() & 0x2000) as usize
312 } else {
313 0
314 }
315 }
316}
317
318use crate::rtc_cntl::SocResetReason;
319
320#[derive(Debug, Copy, Clone)]
322#[cfg_attr(feature = "defmt", derive(defmt::Format))]
323#[instability::unstable]
324pub enum SleepSource {
325 Undefined = 0,
327 All,
330 Ext0,
332 Ext1,
334 Timer,
336 TouchPad,
338 Ulp,
340 Gpio,
342 Uart,
344 Wifi,
346 Cocpu,
348 CocpuTrapTrig,
350 BT,
352}
353
354#[procmacros::doc_replace]
355#[inline]
366pub fn software_reset() -> ! {
367 crate::rom::software_reset()
368}
369
370#[instability::unstable]
372#[inline]
373pub fn software_reset_cpu(cpu: Cpu) {
374 crate::rom::software_reset_cpu(cpu as u32)
375}
376
377#[instability::unstable]
380#[inline]
381pub fn reset_reason() -> Option<SocResetReason> {
382 crate::rtc_cntl::reset_reason(Cpu::current())
383}
384
385#[instability::unstable]
387#[inline]
388pub fn wakeup_cause() -> SleepSource {
389 crate::rtc_cntl::wakeup_cause()
390}