diff --git a/esp-hal-common/ld/esp32s3/esp32s3.x b/esp-hal-common/ld/esp32s3/esp32s3.x index 731d279cc3e..bae052ad0be 100644 --- a/esp-hal-common/ld/esp32s3/esp32s3.x +++ b/esp-hal-common/ld/esp32s3/esp32s3.x @@ -34,6 +34,7 @@ SECTIONS { INSERT BEFORE .data; INCLUDE "fixups/rodata_dummy.x" +INCLUDE "fixups/external_ram_dummy.x" /* End of ESP32S3 fixups */ /* Shared sections - ordering matters */ @@ -44,6 +45,7 @@ INCLUDE "rwdata.x" INCLUDE "rtc_fast.x" INCLUDE "rtc_slow.x" INCLUDE "stack.x" +INCLUDE "external.x" /* End of Shared sections */ EXTERN(DefaultHandler); diff --git a/esp-hal-common/ld/esp32s3/memory.x b/esp-hal-common/ld/esp32s3/memory.x index 3b493fbcfee..1d2d3f96ef9 100644 --- a/esp-hal-common/ld/esp32s3/memory.x +++ b/esp-hal-common/ld/esp32s3/memory.x @@ -36,8 +36,11 @@ MEMORY /* RTC fast memory (executable). Persists over deep sleep. Only for core 0 (PRO_CPU) */ - rtc_fast_seg(RWX) : ORIGIN = 0x600fe000, len = 8k + rtc_fast_seg(RWX) : ORIGIN = 0x600fe000, len = 8k /* RTC slow memory (data accessible). Persists over deep sleep. */ rtc_slow_seg(RW) : ORIGIN = 0x50000000, len = 8k + + /* external memory, including data and text */ + psram_seg(RWX) : ORIGIN = 0x3C000020, len = 32M - 0x20 } diff --git a/esp-hal-common/ld/sections/external.x b/esp-hal-common/ld/sections/external.x new file mode 100644 index 00000000000..0ae2ac784ee --- /dev/null +++ b/esp-hal-common/ld/sections/external.x @@ -0,0 +1,36 @@ + + +SECTIONS { + .external.data : + { + _external_data_start = ABSOLUTE(.); + _external_no_heap_start = ABSOLUTE(.); + . = ALIGN(4); + *(.external.data .external.data.*) + _external_data_end = ABSOLUTE(.); + } > psram_seg AT > RODATA + + .external.bss (NOLOAD) : + { + _external_bss_start = ABSOLUTE(.); + . = ALIGN(4); + *(.external.bss .external.bss.*) + _external_bss_end = ABSOLUTE(.); + } > psram_seg + + .external.noinit (NOLOAD) : + { + . = ALIGN(4); + *(.external.noinit .external.noinit.*) + } > psram_seg + + /* must be last segment using psram_seg */ + .external_heap_start (NOLOAD) : + { + . = ALIGN (4); + _external_heap_start = ABSOLUTE(.); + } > psram_seg +} + +_external_ram_start = ABSOLUTE(ORIGIN(psram_seg)); +_external_ram_end = ABSOLUTE(ORIGIN(psram_seg)+LENGTH(psram_seg)); \ No newline at end of file diff --git a/esp-hal-common/ld/sections/fixups/external_ram_dummy.x b/esp-hal-common/ld/sections/fixups/external_ram_dummy.x new file mode 100644 index 00000000000..d87edf8ccc1 --- /dev/null +++ b/esp-hal-common/ld/sections/fixups/external_ram_dummy.x @@ -0,0 +1,17 @@ +/* + * This section is required to skip flash rodata sections, because `psram_seg` + * and `drom_seg` are on the same bus + */ + +SECTIONS { + .ext_ram_dummy (NOLOAD) : + { + . = ORIGIN(psram_seg) + (_rodata_reserved_end - _rodata_dummy_start); + + /* Prepare the alignment of the section above + */ + + . = ALIGN(0x10000); + } > psram_seg +} +INSERT BEFORE .external.data; \ No newline at end of file diff --git a/esp-hal-common/ld/sections/fixups/rodata_dummy.x b/esp-hal-common/ld/sections/fixups/rodata_dummy.x index 4b2573e9d6b..78b51c845dc 100644 --- a/esp-hal-common/ld/sections/fixups/rodata_dummy.x +++ b/esp-hal-common/ld/sections/fixups/rodata_dummy.x @@ -8,6 +8,7 @@ SECTIONS { * Thus, it must have its alignment and (at least) its size. */ + _rodata_dummy_start = ABSOLUTE(.); /* Start at the same alignment constraint than .flash.text */ . = ALIGN(ALIGNOF(.text)); diff --git a/esp-hal-common/ld/sections/rodata.x b/esp-hal-common/ld/sections/rodata.x index 4d1832a864e..272902183ba 100644 --- a/esp-hal-common/ld/sections/rodata.x +++ b/esp-hal-common/ld/sections/rodata.x @@ -15,6 +15,7 @@ SECTIONS { { . = ALIGN(4); *( .rodata_wlog_*.* ) + _rodata_reserved_end = ABSOLUTE(.); . = ALIGN(4); } > RODATA } \ No newline at end of file diff --git a/esp-hal-common/src/soc/esp32s3/peripherals.rs b/esp-hal-common/src/soc/esp32s3/peripherals.rs index 846bef689b0..caee8eae819 100644 --- a/esp-hal-common/src/soc/esp32s3/peripherals.rs +++ b/esp-hal-common/src/soc/esp32s3/peripherals.rs @@ -84,7 +84,6 @@ crate::peripherals! { // Virtual peripherals: BT <= virtual, - PSRAM <= virtual, ULP_RISCV_CORE <= virtual, WIFI <= virtual, } diff --git a/esp-hal-common/src/soc/esp32s3/psram.rs b/esp-hal-common/src/soc/esp32s3/psram.rs index 36eee7a9078..f0566376679 100644 --- a/esp-hal-common/src/soc/esp32s3/psram.rs +++ b/esp-hal-common/src/soc/esp32s3/psram.rs @@ -16,10 +16,33 @@ //! during the compilation process. The available `PSRAM` sizes are `2MB`, //! `4MB`, and `8MB`. -static mut PSRAM_VADDR: u32 = 0x3C000000; +#[cfg(any( + feature = "psram-2m", + feature = "psram-4m", + feature = "psram-8m", + feature = "opsram-2m", + feature = "opsram-4m", + feature = "opsram-8m", + feature = "opsram-16m" +))] +static mut INFO: Option = None; + +fn psram_vaddr_start() -> u32 { + extern "C" { + static mut _external_no_heap_start: u32; + } + unsafe { (&_external_no_heap_start as *const u32) as u32 } +} + +pub fn psram_heap_bottom() -> usize { + extern "C" { + static mut _external_heap_start: u32; + } + unsafe { (&_external_heap_start as *const u32) as usize } +} -pub fn psram_vaddr_start() -> usize { - unsafe { PSRAM_VADDR as usize } +pub fn psram_heap_size() -> usize { + PSRAM_BYTES - (psram_heap_bottom() - psram_vaddr_start() as usize) } cfg_if::cfg_if! { @@ -42,7 +65,24 @@ cfg_if::cfg_if! { } } -pub const PSRAM_BYTES: usize = PSRAM_SIZE as usize * 1024 * 1024; +const PSRAM_BYTES: usize = PSRAM_SIZE as usize * 1024 * 1024; + +#[cfg(any( + feature = "psram-2m", + feature = "psram-4m", + feature = "psram-8m", + feature = "opsram-2m", + feature = "opsram-4m", + feature = "opsram-8m", + feature = "opsram-16m" +))] +pub fn print_psram_info() { + let info = unsafe { INFO.as_ref().expect("psram not initialized") }; + + utils::print_psram_info(info); + + info!("{} bytes of PSRAM", PSRAM_BYTES); +} /// Initialize PSRAM to be used for data. /// @@ -56,7 +96,9 @@ pub const PSRAM_BYTES: usize = PSRAM_SIZE as usize * 1024 * 1024; feature = "opsram-8m", feature = "opsram-16m" ))] -pub fn init_psram(_peripheral: impl crate::peripheral::Peripheral

) { +pub fn init_psram() { + use procmacros::ram; + const CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE: u32 = 0x4000; const CONFIG_ESP32S3_ICACHE_ASSOCIATED_WAYS: u8 = 8; const CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_SIZE: u8 = 32; @@ -67,6 +109,11 @@ pub fn init_psram(_peripheral: impl crate::peripheral::Peripheral

i32; } + + #[ram] + unsafe fn zero_bss() { + crate::xtensa_lx_rt::zero_bss(&mut _external_bss_start, &mut _external_bss_end); + } + unsafe { - const MMU_PAGE_SIZE: u32 = 0x10000; - const ICACHE_MMU_SIZE: usize = 0x800; - const FLASH_MMU_TABLE_SIZE: usize = ICACHE_MMU_SIZE / core::mem::size_of::(); - const MMU_INVALID: u32 = 1 << 14; - const DR_REG_MMU_TABLE: u32 = 0x600C5000; - - // calculate the PSRAM start address to map - let mut start = PSRAM_VADDR; - let mmu_table_ptr = DR_REG_MMU_TABLE as *const u32; - for i in 0..FLASH_MMU_TABLE_SIZE { - if mmu_table_ptr.add(i).read_volatile() != MMU_INVALID { - start += MMU_PAGE_SIZE; - } else { - break; - } + if INFO.is_some() { + panic!("psram already initialized") } - debug!("PSRAM start address = {:x}", start); - PSRAM_VADDR = start; // Configure the mode of instruction cache : cache size, cache line size. rom_config_instruction_cache_mode( @@ -139,7 +177,7 @@ pub fn init_psram(_peripheral: impl crate::peripheral::Peripheral

PsramInfo { psram_gpio_config(); psram_set_cs_timing(); @@ -228,7 +275,15 @@ pub(crate) mod utils { config_psram_spi_phases(); // Back to the high speed mode. Flash/PSRAM clocks are set to the clock that // user selected. SPI0/1 registers are all set correctly - mspi_timing_enter_high_speed_mode(true); + mspi_timing_enter_high_speed_mode(true) + } + + pub(super) fn print_psram_info(info: &PsramInfo) { + debug!("PSRAM start address = {:x}", super::psram_vaddr_start()); + info!( + "PSRAM core_clock {:?}, flash_div = {}, psram_div = {}", + info.core_clock, info.flash_div, info.psram_div + ); } const PSRAM_CS_IO: u8 = 26; @@ -390,16 +445,11 @@ pub(crate) mod utils { /// This function should always be called after `mspi_timing_flash_tuning` /// or `calculate_best_flash_tuning_config` #[ram] - fn mspi_timing_enter_high_speed_mode(control_spi1: bool) { + fn mspi_timing_enter_high_speed_mode(control_spi1: bool) -> PsramInfo { let core_clock: SpiTimingConfigCoreClock = get_mspi_core_clock(); let flash_div: u32 = get_flash_clock_divider(); let psram_div: u32 = get_psram_clock_divider(); - info!( - "PSRAM core_clock {:?}, flash_div = {}, psram_div = {}", - core_clock, flash_div, psram_div - ); - // Set SPI01 core clock // SPI0 and SPI1 share the register for core clock. So we only set SPI0 here. // Set FLASH module clock @@ -415,6 +465,12 @@ pub(crate) mod utils { // #if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING // set_timing_tuning_regs_as_required(true); // #endif + + PsramInfo { + core_clock, + flash_div, + psram_div, + } } #[ram] @@ -792,7 +848,7 @@ pub(crate) mod utils { feature = "opsram-8m", feature = "opsram-16m" ))] -pub(crate) mod utils { +mod utils { use procmacros::ram; // these should probably be configurable, relates to https://github.com/esp-rs/esp-hal/issues/42 @@ -802,6 +858,8 @@ pub(crate) mod utils { const FLASH_FREQ: FlashFreq = FlashFreq::FlashFreq80m; const SPIRAM_SPEED: SpiRamFreq = SpiRamFreq::Freq40m; + pub(super) type PsramInfo = OpiPsramModeReg; + #[allow(unused)] enum FlashFreq { FlashFreq20m, @@ -854,12 +912,6 @@ pub(crate) mod utils { const OCT_PSRAM_CS_HOLD_TIME: u8 = 3; const OCT_PSRAM_CS_HOLD_DELAY: u8 = 2; - const PSRAM_SIZE_2MB: usize = 2 * 1024 * 1024; - const PSRAM_SIZE_4MB: usize = 4 * 1024 * 1024; - const PSRAM_SIZE_8MB: usize = 8 * 1024 * 1024; - const PSRAM_SIZE_16MB: usize = 16 * 1024 * 1024; - const PSRAM_SIZE_32MB: usize = 32 * 1024 * 1024; - const SPI_CS1_GPIO_NUM: u8 = 26; const FUNC_SPICS1_SPICS1: u8 = 0; @@ -973,13 +1025,13 @@ pub(crate) mod utils { #[derive(Default)] #[repr(C)] - struct OpiPsramModeReg { - pub mr0: u8, - pub mr1: u8, - pub mr2: u8, - pub mr3: u8, - pub mr4: u8, - pub mr8: u8, + pub(super) struct OpiPsramModeReg { + mr0: u8, + mr1: u8, + mr2: u8, + mr3: u8, + mr4: u8, + mr8: u8, } #[allow(unused)] @@ -1175,7 +1227,7 @@ pub(crate) mod utils { } #[ram] - pub(crate) fn psram_init() { + pub(super) fn psram_init() -> OpiPsramModeReg { mspi_pin_init(); init_psram_pins(); set_psram_cs_timing(); @@ -1201,26 +1253,13 @@ pub(crate) mod utils { mode_reg.set_bt(0); init_psram_mode_reg(1, &mode_reg); - // Print PSRAM info - get_psram_mode_reg(1, &mut mode_reg); - print_psram_info(&mode_reg); + get_psram_mode_reg(1, &mut mode_reg); if mode_reg.vendor_id() != OCT_PSRAM_VENDOR_ID { - warn!("PSRAM ID read error: {:x}, PSRAM chip not found or not supported, or wrong PSRAM line mode", mode_reg.vendor_id()); - return; + panic!("PSRAM ID read error: {:x}, PSRAM chip not found or not supported, or wrong PSRAM line mode", mode_reg.vendor_id()); } - let psram_size = match mode_reg.density() { - 0x0 => PSRAM_SIZE_2MB, - 0x1 => PSRAM_SIZE_4MB, - 0x3 => PSRAM_SIZE_8MB, - 0x5 => PSRAM_SIZE_16MB, - 0x7 => PSRAM_SIZE_32MB, - _ => 0, - }; - info!("{} bytes of PSRAM", psram_size); - // Do PSRAM timing tuning, we use SPI1 to do the tuning, and set the // SPI0 PSRAM timing related registers accordingly // this is unsupported for now @@ -1239,6 +1278,8 @@ pub(crate) mod utils { // spi_flash_set_vendor_required_regs(); config_psram_spi_phases(); + + mode_reg } // Configure PSRAM SPI0 phase related registers here according to the PSRAM chip @@ -1612,11 +1653,12 @@ pub(crate) mod utils { // CONFIG_SPIRAM_ECC_ENABLE not yet supported } - fn print_psram_info(reg_val: &OpiPsramModeReg) { + pub(super) fn print_psram_info(info: &OpiPsramModeReg) { + debug!("PSRAM start address = {:x}", super::psram_vaddr_start()); info!( "vendor id : {:02x} ({})", - reg_val.vendor_id(), - if reg_val.vendor_id() == 0x0d { + info.vendor_id(), + if info.vendor_id() == 0x0d { "AP" } else { "UNKNOWN" @@ -1624,19 +1666,19 @@ pub(crate) mod utils { ); info!( "dev id : {:02x} (generation {})", - reg_val.dev_id(), - reg_val.dev_id() + 1 + info.dev_id(), + info.dev_id() + 1 ); info!( "density : {:02x} ({} Mbit)", - reg_val.density(), - if reg_val.density() == 0x1 { + info.density(), + if info.density() == 0x1 { 32 - } else if reg_val.density() == 0x3 { + } else if info.density() == 0x3 { 64 - } else if reg_val.density() == 0x5 { + } else if info.density() == 0x5 { 128 - } else if reg_val.density() == 0x7 { + } else if info.density() == 0x7 { 256 } else { 0 @@ -1644,32 +1686,28 @@ pub(crate) mod utils { ); info!( "good-die : {:02x} ({})", - reg_val.gb(), - if reg_val.gb() == 1 { "Pass" } else { "Fail" } + info.gb(), + if info.gb() == 1 { "Pass" } else { "Fail" } ); info!( "Latency : {:02x} ({})", - reg_val.lt(), - if reg_val.lt() == 1 { - "Fixed" - } else { - "Variable" - } + info.lt(), + if info.lt() == 1 { "Fixed" } else { "Variable" } ); info!( "VCC : {:02x} ({})", - reg_val.vcc(), - if reg_val.vcc() == 1 { "3V" } else { "1.8V" } + info.vcc(), + if info.vcc() == 1 { "3V" } else { "1.8V" } ); info!( "SRF : {:02x} ({} Refresh)", - reg_val.srf(), - if reg_val.srf() == 0x1 { "Fast" } else { "Slow" } + info.srf(), + if info.srf() == 0x1 { "Fast" } else { "Slow" } ); info!( "BurstType : {:02x} ({} Wrap)", - reg_val.bt(), - if reg_val.bt() == 1 && reg_val.bl() != 3 { + info.bt(), + if info.bt() == 1 && info.bl() != 3 { "Hybrid" } else { "" @@ -1677,12 +1715,12 @@ pub(crate) mod utils { ); info!( "BurstLen : {:02x} ({} Byte)", - reg_val.bl(), - if reg_val.bl() == 0x00 { + info.bl(), + if info.bl() == 0x00 { 16 - } else if reg_val.bl() == 0x01 { + } else if info.bl() == 0x01 { 32 - } else if reg_val.bl() == 0x10 { + } else if info.bl() == 0x10 { 64 } else { 1024 @@ -1690,22 +1728,18 @@ pub(crate) mod utils { ); info!( "Readlatency : {:02x} ({} cycles@{})", - reg_val.read_latency(), - reg_val.read_latency() * 2 + 6, - if reg_val.lt() == 1 { - "Fixed" - } else { - "Variable" - } + info.read_latency(), + info.read_latency() * 2 + 6, + if info.lt() == 1 { "Fixed" } else { "Variable" } ); info!( "DriveStrength: {:02x} (1/{})", - reg_val.drive_str(), - if reg_val.drive_str() == 0x00 { + info.drive_str(), + if info.drive_str() == 0x00 { 1 - } else if reg_val.drive_str() == 0x01 { + } else if info.drive_str() == 0x01 { 2 - } else if reg_val.drive_str() == 0x02 { + } else if info.drive_str() == 0x02 { 4 } else { 8 diff --git a/esp32s3-hal/src/lib.rs b/esp32s3-hal/src/lib.rs index b4ea01e8ce1..79f25b8f9b7 100644 --- a/esp32s3-hal/src/lib.rs +++ b/esp32s3-hal/src/lib.rs @@ -151,4 +151,7 @@ unsafe fn post_init() { Wdt::::set_wdt_enabled(false); Wdt::::set_wdt_enabled(false); + + #[cfg(feature = "psram")] + psram::init_psram(); }