Skip to content

Commit

Permalink
Added basic radio clock handling.
Browse files Browse the repository at this point in the history
  • Loading branch information
Frostie314159 committed Nov 13, 2024
1 parent 12c39df commit c4379c1
Show file tree
Hide file tree
Showing 10 changed files with 178 additions and 51 deletions.
4 changes: 4 additions & 0 deletions esp-hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,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 @@ -255,6 +256,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
167 changes: 167 additions & 0 deletions esp-hal/src/radio_clock_ctrl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
use core::{
cell::RefCell,
sync::atomic::{AtomicBool, Ordering},
};

use critical_section::Mutex;

use crate::peripherals::RADIO_CLK;

/// Enumeration of the available radio peripherals for this chip.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[cfg(any(bt, ieee802154, wifi))]
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);
pub struct ModemClocksEnabledError;

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 {
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)
.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);
}
}
}
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);
}

0 comments on commit c4379c1

Please sign in to comment.