Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate out PHY initialization. #2534

Draft
wants to merge 11 commits into
base: main
Choose a base branch
from
4 changes: 4 additions & 0 deletions esp-hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ pub mod rtc_cntl;
pub mod sha;
#[cfg(any(spi0, spi1, spi2, spi3))]
pub mod spi;
#[doc(hidden)]
#[cfg(any(dport, hp_sys, pcr, system))]
pub mod system;
pub mod time;
Expand Down Expand Up @@ -254,6 +255,9 @@ pub mod trapframe {
pub use xtensa_lx_rt::exception::Context as TrapFrame;
}

#[cfg(phy)]
pub mod radio_clock_ctrl;

// The `soc` module contains chip-specific implementation details and should not
// be directly exposed.
mod soc;
Expand Down
171 changes: 171 additions & 0 deletions esp-hal/src/radio_clock_ctrl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
//! Control over the radio clocs.
use core::cell::RefCell;

use critical_section::Mutex;
use portable_atomic::{AtomicBool, Ordering};

use crate::peripherals::RADIO_CLK;

/// Enumeration of the available radio peripherals for this chip.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[cfg(any(bt, ieee802154, wifi))]
bugadani marked this conversation as resolved.
Show resolved Hide resolved
pub enum RadioPeripherals {
/// Represents the PHY (Physical Layer) peripheral.
Phy,
/// Represents the Bluetooth peripheral.
#[cfg(bt)]
Bt,
/// Represents the WiFi peripheral.
#[cfg(wifi)]
Wifi,
/// Represents the IEEE 802.15.4 peripheral.
#[cfg(ieee802154)]
Ieee802154,
}

/// Control the radio peripheral clocks
///
/// NOTE: We don't really want the user messing with the radio clocks, so this
/// is hidden. In the future, we could just make it private.
#[doc(hidden)]
pub trait RadioClockController {
/// Enable the peripheral
fn enable(&mut self, peripheral: RadioPeripherals);

/// Disable the peripheral
fn disable(&mut self, peripheral: RadioPeripherals);

/// Reset the MAC
fn reset_mac(&mut self);

/// Do any common initial initialization needed
fn init_clocks(&mut self);

/// Initialize BLE RTC clocks
fn ble_rtc_clk_init(&mut self);

/// Reset the Resolvable Private Address (RPA).
fn reset_rpa(&mut self);
}

static PHY_CLOCK_ENABLED: AtomicBool = AtomicBool::new(false);
/// The PHY clock couldn't be disabled, because some modem clocks are still
/// active.
pub struct ModemClocksEnabledError;

