Adding clock support for ESP32-P4 (#1145)

* Begin adding clock support for ESP32-P4

* WIP

* WIP: more functionality added, minor example update

* WIP state (testing)

* Format

* Finalizing + populating reset_reason enum

* Update esp-pacs dependency

---------

Co-authored-by: Jesse Braham <jesse@beta7.io>
This commit is contained in:
Kirill Mikhailov 2024-02-07 20:35:25 +01:00 committed by GitHub
parent ac07f3c460
commit a08b38d231
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 686 additions and 17 deletions

View File

@ -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) - Allow for splitting of the USB Serial JTAG peripheral into tx/rx components (#1024)
- `RngCore` trait is implemented (#1122) - `RngCore` trait is implemented (#1122)
- Support Rust's `stack-protector` feature (#1135) - Support Rust's `stack-protector` feature (#1135)
- Adding clock support for `ESP32-P4` (#1145)
### Fixed ### Fixed

View File

@ -65,9 +65,9 @@ ufmt-write = { version = "0.1.0", optional = true }
esp32 = { version = "0.28.0", features = ["critical-section"], optional = true } esp32 = { version = "0.28.0", features = ["critical-section"], optional = true }
esp32c2 = { version = "0.17.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 } 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 } 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 = "a066f0e", 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 = "a066f0e", 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 } esp32s2 = { version = "0.19.0", features = ["critical-section"], optional = true }
esp32s3 = { version = "0.23.0", features = ["critical-section"], optional = true } esp32s3 = { version = "0.23.0", features = ["critical-section"], optional = true }

View File

@ -0,0 +1,3 @@
ets_update_cpu_frequency = 0x4fc00044;
ets_printf = 0x4fc00024;
PROVIDE(ets_delay_us = 0x4fc0003c);

View File

@ -1 +1,469 @@
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;
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;
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_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 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;
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;
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() {
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) {
// CPLL CALIBRATION START
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 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.mhz() == XtalClock::RtcXtalFreq40M.mhz());
match cpll_freq {
PllClock::Pll400MHz => {
div = 6u32;
oc_div_ref = 0u32;
}
PllClock::Pll360MHz => {
div = 5u32;
oc_div_ref = 0u32;
}
_ => (),
}
let i2c_cpll_lref =
(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;
regi2c_write(
I2C_CPLL,
I2C_CPLL_HOSTID,
I2C_CPLL_OC_REF_DIV,
i2c_cpll_lref as u8,
);
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 as u8,
);
// Wait calibration done
while !reg_get_bit(
HP_SYS_CLKRST_ANA_PLL_CTRL0,
HP_SYS_CLKRST_REG_CPU_PLL_CAL_END,
) == 1
{}
unsafe {
ets_delay_us(10);
}
// 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)
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 {
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 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()
.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) 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) as u8));
// Set APB divider
(&*crate::soc::peripherals::HP_SYS_CLKRST::PTR)
.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()
.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)
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);
}
_ => (),
}
}
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
// 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 mut xtal_freq = 0u32;
let mut real_freq = 0u32;
let mut div_integer = 0u32;
let div_denominator = 0u32;
let mut 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 as u32;
}
// Keep default CPLL at 360 MHz
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 == cpu_clock_speed.mhz());
} else {
div_integer = 1;
}
let mut mem_div = 0u32;
let mut sys_div = 0u32;
let mut 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_div = 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_integer - 1) as u8));
(&*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_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_div - 1) as u8));
// Set APB divider
(&*crate::soc::peripherals::HP_SYS_CLKRST::PTR)
.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()
.modify(|_, w| w.reg_soc_clk_div_update().set_bit());
ets_update_cpu_frequency(cpu_clock_speed.mhz());
}
}
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(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) {
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) {
unsafe {
(reg as *mut u32).write_volatile((reg as *mut u32).read_volatile() | bit);
}
}
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);
}
}
fn set_peri_reg_mask(reg: u32, mask: u32) {
unsafe {
(reg as *mut u32).write_volatile((reg as *mut u32).read_volatile() | mask);
}
}

View File

