diff --git a/esp-hal-common/devices/esp32.toml b/esp-hal-common/devices/esp32.toml index da1edc789b2..885237f3c30 100644 --- a/esp-hal-common/devices/esp32.toml +++ b/esp-hal-common/devices/esp32.toml @@ -53,4 +53,7 @@ peripherals = [ "dac", "pdma", "radio", + "phy", + "bt", + "wifi", ] diff --git a/esp-hal-common/devices/esp32c2.toml b/esp-hal-common/devices/esp32c2.toml index 3194eb63d0e..7da5fd0cb57 100644 --- a/esp-hal-common/devices/esp32c2.toml +++ b/esp-hal-common/devices/esp32c2.toml @@ -34,4 +34,7 @@ peripherals = [ "adc", "gdma", "radio", + "phy", + "bt", + "wifi", ] diff --git a/esp-hal-common/devices/esp32c3.toml b/esp-hal-common/devices/esp32c3.toml index 825822bdbf1..45b16a64e78 100644 --- a/esp-hal-common/devices/esp32c3.toml +++ b/esp-hal-common/devices/esp32c3.toml @@ -45,4 +45,7 @@ peripherals = [ "adc", "gdma", "radio", + "phy", + "bt", + "wifi", ] diff --git a/esp-hal-common/devices/esp32c6.toml b/esp-hal-common/devices/esp32c6.toml index 79de77d574e..81469b4e52b 100644 --- a/esp-hal-common/devices/esp32c6.toml +++ b/esp-hal-common/devices/esp32c6.toml @@ -73,4 +73,8 @@ peripherals = [ "large_intr_status", "plic", "radio", + "phy", + "bt", + "wifi", + "ieee802154", ] diff --git a/esp-hal-common/devices/esp32s2.toml b/esp-hal-common/devices/esp32s2.toml index 75e0ce2e611..6804b9269be 100644 --- a/esp-hal-common/devices/esp32s2.toml +++ b/esp-hal-common/devices/esp32s2.toml @@ -51,4 +51,6 @@ peripherals = [ "dac", "pdma", "radio", + "phy", + "wifi", ] diff --git a/esp-hal-common/devices/esp32s3.toml b/esp-hal-common/devices/esp32s3.toml index f48020155db..33f7e2c9a7f 100644 --- a/esp-hal-common/devices/esp32s3.toml +++ b/esp-hal-common/devices/esp32s3.toml @@ -61,4 +61,7 @@ peripherals = [ "adc", "gdma", "radio", + "phy", + "bt", + "wifi", ] diff --git a/esp-hal-common/ld/sections/rodata.x b/esp-hal-common/ld/sections/rodata.x index 1ac1d35db59..842087e7c88 100644 --- a/esp-hal-common/ld/sections/rodata.x +++ b/esp-hal-common/ld/sections/rodata.x @@ -9,9 +9,8 @@ SECTIONS { _rodata_end = ABSOLUTE(.); } > RODATA - .rodata.wifi : + .rodata.wifi : ALIGN(4) { - . = ALIGN(4); *( .rodata_wlog_*.* ) } > RODATA } \ No newline at end of file diff --git a/esp-hal-common/src/soc/esp32/mod.rs b/esp-hal-common/src/soc/esp32/mod.rs index 0f836b86b47..108ee6ad3df 100644 --- a/esp-hal-common/src/soc/esp32/mod.rs +++ b/esp-hal-common/src/soc/esp32/mod.rs @@ -2,3 +2,4 @@ pub mod cpu_control; pub mod efuse; pub mod gpio; pub mod peripherals; +pub mod radio_clocks; diff --git a/esp-hal-common/src/soc/esp32/radio_clocks.rs b/esp-hal-common/src/soc/esp32/radio_clocks.rs new file mode 100644 index 00000000000..8747af08d14 --- /dev/null +++ b/esp-hal-common/src/soc/esp32/radio_clocks.rs @@ -0,0 +1,84 @@ +use crate::system::{RadioClockContoller, RadioClockControl, RadioPeripherals}; + +const SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M: u32 = 0x000003c9; +const SYSTEM_WIFI_CLK_EN: u32 = 0xFFFFFFFF; + +impl RadioClockContoller for RadioClockControl { + fn enable(&mut self, peripheral: RadioPeripherals) { + match peripheral { + RadioPeripherals::Phy => enable_phy(), + RadioPeripherals::Bt => common_wifi_bt_clock_enable(), + RadioPeripherals::Wifi => common_wifi_bt_clock_enable(), + } + } + + fn disable(&mut self, peripheral: RadioPeripherals) { + match peripheral { + RadioPeripherals::Phy => disable_phy(), + RadioPeripherals::Bt => common_wifi_bt_clock_disable(), + RadioPeripherals::Wifi => common_wifi_bt_clock_disable(), + } + } + + fn reset_mac(&mut self) { + reset_mac(); + } + + fn init_clocks(&mut self) { + init_clocks(); + } + + fn ble_rtc_clk_init(&mut self) { + // nothing for this target + } + + fn reset_rpa(&mut self) { + // nothing for this target + } +} + +fn enable_phy() { + let system = unsafe { &*esp32::DPORT::PTR }; + system + .wifi_clk_en + .modify(|r, w| unsafe { w.bits(r.bits() | SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M) }); +} + +fn disable_phy() { + let system = unsafe { &*esp32::DPORT::PTR }; + system + .wifi_clk_en + .modify(|r, w| unsafe { w.bits(r.bits() & !SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M) }); +} + +fn common_wifi_bt_clock_enable() { + let system = unsafe { &*esp32::DPORT::PTR }; + system + .perip_clk_en + .modify(|r, w| unsafe { w.bits(r.bits() | SYSTEM_WIFI_CLK_EN) }); +} + +fn common_wifi_bt_clock_disable() { + let system = unsafe { &*esp32::DPORT::PTR }; + system + .perip_clk_en + .modify(|r, w| unsafe { w.bits(r.bits() & !SYSTEM_WIFI_CLK_EN) }); +} + +fn reset_mac() { + const SYSTEM_MAC_RST: u8 = 1 << 2; + let syscon = unsafe { &*esp32::DPORT::PTR }; + syscon + .core_rst_en + .modify(|r, w| unsafe { w.core_rst().bits(r.core_rst().bits() | SYSTEM_MAC_RST) }); + syscon + .core_rst_en + .modify(|r, w| unsafe { w.core_rst().bits(r.core_rst().bits() & !SYSTEM_MAC_RST) }); +} + +fn init_clocks() { + let syscon = unsafe { &*esp32::DPORT::PTR }; + syscon + .wifi_clk_en + .modify(|_, w| unsafe { w.bits(0xffffffff) }); +} diff --git a/esp-hal-common/src/soc/esp32c2/mod.rs b/esp-hal-common/src/soc/esp32c2/mod.rs index 9055fb32d54..907b45c9302 100644 --- a/esp-hal-common/src/soc/esp32c2/mod.rs +++ b/esp-hal-common/src/soc/esp32c2/mod.rs @@ -1,6 +1,7 @@ pub mod efuse; pub mod gpio; pub mod peripherals; +pub mod radio_clocks; pub(crate) mod registers { pub const INTERRUPT_MAP_BASE: u32 = 0x600c2000; diff --git a/esp-hal-common/src/soc/esp32c2/radio_clocks.rs b/esp-hal-common/src/soc/esp32c2/radio_clocks.rs new file mode 100644 index 00000000000..864e6f73924 --- /dev/null +++ b/esp-hal-common/src/soc/esp32c2/radio_clocks.rs @@ -0,0 +1,127 @@ +use crate::system::{RadioClockContoller, RadioClockControl, RadioPeripherals}; + +// Mask for clock bits used by both WIFI and Bluetooth, 0, 1, 2, 3, 7, 8, 9, 10, +// 19, 20, 21, 22, 23 +const SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M: u32 = 0x78078F; +// SYSTEM_WIFI_CLK_EN : R/W ;bitpos:[31:0] ;default: 32'hfffce030 +// from experiments `0x00FB9FCF` is not enough for esp-wifi to work +const SYSTEM_WIFI_CLK_EN: u32 = 0xFFFFFFFF; + +impl RadioClockContoller for RadioClockControl { + fn enable(&mut self, peripheral: RadioPeripherals) { + match peripheral { + RadioPeripherals::Phy => enable_phy(), + RadioPeripherals::Bt => common_wifi_bt_clock_enable(), + RadioPeripherals::Wifi => common_wifi_bt_clock_enable(), + } + } + + fn disable(&mut self, peripheral: RadioPeripherals) { + match peripheral { + RadioPeripherals::Phy => disable_phy(), + RadioPeripherals::Bt => common_wifi_bt_clock_disable(), + RadioPeripherals::Wifi => common_wifi_bt_clock_disable(), + } + } + + fn reset_mac(&mut self) { + reset_mac(); + } + + fn init_clocks(&mut self) { + init_clocks(); + } + + fn ble_rtc_clk_init(&mut self) { + ble_rtc_clk_init(); + } + + fn reset_rpa(&mut self) { + reset_rpa(); + } +} + +fn enable_phy() { + let system = unsafe { &*esp32c2::SYSTEM::PTR }; + system + .perip_clk_en1 + .modify(|r, w| unsafe { w.bits(r.bits() | SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M) }); +} + +fn disable_phy() { + let system = unsafe { &*esp32c2::SYSTEM::PTR }; + system + .perip_clk_en1 + .modify(|r, w| unsafe { w.bits(r.bits() & !SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M) }); +} + +fn common_wifi_bt_clock_enable() { + let system = unsafe { &*esp32c2::SYSTEM::PTR }; + system + .perip_clk_en1 + .modify(|r, w| unsafe { w.bits(r.bits() | SYSTEM_WIFI_CLK_EN) }); +} + +fn common_wifi_bt_clock_disable() { + let system = unsafe { &*esp32c2::SYSTEM::PTR }; + system + .perip_clk_en1 + .modify(|r, w| unsafe { w.bits(r.bits() & !SYSTEM_WIFI_CLK_EN) }); +} + +fn reset_mac() { + const SYSTEM_MAC_RST: u32 = 1 << 2; + let syscon = unsafe { &*esp32c2::APB_CTRL::PTR }; + syscon + .wifi_rst_en + .modify(|r, w| unsafe { w.wifi_rst().bits(r.wifi_rst().bits() | SYSTEM_MAC_RST) }); + syscon + .wifi_rst_en + .modify(|r, w| unsafe { w.wifi_rst().bits(r.wifi_rst().bits() & !SYSTEM_MAC_RST) }); +} + +fn init_clocks() { + let syscon = unsafe { &*esp32c2::APB_CTRL::PTR }; + syscon + .wifi_clk_en + .modify(|_, w| unsafe { w.bits(0xffffffff) }); +} + +fn ble_rtc_clk_init() { + let modem_clkrst = unsafe { &*esp32c2::MODEM_CLKRST::PTR }; + modem_clkrst + .modem_lp_timer_conf + .modify(|_, w| w.lp_timer_sel_xtal32k().clear_bit()); + modem_clkrst + .modem_lp_timer_conf + .modify(|_, w| w.lp_timer_sel_xtal().set_bit()); + modem_clkrst + .modem_lp_timer_conf + .modify(|_, w| w.lp_timer_sel_8m().clear_bit()); + modem_clkrst + .modem_lp_timer_conf + .modify(|_, w| w.lp_timer_sel_rtc_slow().clear_bit()); + + // assume 40MHz xtal + modem_clkrst + .modem_lp_timer_conf + .modify(|_, w| w.lp_timer_clk_div_num().variant(249)); + + modem_clkrst + .etm_clk_conf + .modify(|_, w| w.etm_clk_active().set_bit()); + modem_clkrst + .etm_clk_conf + .modify(|_, w| w.etm_clk_sel().clear_bit()); +} + +fn reset_rpa() { + const BLE_RPA_REST_BIT: u32 = 1 << 27; + let syscon = unsafe { &*esp32c2::APB_CTRL::PTR }; + syscon + .wifi_rst_en + .modify(|r, w| unsafe { w.bits(r.bits() | BLE_RPA_REST_BIT) }); + syscon + .wifi_rst_en + .modify(|r, w| unsafe { w.bits(r.bits() & !BLE_RPA_REST_BIT) }); +} diff --git a/esp-hal-common/src/soc/esp32c3/mod.rs b/esp-hal-common/src/soc/esp32c3/mod.rs index 9055fb32d54..907b45c9302 100644 --- a/esp-hal-common/src/soc/esp32c3/mod.rs +++ b/esp-hal-common/src/soc/esp32c3/mod.rs @@ -1,6 +1,7 @@ pub mod efuse; pub mod gpio; pub mod peripherals; +pub mod radio_clocks; pub(crate) mod registers { pub const INTERRUPT_MAP_BASE: u32 = 0x600c2000; diff --git a/esp-hal-common/src/soc/esp32c3/radio_clocks.rs b/esp-hal-common/src/soc/esp32c3/radio_clocks.rs new file mode 100644 index 00000000000..a3e64eaa5b8 --- /dev/null +++ b/esp-hal-common/src/soc/esp32c3/radio_clocks.rs @@ -0,0 +1,88 @@ +use crate::system::{RadioClockContoller, RadioClockControl, RadioPeripherals}; + +// Mask for clock bits used by both WIFI and Bluetooth, 0, 1, 2, 3, 7, 8, 9, 10, +// 19, 20, 21, 22, 23 +const SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M: u32 = 0x78078F; +// SYSTEM_WIFI_CLK_EN : R/W ;bitpos:[31:0] ;default: 32'hfffce030 +// from experiments `0x00FB9FCF` is not enough for esp-wifi to work +const SYSTEM_WIFI_CLK_EN: u32 = 0xFFFFFFFF; + +impl RadioClockContoller for RadioClockControl { + fn enable(&mut self, peripheral: RadioPeripherals) { + match peripheral { + RadioPeripherals::Phy => enable_phy(), + RadioPeripherals::Bt => common_wifi_bt_clock_enable(), + RadioPeripherals::Wifi => common_wifi_bt_clock_enable(), + } + } + + fn disable(&mut self, peripheral: RadioPeripherals) { + match peripheral { + RadioPeripherals::Phy => disable_phy(), + RadioPeripherals::Bt => common_wifi_bt_clock_disable(), + RadioPeripherals::Wifi => common_wifi_bt_clock_disable(), + } + } + + fn reset_mac(&mut self) { + reset_mac(); + } + + fn init_clocks(&mut self) { + init_clocks(); + } + + fn ble_rtc_clk_init(&mut self) { + // nothing for this target + } + + fn reset_rpa(&mut self) { + // nothing for this target + } +} + +fn enable_phy() { + let system = unsafe { &*esp32c3::SYSTEM::PTR }; + system + .perip_clk_en1 + .modify(|r, w| unsafe { w.bits(r.bits() | SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M) }); +} + +fn disable_phy() { + let system = unsafe { &*esp32c3::SYSTEM::PTR }; + system + .perip_clk_en1 + .modify(|r, w| unsafe { w.bits(r.bits() & !SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M) }); +} + +fn common_wifi_bt_clock_enable() { + let system = unsafe { &*esp32c3::SYSTEM::PTR }; + system + .perip_clk_en1 + .modify(|r, w| unsafe { w.bits(r.bits() | SYSTEM_WIFI_CLK_EN) }); +} + +fn common_wifi_bt_clock_disable() { + let system = unsafe { &*esp32c3::SYSTEM::PTR }; + system + .perip_clk_en1 + .modify(|r, w| unsafe { w.bits(r.bits() & !SYSTEM_WIFI_CLK_EN) }); +} + +fn reset_mac() { + const SYSTEM_MAC_RST: u32 = 1 << 2; + let syscon = unsafe { &*esp32c3::APB_CTRL::PTR }; + syscon + .wifi_rst_en + .modify(|r, w| unsafe { w.wifi_rst().bits(r.wifi_rst().bits() | SYSTEM_MAC_RST) }); + syscon + .wifi_rst_en + .modify(|r, w| unsafe { w.wifi_rst().bits(r.wifi_rst().bits() & !SYSTEM_MAC_RST) }); +} + +fn init_clocks() { + let syscon = unsafe { &*esp32c3::APB_CTRL::PTR }; + syscon + .wifi_clk_en + .modify(|_, w| unsafe { w.bits(0xffffffff) }); +} diff --git a/esp-hal-common/src/soc/esp32c6/mod.rs b/esp-hal-common/src/soc/esp32c6/mod.rs index 70d1fca9f09..310b8d7141c 100644 --- a/esp-hal-common/src/soc/esp32c6/mod.rs +++ b/esp-hal-common/src/soc/esp32c6/mod.rs @@ -1,6 +1,7 @@ pub mod efuse; pub mod gpio; pub mod peripherals; +pub mod radio_clocks; pub(crate) mod registers { pub const INTERRUPT_MAP_BASE: u32 = 0x60010000; diff --git a/esp-hal-common/src/soc/esp32c6/radio_clocks.rs b/esp-hal-common/src/soc/esp32c6/radio_clocks.rs new file mode 100644 index 00000000000..fabd4b464b0 --- /dev/null +++ b/esp-hal-common/src/soc/esp32c6/radio_clocks.rs @@ -0,0 +1,227 @@ +use crate::system::{RadioClockContoller, RadioClockControl, RadioPeripherals}; + +impl RadioClockContoller for RadioClockControl { + fn enable(&mut self, peripheral: RadioPeripherals) { + match peripheral { + RadioPeripherals::Phy => enable_phy(), + RadioPeripherals::Wifi => wifi_clock_enable(), + RadioPeripherals::Bt => todo!("BLE not yet supported"), + RadioPeripherals::Ieee802154 => ieee802154_clock_enable(), + } + } + + fn disable(&mut self, peripheral: RadioPeripherals) { + match peripheral { + RadioPeripherals::Phy => disable_phy(), + RadioPeripherals::Wifi => wifi_clock_disable(), + RadioPeripherals::Bt => todo!("BLE not yet supported"), + RadioPeripherals::Ieee802154 => ieee802154_clock_disable(), + } + } + + fn reset_mac(&mut self) { + reset_mac(); + } + + fn init_clocks(&mut self) { + init_clocks(); + } + + fn ble_rtc_clk_init(&mut self) { + // nothing for this target (yet) + } + + fn reset_rpa(&mut self) { + // nothing for this target (yet) + } +} + +fn enable_phy() { + let modem_lpcon = unsafe { &*esp32c6::MODEM_LPCON::PTR }; + modem_lpcon + .clk_conf + .modify(|_, w| w.clk_i2c_mst_en().set_bit()); + modem_lpcon + .i2c_mst_clk_conf + .modify(|_, w| w.clk_i2c_mst_sel_160m().set_bit()); +} + +fn disable_phy() { + let modem_lpcon = unsafe { &*esp32c6::MODEM_LPCON::PTR }; + modem_lpcon + .clk_conf + .modify(|_, w| w.clk_i2c_mst_en().clear_bit()); + modem_lpcon + .i2c_mst_clk_conf + .modify(|_, w| w.clk_i2c_mst_sel_160m().clear_bit()); +} + +fn wifi_clock_enable() { + let modem_syscon = unsafe { &*esp32c6::MODEM_SYSCON::PTR }; + let modem_lpcon = unsafe { &*esp32c6::MODEM_LPCON::PTR }; + + modem_syscon.clk_conf1.modify(|_, w| { + w.clk_wifi_apb_en() + .set_bit() + .clk_wifimac_en() + .set_bit() + .clk_fe_apb_en() + .set_bit() + .clk_fe_cal_160m_en() + .set_bit() + .clk_fe_160m_en() + .set_bit() + .clk_fe_80m_en() + .set_bit() + .clk_wifibb_160x1_en() + .set_bit() + .clk_wifibb_80x1_en() + .set_bit() + .clk_wifibb_40x1_en() + .set_bit() + .clk_wifibb_80x_en() + .set_bit() + .clk_wifibb_40x_en() + .set_bit() + .clk_wifibb_80m_en() + .set_bit() + .clk_wifibb_44m_en() + .set_bit() + .clk_wifibb_40m_en() + .set_bit() + .clk_wifibb_22m_en() + .set_bit() + }); + + modem_lpcon + .clk_conf + .modify(|_, w| w.clk_wifipwr_en().set_bit().clk_coex_en().set_bit()); +} + +fn wifi_clock_disable() { + let modem_syscon = unsafe { &*esp32c6::MODEM_SYSCON::PTR }; + let modem_lpcon = unsafe { &*esp32c6::MODEM_LPCON::PTR }; + + modem_syscon.clk_conf1.modify(|_, w| { + w.clk_wifi_apb_en() + .clear_bit() + .clk_wifimac_en() + .clear_bit() + .clk_fe_apb_en() + .clear_bit() + .clk_fe_cal_160m_en() + .clear_bit() + .clk_fe_160m_en() + .clear_bit() + .clk_fe_80m_en() + .clear_bit() + .clk_wifibb_160x1_en() + .clear_bit() + .clk_wifibb_80x1_en() + .clear_bit() + .clk_wifibb_40x1_en() + .clear_bit() + .clk_wifibb_80x_en() + .clear_bit() + .clk_wifibb_40x_en() + .clear_bit() + .clk_wifibb_80m_en() + .clear_bit() + .clk_wifibb_44m_en() + .clear_bit() + .clk_wifibb_40m_en() + .clear_bit() + .clk_wifibb_22m_en() + .clear_bit() + }); + + modem_lpcon + .clk_conf + .modify(|_, w| w.clk_wifipwr_en().clear_bit().clk_coex_en().clear_bit()); +} + +fn ieee802154_clock_enable() { + let modem_syscon = unsafe { &*esp32c6::MODEM_SYSCON::PTR }; + modem_syscon + .clk_conf + .modify(|_, w| w.clk_zb_apb_en().set_bit().clk_zb_mac_en().set_bit()); + wifi_clock_enable(); +} + +fn ieee802154_clock_disable() { + let modem_syscon = unsafe { &*esp32c6::MODEM_SYSCON::PTR }; + modem_syscon + .clk_conf + .modify(|_, w| w.clk_zb_apb_en().clear_bit().clk_zb_mac_en().clear_bit()); + wifi_clock_disable(); +} + +fn reset_mac() { + // empty +} + +fn init_clocks() { + unsafe { + let pmu = &*esp32c6::PMU::PTR; + + pmu.hp_sleep_icg_modem + .modify(|_, w| w.hp_sleep_dig_icg_modem_code().variant(0)); + pmu.hp_modem_icg_modem + .modify(|_, w| w.hp_modem_dig_icg_modem_code().variant(1)); + pmu.hp_active_icg_modem + .modify(|_, w| w.hp_active_dig_icg_modem_code().variant(2)); + pmu.imm_modem_icg + .as_ptr() + .write_volatile(pmu.imm_modem_icg.as_ptr().read_volatile() | 1 << 31); + pmu.imm_sleep_sysclk + .as_ptr() + .write_volatile(pmu.imm_sleep_sysclk.as_ptr().read_volatile() | 1 << 28); + + let modem_syscon = &*esp32c6::MODEM_SYSCON::PTR; + modem_syscon.clk_conf_power_st.modify(|_, w| { + w.clk_modem_apb_st_map() + .variant(6) + .clk_modem_peri_st_map() + .variant(4) + .clk_wifi_st_map() + .variant(6) + .clk_bt_st_map() + .variant(6) + .clk_fe_st_map() + .variant(6) + .clk_zb_st_map() + .variant(6) + }); + + let modem_lpcon = &*esp32c6::MODEM_LPCON::PTR; + modem_lpcon.clk_conf_power_st.modify(|_, w| { + w.clk_lp_apb_st_map() + .variant(6) + .clk_i2c_mst_st_map() + .variant(6) + .clk_coex_st_map() + .variant(6) + .clk_wifipwr_st_map() + .variant(6) + }); + + modem_lpcon.wifi_lp_clk_conf.modify(|_, w| { + w.clk_wifipwr_lp_sel_osc_slow() + .set_bit() + .clk_wifipwr_lp_sel_osc_fast() + .set_bit() + .clk_wifipwr_lp_sel_xtal32k() + .set_bit() + .clk_wifipwr_lp_sel_xtal() + .set_bit() + }); + + modem_lpcon + .wifi_lp_clk_conf + .modify(|_, w| w.clk_wifipwr_lp_div_num().variant(0)); + + modem_lpcon + .clk_conf + .modify(|_, w| w.clk_wifipwr_en().set_bit()); + } +} diff --git a/esp-hal-common/src/soc/esp32s2/mod.rs b/esp-hal-common/src/soc/esp32s2/mod.rs index a2670f84b98..9397b9b0292 100644 --- a/esp-hal-common/src/soc/esp32s2/mod.rs +++ b/esp-hal-common/src/soc/esp32s2/mod.rs @@ -1,3 +1,4 @@ pub mod efuse; pub mod gpio; pub mod peripherals; +pub mod radio_clocks; diff --git a/esp-hal-common/src/soc/esp32s2/radio_clocks.rs b/esp-hal-common/src/soc/esp32s2/radio_clocks.rs new file mode 100644 index 00000000000..c6ff3f98e3c --- /dev/null +++ b/esp-hal-common/src/soc/esp32s2/radio_clocks.rs @@ -0,0 +1,86 @@ +use crate::system::{RadioClockContoller, RadioClockControl, RadioPeripherals}; + +// Mask for clock bits used by both WIFI and Bluetooth, 0, 1, 2, 3, 7, 8, 9, 10, +// 19, 20, 21, 22, 23 +const SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M: u32 = 0x78078F; +// SYSTEM_WIFI_CLK_EN : R/W ;bitpos:[31:0] ;default: 32'hfffce030 +// from experiments `0x00FB9FCF` is not enough for esp-wifi to work +const SYSTEM_WIFI_CLK_EN: u32 = 0xFFFFFFFF; + +impl RadioClockContoller for RadioClockControl { + fn enable(&mut self, peripheral: RadioPeripherals) { + match peripheral { + RadioPeripherals::Phy => enable_phy(), + RadioPeripherals::Wifi => common_wifi_bt_clock_enable(), + } + } + + fn disable(&mut self, peripheral: RadioPeripherals) { + match peripheral { + RadioPeripherals::Phy => disable_phy(), + RadioPeripherals::Wifi => common_wifi_bt_clock_disable(), + } + } + + fn reset_mac(&mut self) { + reset_mac(); + } + + fn init_clocks(&mut self) { + init_clocks(); + } + + fn ble_rtc_clk_init(&mut self) { + // nothing for this target + } + + fn reset_rpa(&mut self) { + // nothing for this target + } +} + +fn enable_phy() { + let system = unsafe { &*esp32s2::SYSTEM::PTR }; + system + .perip_clk_en1 + .modify(|r, w| unsafe { w.bits(r.bits() | SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M) }); +} + +fn disable_phy() { + let system = unsafe { &*esp32s2::SYSTEM::PTR }; + system + .perip_clk_en1 + .modify(|r, w| unsafe { w.bits(r.bits() & !SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M) }); +} + +fn common_wifi_bt_clock_enable() { + let system = unsafe { &*esp32s2::SYSTEM::PTR }; + system + .perip_clk_en1 + .modify(|r, w| unsafe { w.bits(r.bits() | SYSTEM_WIFI_CLK_EN) }); +} + +fn common_wifi_bt_clock_disable() { + let system = unsafe { &*esp32s2::SYSTEM::PTR }; + system + .perip_clk_en1 + .modify(|r, w| unsafe { w.bits(r.bits() & !SYSTEM_WIFI_CLK_EN) }); +} + +fn reset_mac() { + const SYSTEM_MAC_RST: u32 = 1 << 2; + let syscon = unsafe { &*esp32s2::SYSCON::PTR }; + syscon + .wifi_rst_en + .modify(|r, w| unsafe { w.wifi_rst().bits(r.wifi_rst().bits() | SYSTEM_MAC_RST) }); + syscon + .wifi_rst_en + .modify(|r, w| unsafe { w.wifi_rst().bits(r.wifi_rst().bits() & !SYSTEM_MAC_RST) }); +} + +fn init_clocks() { + let syscon = unsafe { &*esp32s2::SYSCON::PTR }; + syscon + .wifi_clk_en + .modify(|_, w| unsafe { w.bits(0xffffffff) }); +} diff --git a/esp-hal-common/src/soc/esp32s3/mod.rs b/esp-hal-common/src/soc/esp32s3/mod.rs index 0f836b86b47..108ee6ad3df 100644 --- a/esp-hal-common/src/soc/esp32s3/mod.rs +++ b/esp-hal-common/src/soc/esp32s3/mod.rs @@ -2,3 +2,4 @@ pub mod cpu_control; pub mod efuse; pub mod gpio; pub mod peripherals; +pub mod radio_clocks; diff --git a/esp-hal-common/src/soc/esp32s3/radio_clocks.rs b/esp-hal-common/src/soc/esp32s3/radio_clocks.rs new file mode 100644 index 00000000000..a61e6433f14 --- /dev/null +++ b/esp-hal-common/src/soc/esp32s3/radio_clocks.rs @@ -0,0 +1,88 @@ +use crate::system::{RadioClockContoller, RadioClockControl, RadioPeripherals}; + +// Mask for clock bits used by both WIFI and Bluetooth, 0, 1, 2, 3, 7, 8, 9, 10, +// 19, 20, 21, 22, 23 +const SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M: u32 = 0x78078F; +// SYSTEM_WIFI_CLK_EN : R/W ;bitpos:[31:0] ;default: 32'hfffce030 +// from experiments `0x00FB9FCF` is not enough for esp-wifi to work +const SYSTEM_WIFI_CLK_EN: u32 = 0xFFFFFFFF; + +impl RadioClockContoller for RadioClockControl { + fn enable(&mut self, peripheral: RadioPeripherals) { + match peripheral { + RadioPeripherals::Phy => enable_phy(), + RadioPeripherals::Bt => common_wifi_bt_clock_enable(), + RadioPeripherals::Wifi => common_wifi_bt_clock_enable(), + } + } + + fn disable(&mut self, peripheral: RadioPeripherals) { + match peripheral { + RadioPeripherals::Phy => disable_phy(), + RadioPeripherals::Bt => common_wifi_bt_clock_disable(), + RadioPeripherals::Wifi => common_wifi_bt_clock_disable(), + } + } + + fn reset_mac(&mut self) { + reset_mac(); + } + + fn init_clocks(&mut self) { + init_clocks(); + } + + fn ble_rtc_clk_init(&mut self) { + // nothing for this target + } + + fn reset_rpa(&mut self) { + // nothing for this target + } +} + +fn enable_phy() { + let system = unsafe { &*esp32s3::SYSTEM::PTR }; + system + .perip_clk_en1 + .modify(|r, w| unsafe { w.bits(r.bits() | SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M) }); +} + +fn disable_phy() { + let system = unsafe { &*esp32s3::SYSTEM::PTR }; + system + .perip_clk_en1 + .modify(|r, w| unsafe { w.bits(r.bits() & !SYSTEM_WIFI_CLK_WIFI_BT_COMMON_M) }); +} + +fn common_wifi_bt_clock_enable() { + let system = unsafe { &*esp32s3::SYSTEM::PTR }; + system + .perip_clk_en1 + .modify(|r, w| unsafe { w.bits(r.bits() | SYSTEM_WIFI_CLK_EN) }); +} + +fn common_wifi_bt_clock_disable() { + let system = unsafe { &*esp32s3::SYSTEM::PTR }; + system + .perip_clk_en1 + .modify(|r, w| unsafe { w.bits(r.bits() & !SYSTEM_WIFI_CLK_EN) }); +} + +fn reset_mac() { + const SYSTEM_MAC_RST: u32 = 1 << 2; + let syscon = unsafe { &*esp32s3::APB_CTRL::PTR }; + syscon + .wifi_rst_en + .modify(|r, w| unsafe { w.wifi_rst().bits(r.wifi_rst().bits() | SYSTEM_MAC_RST) }); + syscon + .wifi_rst_en + .modify(|r, w| unsafe { w.wifi_rst().bits(r.wifi_rst().bits() & !SYSTEM_MAC_RST) }); +} + +fn init_clocks() { + let syscon = unsafe { &*esp32s3::APB_CTRL::PTR }; + syscon + .wifi_clk_en + .modify(|_, w| unsafe { w.bits(0xffffffff) }); +} diff --git a/esp-hal-common/src/system.rs b/esp-hal-common/src/system.rs index e31cdbcf92c..878bb75f7a5 100644 --- a/esp-hal-common/src/system.rs +++ b/esp-hal-common/src/system.rs @@ -293,6 +293,41 @@ pub struct Dma { _private: (), } +pub enum RadioPeripherals { + #[cfg(phy)] + Phy, + #[cfg(bt)] + Bt, + #[cfg(wifi)] + Wifi, + #[cfg(ieee802154)] + Ieee802154, +} + +pub struct RadioClockControl { + _private: (), +} + +/// Control the radio peripheral clocks +pub trait RadioClockContoller { + /// 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); + + fn reset_rpa(&mut self); +} + /// The SYSTEM/DPORT splitted into it's different logical parts. pub struct SystemParts<'d> { _private: PeripheralRef<'d, SystemPeripheral>, @@ -301,6 +336,7 @@ pub struct SystemParts<'d> { pub cpu_control: CpuControl, #[cfg(pdma)] pub dma: Dma, + pub radio_clock_control: RadioClockControl, } /// Extension trait to split a SYSTEM/DPORT peripheral in independent logical @@ -323,6 +359,7 @@ impl<'d, T: crate::peripheral::Peripheral

+ 'd> SystemExt< cpu_control: CpuControl { _private: () }, #[cfg(pdma)] dma: Dma { _private: () }, + radio_clock_control: RadioClockControl { _private: () }, } } }