/// This struct allows shared access to the radio clocks.
pub struct SharedRadioClockControl {
radio_clock: Mutex<RefCell<RADIO_CLK>>,

#[cfg(bt)]
bt_clock_enabled: AtomicBool,
#[cfg(wifi)]
wifi_clock_enabled: AtomicBool,
#[cfg(ieee802154)]
ieee802154_clock_enabled: AtomicBool,
}
impl SharedRadioClockControl {
/// Create a new [SharedRadioClockControl].
pub const fn new(radio_clock: RADIO_CLK) -> Self {
Self {
radio_clock: Mutex::new(RefCell::new(radio_clock)),
#[cfg(bt)]
bt_clock_enabled: AtomicBool::new(false),
#[cfg(wifi)]
wifi_clock_enabled: AtomicBool::new(false),
#[cfg(ieee802154)]
ieee802154_clock_enabled: AtomicBool::new(false),
}
}
/// Check if any modem clocks are enabled.
pub fn any_modem_clocks_enabled(&self) -> bool {
let mut any_clocks_enabled = false;

#[cfg(bt)]
{
any_clocks_enabled |= self.bt_clock_enabled.load(Ordering::Relaxed);
}
#[cfg(wifi)]
{
any_clocks_enabled |= self.wifi_clock_enabled.load(Ordering::Relaxed);
}
#[cfg(ieee802154)]
{
any_clocks_enabled |= self.ieee802154_clock_enabled.load(Ordering::Relaxed);
}

any_clocks_enabled
}
/// Enable or disable the clock.
fn set_clock_status(&self, enabled: bool, radio_peripheral: RadioPeripherals) {
critical_section::with(|cs| {
let mut radio_clock = self.radio_clock.borrow_ref_mut(cs);
if enabled {
radio_clock.enable(radio_peripheral)
} else {
radio_clock.disable(radio_peripheral)
}
})
}
/// Enable or disable the PHY clock.
///
/// If the PHY clock state was successfully changed, or the current state
/// already matched the specified one `Ok(())` is returned.
/// If the PHY clock is being disabled, but other modem clocks are still
/// active `Err(ModemClocksEnabledError)` is returned.
fn set_phy_clock_status(&self, enabled: bool) -> Result<(), ModemClocksEnabledError> {
// We shouldn't disable the PHY clock, if other clocks are still active.
if !enabled && self.any_modem_clocks_enabled() {
return Err(ModemClocksEnabledError);
}
// If the current clock status is already the same as the user provided one, we
// return. Otherwise we store the new value.
if PHY_CLOCK_ENABLED
.compare_exchange(!enabled, enabled, Ordering::Relaxed, Ordering::Relaxed)
.is_err()
{
return Ok(());
}
self.set_clock_status(enabled, RadioPeripherals::Phy);
Ok(())
}
/// Enable or disable a modem clock.
///
/// If required, this will also enabled or disable the PHY clock.
/// # Panics
/// This panics, if [RadioPeripherals::Phy] is passed in, since the PHY
/// clock is controlled internally.
pub fn set_modem_clock_status(&self, enabled: bool, radio_peripheral: RadioPeripherals) {
// We first assert, that the clock we're touching isn't the PHY clock, since
// that's special.
assert_ne!(radio_peripheral, RadioPeripherals::Phy);

// We obtain a reference to the AtomicBool tracking the state of the clock.
let modem_clock_enabled = match radio_peripheral {
#[cfg(bt)]
RadioPeripherals::Bt => &self.bt_clock_enabled,
#[cfg(wifi)]
RadioPeripherals::Wifi => &self.wifi_clock_enabled,
#[cfg(ieee802154)]
RadioPeripherals::Ieee802154 => &self.ieee802154_clock_enabled,
_ => unreachable!(),
};
// If the states already match, we return. Otherwise the new state is stored.
if modem_clock_enabled
.compare_exchange(!enabled, !enabled, Ordering::Relaxed, Ordering::Relaxed)
bugadani marked this conversation as resolved.
Show resolved Hide resolved
.is_err()
{
return;
}

if enabled {
// If the PHY clock isn't enabled yet, we disable it.
let _ = self.set_phy_clock_status(true);
self.set_clock_status(true, radio_peripheral);
} else {
self.set_clock_status(false, radio_peripheral);
let _ = self.set_phy_clock_status(false);
}
bugadani marked this conversation as resolved.
Show resolved Hide resolved
}
}
2 changes: 1 addition & 1 deletion esp-hal/src/rtc_cntl/rtc/esp32c6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ use crate::{
XtalClock,
},
peripherals::TIMG0,
radio_clock_ctrl::RadioPeripherals,
rtc_cntl::RtcClock,
soc::efuse::Efuse,
system::RadioPeripherals,
};

const I2C_DIG_REG: u8 = 0x6d;
Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/soc/esp32/radio_clocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! `RadioClockControl` struct. This trait provides methods to enable, disable,
//! reset the MAC, initialize clocks and perform other related operations.

use crate::system::{RadioClockController, RadioPeripherals};
use crate::radio_clock_ctrl::{RadioClockController, RadioPeripherals};

const DPORT_WIFI_CLK_WIFI_BT_COMMON_M: u32 = 0x000003c9;
const DPORT_WIFI_CLK_WIFI_EN_M: u32 = 0x00000406;
Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/soc/esp32c2/radio_clocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! `RadioClockControl` struct. This trait provides methods to enable, disable,
//! reset the MAC, initialize clocks and perform other related operations.

use crate::system::{RadioClockController, RadioPeripherals};
use crate::radio_clock_ctrl::{RadioClockController, RadioPeripherals};