@ -85,32 +85,48 @@ pub trait Clock {
/// CPU clock speed /// CPU clock speed
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum CpuClock { pub enum CpuClock {
#[cfg(not(esp32h2))] #[cfg(not(any(esp32h2, esp32p4)))]
Clock80MHz, Clock80MHz,
#[cfg(esp32p4)]
Clock90MHz,
#[cfg(esp32h2)] #[cfg(esp32h2)]
Clock96MHz, Clock96MHz,
#[cfg(esp32c2)] #[cfg(esp32c2)]
Clock120MHz, Clock120MHz,
#[cfg(not(any(esp32c2, esp32h2)))] #[cfg(not(any(esp32c2, esp32h2, esp32p4)))]
Clock160MHz, Clock160MHz,
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))] #[cfg(esp32p4)]
Clock180MHz,
#[cfg(xtensa)]
Clock240MHz, Clock240MHz,
#[cfg(esp32p4)]
Clock360MHz,
#[cfg(esp32p4)]
Clock400MHz,
} }
#[allow(dead_code)] #[allow(dead_code)]
impl Clock for CpuClock { impl Clock for CpuClock {
fn frequency(&self) -> HertzU32 { fn frequency(&self) -> HertzU32 {
match self { match self {
#[cfg(not(esp32h2))] #[cfg(not(any(esp32h2, esp32p4)))]
CpuClock::Clock80MHz => HertzU32::MHz(80), CpuClock::Clock80MHz => HertzU32::MHz(80),
#[cfg(esp32p4)]
CpuClock::Clock90MHz => HertzU32::MHz(90),
#[cfg(esp32h2)] #[cfg(esp32h2)]
CpuClock::Clock96MHz => HertzU32::MHz(96), CpuClock::Clock96MHz => HertzU32::MHz(96),
#[cfg(esp32c2)] #[cfg(esp32c2)]
CpuClock::Clock120MHz => HertzU32::MHz(120), CpuClock::Clock120MHz => HertzU32::MHz(120),
#[cfg(not(any(esp32c2, esp32h2)))] #[cfg(not(any(esp32c2, esp32h2, esp32p4)))]
CpuClock::Clock160MHz => HertzU32::MHz(160), CpuClock::Clock160MHz => HertzU32::MHz(160),
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))] #[cfg(esp32p4)]
CpuClock::Clock180MHz => HertzU32::MHz(180),
#[cfg(xtensa)]
CpuClock::Clock240MHz => HertzU32::MHz(240), CpuClock::Clock240MHz => HertzU32::MHz(240),
#[cfg(esp32p4)]
CpuClock::Clock360MHz => HertzU32::MHz(360),
#[cfg(esp32p4)]
CpuClock::Clock400MHz => HertzU32::MHz(400),
} }
} }
} }
@ -164,10 +180,16 @@ pub(crate) enum PllClock {
Pll160MHz, Pll160MHz,
#[cfg(esp32c6)] #[cfg(esp32c6)]
Pll240MHz, Pll240MHz,
#[cfg(not(any(esp32c2, esp32c6, esp32h2)))] #[cfg(not(any(esp32c2, esp32c6, esp32h2, esp32p4)))]
Pll320MHz, Pll320MHz,
#[cfg(esp32p4)]
Pll360MHz,
#[cfg(esp32p4)]
Pll400MHz,
#[cfg(not(esp32h2))] #[cfg(not(esp32h2))]
Pll480MHz, Pll480MHz,
#[cfg(esp32p4)]
Pll500MHz,
} }
impl Clock for PllClock { impl Clock for PllClock {
@ -189,10 +211,16 @@ impl Clock for PllClock {
Self::Pll160MHz => HertzU32::MHz(160), Self::Pll160MHz => HertzU32::MHz(160),
#[cfg(esp32c6)] #[cfg(esp32c6)]
Self::Pll240MHz => HertzU32::MHz(240), Self::Pll240MHz => HertzU32::MHz(240),
#[cfg(not(any(esp32c2, esp32c6, esp32h2)))] #[cfg(not(any(esp32c2, esp32c6, esp32h2, esp32p4)))]
Self::Pll320MHz => HertzU32::MHz(320), Self::Pll320MHz => HertzU32::MHz(320),
#[cfg(esp32p4)]
Self::Pll360MHz => HertzU32::MHz(360),
#[cfg(esp32p4)]
Self::Pll400MHz => HertzU32::MHz(400),
#[cfg(not(esp32h2))] #[cfg(not(esp32h2))]
Self::Pll480MHz => HertzU32::MHz(480), Self::Pll480MHz => HertzU32::MHz(480),
#[cfg(esp32p4)]
Self::Pll500MHz => HertzU32::MHz(500),
} }
} }
} }
@ -202,10 +230,12 @@ impl Clock for PllClock {
pub(crate) enum ApbClock { pub(crate) enum ApbClock {
#[cfg(esp32h2)] #[cfg(esp32h2)]
ApbFreq32MHz, ApbFreq32MHz,
#[cfg(not(esp32h2))] #[cfg(not(any(esp32h2, esp32p4)))]
ApbFreq40MHz, ApbFreq40MHz,
#[cfg(not(esp32h2))] #[cfg(not(any(esp32h2, esp32p4)))]
ApbFreq80MHz, ApbFreq80MHz,
#[cfg(esp32p4)]
ApbFreq100MHz,
ApbFreqOther(u32), ApbFreqOther(u32),
} }
@ -214,10 +244,12 @@ impl Clock for ApbClock {
match self { match self {
#[cfg(esp32h2)] #[cfg(esp32h2)]
ApbClock::ApbFreq32MHz => HertzU32::MHz(32), ApbClock::ApbFreq32MHz => HertzU32::MHz(32),
#[cfg(not(esp32h2))] #[cfg(not(any(esp32h2, esp32p4)))]
ApbClock::ApbFreq40MHz => HertzU32::MHz(40), ApbClock::ApbFreq40MHz => HertzU32::MHz(40),
#[cfg(not(esp32h2))] #[cfg(not(any(esp32h2, esp32p4)))]
ApbClock::ApbFreq80MHz => HertzU32::MHz(80), ApbClock::ApbFreq80MHz => HertzU32::MHz(80),
#[cfg(esp32p4)]
ApbClock::ApbFreq100MHz => HertzU32::MHz(100),
ApbClock::ApbFreqOther(mhz) => HertzU32::MHz(*mhz), ApbClock::ApbFreqOther(mhz) => HertzU32::MHz(*mhz),
} }
} }
@ -624,6 +656,60 @@ 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<P = SystemClockControl> + '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<P = SystemClockControl> + '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, true);
} 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
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);
}
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<P = SystemClockControl> + 'd) -> ClockControl<'d> {
Self::configure(clock_control, CpuClock::Clock400MHz)
}
}
#[cfg(esp32s2)] #[cfg(esp32s2)]
impl<'d> ClockControl<'d> { impl<'d> ClockControl<'d> {
/// Use what is considered the default settings after boot. /// Use what is considered the default settings after boot.

View File

@ -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!()
}
}

