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:
parent
ac07f3c460
commit
a08b38d231
@ -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
|
||||
|
||||
|
||||
@ -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 }
|
||||
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
ets_update_cpu_frequency = 0x4fc00044;
|
||||
ets_printf = 0x4fc00024;
|
||||
PROVIDE(ets_delay_us = 0x4fc0003c);
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,32 +85,48 @@ pub trait Clock {
|
||||
/// CPU clock speed
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum CpuClock {
|
||||
#[cfg(not(esp32h2))]
|
||||
#[cfg(not(any(esp32h2, esp32p4)))]
|
||||
Clock80MHz,
|
||||
#[cfg(esp32p4)]
|
||||
Clock90MHz,
|
||||
#[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(esp32p4)]
|
||||
Clock180MHz,
|
||||
#[cfg(xtensa)]
|
||||
Clock240MHz,
|
||||
#[cfg(esp32p4)]
|
||||
Clock360MHz,
|
||||
#[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(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)))]
|
||||
#[cfg(not(any(esp32c2, esp32h2, esp32p4)))]
|
||||
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),
|
||||
#[cfg(esp32p4)]
|
||||
CpuClock::Clock360MHz => HertzU32::MHz(360),
|
||||
#[cfg(esp32p4)]
|
||||
CpuClock::Clock400MHz => HertzU32::MHz(400),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -164,10 +180,16 @@ pub(crate) enum PllClock {
|
||||
Pll160MHz,
|
||||
#[cfg(esp32c6)]
|
||||
Pll240MHz,
|
||||
#[cfg(not(any(esp32c2, esp32c6, esp32h2)))]
|
||||
#[cfg(not(any(esp32c2, esp32c6, esp32h2, esp32p4)))]
|
||||
Pll320MHz,
|
||||
#[cfg(esp32p4)]
|
||||
Pll360MHz,
|
||||
#[cfg(esp32p4)]
|
||||
Pll400MHz,
|
||||
#[cfg(not(esp32h2))]
|
||||
Pll480MHz,
|
||||
#[cfg(esp32p4)]
|
||||
Pll500MHz,
|
||||
}
|
||||
|
||||
impl Clock for PllClock {
|
||||
@ -189,10 +211,16 @@ 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::Pll360MHz => HertzU32::MHz(360),
|
||||
#[cfg(esp32p4)]
|
||||
Self::Pll400MHz => HertzU32::MHz(400),
|
||||
#[cfg(not(esp32h2))]
|
||||
Self::Pll480MHz => HertzU32::MHz(480),
|
||||
#[cfg(esp32p4)]
|
||||
Self::Pll500MHz => HertzU32::MHz(500),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -202,10 +230,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 +244,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 +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)]
|
||||
impl<'d> ClockControl<'d> {
|
||||
/// Use what is considered the default settings after boot.
|
||||
|
||||
96
esp-hal/src/rtc_cntl/rtc/esp32p4.rs
Normal file
96
esp-hal/src/rtc_cntl/rtc/esp32p4.rs
Normal 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!()
|
||||
}
|
||||
}
|
||||
@ -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: (),
|
||||
|
||||
@ -1,11 +1,20 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use esp32p4_hal::prelude::*;
|
||||
use esp32p4_hal::{
|
||||
clock::{ClockControl, CpuClock},
|
||||
peripherals::Peripherals,
|
||||
prelude::*,
|
||||
system::SystemExt,
|
||||
};
|
||||
use esp_backtrace as _;
|
||||
|
||||
#[entry]
|
||||
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!");
|
||||
loop {}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user