// Mask for clock bits used by both WIFI and Bluetooth, 0, 1, 2, 3, 7, 8, 9, 10,
// 19, 20, 21, 22, 23
Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/soc/esp32c3/radio_clocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! `RadioClockControl` struct. This trait provides methods to enable, disable,
//! reset the MAC, initialize clocks and perform other related operations.

use crate::system::{RadioClockController, RadioPeripherals};
use crate::radio_clock_ctrl::{RadioClockController, RadioPeripherals};

// Mask for clock bits used by both WIFI and Bluetooth, 0, 1, 2, 3, 7, 8, 9, 10,
// 19, 20, 21, 22, 23
Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/soc/esp32c6/radio_clocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! `RadioClockControl` struct. This trait provides methods to enable, disable,
//! reset the MAC, initialize clocks and perform other related operations.

use crate::system::{RadioClockController, RadioPeripherals};
use crate::radio_clock_ctrl::{RadioClockController, RadioPeripherals};

impl RadioClockController for crate::peripherals::RADIO_CLK {
fn enable(&mut self, peripheral: RadioPeripherals) {
Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/soc/esp32h2/radio_clocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! `RadioClockControl` struct. This trait provides methods to enable, disable,
//! reset the MAC, initialize clocks and perform other related operations.

use crate::system::{RadioClockController, RadioPeripherals};
use crate::radio_clock_ctrl::{RadioClockController, RadioPeripherals};

impl RadioClockController for crate::peripherals::RADIO_CLK {
fn enable(&mut self, peripheral: RadioPeripherals) {
Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/soc/esp32s2/radio_clocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! `RadioClockControl` struct. This trait provides methods to enable, disable,
//! reset the MAC, initialize clocks and perform other related operations.

use crate::system::{RadioClockController, RadioPeripherals};
use crate::radio_clock_ctrl::{RadioClockController, RadioPeripherals};

// Mask for clock bits used by both WIFI and Bluetooth, bit 0, 3, 6, 7, 8, 9
const DPORT_WIFI_CLK_WIFI_BT_COMMON_M: u32 = 0x000003c9;
Expand Down
2 changes: 1 addition & 1 deletion esp-hal/src/soc/esp32s3/radio_clocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! `RadioClockControl` struct. This trait provides methods to enable, disable,
//! reset the MAC, initialize clocks and perform other related operations.

use crate::system::{RadioClockController, RadioPeripherals};
use crate::radio_clock_ctrl::{RadioClockController, RadioPeripherals};

// Note: this comment has been copied from esp-idf, including the mistake.
// Mask for clock bits used by both WIFI and Bluetooth, 0, 1, 2, 3, 7,
Expand Down
44 changes: 0 additions & 44 deletions esp-hal/src/system.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
//! # System Control
//!
//! ## Overview
//!
//! This `system` module defines the available radio peripherals and provides an
//! interface to control and configure radio clocks.

use crate::peripherals::SYSTEM;

Expand Down Expand Up @@ -985,42 +980,3 @@ impl PeripheralClockControl {
}
}
}

/// Enumeration of the available radio peripherals for this chip.
#[cfg(any(bt, ieee802154, wifi))]
pub enum RadioPeripherals {
/// Represents the PHY (Physical Layer) peripheral.
#[cfg(phy)]
Phy,
/// Represents the Bluetooth peripheral.
#[cfg(bt)]
Bt,
/// Represents the WiFi peripheral.
#[cfg(wifi)]
Wifi,
/// Represents the IEEE 802.15.4 peripheral.
#[cfg(ieee802154)]
Ieee802154,
}

/// Control the radio peripheral clocks
#[cfg(any(bt, ieee802154, wifi))]
pub trait RadioClockController {
/// Enable the peripheral
fn enable(&mut self, peripheral: RadioPeripherals);

/// Disable the peripheral
fn disable(&mut self, peripheral: RadioPeripherals);

/// Reset the MAC
fn reset_mac(&mut self);

/// Do any common initial initialization needed
fn init_clocks(&mut self);

/// Initialize BLE RTC clocks
fn ble_rtc_clk_init(&mut self);

/// Reset the Resolvable Private Address (RPA).
fn reset_rpa(&mut self);
}
Loading