View File

@ -176,7 +176,7 @@ impl SoftwareInterruptControl {
/// Controls the enablement of peripheral clocks. /// Controls the enablement of peripheral clocks.
pub(crate) struct PeripheralClockControl; pub(crate) struct PeripheralClockControl;
#[cfg(not(any(esp32c6, esp32h2)))] #[cfg(not(any(esp32c6, esp32h2, esp32p4)))]
impl PeripheralClockControl { impl PeripheralClockControl {
/// Enables and resets the given peripheral /// Enables and resets the given peripheral
pub(crate) fn enable(peripheral: 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. /// Controls the configuration of the chip's clocks.
pub struct SystemClockControl { pub struct SystemClockControl {
_private: (), _private: (),

View File

@ -1,11 +1,20 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
use esp32p4_hal::prelude::*; use esp32p4_hal::{
clock::{ClockControl, CpuClock},
peripherals::Peripherals,
prelude::*,
system::SystemExt,
};
use esp_backtrace as _; use esp_backtrace as _;
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
let peripherals = Peripherals::take();
let system = peripherals.SYSTEM.split();
let clocks = ClockControl::configure(system.clock_control, CpuClock::Clock90MHz).freeze();
esp_println::println!("Hello, world!"); esp_println::println!("Hello, world!");
loop {} loop {}
} }