static mut PSRAM_VADDR: u32 = 0x3C000000;
pub fn psram_vaddr_start() -> usize {
unsafe { PSRAM_VADDR as usize }
}
cfg_if::cfg_if! {
if #[cfg(feature = "psram-2m")] {
const PSRAM_SIZE: u32 = 2;
} else if #[cfg(feature = "psram-4m")] {
const PSRAM_SIZE: u32 = 4;
} else if #[cfg(feature = "psram-8m")] {
const PSRAM_SIZE: u32 = 8;
} else if #[cfg(feature = "opsram-2m")] {
const PSRAM_SIZE: u32 = 2;
} else if #[cfg(feature = "opsram-4m")] {
const PSRAM_SIZE: u32 = 4;
} else if #[cfg(feature = "opsram-8m")] {
const PSRAM_SIZE: u32 = 8;
} else if #[cfg(feature = "opsram-16m")] {
const PSRAM_SIZE: u32 = 16;
}else {
const PSRAM_SIZE: u32 = 0;
}
}
pub 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 init_psram(_peripheral: impl crate::peripheral::Peripheral<P = crate::peripherals::PSRAM>) {
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;
const CONFIG_ESP32S3_DATA_CACHE_SIZE: u32 = 0x8000;
const CONFIG_ESP32S3_DCACHE_ASSOCIATED_WAYS: u8 = 8;
const CONFIG_ESP32S3_DATA_CACHE_LINE_SIZE: u8 = 32;
const MMU_ACCESS_SPIRAM: u32 = 1 << 15;
const START_PAGE: u32 = 0;
extern "C" {
fn rom_config_instruction_cache_mode(
cfg_cache_size: u32,
cfg_cache_ways: u8,
cfg_cache_line_size: u8,
);
fn Cache_Suspend_DCache();
fn rom_config_data_cache_mode(
cfg_cache_size: u32,
cfg_cache_ways: u8,
cfg_cache_line_size: u8,
);
fn Cache_Resume_DCache(param: u32);
fn cache_dbus_mmu_set(
ext_ram: u32,
vaddr: u32,
paddr: u32,
psize: u32,
num: u32,
fixed: u32,
) -> i32;
}
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::<u32>();
const MMU_INVALID: u32 = 1 << 14;
const DR_REG_MMU_TABLE: u32 = 0x600C5000;
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;
}
}
debug!("PSRAM start address = {:x}", start);
PSRAM_VADDR = start;
rom_config_instruction_cache_mode(
CONFIG_ESP32S3_INSTRUCTION_CACHE_SIZE,
CONFIG_ESP32S3_ICACHE_ASSOCIATED_WAYS,
CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_SIZE,
);
Cache_Suspend_DCache();
rom_config_data_cache_mode(
CONFIG_ESP32S3_DATA_CACHE_SIZE,
CONFIG_ESP32S3_DCACHE_ASSOCIATED_WAYS,
CONFIG_ESP32S3_DATA_CACHE_LINE_SIZE,
);
if cache_dbus_mmu_set(
MMU_ACCESS_SPIRAM,
PSRAM_VADDR,
START_PAGE << 16,
64,
PSRAM_SIZE * 1024 / 64, 0,
) != 0
{
panic!("cache_dbus_mmu_set failed");
}
let extmem = &*esp32s3::EXTMEM::PTR;
extmem.dcache_ctrl1().modify(|_, w| {
w.dcache_shut_core0_bus()
.clear_bit()
.dcache_shut_core1_bus()
.clear_bit()
});
Cache_Resume_DCache(0);
}
utils::psram_init();
}
#[cfg(any(feature = "psram-2m", feature = "psram-4m", feature = "psram-8m"))]
pub(crate) mod utils {
use procmacros::ram;
const SPI_TIMING_CORE_CLOCK: SpiTimingConfigCoreClock =
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m;
const FLASH_FREQ: FlashFreq = FlashFreq::FlashFreq80m;
cfg_if::cfg_if! {
if #[cfg(feature = "psram-80mhz")] {
const SPIRAM_SPEED: SpiRamFreq = SpiRamFreq::Freq80m;
} else {
const SPIRAM_SPEED: SpiRamFreq = SpiRamFreq::Freq40m;
}
}
#[allow(unused)]
enum FlashFreq {
FlashFreq20m,
FlashFreq40m,
FlashFreq80m,
FlashFreq120m,
}
#[allow(unused)]
enum SpiRamFreq {
Freq40m,
Freq80m,
Freq120m,
}
#[allow(unused)]
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
enum SpiTimingConfigCoreClock {
SpiTimingConfigCoreClock80m,
SpiTimingConfigCoreClock120m,
SpiTimingConfigCoreClock160m,
SpiTimingConfigCoreClock240m,
}
impl SpiTimingConfigCoreClock {
fn mhz(&self) -> u32 {
match self {
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m => 80,
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock120m => 120,
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock160m => 160,
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock240m => 240,
}
}
}
#[ram]
pub(crate) fn psram_init() {
psram_gpio_config();
psram_set_cs_timing();
psram_reset_mode_spi1();
psram_enable_qio_mode_spi1();
mspi_timing_psram_tuning();
config_psram_spi_phases();
mspi_timing_enter_high_speed_mode(true);
}
const PSRAM_CS_IO: u8 = 26;
const SPI_CS1_GPIO_NUM: u8 = 26;
const FUNC_SPICS1_SPICS1: u8 = 0;
const PIN_FUNC_GPIO: u8 = 2;
const PSRAM_SPIWP_SD3_IO: u8 = 10;
const ESP_ROM_EFUSE_FLASH_DEFAULT_SPI: u32 = 0;
const SPICS1_OUT_IDX: u8 = 6;
const DR_REG_SPI0_BASE: u32 = 0x60003000;
const SPI0_MEM_SPI_SMEM_AC_REG: u32 = DR_REG_SPI0_BASE + 0xDC;
const SPI_MEM_SPI_SMEM_CS_HOLD_TIME_V: u32 = 0x1F;
const SPI_MEM_SPI_SMEM_CS_HOLD_TIME_S: u32 = 7;
const SPI_MEM_SPI_SMEM_CS_SETUP_TIME_V: u32 = 0x1F;
const SPI_MEM_SPI_SMEM_CS_SETUP_TIME_S: u32 = 2;
const SPI_MEM_SPI_SMEM_CS_HOLD_M: u32 = 1 << 1;
const SPI_MEM_SPI_SMEM_CS_SETUP_M: u32 = 1 << 0;
const SPI0_MEM_CACHE_SCTRL_REG: u32 = DR_REG_SPI0_BASE + 0x40;
const SPI0_MEM_SRAM_DWR_CMD_REG: u32 = DR_REG_SPI0_BASE + 0x4C;
const SPI0_MEM_SRAM_DRD_CMD_REG: u32 = DR_REG_SPI0_BASE + 0x48;
const SPI_MEM_USR_SRAM_DIO_M: u32 = 1 << 1;
const SPI_MEM_USR_SRAM_QIO_M: u32 = 1 << 2;
const SPI_MEM_CACHE_SRAM_USR_RCMD_M: u32 = 1 << 5;
const SPI_MEM_CACHE_SRAM_USR_WCMD_M: u32 = 1 << 20;
const SPI_MEM_CACHE_SRAM_USR_WR_CMD_BITLEN: u32 = 0x0000000F;
const SPI_MEM_CACHE_SRAM_USR_WR_CMD_BITLEN_S: u32 = 28;
const SPI_MEM_CACHE_SRAM_USR_WR_CMD_VALUE: u32 = 0x0000FFFF;
const SPI_MEM_CACHE_SRAM_USR_WR_CMD_VALUE_S: u32 = 0;
const PSRAM_QUAD_WRITE: u32 = 0x38;
const SPI_MEM_CACHE_SRAM_USR_RD_CMD_BITLEN_V: u32 = 0xF;
const SPI_MEM_CACHE_SRAM_USR_RD_CMD_BITLEN_S: u32 = 28;
const SPI_MEM_CACHE_SRAM_USR_RD_CMD_VALUE_V: u32 = 0xFFFF;
const PSRAM_FAST_READ_QUAD: u32 = 0xEB;
const SPI_MEM_CACHE_SRAM_USR_RD_CMD_VALUE_S: u32 = 0;
const SPI_MEM_SRAM_ADDR_BITLEN_V: u32 = 0x3F;
const SPI_MEM_SRAM_ADDR_BITLEN_S: u32 = 14;
const SPI_MEM_USR_RD_SRAM_DUMMY_M: u32 = 1 << 4;
const SPI_MEM_SRAM_RDUMMY_CYCLELEN_V: u32 = 0x3F;
const PSRAM_FAST_READ_QUAD_DUMMY: u32 = 6;
const SPI_MEM_SRAM_RDUMMY_CYCLELEN_S: u32 = 6;
const SPI0_MEM_MISC_REG: u32 = DR_REG_SPI0_BASE + 0x34;
const SPI_MEM_CS1_DIS_M: u32 = 1 << 1;
const SPI0_MEM_CORE_CLK_SEL_REG: u32 = DR_REG_SPI0_BASE + 0xEC;
const SPI_MEM_CORE_CLK_SEL: u32 = 0x00000003;
const DR_REG_SPI1_BASE: u32 = 0x60002000;
const SPI0_MEM_CLOCK_REG: u32 = DR_REG_SPI0_BASE + 0x14;
const SPI1_MEM_CLOCK_REG: u32 = DR_REG_SPI1_BASE + 0x14;
const SPI0_MEM_SRAM_CLK_REG: u32 = DR_REG_SPI0_BASE + 0x50;
const SPI_MEM_CLK_EQU_SYSCLK: u32 = 1 << 31;
const SPI_MEM_SCLK_EQU_SYSCLK: u32 = 1 << 31;
const SPI_MEM_CLKCNT_N_S: u32 = 16;
const SPI_MEM_SCLKCNT_N_S: u32 = 16;
const SPI_MEM_CLKCNT_H_S: u32 = 8;
const SPI_MEM_SCLKCNT_H_S: u32 = 8;
const SPI_MEM_CLKCNT_L_S: u32 = 0;
const SPI_MEM_SCLKCNT_L_S: u32 = 0;
extern "C" {
fn esp_rom_efuse_get_flash_gpio_info() -> u32;
fn esp_rom_efuse_get_flash_wp_gpio() -> u8;
fn esp_rom_gpio_connect_out_signal(
gpio_num: u8,
signal_idx: u8,
out_inv: bool,
oen_inv: bool,
);
fn esp_rom_spiflash_select_qio_pins(wp_gpio_num: u8, spiconfig: u32);
}
#[ram]
fn config_psram_spi_phases() {
clear_peri_reg_mask(SPI0_MEM_CACHE_SCTRL_REG, SPI_MEM_USR_SRAM_DIO_M); set_peri_reg_mask(SPI0_MEM_CACHE_SCTRL_REG, SPI_MEM_USR_SRAM_QIO_M); set_peri_reg_mask(SPI0_MEM_CACHE_SCTRL_REG, SPI_MEM_CACHE_SRAM_USR_RCMD_M); set_peri_reg_mask(SPI0_MEM_CACHE_SCTRL_REG, SPI_MEM_CACHE_SRAM_USR_WCMD_M); set_peri_reg_bits(
SPI0_MEM_SRAM_DWR_CMD_REG,
SPI_MEM_CACHE_SRAM_USR_WR_CMD_BITLEN,
7,
SPI_MEM_CACHE_SRAM_USR_WR_CMD_BITLEN_S,
);
set_peri_reg_bits(
SPI0_MEM_SRAM_DWR_CMD_REG,
SPI_MEM_CACHE_SRAM_USR_WR_CMD_VALUE,
PSRAM_QUAD_WRITE,
SPI_MEM_CACHE_SRAM_USR_WR_CMD_VALUE_S,
); set_peri_reg_bits(
SPI0_MEM_SRAM_DRD_CMD_REG,
SPI_MEM_CACHE_SRAM_USR_RD_CMD_BITLEN_V,
7,
SPI_MEM_CACHE_SRAM_USR_RD_CMD_BITLEN_S,
);
set_peri_reg_bits(
SPI0_MEM_SRAM_DRD_CMD_REG,
SPI_MEM_CACHE_SRAM_USR_RD_CMD_VALUE_V,
PSRAM_FAST_READ_QUAD,
SPI_MEM_CACHE_SRAM_USR_RD_CMD_VALUE_S,
);
set_peri_reg_bits(
SPI0_MEM_CACHE_SCTRL_REG,
SPI_MEM_SRAM_ADDR_BITLEN_V,
23,
SPI_MEM_SRAM_ADDR_BITLEN_S,
);
set_peri_reg_mask(SPI0_MEM_CACHE_SCTRL_REG, SPI_MEM_USR_RD_SRAM_DUMMY_M); set_peri_reg_bits(
SPI0_MEM_CACHE_SCTRL_REG,
SPI_MEM_SRAM_RDUMMY_CYCLELEN_V,
PSRAM_FAST_READ_QUAD_DUMMY - 1,
SPI_MEM_SRAM_RDUMMY_CYCLELEN_S,
);
clear_peri_reg_mask(SPI0_MEM_MISC_REG, SPI_MEM_CS1_DIS_M); }
#[ram]
fn mspi_timing_psram_tuning() {
}
#[ram]
fn mspi_timing_enter_high_speed_mode(control_spi1: bool) {
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
);
spi0_timing_config_set_core_clock(core_clock);
spi0_timing_config_set_flash_clock(flash_div);
if control_spi1 {
spi1_timing_config_set_flash_clock(flash_div);
}
spi0_timing_config_set_psram_clock(psram_div);
}
#[ram]
fn spi0_timing_config_set_core_clock(core_clock: SpiTimingConfigCoreClock) {
let reg_val = match core_clock {
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m => 0,
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock120m => 1,
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock160m => 2,
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock240m => 3,
};
set_peri_reg_bits(SPI0_MEM_CORE_CLK_SEL_REG, SPI_MEM_CORE_CLK_SEL, reg_val, 0);
}
#[ram]
fn spi0_timing_config_set_flash_clock(freqdiv: u32) {
if freqdiv == 1 {
write_peri_reg(SPI0_MEM_CLOCK_REG, SPI_MEM_CLK_EQU_SYSCLK);
} else {
let freqbits: u32 = ((freqdiv - 1) << SPI_MEM_CLKCNT_N_S)
| ((freqdiv / 2 - 1) << SPI_MEM_CLKCNT_H_S)
| ((freqdiv - 1) << SPI_MEM_CLKCNT_L_S);
write_peri_reg(SPI0_MEM_CLOCK_REG, freqbits);
}
}
#[ram]
fn spi1_timing_config_set_flash_clock(freqdiv: u32) {
if freqdiv == 1 {
write_peri_reg(SPI1_MEM_CLOCK_REG, SPI_MEM_CLK_EQU_SYSCLK);
} else {
let freqbits: u32 = ((freqdiv - 1) << SPI_MEM_CLKCNT_N_S)
| ((freqdiv / 2 - 1) << SPI_MEM_CLKCNT_H_S)
| ((freqdiv - 1) << SPI_MEM_CLKCNT_L_S);
write_peri_reg(SPI1_MEM_CLOCK_REG, freqbits);
}
}
#[ram]
fn spi0_timing_config_set_psram_clock(freqdiv: u32) {
if freqdiv == 1 {
write_peri_reg(SPI0_MEM_SRAM_CLK_REG, SPI_MEM_SCLK_EQU_SYSCLK);
} else {
let freqbits: u32 = ((freqdiv - 1) << SPI_MEM_SCLKCNT_N_S)
| ((freqdiv / 2 - 1) << SPI_MEM_SCLKCNT_H_S)
| ((freqdiv - 1) << SPI_MEM_SCLKCNT_L_S);
write_peri_reg(SPI0_MEM_SRAM_CLK_REG, freqbits);
}
}
#[ram]
fn get_mspi_core_clock() -> SpiTimingConfigCoreClock {
SPI_TIMING_CORE_CLOCK
}
#[ram]
fn get_flash_clock_divider() -> u32 {
match FLASH_FREQ {
FlashFreq::FlashFreq20m => SPI_TIMING_CORE_CLOCK.mhz() / 20,
FlashFreq::FlashFreq40m => SPI_TIMING_CORE_CLOCK.mhz() / 40,
FlashFreq::FlashFreq80m => SPI_TIMING_CORE_CLOCK.mhz() / 80,
FlashFreq::FlashFreq120m => SPI_TIMING_CORE_CLOCK.mhz() / 120,
}
}
#[ram]
fn get_psram_clock_divider() -> u32 {
match SPIRAM_SPEED {
SpiRamFreq::Freq40m => SPI_TIMING_CORE_CLOCK.mhz() / 40,
SpiRamFreq::Freq80m => SPI_TIMING_CORE_CLOCK.mhz() / 80,
SpiRamFreq::Freq120m => SPI_TIMING_CORE_CLOCK.mhz() / 120,
}
}
#[ram]
fn psram_reset_mode_spi1() {
const PSRAM_RESET_EN: u16 = 0x66;
const PSRAM_RESET: u16 = 0x99;
const CS_PSRAM_SEL: u8 = 1 << 1;
psram_exec_cmd(
CommandMode::PsramCmdSpi,
PSRAM_RESET_EN,
8, 0,
0, 0, core::ptr::null(),
0, core::ptr::null_mut(),
0, CS_PSRAM_SEL, false,
);
psram_exec_cmd(
CommandMode::PsramCmdSpi,
PSRAM_RESET,
8, 0,
0, 0, core::ptr::null(),
0, core::ptr::null_mut(),
0, CS_PSRAM_SEL, false,
); }
#[derive(PartialEq)]
#[allow(unused)]
enum CommandMode {
PsramCmdQpi = 0,
PsramCmdSpi = 1,
}
#[ram]
fn psram_exec_cmd(
mode: CommandMode,
cmd: u16,
cmd_bit_len: u16,
addr: u32,
addr_bit_len: u32,
dummy_bits: u32,
mosi_data: *const u8,
mosi_bit_len: u32,
miso_data: *mut u8,
miso_bit_len: u32,
cs_mask: u8,
is_write_erase_operation: bool,
) {
extern "C" {
fn esp_rom_spi_cmd_start(
spi_num: u32,
rx_buf: *const u8,
rx_len: u16,
cs_en_mask: u8,
is_write_erase: bool,
);
}
unsafe {
let spi1 = &*esp32s3::SPI1::PTR;
let backup_usr = spi1.user().read().bits();
let backup_usr1 = spi1.user1().read().bits();
let backup_usr2 = spi1.user2().read().bits();
let backup_ctrl = spi1.ctrl().read().bits();
psram_set_op_mode(mode);
_psram_exec_cmd(
cmd,
cmd_bit_len,
addr,
addr_bit_len,
dummy_bits,
mosi_data,
mosi_bit_len,
miso_data,
miso_bit_len,
);
esp_rom_spi_cmd_start(
1,
miso_data,
(miso_bit_len / 8) as u16,
cs_mask,
is_write_erase_operation,
);
spi1.user().write(|w| w.bits(backup_usr));
spi1.user1().write(|w| w.bits(backup_usr1));
spi1.user2().write(|w| w.bits(backup_usr2));
spi1.ctrl().write(|w| w.bits(backup_ctrl));
}
}
#[ram]
fn _psram_exec_cmd(
cmd: u16,
cmd_bit_len: u16,
addr: u32,
addr_bit_len: u32,
dummy_bits: u32,
mosi_data: *const u8,
mosi_bit_len: u32,
miso_data: *mut u8,
miso_bit_len: u32,
) {
#[repr(C)]
struct esp_rom_spi_cmd_t {
cmd: u16, cmd_bit_len: u16, addr: *const u32, addr_bit_len: u32, tx_data: *const u32, tx_data_bit_len: u32, rx_data: *mut u32, rx_data_bit_len: u32, dummy_bit_len: u32,
}
extern "C" {
fn esp_rom_spi_cmd_config(spi_num: u32, pcmd: *const esp_rom_spi_cmd_t);
}
let conf = esp_rom_spi_cmd_t {
cmd,
cmd_bit_len,
addr: addr as *const u32,
addr_bit_len,
tx_data: mosi_data as *const u32,
tx_data_bit_len: mosi_bit_len,
rx_data: miso_data as *mut u32,
rx_data_bit_len: miso_bit_len,
dummy_bit_len: dummy_bits,
};
unsafe {
esp_rom_spi_cmd_config(1, &conf);
}
}
#[ram]
fn psram_set_op_mode(mode: CommandMode) {
extern "C" {
fn esp_rom_spi_set_op_mode(spi: u32, mode: u32);
}
const ESP_ROM_SPIFLASH_QIO_MODE: u32 = 0;
const ESP_ROM_SPIFLASH_SLOWRD_MODE: u32 = 5;
unsafe {
match mode {
CommandMode::PsramCmdQpi => {
esp_rom_spi_set_op_mode(1, ESP_ROM_SPIFLASH_QIO_MODE);
let spi1 = &*esp32s3::SPI1::PTR;
spi1.ctrl().modify(|_, w| w.fcmd_quad().set_bit());
}
CommandMode::PsramCmdSpi => {
esp_rom_spi_set_op_mode(1, ESP_ROM_SPIFLASH_SLOWRD_MODE);
}
}
}
}
#[ram]
fn psram_enable_qio_mode_spi1() {
const PSRAM_ENTER_QMODE: u16 = 0x35;
const CS_PSRAM_SEL: u8 = 1 << 1;
psram_exec_cmd(
CommandMode::PsramCmdSpi,
PSRAM_ENTER_QMODE,
8, 0,
0, 0, core::ptr::null(),
0, core::ptr::null_mut(),
0, CS_PSRAM_SEL, false, );
}
#[ram]
fn psram_set_cs_timing() {
set_peri_reg_bits(
SPI0_MEM_SPI_SMEM_AC_REG,
SPI_MEM_SPI_SMEM_CS_HOLD_TIME_V,
0,
SPI_MEM_SPI_SMEM_CS_HOLD_TIME_S,
);
set_peri_reg_bits(
SPI0_MEM_SPI_SMEM_AC_REG,
SPI_MEM_SPI_SMEM_CS_SETUP_TIME_V,
0,
SPI_MEM_SPI_SMEM_CS_SETUP_TIME_S,
);
set_peri_reg_mask(
SPI0_MEM_SPI_SMEM_AC_REG,
SPI_MEM_SPI_SMEM_CS_HOLD_M | SPI_MEM_SPI_SMEM_CS_SETUP_M,
);
}
#[ram]
fn psram_gpio_config() {
let cs1_io: u8 = PSRAM_CS_IO;
if cs1_io == SPI_CS1_GPIO_NUM {
unsafe {
let iomux = &*esp32s3::IO_MUX::PTR;
iomux
.gpio(cs1_io as usize)
.modify(|_, w| w.mcu_sel().variant(FUNC_SPICS1_SPICS1))
}
} else {
unsafe {
esp_rom_gpio_connect_out_signal(cs1_io, SPICS1_OUT_IDX, false, false);
let iomux = &*esp32s3::IO_MUX::PTR;
iomux
.gpio(cs1_io as usize)
.modify(|_, w| w.mcu_sel().variant(PIN_FUNC_GPIO))
}
}
let mut wp_io: u8 = PSRAM_SPIWP_SD3_IO;
let spiconfig = unsafe { esp_rom_efuse_get_flash_gpio_info() };
if spiconfig == ESP_ROM_EFUSE_FLASH_DEFAULT_SPI {
} else {
wp_io = unsafe { esp_rom_efuse_get_flash_wp_gpio() };
}
unsafe {
esp_rom_spiflash_select_qio_pins(wp_io, spiconfig);
}
}
#[inline(always)]
fn clear_peri_reg_mask(reg: u32, mask: u32) {
unsafe {
(reg as *mut u32).write_volatile((reg as *mut u32).read_volatile() & !mask);
}
}
#[inline(always)]
fn set_peri_reg_mask(reg: u32, mask: u32) {
unsafe {
(reg as *mut u32).write_volatile((reg as *mut u32).read_volatile() | mask);
}
}
#[inline(always)]
fn set_peri_reg_bits(reg: u32, bitmap: u32, value: u32, shift: u32) {
unsafe {
(reg as *mut u32).write_volatile(
((reg as *mut u32).read_volatile() & !(bitmap << shift))
| ((value & bitmap) << shift),
);
}
}
#[inline(always)]
fn write_peri_reg(reg: u32, val: u32) {
unsafe {
(reg as *mut u32).write_volatile(val);
}
}
}
#[cfg(any(
feature = "opsram-2m",
feature = "opsram-4m",
feature = "opsram-8m",
feature = "opsram-16m"
))]
pub(crate) mod utils {
use procmacros::ram;
const SPI_TIMING_CORE_CLOCK: SpiTimingConfigCoreClock =
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m;
const FLASH_FREQ: FlashFreq = FlashFreq::FlashFreq80m;
cfg_if::cfg_if! {
if #[cfg(feature = "psram-80mhz")] {
const SPIRAM_SPEED: SpiRamFreq = SpiRamFreq::Freq80m;
} else {
const SPIRAM_SPEED: SpiRamFreq = SpiRamFreq::Freq40m;
}
}
#[allow(unused)]
enum FlashFreq {
FlashFreq20m,
FlashFreq40m,
FlashFreq80m,
FlashFreq120m,
}
#[allow(unused)]
enum SpiRamFreq {
Freq40m,
Freq80m,
Freq120m,
}
#[allow(unused)]
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
enum SpiTimingConfigCoreClock {
SpiTimingConfigCoreClock80m,
SpiTimingConfigCoreClock120m,
SpiTimingConfigCoreClock160m,
SpiTimingConfigCoreClock240m,
}
impl SpiTimingConfigCoreClock {
fn mhz(&self) -> u32 {
match self {
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m => 80,
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock120m => 120,
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock160m => 160,
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock240m => 240,
}
}
}
const OPI_PSRAM_SYNC_READ: u16 = 0x0000;
const OPI_PSRAM_SYNC_WRITE: u16 = 0x8080;
const OPI_PSRAM_REG_READ: u16 = 0x4040;
const OPI_PSRAM_REG_WRITE: u16 = 0xC0C0;
const OCT_PSRAM_RD_CMD_BITLEN: u8 = 16;
const OCT_PSRAM_WR_CMD_BITLEN: u8 = 16;
const OCT_PSRAM_ADDR_BITLEN: u8 = 32;
const OCT_PSRAM_RD_DUMMY_BITLEN: u8 = 2 * (10 - 1);
const OCT_PSRAM_WR_DUMMY_BITLEN: u8 = 2 * (5 - 1);
const OCT_PSRAM_CS1_IO: u8 = SPI_CS1_GPIO_NUM;
const OCT_PSRAM_VENDOR_ID: u8 = 0xD;
const OCT_PSRAM_CS_SETUP_TIME: u8 = 3;
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;
const SPI1_MEM_DDR_REG: u32 = DR_REG_SPI1_BASE + 0xe0;
const SPI_MEM_SPI_FMEM_VAR_DUMMY: u32 = 1 << 1;
const DR_REG_SPI0_BASE: u32 = 0x60003000;
const SPI0_MEM_SPI_SMEM_AC_REG: u32 = DR_REG_SPI0_BASE + 0xDC;
const SPI_MEM_SPI_SMEM_CS_HOLD_TIME_V: u32 = 0x1F;
const SPI_MEM_SPI_SMEM_CS_HOLD_TIME_S: u32 = 7;
const SPI_MEM_SPI_SMEM_CS_SETUP_TIME_V: u32 = 0x1F;
const SPI_MEM_SPI_SMEM_CS_SETUP_TIME_S: u32 = 2;
const SPI_MEM_SPI_SMEM_CS_HOLD_M: u32 = 1 << 1;
const SPI_MEM_SPI_SMEM_CS_SETUP_M: u32 = 1 << 0;
const SPI0_MEM_CACHE_SCTRL_REG: u32 = DR_REG_SPI0_BASE + 0x40;
const SPI0_MEM_SRAM_DWR_CMD_REG: u32 = DR_REG_SPI0_BASE + 0x4C;
const SPI0_MEM_SRAM_DRD_CMD_REG: u32 = DR_REG_SPI0_BASE + 0x48;
const SPI_MEM_CACHE_SRAM_USR_RCMD_M: u32 = 1 << 5;
const SPI_MEM_CACHE_SRAM_USR_WCMD_M: u32 = 1 << 20;
const SPI_MEM_CACHE_SRAM_USR_WR_CMD_BITLEN: u32 = 0x0000000F;
const SPI_MEM_CACHE_SRAM_USR_WR_CMD_BITLEN_S: u32 = 28;
const SPI_MEM_CACHE_SRAM_USR_WR_CMD_VALUE: u32 = 0x0000FFFF;
const SPI_MEM_CACHE_SRAM_USR_WR_CMD_VALUE_S: u32 = 0;
const SPI_MEM_CACHE_SRAM_USR_RD_CMD_BITLEN_V: u32 = 0xF;
const SPI_MEM_CACHE_SRAM_USR_RD_CMD_BITLEN_S: u32 = 28;
const SPI_MEM_CACHE_SRAM_USR_RD_CMD_VALUE_V: u32 = 0xFFFF;
const SPI_MEM_CACHE_SRAM_USR_RD_CMD_VALUE_S: u32 = 0;
const SPI_MEM_SRAM_ADDR_BITLEN_V: u32 = 0x3F;
const SPI_MEM_SRAM_ADDR_BITLEN_S: u32 = 14;
const SPI_MEM_USR_RD_SRAM_DUMMY_M: u32 = 1 << 4;
const SPI_MEM_SRAM_RDUMMY_CYCLELEN_V: u32 = 0x3F;
const SPI_MEM_SRAM_RDUMMY_CYCLELEN_S: u32 = 6;
const SPI0_MEM_CORE_CLK_SEL_REG: u32 = DR_REG_SPI0_BASE + 0xEC;
const SPI_MEM_CORE_CLK_SEL: u32 = 0x00000003;
const DR_REG_SPI1_BASE: u32 = 0x60002000;
const SPI0_MEM_DATE_REG: u32 = DR_REG_SPI0_BASE + 0x3FC;
const SPI0_MEM_CLOCK_REG: u32 = DR_REG_SPI0_BASE + 0x14;
const SPI1_MEM_CLOCK_REG: u32 = DR_REG_SPI1_BASE + 0x14;
const SPI0_MEM_SRAM_CLK_REG: u32 = DR_REG_SPI0_BASE + 0x50;
const SPI_MEM_CLK_EQU_SYSCLK: u32 = 1 << 31;
const SPI_MEM_SCLK_EQU_SYSCLK: u32 = 1 << 31;
const SPI_MEM_CLKCNT_N_S: u32 = 16;
const SPI_MEM_SCLKCNT_N_S: u32 = 16;
const SPI_MEM_CLKCNT_H_S: u32 = 8;
const SPI_MEM_SCLKCNT_H_S: u32 = 8;
const SPI_MEM_CLKCNT_L_S: u32 = 0;
const SPI_MEM_SCLKCNT_L_S: u32 = 0;
const SPI_MEM_CACHE_USR_SCMD_4BYTE_M: u32 = 1 << 0;
const SPI_MEM_USR_WR_SRAM_DUMMY_M: u32 = 1 << 3;
const SPI0_MEM_SPI_SMEM_DDR_REG: u32 = DR_REG_SPI0_BASE + 0xE4;
const SPI0_MEM_SRAM_CMD_REG: u32 = DR_REG_SPI0_BASE + 0x44;
const SPI_MEM_SPI_SMEM_VAR_DUMMY_M: u32 = 1 << 1;
const SPI_MEM_SRAM_WDUMMY_CYCLELEN_V: u32 = 0x3F;
const SPI_MEM_SRAM_WDUMMY_CYCLELEN_S: u32 = 22;
const SPI_MEM_SPI_SMEM_DDR_WDAT_SWP_M: u32 = 1 << 3;
const SPI_MEM_SPI_SMEM_DDR_RDAT_SWP_M: u32 = 1 << 2;
const SPI_MEM_SPI_SMEM_DDR_EN_M: u32 = 1 << 0;
const SPI_MEM_SDUMMY_OUT_M: u32 = 1 << 22;
const SPI_MEM_SCMD_OCT_M: u32 = 1 << 21;
const SPI_MEM_SADDR_OCT_M: u32 = 1 << 20;
const SPI_MEM_SDOUT_OCT_M: u32 = 1 << 19;
const SPI_MEM_SDIN_OCT_M: u32 = 1 << 18;
const SPI_MEM_SRAM_OCT_M: u32 = 1 << 21;
const SPI_MEM_SPI_SMEM_CS_HOLD_DELAY_V: u32 = 0x3F;
const SPI_MEM_SPI_SMEM_CS_HOLD_DELAY_S: u32 = 25;
const SPI_MEM_SPI_SMEM_SPICLK_FUN_DRV: u32 = 0x00000003;
const SPI_MEM_SPI_SMEM_SPICLK_FUN_DRV_V: u32 = 0x3;
const SPI_MEM_SPI_SMEM_SPICLK_FUN_DRV_S: u32 = 0;
const ESP_ROM_SPIFLASH_OPI_DTR_MODE: u8 = 7;
extern "C" {
fn esp_rom_opiflash_exec_cmd(
spi_num: u32,
mode: u8,
cmd: u32,
cmd_bit_len: u32,
addr: u32,
addr_bit_len: u32,
dummy_bits: u32,
mosi_data: *const u8,
mosi_bit_len: u32,
miso_data: *mut u8,
miso_bit_len: u32,
cs_mask: u32,
is_write_erase_operation: bool,
);
fn esp_rom_spi_set_dtr_swap_mode(spi: u32, wr_swap: bool, rd_swap: bool);
fn esp_rom_opiflash_pin_config();
}
#[derive(Default)]
#[repr(C)]
struct OpiPsramModeReg {
pub mr0: u8,
pub mr1: u8,
pub mr2: u8,
pub mr3: u8,
pub mr4: u8,
pub mr8: u8,
}
#[allow(unused)]
impl OpiPsramModeReg {
fn drive_str(&self) -> u8 {
self.mr0 & 0b11
}
fn set_drive_str(&mut self, value: u8) {
self.mr0 &= !0b11;
self.mr0 |= value & 0b11;
}
fn read_latency(&self) -> u8 {
(self.mr0 >> 2) & 0b111
}
fn set_read_latency(&mut self, value: u8) {
self.mr0 &= !(0b111 << 2);
self.mr0 |= (value & 0b111) << 2;
}
fn lt(&self) -> u8 {
(self.mr0 >> 5) & 0b1
}
fn set_lt(&mut self, value: u8) {
self.mr0 &= !(0b1 << 5);
self.mr0 |= (value & 0b1) << 5;
}
fn rsvd0_1(&self) -> u8 {
(self.mr0 >> 6) & 0b11
}
fn set_rsvd0_1(&mut self, value: u8) {
self.mr0 &= !(0b11 << 6);
self.mr0 |= (value & 0b11) << 6;
}
fn vendor_id(&self) -> u8 {
self.mr1 & 0b11111
}
fn set_vendor_id(&mut self, value: u8) {
self.mr1 &= !0b11111;
self.mr1 |= value & 0b11111;
}
fn rsvd0_2(&self) -> u8 {
(self.mr1 >> 5) & 0b111
}
fn set_rsvd0_2(&mut self, value: u8) {
self.mr1 &= !(0b111 << 5);
self.mr1 |= (value & 0b111) << 5;
}
fn density(&self) -> u8 {
self.mr2 & 0b111
}
fn set_density(&mut self, value: u8) {
self.mr2 &= !0b111;
self.mr2 |= value & 0b111;
}
fn dev_id(&self) -> u8 {
(self.mr2 >> 3) & 0b11
}
fn set_dev_id(&mut self, value: u8) {
self.mr2 &= !(0b11 << 3);
self.mr2 |= (value & 0b11) << 3;
}
fn rsvd1_2(&self) -> u8 {
(self.mr2 >> 5) & 0b11
}
fn set_rsvd1_2(&mut self, value: u8) {
self.mr2 &= !(0b11 << 5);
self.mr2 |= (value & 0b11) << 5;
}
fn gb(&self) -> u8 {
(self.mr2 >> 7) & 0b1
}
fn set_gb(&mut self, value: u8) {
self.mr2 &= !(0b1 << 7);
self.mr2 |= (value & 0b1) << 7;
}
fn rsvd3_7(&self) -> u8 {
self.mr3 & 0b11111
}
fn set_rsvd3_7(&mut self, value: u8) {
self.mr3 &= !0b11111;
self.mr3 |= value & 0b11111;
}
fn srf(&self) -> u8 {
(self.mr3 >> 5) & 0b1
}
fn set_srf(&mut self, value: u8) {
self.mr3 &= !(0b1 << 5);
self.mr3 |= (value & 0b1) << 5;
}
fn vcc(&self) -> u8 {
(self.mr3 >> 6) & 0b1
}
fn set_vcc(&mut self, value: u8) {
self.mr3 &= !(0b1 << 6);
self.mr3 |= (value & 0b1) << 6;
}
fn rsvd0(&self) -> u8 {
(self.mr3 >> 7) & 0b1
}
fn set_rsvd0(&mut self, value: u8) {
self.mr3 &= !(0b1 << 7);
self.mr3 |= (value & 0b1) << 7;
}
fn pasr(&self) -> u8 {
self.mr4 & 0b111
}
fn set_pasr(&mut self, value: u8) {
self.mr4 &= !0b111;
self.mr4 |= value & 0b111;
}
fn rf(&self) -> u8 {
(self.mr4 >> 3) & 0b1
}
fn set_rf(&mut self, value: u8) {
self.mr4 &= !(0b1 << 3);
self.mr4 |= (value & 0b1) << 3;
}
fn rsvd3(&self) -> u8 {
(self.mr4 >> 4) & 0b1
}
fn set_rsvd3(&mut self, value: u8) {
self.mr4 &= !(0b1 << 4);
self.mr4 |= (value & 0b1) << 4;
}
fn wr_latency(&self) -> u8 {
(self.mr4 >> 5) & 0b111
}
fn set_wr_latency(&mut self, value: u8) {
self.mr4 &= !(0b111 << 5);
self.mr4 |= (value & 0b111) << 5;
}
fn bl(&self) -> u8 {
self.mr8 & 0b11
}
fn set_bl(&mut self, value: u8) {
self.mr8 &= !0b11;
self.mr8 |= value & 0b11;
}
fn bt(&self) -> u8 {
(self.mr8 >> 2) & 0b1
}
fn set_bt(&mut self, value: u8) {
self.mr8 &= !(0b1 << 2);
self.mr8 |= (value & 0b1) << 2;
}
fn rsvd0_4(&self) -> u8 {
(self.mr8 >> 3) & 0b11111
}
fn set_rsvd0_4(&mut self, value: u8) {
self.mr8 &= !(0b11111 << 3);
self.mr8 |= (value & 0b11111) << 3;
}
}
#[ram]
pub(crate) fn psram_init() {
mspi_pin_init();
init_psram_pins();
set_psram_cs_timing();
spi_timing_enter_mspi_low_speed_mode(true);
set_peri_reg_mask(SPI1_MEM_DDR_REG, SPI_MEM_SPI_FMEM_VAR_DUMMY);
unsafe {
esp_rom_spi_set_dtr_swap_mode(1, false, false);
}
let mut mode_reg = OpiPsramModeReg::default();
mode_reg.set_lt(1);
mode_reg.set_read_latency(2);
mode_reg.set_drive_str(0);
mode_reg.set_bl(3);
mode_reg.set_bt(0);
init_psram_mode_reg(1, &mode_reg);
get_psram_mode_reg(1, &mut mode_reg);
print_psram_info(&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;
}
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);
spi_timing_enter_mspi_high_speed_mode(true);
spi_flash_set_rom_required_regs();
config_psram_spi_phases();
}
fn config_psram_spi_phases() {
set_peri_reg_mask(SPI0_MEM_CACHE_SCTRL_REG, SPI_MEM_CACHE_SRAM_USR_WCMD_M);
set_peri_reg_bits(
SPI0_MEM_SRAM_DWR_CMD_REG,
SPI_MEM_CACHE_SRAM_USR_WR_CMD_BITLEN,
(OCT_PSRAM_WR_CMD_BITLEN - 1) as u32,
SPI_MEM_CACHE_SRAM_USR_WR_CMD_BITLEN_S,
);
set_peri_reg_bits(
SPI0_MEM_SRAM_DWR_CMD_REG,
SPI_MEM_CACHE_SRAM_USR_WR_CMD_VALUE,
OPI_PSRAM_SYNC_WRITE as u32,
SPI_MEM_CACHE_SRAM_USR_WR_CMD_VALUE_S,
);
set_peri_reg_mask(SPI0_MEM_CACHE_SCTRL_REG, SPI_MEM_CACHE_SRAM_USR_RCMD_M);
set_peri_reg_bits(
SPI0_MEM_SRAM_DRD_CMD_REG,
SPI_MEM_CACHE_SRAM_USR_RD_CMD_BITLEN_V,
(OCT_PSRAM_RD_CMD_BITLEN - 1) as u32,
SPI_MEM_CACHE_SRAM_USR_RD_CMD_BITLEN_S,
);
set_peri_reg_bits(
SPI0_MEM_SRAM_DRD_CMD_REG,
SPI_MEM_CACHE_SRAM_USR_RD_CMD_VALUE_V,
OPI_PSRAM_SYNC_READ as u32,
SPI_MEM_CACHE_SRAM_USR_RD_CMD_VALUE_S,
);
set_peri_reg_bits(
SPI0_MEM_CACHE_SCTRL_REG,
SPI_MEM_SRAM_ADDR_BITLEN_V,
(OCT_PSRAM_ADDR_BITLEN - 1) as u32,
SPI_MEM_SRAM_ADDR_BITLEN_S,
);
set_peri_reg_mask(SPI0_MEM_CACHE_SCTRL_REG, SPI_MEM_CACHE_USR_SCMD_4BYTE_M);
set_peri_reg_mask(
SPI0_MEM_CACHE_SCTRL_REG,
SPI_MEM_USR_RD_SRAM_DUMMY_M | SPI_MEM_USR_WR_SRAM_DUMMY_M,
);
set_peri_reg_bits(
SPI0_MEM_CACHE_SCTRL_REG,
SPI_MEM_SRAM_RDUMMY_CYCLELEN_V,
(OCT_PSRAM_RD_DUMMY_BITLEN - 1) as u32,
SPI_MEM_SRAM_RDUMMY_CYCLELEN_S,
);
set_peri_reg_mask(SPI0_MEM_SPI_SMEM_DDR_REG, SPI_MEM_SPI_SMEM_VAR_DUMMY_M);
set_peri_reg_bits(
SPI0_MEM_CACHE_SCTRL_REG,
SPI_MEM_SRAM_WDUMMY_CYCLELEN_V,
(OCT_PSRAM_WR_DUMMY_BITLEN - 1) as u32,
SPI_MEM_SRAM_WDUMMY_CYCLELEN_S,
);
clear_peri_reg_mask(
SPI0_MEM_SPI_SMEM_DDR_REG,
SPI_MEM_SPI_SMEM_DDR_WDAT_SWP_M | SPI_MEM_SPI_SMEM_DDR_RDAT_SWP_M,
);
set_peri_reg_mask(SPI0_MEM_SPI_SMEM_DDR_REG, SPI_MEM_SPI_SMEM_DDR_EN_M);
set_peri_reg_mask(
SPI0_MEM_SRAM_CMD_REG,
SPI_MEM_SDUMMY_OUT_M
| SPI_MEM_SCMD_OCT_M
| SPI_MEM_SADDR_OCT_M
| SPI_MEM_SDOUT_OCT_M
| SPI_MEM_SDIN_OCT_M,
);
set_peri_reg_mask(SPI0_MEM_CACHE_SCTRL_REG, SPI_MEM_SRAM_OCT_M);
}
#[ram]
fn spi_flash_set_rom_required_regs() {
clear_peri_reg_mask(SPI1_MEM_DDR_REG, SPI_MEM_SPI_FMEM_VAR_DUMMY);
}
#[ram]
fn mspi_pin_init() {
unsafe {
esp_rom_opiflash_pin_config();
}
spi_timing_set_pin_drive_strength();
}
#[ram]
fn spi_timing_set_pin_drive_strength() {
set_peri_reg_mask(SPI0_MEM_DATE_REG, SPI_MEM_SPICLK_PAD_DRV_CTL_EN);
set_peri_reg_bits(
SPI0_MEM_DATE_REG,
SPI_MEM_SPI_SMEM_SPICLK_FUN_DRV,
3,
SPI_MEM_SPI_SMEM_SPICLK_FUN_DRV_S,
);
set_peri_reg_bits(
SPI0_MEM_DATE_REG,
SPI_MEM_SPI_FMEM_SPICLK_FUN_DRV,
3,
SPI_MEM_SPI_FMEM_SPICLK_FUN_DRV_S,
);
let pins = &[27usize, 28, 31, 32, 33, 34, 35, 36, 37];
for pin in pins {
unsafe {
let iomux = &*esp32s3::IO_MUX::PTR;
iomux.gpio(*pin).modify(|_, w| w.fun_drv().variant(3))
}
}
}
const SPI_MEM_SPICLK_PAD_DRV_CTL_EN: u32 = 1 << 4;
const SPI_MEM_SPI_FMEM_SPICLK_FUN_DRV: u32 = 0x00000003;
const SPI_MEM_SPI_FMEM_SPICLK_FUN_DRV_S: u32 = 2;
fn spi_timing_enter_mspi_low_speed_mode(control_spi1: bool) {
spi0_timing_config_set_core_clock(SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m); spi0_timing_config_set_flash_clock(4);
if control_spi1 {
spi1_timing_config_set_flash_clock(4);
}
spi0_timing_config_set_psram_clock(4);
}
fn spi_timing_enter_mspi_high_speed_mode(control_spi1: bool) {
let core_clock = SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m;
let flash_div: u32 = get_flash_clock_divider();
let psram_div: u32 = get_psram_clock_divider();
spi0_timing_config_set_core_clock(core_clock); spi0_timing_config_set_flash_clock(flash_div);
if control_spi1 {
spi1_timing_config_set_flash_clock(flash_div);
}
spi0_timing_config_set_psram_clock(psram_div);
}
fn set_psram_cs_timing() {
set_peri_reg_mask(
SPI0_MEM_SPI_SMEM_AC_REG,
SPI_MEM_SPI_SMEM_CS_HOLD_M | SPI_MEM_SPI_SMEM_CS_SETUP_M,
);
set_peri_reg_bits(
SPI0_MEM_SPI_SMEM_AC_REG,
SPI_MEM_SPI_SMEM_CS_HOLD_TIME_V,
OCT_PSRAM_CS_HOLD_TIME as u32,
SPI_MEM_SPI_SMEM_CS_HOLD_TIME_S,
);
set_peri_reg_bits(
SPI0_MEM_SPI_SMEM_AC_REG,
SPI_MEM_SPI_SMEM_CS_SETUP_TIME_V,
OCT_PSRAM_CS_SETUP_TIME as u32,
SPI_MEM_SPI_SMEM_CS_SETUP_TIME_S,
);
set_peri_reg_bits(
SPI0_MEM_SPI_SMEM_AC_REG,
SPI_MEM_SPI_SMEM_CS_HOLD_DELAY_V,
OCT_PSRAM_CS_HOLD_DELAY as u32,
SPI_MEM_SPI_SMEM_CS_HOLD_DELAY_S,
);
}
fn init_psram_pins() {
unsafe {
let iomux = &*esp32s3::IO_MUX::PTR;
iomux
.gpio(OCT_PSRAM_CS1_IO as usize)
.modify(|_, w| w.mcu_sel().variant(FUNC_SPICS1_SPICS1))
}
unsafe {
let iomux = &*esp32s3::IO_MUX::PTR;
iomux
.gpio(OCT_PSRAM_CS1_IO as usize)
.modify(|_, w| w.fun_drv().variant(3))
}
set_peri_reg_bits(
SPI0_MEM_DATE_REG,
SPI_MEM_SPI_SMEM_SPICLK_FUN_DRV_V,
3,
SPI_MEM_SPI_SMEM_SPICLK_FUN_DRV_S,
);
}
fn get_psram_mode_reg(spi_num: u32, out_reg: &mut OpiPsramModeReg) {
let mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE;
let cmd_len: u32 = 16;
let addr_bit_len: u32 = 32;
let dummy: u32 = OCT_PSRAM_RD_DUMMY_BITLEN as u32;
let mut data_bit_len: u32 = 16;
unsafe {
esp_rom_opiflash_exec_cmd(
spi_num,
mode,
OPI_PSRAM_REG_READ as u32,
cmd_len,
0x0,
addr_bit_len,
dummy,
core::ptr::null(),
0,
&mut out_reg.mr0,
data_bit_len,
1 << 1,
false,
);
esp_rom_opiflash_exec_cmd(
spi_num,
mode,
OPI_PSRAM_REG_READ as u32,
cmd_len,
0x2,
addr_bit_len,
dummy,
core::ptr::null(),
0,
&mut out_reg.mr2,
data_bit_len,
1 << 1,
false,
);
data_bit_len = 8;
esp_rom_opiflash_exec_cmd(
spi_num,
mode,
OPI_PSRAM_REG_READ as u32,
cmd_len,
0x4,
addr_bit_len,
dummy,
core::ptr::null(),
0,
&mut out_reg.mr4,
data_bit_len,
1 << 1,
false,
);
esp_rom_opiflash_exec_cmd(
spi_num,
mode,
OPI_PSRAM_REG_READ as u32,
cmd_len,
0x8,
addr_bit_len,
dummy,
core::ptr::null(),
0,
&mut out_reg.mr8,
data_bit_len,
1 << 1,
false,
);
}
}
fn init_psram_mode_reg(spi_num: u32, mode_reg_config: &OpiPsramModeReg) {
let mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE;
let cmd_len: u32 = 16;
let addr: u32 = 0x0; let addr_bit_len: u32 = 32;
let dummy = OCT_PSRAM_RD_DUMMY_BITLEN as u32;
let mut mode_reg = OpiPsramModeReg::default();
let data_bit_len: u32 = 16;
unsafe {
esp_rom_opiflash_exec_cmd(
spi_num,
mode,
OPI_PSRAM_REG_READ as u32,
cmd_len,
addr,
addr_bit_len,
dummy,
core::ptr::null(),
0,
&mut mode_reg.mr0,
data_bit_len,
1 << 1,
false,
);
}
mode_reg.set_lt(mode_reg_config.lt());
mode_reg.set_read_latency(mode_reg_config.read_latency());
mode_reg.set_drive_str(mode_reg_config.drive_str());
unsafe {
esp_rom_opiflash_exec_cmd(
spi_num,
mode,
OPI_PSRAM_REG_WRITE as u32,
cmd_len,
addr,
addr_bit_len,
0,
&mode_reg.mr0,
16,
core::ptr::null_mut(),
0,
1 << 1,
false,
);
}
}
fn print_psram_info(reg_val: &OpiPsramModeReg) {
info!(
"vendor id : {:02x} ({})",
reg_val.vendor_id(),
if reg_val.vendor_id() == 0x0d {
"AP"
} else {
"UNKNOWN"
}
);
info!(
"dev id : {:02x} (generation {})",
reg_val.dev_id(),
reg_val.dev_id() + 1
);
info!(
"density : {:02x} ({} Mbit)",
reg_val.density(),
if reg_val.density() == 0x1 {
32
} else if reg_val.density() == 0x3 {
64
} else if reg_val.density() == 0x5 {
128
} else if reg_val.density() == 0x7 {
256
} else {
0
}
);
info!(
"good-die : {:02x} ({})",
reg_val.gb(),
if reg_val.gb() == 1 { "Pass" } else { "Fail" }
);
info!(
"Latency : {:02x} ({})",
reg_val.lt(),
if reg_val.lt() == 1 {
"Fixed"
} else {
"Variable"
}
);
info!(
"VCC : {:02x} ({})",
reg_val.vcc(),
if reg_val.vcc() == 1 { "3V" } else { "1.8V" }
);
info!(
"SRF : {:02x} ({} Refresh)",
reg_val.srf(),
if reg_val.srf() == 0x1 { "Fast" } else { "Slow" }
);
info!(
"BurstType : {:02x} ({} Wrap)",
reg_val.bt(),
if reg_val.bt() == 1 && reg_val.bl() != 3 {
"Hybrid"
} else {
""
}
);
info!(
"BurstLen : {:02x} ({} Byte)",
reg_val.bl(),
if reg_val.bl() == 0x00 {
16
} else if reg_val.bl() == 0x01 {
32
} else if reg_val.bl() == 0x10 {
64
} else {
1024
}
);
info!(
"Readlatency : {:02x} ({} cycles@{})",
reg_val.read_latency(),
reg_val.read_latency() * 2 + 6,
if reg_val.lt() == 1 {
"Fixed"
} else {
"Variable"
}
);
info!(
"DriveStrength: {:02x} (1/{})",
reg_val.drive_str(),
if reg_val.drive_str() == 0x00 {
1
} else if reg_val.drive_str() == 0x01 {
2
} else if reg_val.drive_str() == 0x02 {
4
} else {
8
}
);
}
#[ram]
fn spi0_timing_config_set_core_clock(core_clock: SpiTimingConfigCoreClock) {
let reg_val = match core_clock {
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m => 0,
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock120m => 1,
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock160m => 2,
SpiTimingConfigCoreClock::SpiTimingConfigCoreClock240m => 3,
};
set_peri_reg_bits(SPI0_MEM_CORE_CLK_SEL_REG, SPI_MEM_CORE_CLK_SEL, reg_val, 0);
}
#[ram]
fn spi0_timing_config_set_flash_clock(freqdiv: u32) {
if freqdiv == 1 {
write_peri_reg(SPI0_MEM_CLOCK_REG, SPI_MEM_CLK_EQU_SYSCLK);
} else {
let freqbits: u32 = ((freqdiv - 1) << SPI_MEM_CLKCNT_N_S)
| ((freqdiv / 2 - 1) << SPI_MEM_CLKCNT_H_S)
| ((freqdiv - 1) << SPI_MEM_CLKCNT_L_S);
write_peri_reg(SPI0_MEM_CLOCK_REG, freqbits);
}
}
#[ram]
fn spi1_timing_config_set_flash_clock(freqdiv: u32) {
if freqdiv == 1 {
write_peri_reg(SPI1_MEM_CLOCK_REG, SPI_MEM_CLK_EQU_SYSCLK);
} else {
let freqbits: u32 = ((freqdiv - 1) << SPI_MEM_CLKCNT_N_S)
| ((freqdiv / 2 - 1) << SPI_MEM_CLKCNT_H_S)
| ((freqdiv - 1) << SPI_MEM_CLKCNT_L_S);
write_peri_reg(SPI1_MEM_CLOCK_REG, freqbits);
}
}
#[ram]
fn spi0_timing_config_set_psram_clock(freqdiv: u32) {
if freqdiv == 1 {
write_peri_reg(SPI0_MEM_SRAM_CLK_REG, SPI_MEM_SCLK_EQU_SYSCLK);
} else {
let freqbits: u32 = ((freqdiv - 1) << SPI_MEM_SCLKCNT_N_S)
| ((freqdiv / 2 - 1) << SPI_MEM_SCLKCNT_H_S)
| ((freqdiv - 1) << SPI_MEM_SCLKCNT_L_S);
write_peri_reg(SPI0_MEM_SRAM_CLK_REG, freqbits);
}
}
#[ram]
fn get_flash_clock_divider() -> u32 {
match FLASH_FREQ {
FlashFreq::FlashFreq20m => SPI_TIMING_CORE_CLOCK.mhz() / 20,
FlashFreq::FlashFreq40m => SPI_TIMING_CORE_CLOCK.mhz() / 40,
FlashFreq::FlashFreq80m => SPI_TIMING_CORE_CLOCK.mhz() / 80,
FlashFreq::FlashFreq120m => SPI_TIMING_CORE_CLOCK.mhz() / 120,
}
}
#[ram]
fn get_psram_clock_divider() -> u32 {
match SPIRAM_SPEED {
SpiRamFreq::Freq40m => SPI_TIMING_CORE_CLOCK.mhz() / 40,
SpiRamFreq::Freq80m => SPI_TIMING_CORE_CLOCK.mhz() / 80,
SpiRamFreq::Freq120m => SPI_TIMING_CORE_CLOCK.mhz() / 120,
}
}
#[inline(always)]
fn clear_peri_reg_mask(reg: u32, mask: u32) {
unsafe {
(reg as *mut u32).write_volatile((reg as *mut u32).read_volatile() & !mask);
}
}
#[inline(always)]
fn set_peri_reg_mask(reg: u32, mask: u32) {
unsafe {
(reg as *mut u32).write_volatile((reg as *mut u32).read_volatile() | mask);
}
}
#[inline(always)]
fn set_peri_reg_bits(reg: u32, bitmap: u32, value: u32, shift: u32) {
unsafe {
(reg as *mut u32).write_volatile(
((reg as *mut u32).read_volatile() & !(bitmap << shift))
| ((value & bitmap) << shift),
);
}
}
#[inline(always)]
fn write_peri_reg(reg: u32, val: u32) {
unsafe {
(reg as *mut u32).write_volatile(val);
}
}
}