From 48ff2212c982f9abae9c31b6df987210497bcdd8 Mon Sep 17 00:00:00 2001 From: Jesse Braham Date: Mon, 29 Jan 2024 09:28:48 -0800 Subject: [PATCH 1/7] Begin adding clock support for ESP32-P4 --- esp-hal/src/clock/mod.rs | 93 ++++++++++++++++++++++++++++++++++------ esp-hal/src/system.rs | 8 +++- 2 files changed, 88 insertions(+), 13 deletions(-) diff --git a/esp-hal/src/clock/mod.rs b/esp-hal/src/clock/mod.rs index 6d6caadf656..5c2617b178a 100644 --- a/esp-hal/src/clock/mod.rs +++ b/esp-hal/src/clock/mod.rs @@ -85,32 +85,36 @@ pub trait Clock { /// CPU clock speed #[derive(Debug, Clone, Copy)] pub enum CpuClock { - #[cfg(not(esp32h2))] + #[cfg(not(any(esp32h2, esp32p4)))] Clock80MHz, #[cfg(esp32h2)] Clock96MHz, #[cfg(esp32c2)] Clock120MHz, - #[cfg(not(any(esp32c2, esp32h2)))] + #[cfg(not(any(esp32c2, esp32h2, esp32p4)))] Clock160MHz, - #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))] + #[cfg(xtensa)] Clock240MHz, + #[cfg(esp32p4)] + Clock400MHz, } #[allow(dead_code)] impl Clock for CpuClock { fn frequency(&self) -> HertzU32 { match self { - #[cfg(not(esp32h2))] + #[cfg(not(any(esp32h2, esp32p4)))] CpuClock::Clock80MHz => HertzU32::MHz(80), #[cfg(esp32h2)] CpuClock::Clock96MHz => HertzU32::MHz(96), #[cfg(esp32c2)] CpuClock::Clock120MHz => HertzU32::MHz(120), - #[cfg(not(any(esp32c2, esp32h2)))] + #[cfg(not(any(esp32c2, esp32h2, esp32p4)))] CpuClock::Clock160MHz => HertzU32::MHz(160), - #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))] + #[cfg(xtensa)] CpuClock::Clock240MHz => HertzU32::MHz(240), + #[cfg(esp32p4)] + CpuClock::Clock400MHz => HertzU32::MHz(400), } } } @@ -164,10 +168,14 @@ pub(crate) enum PllClock { Pll160MHz, #[cfg(esp32c6)] Pll240MHz, - #[cfg(not(any(esp32c2, esp32c6, esp32h2)))] + #[cfg(not(any(esp32c2, esp32c6, esp32h2, esp32p4)))] Pll320MHz, + #[cfg(esp32p4)] + Pll400MHz, #[cfg(not(esp32h2))] Pll480MHz, + #[cfg(esp32p4)] + Pll500MHz, } impl Clock for PllClock { @@ -189,10 +197,14 @@ impl Clock for PllClock { Self::Pll160MHz => HertzU32::MHz(160), #[cfg(esp32c6)] Self::Pll240MHz => HertzU32::MHz(240), - #[cfg(not(any(esp32c2, esp32c6, esp32h2)))] + #[cfg(not(any(esp32c2, esp32c6, esp32h2, esp32p4)))] Self::Pll320MHz => HertzU32::MHz(320), + #[cfg(esp32p4)] + Self::Pll400MHz => HertzU32::MHz(400), #[cfg(not(esp32h2))] Self::Pll480MHz => HertzU32::MHz(480), + #[cfg(esp32p4)] + Self::Pll500MHz => HertzU32::MHz(500), } } } @@ -202,10 +214,12 @@ impl Clock for PllClock { pub(crate) enum ApbClock { #[cfg(esp32h2)] ApbFreq32MHz, - #[cfg(not(esp32h2))] + #[cfg(not(any(esp32h2, esp32p4)))] ApbFreq40MHz, - #[cfg(not(esp32h2))] + #[cfg(not(any(esp32h2, esp32p4)))] ApbFreq80MHz, + #[cfg(esp32p4)] + ApbFreq100MHz, ApbFreqOther(u32), } @@ -214,10 +228,12 @@ impl Clock for ApbClock { match self { #[cfg(esp32h2)] ApbClock::ApbFreq32MHz => HertzU32::MHz(32), - #[cfg(not(esp32h2))] + #[cfg(not(any(esp32h2, esp32p4)))] ApbClock::ApbFreq40MHz => HertzU32::MHz(40), - #[cfg(not(esp32h2))] + #[cfg(not(any(esp32h2, esp32p4)))] ApbClock::ApbFreq80MHz => HertzU32::MHz(80), + #[cfg(esp32p4)] + ApbClock::ApbFreq100MHz => HertzU32::MHz(100), ApbClock::ApbFreqOther(mhz) => HertzU32::MHz(*mhz), } } @@ -624,6 +640,59 @@ impl<'d> ClockControl<'d> { } } +#[cfg(esp32p4)] +impl<'d> ClockControl<'d> { + /// Use what is considered the default settings after boot. + pub fn boot_defaults( + clock_control: impl Peripheral

+ 'd, + ) -> ClockControl<'d> { + ClockControl { + _private: clock_control.into_ref(), + desired_rates: RawClocks { + cpu_clock: HertzU32::MHz(400), + apb_clock: HertzU32::MHz(100), + xtal_clock: HertzU32::MHz(40), + }, + } + } + + /// Configure the CPU clock speed. + pub fn configure( + clock_control: impl Peripheral

+ 'd, + cpu_clock_speed: CpuClock, + ) -> ClockControl<'d> { + let apb_freq; + let xtal_freq = XtalClock::RtcXtalFreq40M; + let pll_freq = PllClock::Pll480MHz; + + if cpu_clock_speed.mhz() <= xtal_freq.mhz() { + apb_freq = ApbClock::ApbFreqOther(cpu_clock_speed.mhz()); + // clocks_ll::esp32p4_rtc_update_to_xtal(xtal_freq, 1); + // clocks_ll::esp32p4_rtc_apb_freq_update(apb_freq); + } else { + apb_freq = ApbClock::ApbFreq100MHz; + // clocks_ll::esp32p4_rtc_bbpll_enable(); + // clocks_ll::esp32p4_rtc_bbpll_configure(xtal_freq, pll_freq); + // clocks_ll::esp32p4_rtc_freq_to_pll_mhz(cpu_clock_speed); + // clocks_ll::esp32p4_rtc_apb_freq_update(apb_freq); + } + + ClockControl { + _private: clock_control.into_ref(), + desired_rates: RawClocks { + cpu_clock: cpu_clock_speed.frequency(), + apb_clock: apb_freq.frequency(), + xtal_clock: xtal_freq.frequency(), + }, + } + } + + /// Use the highest possible frequency for a particular chip + pub fn max(clock_control: impl Peripheral

+ 'd) -> ClockControl<'d> { + Self::configure(clock_control, CpuClock::Clock400MHz) + } +} + #[cfg(esp32s2)] impl<'d> ClockControl<'d> { /// Use what is considered the default settings after boot. diff --git a/esp-hal/src/system.rs b/esp-hal/src/system.rs index 61b2472241f..e119147dae5 100755 --- a/esp-hal/src/system.rs +++ b/esp-hal/src/system.rs @@ -176,7 +176,7 @@ impl SoftwareInterruptControl { /// Controls the enablement of peripheral clocks. pub(crate) struct PeripheralClockControl; -#[cfg(not(any(esp32c6, esp32h2)))] +#[cfg(not(any(esp32c6, esp32h2, esp32p4)))] impl PeripheralClockControl { /// Enables and resets the given peripheral pub(crate) fn enable(peripheral: Peripheral) { @@ -605,6 +605,12 @@ impl PeripheralClockControl { } } +#[cfg(esp32p4)] +impl PeripheralClockControl { + /// Enables and resets the given peripheral + pub(crate) fn enable(_peripheral: Peripheral) {} +} + /// Controls the configuration of the chip's clocks. pub struct SystemClockControl { _private: (), From d6609aac076bab9b2fdd254f67fcb0e0c72d13de Mon Sep 17 00:00:00 2001 From: Kirill Mikhailov Date: Tue, 30 Jan 2024 17:06:41 +0100 Subject: [PATCH 2/7] WIP --- esp-hal/src/clock/clocks_ll/esp32p4.rs | 245 +++++++++++++++++++++++++ esp-hal/src/clock/mod.rs | 2 + 2 files changed, 247 insertions(+) diff --git a/esp-hal/src/clock/clocks_ll/esp32p4.rs b/esp-hal/src/clock/clocks_ll/esp32p4.rs index 8b137891791..6332ecd93b4 100644 --- a/esp-hal/src/clock/clocks_ll/esp32p4.rs +++ b/esp-hal/src/clock/clocks_ll/esp32p4.rs @@ -1 +1,246 @@ +use crate::clock::{PllClock, XtalClock}; +const DR_REG_LPPERIPH_BASE: u32 = 0x50120000; +const DR_REG_I2C_ANA_MST_BASE: u32 = DR_REG_LPPERIPH_BASE + 0x4000; + +const LPPERI_CLK_EN_REG: u32 = DR_REG_LPPERIPH_BASE + 0x0; +const LPPERI_CK_EN_LP_I2CMST: u32 = 1 << 27; + +const I2C_CPLL_OC_DCHGP_LSB: u8 = 4; +const I2C_CPLL_OC_ENB_FCAL_LSB: u8 = 7; +const I2C_CPLL_OC_DLREF_SEL_LSB: u8 = 6; +const I2C_CPLL_OC_DHREF_SEL_LSB: u8 = 4; +const I2C_ANA_MST_CLK160M_REG: u32 = DR_REG_I2C_ANA_MST_BASE + 0x34; +const I2C_ANA_MST_CLK_I2C_MST_SEL_160M: u32 = 1 << 0; + +const I2C_CPLL: u8 = 0x67; +const I2C_CPLL_HOSTID: u8 = 0; +const I2C_CPLL_OC_REF_DIV: u8 = 2; +const I2C_CPLL_OC_DIV_7_0: u8 = 3; +const I2C_CPLL_OC_DCUR: u8 = 6; + +const I2C_ANA_MST_ANA_CONF1_REG: u32 = DR_REG_I2C_ANA_MST_BASE + 0x1C; +const I2C_ANA_MST_ANA_CONF1: u32 = 0x00FFFFFF; +const I2C_ANA_MST_ANA_CONF1_V: u32 = 0xFFFFFF; +const I2C_ANA_MST_ANA_CONF1_S: u32 = 0; + +const I2C_ANA_MST_ANA_CONF2_REG: u32 = DR_REG_I2C_ANA_MST_BASE + 0x20; +const I2C_ANA_MST_ANA_CONF2: u32 = 0x00FFFFFF; +const I2C_ANA_MST_ANA_CONF2_V: u32 = 0xFFFFFF; +const I2C_ANA_MST_ANA_CONF2_S: u32 = 0; + +const REGI2C_RTC_SLAVE_ID_V: u8 = 0xFF; +const REGI2C_RTC_SLAVE_ID_S: u8 = 0; +const REGI2C_RTC_ADDR_V: u8 = 0xFF; +const REGI2C_RTC_ADDR_S: u8 = 8; +const REGI2C_RTC_WR_CNTL_V: u8 = 0x1; +const REGI2C_RTC_WR_CNTL_S: u8 = 24; +const REGI2C_RTC_DATA_V: u8 = 0xFF; +const REGI2C_RTC_DATA_S: u8 = 16; +const REGI2C_RTC_BUSY: u32 = 1 << 25; + +const I2C_ANA_MST_I2C0_CTRL_REG: u32 = DR_REG_I2C_ANA_MST_BASE + 0x0; + +const DR_REG_LPAON_BASE: u32 = 0x50110000; +const DR_REG_PMU_BASE: u32 = DR_REG_LPAON_BASE = 0x5000; +const PMU_IMM_HP_CK_POWER: u32 = DR_REG_PMU_BASE + 0xcc; +const PMU_TIE_HIGH_XPD_CPLL: u32 = 1 << 27; +const PMU_TIE_HIGH_XPD_CPLL_I2C: u32 = 1 << 23; +const PMU_TIE_HIGH_GLOBAL_CPLL_ICG: u32 = 1 << 17; + +const DR_REG_HPPERIPH1_BASE: u32 = 0x500C0000; +const DR_REG_HP_SYS_CLKRST_BASE: u32 = DR_REG_HPPERIPH1_BASE + 0x26000; +const HP_SYS_CLKRST_ANA_PLL_CTRL0: u32 = DR_REG_HP_SYS_CLKRST_BASE + 0xbc; +const HP_SYS_CLKRST_REG_CPU_PLL_CAL_STOP: u32 = 1 << 3; + +const REGI2C_DIG_REG: u8 = 0x6d; +const REGI2C_CPU_PLL: u8 = 0x67; +const REGI2C_SDIO_PLL: u8 = 0x62; +const REGI2C_BIAS: u8 = 0x6a; +const REGI2C_MSPI: u8 = 0x63; +const REGI2C_SYS_PLL: u8 = 0x66; +const REGI2C_PLLA: u8 = 0x6f; +const REGI2C_SAR_I2C: u8 = 0x69; + +const REGI2C_DIG_REG_MST_SEL: u32 = 1 << 10; +const REGI2C_PLL_CPU_MST_SEL: u32 = 1 << 11; +const REGI2C_PLL_SDIO_MST_SEL: u32 = 1 << 6; +const REGI2C_BIAS_MST_SEL: u32 = 1 << 12; +const REGI2C_MSPI_XTAL_MST_SEL: u32 = 1 << 9; +const REGI2C_PLL_SYS_MST_SEL: u32 = 1 << 5; +const REGI2C_PLLA_MST_SEL: u32 = 1 << 8; +const REGI2C_SAR_I2C_MST_SEL: u32 = 1 << 7; + +// rtc_clk.c (L125) -> clk_tree_ll.h +pub(crate) fn esp32p4_rtc_cpll_enable() { + (PMU_IMM_HP_CK_POWER as *mut u32).write_volatile( + (PMU_IMM_HP_CK_POWER as *mut u32).read_volatile() + | (PMU_TIE_HIGH_XPD_CPLL | PMU_TIE_HIGH_XPD_CPLL_I2C), + ); + + (PMU_IMM_HP_CK_POWER as *mut u32).write_volatile( + (PMU_IMM_HP_CK_POWER as *mut u32).read_volatile() | PMU_TIE_HIGH_GLOBAL_CPLL_ICG, + ) +} + +// rtc_clk.c (L136) +pub(crate) fn esp32p4_rtc_cpll_configure(_xtal_freq: XtalClock, _cpll_freq: PllClock) { + // CPLL CALIBRATION START + (HP_SYS_CLKRST_ANA_PLL_CTRL0_REG as *mut u32).write_volatile( + (HP_SYS_CLKRST_ANA_PLL_CTRL0_REG as *mut u32).read_volatile() + | !HP_SYS_CLKRST_REG_CPU_PLL_CAL_STOP, + ); + + // Set configuration + let oc_div_ref = 0u32; + let div = 1u32; + let dcur = 3u32; + let dchgp = 5u32; + let enb_fcal = 0u32; + + // Currently only supporting 40MHz XTAL + assert!(xtal_freq == XtalClock::RtcXtalFreq40M); + + match cpll_freq { + PllClock::Pll400MHz => { + div = 6u32; + dif_ref = 0u32; + } + PllClock::Pll360MHz => { + div = 5u32; + div_ref = 0u32; + } + } + + let i2c_cpll_lref = + (oc_enb_fcal << I2C_CPLL_OC_ENB_FCAL_LSB) | (dchgp << I2C_CPLL_OC_DCHGP_LSB) | (dif_ref); + + let i2c_cpll_dcur = (1 << I2C_CPLL_OC_DLREF_SEL_LSB) | (3 << I2C_CPLL_OC_DHREF_SEL_LSB) | dcur; + + regi2c_write( + I2C_CPLL, + I2C_CPLL_HOSTID, + I2C_CPLL_OC_REF_DIV, + i2c_cpll_lref, + ); + + regi2c_write(I2C_CPLL, I2C_CPLL_HOSTID, I2C_CPLL_OC_DIV_7_0, div); + + regi2c_write(I2C_CPLL, I2C_CPLL_HOSTID, I2C_CPLL_OC_DCUR, i2c_cpll_dcur); +} + +// esp_rom_regi2c_esp32p4.c (L84) +fn regi2c_enable_block(block: u8) { + reg_set_bit(LPPERI_CLK_EN_REG, LPPERI_CK_EN_LP_I2CMST); + set_peri_reg_mask(I2C_ANA_MST_CLK160M_REG, I2C_ANA_MST_CLK_I2C_MST_SEL_160M); + + reg_set_field( + I2C_ANA_MST_ANA_CONF2_REG, + I2C_ANA_MST_ANA_CONF2_V, + I2C_ANA_MST_ANA_CONF2_S, + 0, + ); + + reg_set_field( + I2C_ANA_MST_ANA_CONF1_REG, + I2C_ANA_MST_ANA_CONF1_V, + I2C_ANA_MST_ANA_CONF1_S, + 0, + ); + + match block { + REGI2C_DIG_REG => { + reg_set_bit(I2C_ANA_MST_ANA_CONF2_REG, REGI2C_DIG_REG_MST_SEL); + } + REGI2C_CPU_PLL => { + reg_set_bit(I2C_ANA_MST_ANA_CONF2_REG, REGI2C_PLL_CPU_MST_SEL); + } + REGI2C_SDIO_PLL => { + reg_set_bit(I2C_ANA_MST_ANA_CONF2_REG, REGI2C_PLL_SDIO_MST_SEL); + } + REGI2C_BIAS => { + reg_set_bit(I2C_ANA_MST_ANA_CONF2_REG, REGI2C_BIAS_MST_SEL); + } + REGI2C_MSPI => { + reg_set_bit(I2C_ANA_MST_ANA_CONF2_REG, REGI2C_MSPI_XTAL_MST_SEL); + } + REGI2C_SYS_PLL => { + reg_set_bit(I2C_ANA_MST_ANA_CONF2_REG, REGI2C_PLL_SYS_MST_SEL); + } + REGI2C_PLLA => { + reg_set_bit(I2C_ANA_MST_ANA_CONF2_REG, REGI2C_PLLA_MST_SEL); + } + REGI2C_SAR_I2C => { + reg_set_bit(I2C_ANA_MST_ANA_CONF2_REG, REGI2C_SAR_I2C_MST_SEL); + } + _ => (), + } +} + +fn regi2c_disable_block(block: u8) { + match block { + REGI2C_DIG_REG => { + reg_clr_bit(I2C_ANA_MST_ANA_CONF2_REG, REGI2C_DIG_REG_MST_SEL); + } + REGI2C_CPU_PLL => { + reg_clr_bit(I2C_ANA_MST_ANA_CONF2_REG, REGI2C_PLL_CPU_MST_SEL); + } + REGI2C_SDIO_PLL => { + reg_clr_bit(I2C_ANA_MST_ANA_CONF2_REG, REGI2C_PLL_SDIO_MST_SEL); + } + REGI2C_BIAS => { + reg_clr_bit(I2C_ANA_MST_ANA_CONF2_REG, REGI2C_BIAS_MST_SEL); + } + REGI2C_MSPI => { + reg_clr_bit(I2C_ANA_MST_ANA_CONF2_REG, REGI2C_MSPI_XTAL_MST_SEL); + } + REGI2C_SYS_PLL => { + reg_clr_bit(I2C_ANA_MST_ANA_CONF2_REG, REGI2C_PLL_SYS_MST_SEL); + } + REGI2C_PLLA => { + reg_clr_bit(I2C_ANA_MST_ANA_CONF2_REG, REGI2C_PLLA_MST_SEL); + } + REGI2C_SAR_I2C => { + reg_clr_bit(I2C_ANA_MST_ANA_CONF2_REG, REGI2C_SAR_I2C_MST_SEL); + } + _ => (), + } +} + +pub(crate) fn regi2c_write(block: u8, _host_id: u8, reg_add: u8, data: u8) { + regi2c_enable_block(block); + + let temp: u32 = ((block as u32 & REGI2C_RTC_SLAVE_ID_V as u32) << REGI2C_RTC_SLAVE_ID_S as u32) + | ((reg_add as u32 & REGI2C_RTC_ADDR_V as u32) << REGI2C_RTC_ADDR_S as u32) + | ((0x1 & REGI2C_RTC_WR_CNTL_V as u32) << REGI2C_RTC_WR_CNTL_S as u32) // 0: READ I2C register; 1: Write I2C register; + | (((data as u32) & REGI2C_RTC_DATA_V as u32) << REGI2C_RTC_DATA_S as u32); + reg_write(LP_I2C_ANA_MST_I2C0_CTRL_REG, temp); + while reg_get_bit(I2C_ANA_MST_I2C0_CTRL_REG, REGI2C_RTC_BUSY) != 0 {} + + regi2c_disable_block(block); +} + +fn reg_set_field(reg: u32, field_v: u32, field_s: u32, value: u32) { + (reg as *mut u32).write_volatile( + ((reg as *mut u32).read_volatile() & !(field_v << field_s)) + | ((value & field_v) << field_s), + ) +} + +fn reg_set_bit(reg: u32, bit: u32) { + unsafe { + (reg as *mut u32).write_volatile((reg as *mut u32).read_volatile() | bit); + } +} + +fn reg_clr_bit(reg: u32, bit: u32) { + unsafe { + (reg as *mut u32).write_volatile((reg as *mut u32).read_volatile() & !bit); + } +} + +fn set_peri_reg_mask(reg: u32, mask: u32) { + unsafe { + (reg as *mut u32).write_volatile((reg as *mut u32).read_volatile() | mask); + } +} diff --git a/esp-hal/src/clock/mod.rs b/esp-hal/src/clock/mod.rs index 5c2617b178a..64fb0a50844 100644 --- a/esp-hal/src/clock/mod.rs +++ b/esp-hal/src/clock/mod.rs @@ -171,6 +171,8 @@ pub(crate) enum PllClock { #[cfg(not(any(esp32c2, esp32c6, esp32h2, esp32p4)))] Pll320MHz, #[cfg(esp32p4)] + Pll360MHz, + #[cfg(esp32p4)] Pll400MHz, #[cfg(not(esp32h2))] Pll480MHz, From f9e32707bd2be37ca1974abf488bb7a87875104a Mon Sep 17 00:00:00 2001 From: Kirill Mikhailov Date: Thu, 1 Feb 2024 15:59:43 +0100 Subject: [PATCH 3/7] WIP: more functionality added, minor example update --- esp-hal/src/clock/clocks_ll/esp32p4.rs | 201 ++++++++++++++++++++++++- esp-hal/src/clock/mod.rs | 20 ++- esp32p4-hal/examples/hello_world.rs | 6 +- 3 files changed, 217 insertions(+), 10 deletions(-) diff --git a/esp-hal/src/clock/clocks_ll/esp32p4.rs b/esp-hal/src/clock/clocks_ll/esp32p4.rs index 6332ecd93b4..3554f017938 100644 --- a/esp-hal/src/clock/clocks_ll/esp32p4.rs +++ b/esp-hal/src/clock/clocks_ll/esp32p4.rs @@ -1,5 +1,11 @@ use crate::clock::{PllClock, XtalClock}; +extern "C" { + fn ets_update_cpu_frequency(ticks_per_us: u32); +} + +const DR_REG_LPAON_BASE: u32 = 0x50110000; +const DR_REG_LP_SYS_BASE: u32 = DR_REG_LPAON_BASE + 0x0; const DR_REG_LPPERIPH_BASE: u32 = 0x50120000; const DR_REG_I2C_ANA_MST_BASE: u32 = DR_REG_LPPERIPH_BASE + 0x4000; @@ -41,7 +47,6 @@ const REGI2C_RTC_BUSY: u32 = 1 << 25; const I2C_ANA_MST_I2C0_CTRL_REG: u32 = DR_REG_I2C_ANA_MST_BASE + 0x0; -const DR_REG_LPAON_BASE: u32 = 0x50110000; const DR_REG_PMU_BASE: u32 = DR_REG_LPAON_BASE = 0x5000; const PMU_IMM_HP_CK_POWER: u32 = DR_REG_PMU_BASE + 0xcc; const PMU_TIE_HIGH_XPD_CPLL: u32 = 1 << 27; @@ -52,6 +57,8 @@ const DR_REG_HPPERIPH1_BASE: u32 = 0x500C0000; const DR_REG_HP_SYS_CLKRST_BASE: u32 = DR_REG_HPPERIPH1_BASE + 0x26000; const HP_SYS_CLKRST_ANA_PLL_CTRL0: u32 = DR_REG_HP_SYS_CLKRST_BASE + 0xbc; const HP_SYS_CLKRST_REG_CPU_PLL_CAL_STOP: u32 = 1 << 3; +const HP_SYS_CLKRST_REG_CPU_PLL_CAL_END: u32 = 1 << 2; +const HP_SYS_CLKRST_REG_CPU_CLK_DIV_NUM_V: u32 = 0x000000FF; const REGI2C_DIG_REG: u8 = 0x6d; const REGI2C_CPU_PLL: u8 = 0x67; @@ -71,6 +78,9 @@ const REGI2C_PLL_SYS_MST_SEL: u32 = 1 << 5; const REGI2C_PLLA_MST_SEL: u32 = 1 << 8; const REGI2C_SAR_I2C_MST_SEL: u32 = 1 << 7; +const RTC_XTAL_FREQ_REG: u32 = DR_REG_LP_SYS_BASE + 0x3c; +const RTC_DISABLE_ROM_LOG: u32 = ((1 << 0) | (1 << 16)); + // rtc_clk.c (L125) -> clk_tree_ll.h pub(crate) fn esp32p4_rtc_cpll_enable() { (PMU_IMM_HP_CK_POWER as *mut u32).write_volatile( @@ -86,8 +96,8 @@ pub(crate) fn esp32p4_rtc_cpll_enable() { // rtc_clk.c (L136) pub(crate) fn esp32p4_rtc_cpll_configure(_xtal_freq: XtalClock, _cpll_freq: PllClock) { // CPLL CALIBRATION START - (HP_SYS_CLKRST_ANA_PLL_CTRL0_REG as *mut u32).write_volatile( - (HP_SYS_CLKRST_ANA_PLL_CTRL0_REG as *mut u32).read_volatile() + (HP_SYS_CLKRST_ANA_PLL_CTRL0 as *mut u32).write_volatile( + (HP_SYS_CLKRST_ANA_PLL_CTRL0 as *mut u32).read_volatile() | !HP_SYS_CLKRST_REG_CPU_PLL_CAL_STOP, ); @@ -127,6 +137,86 @@ pub(crate) fn esp32p4_rtc_cpll_configure(_xtal_freq: XtalClock, _cpll_freq: PllC regi2c_write(I2C_CPLL, I2C_CPLL_HOSTID, I2C_CPLL_OC_DIV_7_0, div); regi2c_write(I2C_CPLL, I2C_CPLL_HOSTID, I2C_CPLL_OC_DCUR, i2c_cpll_dcur); + + // Wait calibration done + while !reg_get_bit( + HP_SYS_CLKRST_ANA_PLL_CTRL0, + HP_SYS_CLKRST_REG_CPU_PLL_CAL_END, + ) {} + + // TODO requires sleep + + // CPLL calibration stop + set_peri_reg_mask( + HP_SYS_CLKRST_ANA_PLL_CTRL0, + HP_SYS_CLKRST_REG_CPU_PLL_CAL_STOP, + ); +} + +// rtc_clk.c (L161) +fn esp32p4_rtc_update_to_xtal(freq: XtalClock, _div: u8, default: bool) { + let mem_divider = 1u32; + let sys_divider = 1u32; + let apb_divider = 1u32; + + if default { + mem_divider = 2u32; + sys_divider = 2u32; + } + + //clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL -> 0) + unsafe { + (&*crate::soc::peripherals::LP_AON_CLKRST::PTR) + .lp_aonclkrst_hp_clk_ctrl + .modify(|_, w| w.lp_aonclkrst_hp_root_clk_src_sel().bits(0b00)) + } + + // clk_ll_cpu_set_divider(div, 0, 0) -> clk_tree_ll.h(comp/hal/p4/include/hal/L407) + assert(div >= 1 && div < HP_SYS_CLKRST_REG_CPU_CLK_DIV_NUM_V); + + // Set CPU divider + unsafe { + (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) + .root_clk_ctrl0 + .modify(|_, w| w.reg_cpu_clk_div_num().bits(div - 1)); + + (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) + .root_clk_ctrl0 + .modify(|_, w| w.reg_cpu_clk_div_numerator().bits(0)); + + (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) + .root_clk_ctrl0 + .modify(|_, w| w.reg_cpu_clk_div_denominator().bits(0)); + + // Set memory divider + (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) + .root_clk_ctrl1 + .modify(|_, w| w.reg_mem_clk_div_num().bits(mem_divider - 1)); + + // Set system divider + (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) + .root_clk_ctrl1 + .modify(|_, w| w.reg_sys_clk_div_num().bits(sys_divider - 1)); + + // Set APB divider + (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) + .root_clk_ctrl1 + .modify(|_, w| w.reg_apb_clk_div_num().bits(apb_divider - 1)); + + // Bus update + (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) + .root_clk_ctrl0 + .modify(|_, w| w.reg_soc_clk_div_update().set_bit()); + + while (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) + .root_clk_ctrl0 + .read() + .reg_soc_clk_div_update() + .bit_is_set() + {} + + ets_update_cpu_frequency(freq.mhz()); + } } // esp_rom_regi2c_esp32p4.c (L84) @@ -177,6 +267,111 @@ fn regi2c_enable_block(block: u8) { } } +fn esp32p4_rtc_freq_to_cpll_mhz(cpu_clock_speed: CpuClock) { + // CPLL -> CPU_CLK -> MEM_CLK -> SYS_CLK -> APB_CLK + // Constraint: MEM_CLK <= 200MHz, APB_CLK <= 100MHz + // This implies that when clock source is CPLL, + // If cpu_divider < 2, mem_divider must be larger or equal to 2 + // If cpu_divider < 2, mem_divider = 2, sys_divider < 2, apb_divider must be larger or equal to 2 + // Current available configurations: + // 360 - 360 - 180 - 180 - 90 + // 360 - 180 - 180 - 180 - 90 + // 360 - 90 - 90 - 90 - 90 + + //freq_mhz_to_config part (rtc_clk.c L251) + + // rtc_clk_xtal_freq_get() -> xtal_load_freq_mhz() + let xtal_freq_reg = unsafe { (RTC_XTAL_FREQ_REG as *mut u32).read_volatile() as u32 }; + let xtal_freq = 0u32; + + let real_freq = 0u32; + + let div_integer = 0u32; + let div_denominator = 0u32; + let div_numerator = 0u32; + + if ((xtal_freq_reg & 0xFFFF) == ((xtal_freq_reg >> 16) & 0xFFFF) + && xtal_freq_reg != 0 + && xtal_freq_reg != u32::MAX) + { + xtal_freq = xtal_freq_reg & !RTC_DISABLE_ROM_LOG & u16::MAX; + } + + // Keep default CPLL at 360 MHz + if cpu_clock_speed <= xtal_freq && cpu_clock_speed != 0 { + div_integer = xtal_freq / cpu_divider; + real_freq = (xtal_freq + div_integer / 2) / div_integer; // round + + // Check whether divider is suitable + assert!(real_freq == freq_mhz); + } else { + div_integer = 1; + } + + let mem_div = 0u32; + let sys_div = 0u32; + let apb_div = 0u32; + + match cpu_clock_speed { + CpuClock::Clock360MHz => { + mem_div = 2; + apb_div = 2; + } + CpuClock::Clock180MHz => { + mem_div = 1; + apb_div = 2; + } + CpuClock::Clock90MHz => { + mem_divider = 1; + apb_div = 1; + } + _ => { + panic!("Unsupported configuration") + } + } + + // clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_PLL); (rtc_clk.c L242) + unsafe { + (&*crate::soc::peripherals::LP_AON_CLKRST::PTR) + .lp_aonclkrst_hp_clk_ctrl + .modify(|_, w| w.lp_aonclkrst_hp_root_clk_src_sel().bits(0b01)); + + (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) + .root_clk_ctrl0 + .modify(|_, w| w.reg_cpu_clk_div_num().bits(div - 1)); + + (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) + .root_clk_ctrl0 + .modify(|_, w| w.reg_cpu_clk_div_numerator().bits(0)); + + (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) + .root_clk_ctrl0 + .modify(|_, w| w.reg_cpu_clk_div_denominator().bits(0)); + + // Set memory divider + (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) + .root_clk_ctrl1 + .modify(|_, w| w.reg_mem_clk_div_num().bits(mem_divider - 1)); + + // Set system divider + (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) + .root_clk_ctrl1 + .modify(|_, w| w.reg_sys_clk_div_num().bits(sys_divider - 1)); + + // Set APB divider + (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) + .root_clk_ctrl1 + .modify(|_, w| w.reg_apb_clk_div_num().bits(apb_divider - 1)); + + // Bus update + (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) + .root_clk_ctrl0 + .modify(|_, w| w.reg_soc_clk_div_update().set_bit()); + + ets_update_cpu_frequency(cpu_clock_speed); + } +} + fn regi2c_disable_block(block: u8) { match block { REGI2C_DIG_REG => { diff --git a/esp-hal/src/clock/mod.rs b/esp-hal/src/clock/mod.rs index 64fb0a50844..b8aa270adc2 100644 --- a/esp-hal/src/clock/mod.rs +++ b/esp-hal/src/clock/mod.rs @@ -87,15 +87,21 @@ pub trait Clock { pub enum CpuClock { #[cfg(not(any(esp32h2, esp32p4)))] Clock80MHz, + #[cfg(esp32p4)] + Clock90MHz, #[cfg(esp32h2)] Clock96MHz, #[cfg(esp32c2)] Clock120MHz, #[cfg(not(any(esp32c2, esp32h2, esp32p4)))] Clock160MHz, + #[cfg(esp32p4)] + Clock180MHz, #[cfg(xtensa)] Clock240MHz, #[cfg(esp32p4)] + Clock360MHz, + #[cfg(esp32p4)] Clock400MHz, } @@ -669,14 +675,16 @@ impl<'d> ClockControl<'d> { if cpu_clock_speed.mhz() <= xtal_freq.mhz() { apb_freq = ApbClock::ApbFreqOther(cpu_clock_speed.mhz()); - // clocks_ll::esp32p4_rtc_update_to_xtal(xtal_freq, 1); + clocks_ll::esp32p4_rtc_update_to_xtal(xtal_freq, 1, true); // clocks_ll::esp32p4_rtc_apb_freq_update(apb_freq); } else { - apb_freq = ApbClock::ApbFreq100MHz; - // clocks_ll::esp32p4_rtc_bbpll_enable(); - // clocks_ll::esp32p4_rtc_bbpll_configure(xtal_freq, pll_freq); - // clocks_ll::esp32p4_rtc_freq_to_pll_mhz(cpu_clock_speed); - // clocks_ll::esp32p4_rtc_apb_freq_update(apb_freq); + // apb_freq = ApbClock::ApbFreq100MHz; + clocks_ll::esp32p4_rtc_cpll_enable(); + // Calibrate CPLL freq to a new value requires to switch CPU clock source to XTAL first + clocks_ll::esp32h2_rtc_update_to_xtal(xtal_freq, 1, false); + clocks_ll::esp32p4_rtc_cpll_configure(xtal_freq, pll_freq); + clocks_ll::esp32p4_rtc_freq_to_cpll_mhz(cpu_clock_speed); // rtc_clk_cpu_freq_mhz_to_config blocking + // clocks_ll::esp32p4_rtc_apb_freq_update(apb_freq); } ClockControl { diff --git a/esp32p4-hal/examples/hello_world.rs b/esp32p4-hal/examples/hello_world.rs index 23c8ac5d039..49a326ee8eb 100644 --- a/esp32p4-hal/examples/hello_world.rs +++ b/esp32p4-hal/examples/hello_world.rs @@ -1,11 +1,15 @@ #![no_std] #![no_main] -use esp32p4_hal::prelude::*; +use esp32p4_hal::{clock::ClockControl, peripherals::Peripherals, prelude::*}; use esp_backtrace as _; #[entry] fn main() -> ! { + let peripherals = Peripherals::take(); + let system = peripherals.SYSTEM.split(); + let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + esp_println::println!("Hello, world!"); loop {} } From 1360c2ed9877697e5a0f4d09e04cad191613ee8a Mon Sep 17 00:00:00 2001 From: Kirill Mikhailov Date: Tue, 6 Feb 2024 13:43:47 +0100 Subject: [PATCH 4/7] WIP state (testing) --- esp-hal/src/clock/clocks_ll/esp32p4.rs | 173 ++++++++++++++----------- esp-hal/src/clock/mod.rs | 12 +- esp32p4-hal/examples/hello_world.rs | 12 +- 3 files changed, 117 insertions(+), 80 deletions(-) diff --git a/esp-hal/src/clock/clocks_ll/esp32p4.rs b/esp-hal/src/clock/clocks_ll/esp32p4.rs index 3554f017938..341b721c76d 100644 --- a/esp-hal/src/clock/clocks_ll/esp32p4.rs +++ b/esp-hal/src/clock/clocks_ll/esp32p4.rs @@ -1,4 +1,4 @@ -use crate::clock::{PllClock, XtalClock}; +use crate::clock::{Clock, CpuClock, PllClock, XtalClock}; extern "C" { fn ets_update_cpu_frequency(ticks_per_us: u32); @@ -47,7 +47,7 @@ const REGI2C_RTC_BUSY: u32 = 1 << 25; const I2C_ANA_MST_I2C0_CTRL_REG: u32 = DR_REG_I2C_ANA_MST_BASE + 0x0; -const DR_REG_PMU_BASE: u32 = DR_REG_LPAON_BASE = 0x5000; +const DR_REG_PMU_BASE: u32 = DR_REG_LPAON_BASE + 0x5000; const PMU_IMM_HP_CK_POWER: u32 = DR_REG_PMU_BASE + 0xcc; const PMU_TIE_HIGH_XPD_CPLL: u32 = 1 << 27; const PMU_TIE_HIGH_XPD_CPLL_I2C: u32 = 1 << 23; @@ -79,51 +79,56 @@ const REGI2C_PLLA_MST_SEL: u32 = 1 << 8; const REGI2C_SAR_I2C_MST_SEL: u32 = 1 << 7; const RTC_XTAL_FREQ_REG: u32 = DR_REG_LP_SYS_BASE + 0x3c; -const RTC_DISABLE_ROM_LOG: u32 = ((1 << 0) | (1 << 16)); +const RTC_DISABLE_ROM_LOG: u32 = (1 << 0) | (1 << 16); // rtc_clk.c (L125) -> clk_tree_ll.h pub(crate) fn esp32p4_rtc_cpll_enable() { - (PMU_IMM_HP_CK_POWER as *mut u32).write_volatile( - (PMU_IMM_HP_CK_POWER as *mut u32).read_volatile() - | (PMU_TIE_HIGH_XPD_CPLL | PMU_TIE_HIGH_XPD_CPLL_I2C), - ); - - (PMU_IMM_HP_CK_POWER as *mut u32).write_volatile( - (PMU_IMM_HP_CK_POWER as *mut u32).read_volatile() | PMU_TIE_HIGH_GLOBAL_CPLL_ICG, - ) + unsafe { + (PMU_IMM_HP_CK_POWER as *mut u32).write_volatile( + (PMU_IMM_HP_CK_POWER as *mut u32).read_volatile() + | (PMU_TIE_HIGH_XPD_CPLL | PMU_TIE_HIGH_XPD_CPLL_I2C), + ); + + (PMU_IMM_HP_CK_POWER as *mut u32).write_volatile( + (PMU_IMM_HP_CK_POWER as *mut u32).read_volatile() | PMU_TIE_HIGH_GLOBAL_CPLL_ICG, + ) + } } // rtc_clk.c (L136) -pub(crate) fn esp32p4_rtc_cpll_configure(_xtal_freq: XtalClock, _cpll_freq: PllClock) { +pub(crate) fn esp32p4_rtc_cpll_configure(xtal_freq: XtalClock, cpll_freq: PllClock) { // CPLL CALIBRATION START - (HP_SYS_CLKRST_ANA_PLL_CTRL0 as *mut u32).write_volatile( - (HP_SYS_CLKRST_ANA_PLL_CTRL0 as *mut u32).read_volatile() - | !HP_SYS_CLKRST_REG_CPU_PLL_CAL_STOP, - ); + unsafe { + (HP_SYS_CLKRST_ANA_PLL_CTRL0 as *mut u32).write_volatile( + (HP_SYS_CLKRST_ANA_PLL_CTRL0 as *mut u32).read_volatile() + | !HP_SYS_CLKRST_REG_CPU_PLL_CAL_STOP, + ); + } // Set configuration - let oc_div_ref = 0u32; - let div = 1u32; + let mut oc_div_ref = 0u32; + let mut div = 1u32; let dcur = 3u32; let dchgp = 5u32; let enb_fcal = 0u32; // Currently only supporting 40MHz XTAL - assert!(xtal_freq == XtalClock::RtcXtalFreq40M); + assert!(xtal_freq.mhz() == XtalClock::RtcXtalFreq40M.mhz()); match cpll_freq { PllClock::Pll400MHz => { div = 6u32; - dif_ref = 0u32; + oc_div_ref = 0u32; } PllClock::Pll360MHz => { div = 5u32; - div_ref = 0u32; + oc_div_ref = 0u32; } + _ => (), } let i2c_cpll_lref = - (oc_enb_fcal << I2C_CPLL_OC_ENB_FCAL_LSB) | (dchgp << I2C_CPLL_OC_DCHGP_LSB) | (dif_ref); + (enb_fcal << I2C_CPLL_OC_ENB_FCAL_LSB) | (dchgp << I2C_CPLL_OC_DCHGP_LSB) | (oc_div_ref); let i2c_cpll_dcur = (1 << I2C_CPLL_OC_DLREF_SEL_LSB) | (3 << I2C_CPLL_OC_DHREF_SEL_LSB) | dcur; @@ -131,18 +136,24 @@ pub(crate) fn esp32p4_rtc_cpll_configure(_xtal_freq: XtalClock, _cpll_freq: PllC I2C_CPLL, I2C_CPLL_HOSTID, I2C_CPLL_OC_REF_DIV, - i2c_cpll_lref, + i2c_cpll_lref as u8, ); - regi2c_write(I2C_CPLL, I2C_CPLL_HOSTID, I2C_CPLL_OC_DIV_7_0, div); + regi2c_write(I2C_CPLL, I2C_CPLL_HOSTID, I2C_CPLL_OC_DIV_7_0, div as u8); - regi2c_write(I2C_CPLL, I2C_CPLL_HOSTID, I2C_CPLL_OC_DCUR, i2c_cpll_dcur); + regi2c_write( + I2C_CPLL, + I2C_CPLL_HOSTID, + I2C_CPLL_OC_DCUR, + i2c_cpll_dcur as u8, + ); // Wait calibration done while !reg_get_bit( HP_SYS_CLKRST_ANA_PLL_CTRL0, HP_SYS_CLKRST_REG_CPU_PLL_CAL_END, - ) {} + ) == 1 + {} // TODO requires sleep @@ -154,9 +165,9 @@ pub(crate) fn esp32p4_rtc_cpll_configure(_xtal_freq: XtalClock, _cpll_freq: PllC } // rtc_clk.c (L161) -fn esp32p4_rtc_update_to_xtal(freq: XtalClock, _div: u8, default: bool) { - let mem_divider = 1u32; - let sys_divider = 1u32; +pub(crate) fn esp32p4_rtc_update_to_xtal(freq: XtalClock, div: u8, default: bool) { + let mut mem_divider = 1u32; + let mut sys_divider = 1u32; let apb_divider = 1u32; if default { @@ -167,49 +178,49 @@ fn esp32p4_rtc_update_to_xtal(freq: XtalClock, _div: u8, default: bool) { //clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL -> 0) unsafe { (&*crate::soc::peripherals::LP_AON_CLKRST::PTR) - .lp_aonclkrst_hp_clk_ctrl + .lp_aonclkrst_hp_clk_ctrl() .modify(|_, w| w.lp_aonclkrst_hp_root_clk_src_sel().bits(0b00)) } // clk_ll_cpu_set_divider(div, 0, 0) -> clk_tree_ll.h(comp/hal/p4/include/hal/L407) - assert(div >= 1 && div < HP_SYS_CLKRST_REG_CPU_CLK_DIV_NUM_V); + assert!(div >= 1 && (div as u32) < HP_SYS_CLKRST_REG_CPU_CLK_DIV_NUM_V); // Set CPU divider unsafe { (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) - .root_clk_ctrl0 + .root_clk_ctrl0() .modify(|_, w| w.reg_cpu_clk_div_num().bits(div - 1)); (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) - .root_clk_ctrl0 + .root_clk_ctrl0() .modify(|_, w| w.reg_cpu_clk_div_numerator().bits(0)); (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) - .root_clk_ctrl0 + .root_clk_ctrl0() .modify(|_, w| w.reg_cpu_clk_div_denominator().bits(0)); // Set memory divider (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) - .root_clk_ctrl1 - .modify(|_, w| w.reg_mem_clk_div_num().bits(mem_divider - 1)); + .root_clk_ctrl1() + .modify(|_, w| w.reg_mem_clk_div_num().bits((mem_divider - 1) as u8)); // Set system divider (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) - .root_clk_ctrl1 - .modify(|_, w| w.reg_sys_clk_div_num().bits(sys_divider - 1)); + .root_clk_ctrl1() + .modify(|_, w| w.reg_sys_clk_div_num().bits((sys_divider - 1) as u8)); // Set APB divider (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) - .root_clk_ctrl1 - .modify(|_, w| w.reg_apb_clk_div_num().bits(apb_divider - 1)); + .root_clk_ctrl2() + .modify(|_, w| w.reg_apb_clk_div_num().bits((apb_divider - 1) as u8)); // Bus update (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) - .root_clk_ctrl0 + .root_clk_ctrl0() .modify(|_, w| w.reg_soc_clk_div_update().set_bit()); while (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) - .root_clk_ctrl0 + .root_clk_ctrl0() .read() .reg_soc_clk_div_update() .bit_is_set() @@ -267,7 +278,7 @@ fn regi2c_enable_block(block: u8) { } } -fn esp32p4_rtc_freq_to_cpll_mhz(cpu_clock_speed: CpuClock) { +pub(crate) fn esp32p4_rtc_freq_to_cpll_mhz(cpu_clock_speed: CpuClock) { // CPLL -> CPU_CLK -> MEM_CLK -> SYS_CLK -> APB_CLK // Constraint: MEM_CLK <= 200MHz, APB_CLK <= 100MHz // This implies that when clock source is CPLL, @@ -282,35 +293,35 @@ fn esp32p4_rtc_freq_to_cpll_mhz(cpu_clock_speed: CpuClock) { // rtc_clk_xtal_freq_get() -> xtal_load_freq_mhz() let xtal_freq_reg = unsafe { (RTC_XTAL_FREQ_REG as *mut u32).read_volatile() as u32 }; - let xtal_freq = 0u32; + let mut xtal_freq = 0u32; - let real_freq = 0u32; + let mut real_freq = 0u32; - let div_integer = 0u32; + let mut div_integer = 0u32; let div_denominator = 0u32; - let div_numerator = 0u32; + let mut div_numerator = 0u32; - if ((xtal_freq_reg & 0xFFFF) == ((xtal_freq_reg >> 16) & 0xFFFF) + if (xtal_freq_reg & 0xFFFF) == ((xtal_freq_reg >> 16) & 0xFFFF) && xtal_freq_reg != 0 - && xtal_freq_reg != u32::MAX) + && xtal_freq_reg != u32::MAX { - xtal_freq = xtal_freq_reg & !RTC_DISABLE_ROM_LOG & u16::MAX; + xtal_freq = xtal_freq_reg & !RTC_DISABLE_ROM_LOG & u16::MAX as u32; } // Keep default CPLL at 360 MHz - if cpu_clock_speed <= xtal_freq && cpu_clock_speed != 0 { - div_integer = xtal_freq / cpu_divider; + if cpu_clock_speed.mhz() <= xtal_freq { + div_integer = xtal_freq / cpu_clock_speed.mhz(); real_freq = (xtal_freq + div_integer / 2) / div_integer; // round // Check whether divider is suitable - assert!(real_freq == freq_mhz); + assert!(real_freq == cpu_clock_speed.mhz()); } else { div_integer = 1; } - let mem_div = 0u32; - let sys_div = 0u32; - let apb_div = 0u32; + let mut mem_div = 0u32; + let mut sys_div = 0u32; + let mut apb_div = 0u32; match cpu_clock_speed { CpuClock::Clock360MHz => { @@ -322,7 +333,7 @@ fn esp32p4_rtc_freq_to_cpll_mhz(cpu_clock_speed: CpuClock) { apb_div = 2; } CpuClock::Clock90MHz => { - mem_divider = 1; + mem_div = 1; apb_div = 1; } _ => { @@ -333,42 +344,42 @@ fn esp32p4_rtc_freq_to_cpll_mhz(cpu_clock_speed: CpuClock) { // clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_PLL); (rtc_clk.c L242) unsafe { (&*crate::soc::peripherals::LP_AON_CLKRST::PTR) - .lp_aonclkrst_hp_clk_ctrl + .lp_aonclkrst_hp_clk_ctrl() .modify(|_, w| w.lp_aonclkrst_hp_root_clk_src_sel().bits(0b01)); (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) - .root_clk_ctrl0 - .modify(|_, w| w.reg_cpu_clk_div_num().bits(div - 1)); + .root_clk_ctrl0() + .modify(|_, w| w.reg_cpu_clk_div_num().bits((div_integer - 1) as u8)); (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) - .root_clk_ctrl0 + .root_clk_ctrl0() .modify(|_, w| w.reg_cpu_clk_div_numerator().bits(0)); (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) - .root_clk_ctrl0 + .root_clk_ctrl0() .modify(|_, w| w.reg_cpu_clk_div_denominator().bits(0)); // Set memory divider (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) - .root_clk_ctrl1 - .modify(|_, w| w.reg_mem_clk_div_num().bits(mem_divider - 1)); + .root_clk_ctrl1() + .modify(|_, w| w.reg_mem_clk_div_num().bits((mem_div - 1) as u8)); // Set system divider (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) - .root_clk_ctrl1 - .modify(|_, w| w.reg_sys_clk_div_num().bits(sys_divider - 1)); + .root_clk_ctrl1() + .modify(|_, w| w.reg_sys_clk_div_num().bits((sys_div - 1) as u8)); // Set APB divider (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) - .root_clk_ctrl1 - .modify(|_, w| w.reg_apb_clk_div_num().bits(apb_divider - 1)); + .root_clk_ctrl2() + .modify(|_, w| w.reg_apb_clk_div_num().bits((apb_div - 1) as u8)); // Bus update (&*crate::soc::peripherals::HP_SYS_CLKRST::PTR) - .root_clk_ctrl0 + .root_clk_ctrl0() .modify(|_, w| w.reg_soc_clk_div_update().set_bit()); - ets_update_cpu_frequency(cpu_clock_speed); + ets_update_cpu_frequency(cpu_clock_speed.mhz()); } } @@ -409,17 +420,19 @@ pub(crate) fn regi2c_write(block: u8, _host_id: u8, reg_add: u8, data: u8) { | ((reg_add as u32 & REGI2C_RTC_ADDR_V as u32) << REGI2C_RTC_ADDR_S as u32) | ((0x1 & REGI2C_RTC_WR_CNTL_V as u32) << REGI2C_RTC_WR_CNTL_S as u32) // 0: READ I2C register; 1: Write I2C register; | (((data as u32) & REGI2C_RTC_DATA_V as u32) << REGI2C_RTC_DATA_S as u32); - reg_write(LP_I2C_ANA_MST_I2C0_CTRL_REG, temp); + reg_write(I2C_ANA_MST_I2C0_CTRL_REG, temp); while reg_get_bit(I2C_ANA_MST_I2C0_CTRL_REG, REGI2C_RTC_BUSY) != 0 {} regi2c_disable_block(block); } fn reg_set_field(reg: u32, field_v: u32, field_s: u32, value: u32) { - (reg as *mut u32).write_volatile( - ((reg as *mut u32).read_volatile() & !(field_v << field_s)) - | ((value & field_v) << field_s), - ) + unsafe { + (reg as *mut u32).write_volatile( + ((reg as *mut u32).read_volatile() & !(field_v << field_s)) + | ((value & field_v) << field_s), + ) + } } fn reg_set_bit(reg: u32, bit: u32) { @@ -428,6 +441,16 @@ fn reg_set_bit(reg: u32, bit: u32) { } } +fn reg_write(reg: u32, v: u32) { + unsafe { + (reg as *mut u32).write_volatile(v); + } +} + +fn reg_get_bit(reg: u32, b: u32) -> u32 { + unsafe { (reg as *mut u32).read_volatile() & b } +} + fn reg_clr_bit(reg: u32, bit: u32) { unsafe { (reg as *mut u32).write_volatile((reg as *mut u32).read_volatile() & !bit); diff --git a/esp-hal/src/clock/mod.rs b/esp-hal/src/clock/mod.rs index b8aa270adc2..a9b198da0a4 100644 --- a/esp-hal/src/clock/mod.rs +++ b/esp-hal/src/clock/mod.rs @@ -111,15 +111,21 @@ impl Clock for CpuClock { match self { #[cfg(not(any(esp32h2, esp32p4)))] CpuClock::Clock80MHz => HertzU32::MHz(80), + #[cfg(esp32p4)] + CpuClock::Clock90MHz => HertzU32::MHz(90), #[cfg(esp32h2)] CpuClock::Clock96MHz => HertzU32::MHz(96), #[cfg(esp32c2)] CpuClock::Clock120MHz => HertzU32::MHz(120), #[cfg(not(any(esp32c2, esp32h2, esp32p4)))] CpuClock::Clock160MHz => HertzU32::MHz(160), + #[cfg(esp32p4)] + CpuClock::Clock180MHz => HertzU32::MHz(180), #[cfg(xtensa)] CpuClock::Clock240MHz => HertzU32::MHz(240), #[cfg(esp32p4)] + CpuClock::Clock360MHz => HertzU32::MHz(360), + #[cfg(esp32p4)] CpuClock::Clock400MHz => HertzU32::MHz(400), } } @@ -208,6 +214,8 @@ impl Clock for PllClock { #[cfg(not(any(esp32c2, esp32c6, esp32h2, esp32p4)))] Self::Pll320MHz => HertzU32::MHz(320), #[cfg(esp32p4)] + Self::Pll360MHz => HertzU32::MHz(360), + #[cfg(esp32p4)] Self::Pll400MHz => HertzU32::MHz(400), #[cfg(not(esp32h2))] Self::Pll480MHz => HertzU32::MHz(480), @@ -678,10 +686,10 @@ impl<'d> ClockControl<'d> { clocks_ll::esp32p4_rtc_update_to_xtal(xtal_freq, 1, true); // clocks_ll::esp32p4_rtc_apb_freq_update(apb_freq); } else { - // apb_freq = ApbClock::ApbFreq100MHz; + apb_freq = ApbClock::ApbFreq100MHz; clocks_ll::esp32p4_rtc_cpll_enable(); // Calibrate CPLL freq to a new value requires to switch CPU clock source to XTAL first - clocks_ll::esp32h2_rtc_update_to_xtal(xtal_freq, 1, false); + clocks_ll::esp32p4_rtc_update_to_xtal(xtal_freq, 1, false); clocks_ll::esp32p4_rtc_cpll_configure(xtal_freq, pll_freq); clocks_ll::esp32p4_rtc_freq_to_cpll_mhz(cpu_clock_speed); // rtc_clk_cpu_freq_mhz_to_config blocking // clocks_ll::esp32p4_rtc_apb_freq_update(apb_freq); diff --git a/esp32p4-hal/examples/hello_world.rs b/esp32p4-hal/examples/hello_world.rs index 49a326ee8eb..eb256eec76b 100644 --- a/esp32p4-hal/examples/hello_world.rs +++ b/esp32p4-hal/examples/hello_world.rs @@ -1,7 +1,9 @@ #![no_std] #![no_main] -use esp32p4_hal::{clock::ClockControl, peripherals::Peripherals, prelude::*}; +use esp32p4_hal::{ + clock::ClockControl, peripherals::Peripherals, prelude::*, system::SystemExt, Delay, +}; use esp_backtrace as _; #[entry] @@ -10,6 +12,10 @@ fn main() -> ! { let system = peripherals.SYSTEM.split(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - esp_println::println!("Hello, world!"); - loop {} + let mut delay = Delay::new(&clocks); + + loop { + esp_println::println!("Hello, world!"); + delay.delay_ms(1000 as u32); + } } From 6ff43b51fa641d1235948642e45c16cc5baef457 Mon Sep 17 00:00:00 2001 From: Kirill Mikhailov Date: Wed, 7 Feb 2024 14:30:29 +0100 Subject: [PATCH 5/7] Format --- esp-hal/src/clock/clocks_ll/esp32p4.rs | 15 ++++++++------- esp-hal/src/clock/mod.rs | 7 +++---- esp32p4-hal/examples/hello_world.rs | 10 +++------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/esp-hal/src/clock/clocks_ll/esp32p4.rs b/esp-hal/src/clock/clocks_ll/esp32p4.rs index 341b721c76d..53fb58b93e1 100644 --- a/esp-hal/src/clock/clocks_ll/esp32p4.rs +++ b/esp-hal/src/clock/clocks_ll/esp32p4.rs @@ -175,14 +175,15 @@ pub(crate) fn esp32p4_rtc_update_to_xtal(freq: XtalClock, div: u8, default: bool sys_divider = 2u32; } - //clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL -> 0) + // clk_ll_cpu_set_src(SOC_CPU_CLK_SRC_XTAL -> 0) unsafe { (&*crate::soc::peripherals::LP_AON_CLKRST::PTR) .lp_aonclkrst_hp_clk_ctrl() .modify(|_, w| w.lp_aonclkrst_hp_root_clk_src_sel().bits(0b00)) } - // clk_ll_cpu_set_divider(div, 0, 0) -> clk_tree_ll.h(comp/hal/p4/include/hal/L407) + // clk_ll_cpu_set_divider(div, 0, 0) -> + // clk_tree_ll.h(comp/hal/p4/include/hal/L407) assert!(div >= 1 && (div as u32) < HP_SYS_CLKRST_REG_CPU_CLK_DIV_NUM_V); // Set CPU divider @@ -282,14 +283,14 @@ pub(crate) fn esp32p4_rtc_freq_to_cpll_mhz(cpu_clock_speed: CpuClock) { // CPLL -> CPU_CLK -> MEM_CLK -> SYS_CLK -> APB_CLK // Constraint: MEM_CLK <= 200MHz, APB_CLK <= 100MHz // This implies that when clock source is CPLL, - // If cpu_divider < 2, mem_divider must be larger or equal to 2 - // If cpu_divider < 2, mem_divider = 2, sys_divider < 2, apb_divider must be larger or equal to 2 - // Current available configurations: - // 360 - 360 - 180 - 180 - 90 + // If cpu_divider < 2, mem_divider must be larger or equal to + // 2 If cpu_divider < 2, mem_divider = 2, sys_divider < 2, + // apb_divider must be larger or equal to 2 Current available + // configurations: 360 - 360 - 180 - 180 - 90 // 360 - 180 - 180 - 180 - 90 // 360 - 90 - 90 - 90 - 90 - //freq_mhz_to_config part (rtc_clk.c L251) + // freq_mhz_to_config part (rtc_clk.c L251) // rtc_clk_xtal_freq_get() -> xtal_load_freq_mhz() let xtal_freq_reg = unsafe { (RTC_XTAL_FREQ_REG as *mut u32).read_volatile() as u32 }; diff --git a/esp-hal/src/clock/mod.rs b/esp-hal/src/clock/mod.rs index a9b198da0a4..2efb060562c 100644 --- a/esp-hal/src/clock/mod.rs +++ b/esp-hal/src/clock/mod.rs @@ -684,15 +684,14 @@ impl<'d> ClockControl<'d> { if cpu_clock_speed.mhz() <= xtal_freq.mhz() { apb_freq = ApbClock::ApbFreqOther(cpu_clock_speed.mhz()); clocks_ll::esp32p4_rtc_update_to_xtal(xtal_freq, 1, true); - // clocks_ll::esp32p4_rtc_apb_freq_update(apb_freq); } else { apb_freq = ApbClock::ApbFreq100MHz; clocks_ll::esp32p4_rtc_cpll_enable(); - // Calibrate CPLL freq to a new value requires to switch CPU clock source to XTAL first + // Calibrate CPLL freq to a new value requires to switch CPU clock source to + // XTAL first clocks_ll::esp32p4_rtc_update_to_xtal(xtal_freq, 1, false); clocks_ll::esp32p4_rtc_cpll_configure(xtal_freq, pll_freq); - clocks_ll::esp32p4_rtc_freq_to_cpll_mhz(cpu_clock_speed); // rtc_clk_cpu_freq_mhz_to_config blocking - // clocks_ll::esp32p4_rtc_apb_freq_update(apb_freq); + clocks_ll::esp32p4_rtc_freq_to_cpll_mhz(cpu_clock_speed); } ClockControl { diff --git a/esp32p4-hal/examples/hello_world.rs b/esp32p4-hal/examples/hello_world.rs index eb256eec76b..a128642082f 100644 --- a/esp32p4-hal/examples/hello_world.rs +++ b/esp32p4-hal/examples/hello_world.rs @@ -10,12 +10,8 @@ use esp_backtrace as _; fn main() -> ! { let peripherals = Peripherals::take(); let system = peripherals.SYSTEM.split(); - let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock360MHz).freeze(); - let mut delay = Delay::new(&clocks); - - loop { - esp_println::println!("Hello, world!"); - delay.delay_ms(1000 as u32); - } + esp_println::println!("Hello, world!"); + loop {} } From e529c6488d6fa82ad984e6d45c39cc6e64ac05d4 Mon Sep 17 00:00:00 2001 From: Kirill Mikhailov Date: Wed, 7 Feb 2024 15:19:55 +0100 Subject: [PATCH 6/7] Finalizing + populating reset_reason enum --- CHANGELOG.md | 1 + esp-hal/ld/esp32p4/rom-functions.x | 3 + esp-hal/src/clock/clocks_ll/esp32p4.rs | 6 +- esp-hal/src/rtc_cntl/rtc/esp32p4.rs | 96 ++++++++++++++++++++++++++ esp32p4-hal/examples/hello_world.rs | 7 +- 5 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 esp-hal/src/rtc_cntl/rtc/esp32p4.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 0eb73c40418..5f55ae54be1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Allow for splitting of the USB Serial JTAG peripheral into tx/rx components (#1024) - `RngCore` trait is implemented (#1122) - Support Rust's `stack-protector` feature (#1135) +- Adding clock support for `ESP32-P4` (#1145) ### Fixed diff --git a/esp-hal/ld/esp32p4/rom-functions.x b/esp-hal/ld/esp32p4/rom-functions.x index e69de29bb2d..530978401e1 100644 --- a/esp-hal/ld/esp32p4/rom-functions.x +++ b/esp-hal/ld/esp32p4/rom-functions.x @@ -0,0 +1,3 @@ +ets_update_cpu_frequency = 0x4fc00044; +ets_printf = 0x4fc00024; +PROVIDE(ets_delay_us = 0x4fc0003c); diff --git a/esp-hal/src/clock/clocks_ll/esp32p4.rs b/esp-hal/src/clock/clocks_ll/esp32p4.rs index 53fb58b93e1..d7c4de3a68f 100644 --- a/esp-hal/src/clock/clocks_ll/esp32p4.rs +++ b/esp-hal/src/clock/clocks_ll/esp32p4.rs @@ -2,6 +2,8 @@ use crate::clock::{Clock, CpuClock, PllClock, XtalClock}; extern "C" { fn ets_update_cpu_frequency(ticks_per_us: u32); + fn ets_delay_us(delay: u32); + } const DR_REG_LPAON_BASE: u32 = 0x50110000; @@ -155,7 +157,9 @@ pub(crate) fn esp32p4_rtc_cpll_configure(xtal_freq: XtalClock, cpll_freq: PllClo ) == 1 {} - // TODO requires sleep + unsafe { + ets_delay_us(10); + } // CPLL calibration stop set_peri_reg_mask( diff --git a/esp-hal/src/rtc_cntl/rtc/esp32p4.rs b/esp-hal/src/rtc_cntl/rtc/esp32p4.rs new file mode 100644 index 00000000000..3bd82eb564c --- /dev/null +++ b/esp-hal/src/rtc_cntl/rtc/esp32p4.rs @@ -0,0 +1,96 @@ +use fugit::HertzU32; +use strum::FromRepr; + +use crate::clock::Clock; + +pub(crate) fn init() { + todo!() +} + +pub(crate) fn configure_clock() { + todo!() +} + +// Terminology: +// +// CPU Reset: Reset CPU core only, once reset done, CPU will execute from +// reset vector +// Core Reset: Reset the whole digital system except RTC sub-system +// System Reset: Reset the whole digital system, including RTC sub-system +// Chip Reset: Reset the whole chip, including the analog part + +// spc/p4/include/soc/reset_reasons.h +#[derive(Debug, Clone, Copy, PartialEq, Eq, FromRepr)] +pub enum SocResetReason { + /// Power on reset + /// + /// In ESP-IDF this value (0x01) can *also* be `ChipBrownOut` or + /// `ChipSuperWdt`, however that is not really compatible with Rust-style + /// enums. + ChipPowerOn = 0x01, + /// Software resets the digital core by RTC_CNTL_SW_SYS_RST + CoreSw = 0x03, + /// Deep sleep reset the digital core + CoreDeepSleep = 0x05, + // PMU HP power down system reset + SysPmuPwrDown = 0x05, + // PMU HP power down CPU reset + CpuPmuPwrDown = 0x06, + /// HP watch dog resets system + SysHpWdt = 0x07, + /// LP watch dog resets system + SysLpWdt = 0x09, + /// HP watch dog resets digital core + CoreHpWdt = 0x0B, + /// Software resets CPU 0 + Cpu0Sw = 0x0C, + /// LP watch dog resets digital core + CpuLpWdt = 0x0D, + /// VDD voltage is not stable and resets the digital core + SysBrownOut = 0x0F, + /// LP watch dog resets chip + ChipLpWdt = 0x10, + /// Super watch dog resets the digital core and rtc module + SysSuperWdt = 0x12, + /// Glitch on clock resets the digital core and rtc module + SysClkGlitch = 0x13, + /// eFuse CRC error resets the digital core + CoreEfuseCrc = 0x14, + /// USB JTAG resets the digital core + CoreUsbJtag = 0x16, + // USB Serial/JTAG controller's UART resets the digital core + CoreUsbUart = 0x17, + // Glitch on power resets the digital core + CpuJtag = 0x18, +} + +/// RTC SLOW_CLK frequency values +#[derive(Debug, Clone, Copy)] +pub(crate) enum RtcFastClock {} + +impl Clock for RtcFastClock { + fn frequency(&self) -> HertzU32 { + todo!() + } +} + +/// RTC SLOW_CLK frequency values +#[derive(Debug, Clone, Copy, PartialEq)] +pub(crate) enum RtcSlowClock {} + +impl Clock for RtcSlowClock { + fn frequency(&self) -> HertzU32 { + todo!() + } +} + +/// RTC Watchdog Timer +pub struct RtcClock; + +/// RTC Watchdog Timer driver +impl RtcClock { + /// Calculate the necessary RTC_SLOW_CLK cycles to complete 1 millisecond. + pub(crate) fn cycles_to_1ms() -> u16 { + todo!() + } +} diff --git a/esp32p4-hal/examples/hello_world.rs b/esp32p4-hal/examples/hello_world.rs index a128642082f..341a8535589 100644 --- a/esp32p4-hal/examples/hello_world.rs +++ b/esp32p4-hal/examples/hello_world.rs @@ -2,7 +2,10 @@ #![no_main] use esp32p4_hal::{ - clock::ClockControl, peripherals::Peripherals, prelude::*, system::SystemExt, Delay, + clock::{ClockControl, CpuClock}, + peripherals::Peripherals, + prelude::*, + system::SystemExt, }; use esp_backtrace as _; @@ -10,7 +13,7 @@ use esp_backtrace as _; fn main() -> ! { let peripherals = Peripherals::take(); let system = peripherals.SYSTEM.split(); - let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock360MHz).freeze(); + let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock90MHz).freeze(); esp_println::println!("Hello, world!"); loop {} From be02202f30f9cb7224869faecd49618ac4eced0b Mon Sep 17 00:00:00 2001 From: Kirill Mikhailov <62840029+playfulFence@users.noreply.github.com> Date: Wed, 7 Feb 2024 19:12:41 +0100 Subject: [PATCH 7/7] Update esp-pacs dependency --- esp-hal/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esp-hal/Cargo.toml b/esp-hal/Cargo.toml index 975e3cffe5e..9c7cc865d6c 100644 --- a/esp-hal/Cargo.toml +++ b/esp-hal/Cargo.toml @@ -65,9 +65,9 @@ ufmt-write = { version = "0.1.0", optional = true } esp32 = { version = "0.28.0", features = ["critical-section"], optional = true } esp32c2 = { version = "0.17.0", features = ["critical-section"], optional = true } esp32c3 = { version = "0.20.0", features = ["critical-section"], optional = true } -esp32c6 = { git = "https://github.com/esp-rs/esp-pacs", rev = "a066f0e", features = ["critical-section"], optional = true } -esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "a066f0e", features = ["critical-section"], optional = true } -esp32p4 = { git = "https://github.com/esp-rs/esp-pacs", rev = "a066f0e", features = ["critical-section"], optional = true } +esp32c6 = { git = "https://github.com/esp-rs/esp-pacs", rev = "9cd33c6", features = ["critical-section"], optional = true } +esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "9cd33c6", features = ["critical-section"], optional = true } +esp32p4 = { git = "https://github.com/esp-rs/esp-pacs", rev = "9cd33c6", features = ["critical-section"], optional = true } esp32s2 = { version = "0.19.0", features = ["critical-section"], optional = true } esp32s3 = { version = "0.23.0", features = ["critical-section"], optional = true }