1#![doc = include_str!(concat!(env!("OUT_DIR"), "/esp_phy_config_table.md"))]
16#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
18#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
19#![no_std]
20#![deny(missing_docs)]
21
22mod fmt;
24pub(crate) mod reg_access;
25
26use core::{cell::Cell, marker::PhantomData};
27
28use esp_hal::system::Cpu;
29#[cfg(esp32)]
30use esp_hal::time::{Duration, Instant};
31use esp_sync::{NonReentrantMutex, RawMutex};
32
33static PHY_CLOCK_REF_COUNTER: embassy_sync::blocking_mutex::Mutex<RawMutex, Cell<u8>> =
35 embassy_sync::blocking_mutex::Mutex::new(Cell::new(0));
36
37fn increase_phy_clock_ref_count_internal() {
38 PHY_CLOCK_REF_COUNTER.lock(|phy_clock_ref_counter| {
39 let phy_clock_ref_count = phy_clock_ref_counter.get();
40
41 if phy_clock_ref_count == 0 {
42 phy_clocks::enable_phy(true);
43 }
44 let new_phy_clock_ref_count = unwrap!(
45 phy_clock_ref_count.checked_add(1),
46 "PHY clock ref count overflowed."
47 );
48
49 phy_clock_ref_counter.set(new_phy_clock_ref_count);
50 })
51}
52
53fn decrease_phy_clock_ref_count_internal() {
54 PHY_CLOCK_REF_COUNTER.lock(|phy_clock_ref_counter| {
55 let new_phy_clock_ref_count = unwrap!(
56 phy_clock_ref_counter.get().checked_sub(1),
57 "PHY clock ref count underflowed. Either you forgot a PhyClockGuard, or used PhyController::decrease_phy_clock_ref_count incorrectly."
58 );
59
60 if new_phy_clock_ref_count == 0 {
61 phy_clocks::enable_phy(false);
62 }
63
64 phy_clock_ref_counter.set(new_phy_clock_ref_count);
65 })
66}
67
68#[derive(Debug)]
69pub struct PhyClockGuard<'d> {
75 _phantom: PhantomData<&'d ()>,
76}
77
78impl PhyClockGuard<'_> {
79 #[inline]
80 pub fn release(self) {
84 }
86}
87
88impl Drop for PhyClockGuard<'_> {
89 fn drop(&mut self) {
90 decrease_phy_clock_ref_count_internal();
91 }
92}
93pub(crate) mod sys {
94 #[cfg(esp32)]
95 pub use esp_wifi_sys_esp32::*;
96 #[cfg(esp32c2)]
97 pub use esp_wifi_sys_esp32c2::*;
98 #[cfg(esp32c3)]
99 pub use esp_wifi_sys_esp32c3::*;
100 #[cfg(esp32c5)]
101 pub use esp_wifi_sys_esp32c5::*;
102 #[cfg(esp32c6)]
103 pub use esp_wifi_sys_esp32c6::*;
104 #[cfg(esp32c61)]
105 pub use esp_wifi_sys_esp32c61::*;
106 #[cfg(esp32h2)]
107 pub use esp_wifi_sys_esp32h2::*;
108 #[cfg(esp32s2)]
109 pub use esp_wifi_sys_esp32s2::*;
110 #[cfg(esp32s3)]
111 pub use esp_wifi_sys_esp32s3::*;
112}
113
114mod common_adapter;
115mod phy_clocks;
116mod phy_init_data;
117
118pub const PHY_CALIBRATION_DATA_LENGTH: usize =
120 core::mem::size_of::<sys::include::esp_phy_calibration_data_t>();
121
122pub type PhyCalibrationData = [u8; PHY_CALIBRATION_DATA_LENGTH];
124
125#[cfg(phy_backed_up_digital_register_count_is_set)]
126type PhyDigRegsBackup =
127 [u32; esp_metadata_generated::property!("phy.backed_up_digital_register_count")];
128
129#[cfg(esp32)]
130pub type MacTimeUpdateCb = fn(Duration);
136
137static ESP_PHY_LOCK: RawMutex = RawMutex::new();
138
139struct PhyState {
141 ref_count: usize,
143 calibration_data: Option<PhyCalibrationData>,
148 calibrated: bool,
150 calibration_result: i32,
152
153 #[cfg(phy_backed_up_digital_register_count_is_set)]
154 phy_digital_register_backup: Option<PhyDigRegsBackup>,
156
157 #[cfg(esp32)]
159 phy_clock_state_transition_timestamp: Instant,
161 #[cfg(esp32)]
162 mac_clock_delta_since_last_call: Duration,
164 #[cfg(esp32)]
165 mac_time_update_cb: Option<MacTimeUpdateCb>,
167}
168
169impl PhyState {
170 pub const fn new() -> Self {
172 Self {
173 ref_count: 0,
174 calibration_data: None,
175 calibrated: false,
176 calibration_result: 0,
177
178 #[cfg(phy_backed_up_digital_register_count_is_set)]
179 phy_digital_register_backup: None,
180
181 #[cfg(esp32)]
182 phy_clock_state_transition_timestamp: Instant::EPOCH,
183 #[cfg(esp32)]
184 mac_clock_delta_since_last_call: Duration::ZERO,
185 #[cfg(esp32)]
186 mac_time_update_cb: None,
187 }
188 }
189
190 pub fn calibration_data(&mut self) -> &mut PhyCalibrationData {
194 self.calibration_data
195 .get_or_insert([0u8; PHY_CALIBRATION_DATA_LENGTH])
196 }
197
198 fn calibrate(&mut self) {
200 #[cfg(esp32s2)]
201 unsafe {
202 sys::include::phy_eco_version_sel(esp_hal::efuse::chip_revision().major);
203 }
204 #[cfg(all(
212 phy_enable_usb,
213 any(soc_has_usb0, soc_has_usb_device),
214 not(any(esp32s2, esp32h2))
215 ))]
216 unsafe {
217 unsafe extern "C" {
220 fn phy_bbpll_en_usb(param: bool);
221 }
222 phy_bbpll_en_usb(true);
223 }
224
225 let calibration_data_available = self.calibration_data.is_some();
226 let calibration_mode = if calibration_data_available {
227 if cfg!(phy_skip_calibration_after_deep_sleep) && is_reset_from_deepsleep() {
231 sys::include::esp_phy_calibration_mode_t_PHY_RF_CAL_NONE
232 } else if cfg!(phy_full_calibration) {
233 sys::include::esp_phy_calibration_mode_t_PHY_RF_CAL_FULL
234 } else {
235 sys::include::esp_phy_calibration_mode_t_PHY_RF_CAL_PARTIAL
236 }
237 } else {
238 sys::include::esp_phy_calibration_mode_t_PHY_RF_CAL_FULL
239 };
240 let init_data = &phy_init_data::PHY_INIT_DATA_DEFAULT;
241 unsafe {
242 self.calibration_result = sys::include::register_chipv7_phy(
243 init_data,
244 self.calibration_data() as *mut PhyCalibrationData as *mut _,
245 calibration_mode,
246 );
247 }
248 self.calibrated = true;
249 }
250
251 #[cfg(phy_backed_up_digital_register_count_is_set)]
252 fn backup_digital_regs(&mut self) {
254 unsafe {
255 sys::include::phy_dig_reg_backup(
256 true,
257 self.phy_digital_register_backup.get_or_insert_default() as *mut u32,
258 );
259 }
260 }
261
262 #[cfg(phy_backed_up_digital_register_count_is_set)]
263 fn restore_digital_regs(&mut self) {
267 unsafe {
268 sys::include::phy_dig_reg_backup(
269 false,
270 self.phy_digital_register_backup
271 .as_mut()
272 .expect("Can't restore digital PHY registers from backup, without a backup.")
273 as *mut u32,
274 );
275 self.phy_digital_register_backup = None;
276 }
277 }
278
279 pub fn increase_ref_count(&mut self) {
283 if self.ref_count == 0 {
284 #[cfg(esp32)]
285 {
286 let now = Instant::now();
287 let delta = now - self.phy_clock_state_transition_timestamp;
288 self.phy_clock_state_transition_timestamp = now;
289 self.mac_clock_delta_since_last_call += delta;
290 }
291 if self.calibrated {
292 unsafe {
293 sys::include::phy_wakeup_init();
294 }
295 #[cfg(phy_backed_up_digital_register_count_is_set)]
296 self.restore_digital_regs();
297 } else {
298 self.calibrate();
299 self.calibrated = true;
300 }
301 }
302 #[cfg(esp32)]
303 if let Some(cb) = self.mac_time_update_cb {
304 (cb)(self.mac_clock_delta_since_last_call);
305 self.mac_clock_delta_since_last_call = Duration::ZERO;
306 }
307
308 self.ref_count += 1;
309 }
310
311 pub fn decrease_ref_count(&mut self) {
318 self.ref_count = self
319 .ref_count
320 .checked_sub(1)
321 .expect("PHY init ref count dropped below zero.");
322 if self.ref_count == 0 {
323 #[cfg(phy_backed_up_digital_register_count_is_set)]
324 self.backup_digital_regs();
325 unsafe {
326 sys::include::phy_close_rf();
328
329 #[cfg(not(esp32))]
331 sys::include::phy_xpd_tsens();
332 }
333 #[cfg(esp32)]
334 {
335 self.phy_clock_state_transition_timestamp = Instant::now();
336 }
337 }
341 }
342}
343
344fn is_reset_from_deepsleep() -> bool {
345 #[cfg(any(
347 esp32, esp32c2, esp32c3, esp32c5, esp32c6, esp32c61, esp32h2, esp32s2, esp32s3
348 ))]
349 const CORE_DEEP_SLEEP: u32 = 5;
350
351 unsafe extern "C" {
352 fn rtc_get_reset_reason(cpu_num: u32) -> u32;
353 }
354
355 let reason = unsafe { rtc_get_reset_reason(Cpu::current() as u32) };
356
357 reason == CORE_DEEP_SLEEP
358}
359
360static PHY_STATE: NonReentrantMutex<PhyState> = NonReentrantMutex::new(PhyState::new());
362
363#[derive(Debug)]
369pub struct PhyInitGuard<'d> {
370 _phy_clock_guard: PhyClockGuard<'d>,
371}
372
373impl PhyInitGuard<'_> {
374 #[inline]
375 pub fn release(self) {
379 }
381}
382
383impl Drop for PhyInitGuard<'_> {
384 fn drop(&mut self) {
385 PHY_STATE.with(|phy_state| phy_state.decrease_ref_count());
386 }
387}
388
389pub fn enable_phy<'d>() -> PhyInitGuard<'d> {
395 let _phy_clock_guard = enable_phy_clock();
398
399 PHY_STATE.with(|phy_state| phy_state.increase_ref_count());
400
401 PhyInitGuard { _phy_clock_guard }
402}
403
404pub fn disable_phy() {
408 PHY_STATE.with(|phy_state| phy_state.decrease_ref_count());
409 decrease_phy_clock_ref_count_internal();
413}
414
415pub fn enable_phy_clock<'d>() -> PhyClockGuard<'d> {
419 increase_phy_clock_ref_count_internal();
420 PhyClockGuard {
421 _phantom: PhantomData,
422 }
423}
424
425#[cfg(esp32)]
429pub fn set_mac_time_update_cb(mac_time_update_cb: MacTimeUpdateCb) {
430 PHY_STATE.with(|phy_state| phy_state.mac_time_update_cb = Some(mac_time_update_cb));
431}
432
433#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
434#[cfg_attr(feature = "defmt", derive(defmt::Format))]
435pub struct CalibrationDataAlreadySetError;
437
438#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
439#[cfg_attr(feature = "defmt", derive(defmt::Format))]
440pub struct NoCalibrationDataError;
442
443#[derive(Debug, Clone, Copy)]
445#[cfg_attr(feature = "defmt", derive(defmt::Format))]
446#[non_exhaustive]
447pub enum CalibrationResult {
448 Ok,
450
451 DataCheckFailed,
453}
454
455pub fn set_phy_calibration_data(
457 calibration_data: &PhyCalibrationData,
458) -> Result<(), CalibrationDataAlreadySetError> {
459 PHY_STATE.with(|phy_state| {
460 if phy_state.calibration_data.is_some() {
461 Err(CalibrationDataAlreadySetError)
462 } else {
463 phy_state.calibration_data = Some(*calibration_data);
464 Ok(())
465 }
466 })
467}
468
469pub fn backup_phy_calibration_data(
471 buffer: &mut PhyCalibrationData,
472) -> Result<(), NoCalibrationDataError> {
473 PHY_STATE.with(|phy_state| {
474 phy_state
475 .calibration_data
476 .as_mut()
477 .ok_or(NoCalibrationDataError)
478 .map(|calibration_data| buffer.copy_from_slice(calibration_data.as_slice()))
479 })
480}
481
482pub fn last_calibration_result() -> Option<CalibrationResult> {
487 PHY_STATE.with(|phy_state| {
488 if phy_state.calibrated {
489 Some(
490 if phy_state.calibration_result == sys::include::ESP_CAL_DATA_CHECK_FAIL as i32 {
491 CalibrationResult::DataCheckFailed
492 } else {
493 CalibrationResult::Ok
494 },
495 )
496 } else {
497 None
498 }
499 })
500}