1use core::ops::Range;
2
3use super::{EXTMEM_ORIGIN, PsramSize};
4
5#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
8#[allow(missing_docs)]
9pub enum PsramCacheSpeed {
10 #[default]
11 PsramCacheF80mS40m = 0,
12 PsramCacheF40mS40m,
13 PsramCacheF80mS80m,
14}
15
16#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
20#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21pub enum PsramVaddrMode {
22 #[default]
26 Normal = 0,
27 LowHigh,
32 Evenodd,
37}
38
39#[derive(Copy, Clone, Debug, Default)]
41#[cfg_attr(feature = "defmt", derive(defmt::Format))]
42pub struct PsramConfig {
43 pub size: PsramSize,
45 pub cache_speed: PsramCacheSpeed,
47 pub psram_vaddr_mode: PsramVaddrMode,
49}
50
51#[procmacros::ram]
53pub(crate) fn init_psram(config: &mut PsramConfig) -> bool {
54 utils::psram_init(config);
55 true
56}
57
58#[procmacros::ram]
59pub(crate) fn map_psram(mut config: PsramConfig) -> Range<usize> {
60 if config.size.is_auto() {
61 const MAX_MEM_SIZE: usize = 4 * 1024 * 1024;
62
63 utils::s_mapping(EXTMEM_ORIGIN as u32, MAX_MEM_SIZE as u32);
69
70 let guessed_size = unsafe {
71 let ptr = EXTMEM_ORIGIN as *mut u8;
72 for i in (1023..MAX_MEM_SIZE).step_by(1024) {
73 ptr.add(i).write_volatile(0x7f);
74 }
75
76 let mut last_correctly_read = 0;
77 for i in (1023..MAX_MEM_SIZE).step_by(1024) {
78 if ptr.add(i).read_volatile() == 0x7f {
79 last_correctly_read = i;
80 } else {
81 break;
82 }
83 }
84
85 last_correctly_read + 1
86 };
87
88 info!("Assuming {} bytes of PSRAM", guessed_size);
89 config.size = PsramSize::Size(guessed_size);
90 }
91
92 utils::s_mapping(EXTMEM_ORIGIN as u32, config.size.get() as u32);
93
94 EXTMEM_ORIGIN..EXTMEM_ORIGIN + config.size.get()
95}
96
97pub(crate) mod utils {
98 use core::ptr::addr_of_mut;
99
100 use procmacros::ram;
101
102 use super::*;
103 use crate::peripherals::{DPORT, SPI0, SPI1};
104
105 #[ram]
106 pub(crate) fn s_mapping(v_start: u32, size: u32) {
107 cache_sram_mmu_set(0, 0, v_start, 0, 32, size / 1024 / 32);
109 DPORT::regs()
111 .app_cache_ctrl1()
112 .modify(|_, w| w.app_cache_mask_dram1().clear_bit());
113
114 cache_sram_mmu_set(1, 0, v_start, 0, 32, size / 1024 / 32);
115 }
116
117 #[ram]
120 fn cache_sram_mmu_set(
121 cpu_no: u32,
122 pid: u32,
123 vaddr: u32,
124 paddr: u32,
125 psize: u32,
126 num: u32,
127 ) -> i32 {
128 unsafe { cache_sram_mmu_set_rom(cpu_no, pid, vaddr, paddr, psize, num) }
129 }
130
131 const D0WD_PSRAM_CLK_IO: u8 = 17;
135 const D0WD_PSRAM_CS_IO: u8 = 16;
136
137 const D2WD_PSRAM_CLK_IO: u8 = 9; const D2WD_PSRAM_CS_IO: u8 = 10; const PICO_PSRAM_CLK_IO: u8 = 6;
143 const PICO_PSRAM_CS_IO: u8 = 10; const PICO_V3_02_PSRAM_CLK_IO: u8 = 10;
146 const PICO_V3_02_PSRAM_CS_IO: u8 = 9;
147 const PICO_V3_02_PSRAM_SPIWP_SD3_IO: u8 = 18;
148
149 const ESP_ROM_EFUSE_FLASH_DEFAULT_SPI: u32 = 0;
150 const ESP_ROM_EFUSE_FLASH_DEFAULT_HSPI: u32 = 1;
151
152 const SPI_IOMUX_PIN_NUM_CLK: u8 = 6;
153 const SPI_IOMUX_PIN_NUM_CS: u8 = 11;
154
155 const PSRAM_SPIQ_SD0_IO: u8 = 7;
161 const PSRAM_SPID_SD1_IO: u8 = 8;
162 const PSRAM_SPIWP_SD3_IO: u8 = 10;
163 const PSRAM_SPIHD_SD2_IO: u8 = 9;
164
165 const FLASH_HSPI_CLK_IO: u8 = 14;
166 const FLASH_HSPI_CS_IO: u8 = 15;
167
168 const PSRAM_HSPI_SPIQ_SD0_IO: u8 = 12;
169 const PSRAM_HSPI_SPID_SD1_IO: u8 = 13;
170 const PSRAM_HSPI_SPIWP_SD3_IO: u8 = 2;
171 const PSRAM_HSPI_SPIHD_SD2_IO: u8 = 4;
172
173 const DR_REG_SPI1_BASE: u32 = 0x3ff42000;
174 const SPI1_USER_REG: u32 = DR_REG_SPI1_BASE + 0x1C;
175 const SPI1_W0_REG: u32 = DR_REG_SPI1_BASE + 0x80;
176
177 const fn psram_cs_hold_time_from_psram_speed(speed: PsramCacheSpeed) -> u32 {
178 match speed {
179 PsramCacheSpeed::PsramCacheF80mS40m => 0,
180 PsramCacheSpeed::PsramCacheF40mS40m => 0,
181 PsramCacheSpeed::PsramCacheF80mS80m => 1,
182 }
183 }
184
185 const PSRAM_INTERNAL_IO_28: u32 = 28;
186 const PSRAM_INTERNAL_IO_29: u32 = 29;
187 const SIG_GPIO_OUT_IDX: u32 = 256;
188 const SPICLK_OUT_IDX: u32 = 0;
189 const SIG_IN_FUNC224_IDX: u32 = 224;
190 const SIG_IN_FUNC225_IDX: u32 = 225;
191 const SPICS0_OUT_IDX: u32 = 5;
192 const SPICS1_OUT_IDX: u32 = 6;
193 const SPIQ_OUT_IDX: u32 = 1;
194 const SPIQ_IN_IDX: u32 = 1;
195 const SPID_OUT_IDX: u32 = 2;
196 const SPID_IN_IDX: u32 = 2;
197 const SPIWP_OUT_IDX: u32 = 4;
198 const SPIWP_IN_IDX: u32 = 4;
199 const SPIHD_OUT_IDX: u32 = 3;
200 const SPIHD_IN_IDX: u32 = 3;
201 const FUNC_SD_CLK_SPICLK: u32 = 1;
202 const PIN_FUNC_GPIO: u32 = 2;
203
204 const PSRAM_QUAD_WRITE: u32 = 0x38;
205 const PSRAM_FAST_READ_QUAD_DUMMY: u32 = 0x5;
206 const PSRAM_FAST_READ_QUAD: u32 = 0xEB;
207
208 const SPI_FWRITE_DUAL_S: u32 = 12;
209 const SPI_FWRITE_DUAL_M: u32 = 1 << 12;
210
211 const SPI_FREAD_QIO_M: u32 = 1 << 24;
212 const SPI0_R_QIO_DUMMY_CYCLELEN: u32 = 3;
213 const SPI_FREAD_DIO_M: u32 = 1 << 23;
214 const SPI0_R_DIO_DUMMY_CYCLELEN: u32 = 1;
215 const SPI0_R_DIO_ADDR_BITSLEN: u32 = 27;
216 const SPI_FREAD_QUAD_M: u32 = 1 << 20;
217 const SPI_FREAD_DUAL_M: u32 = 1 << 14;
218 const SPI0_R_FAST_DUMMY_CYCLELEN: u32 = 7;
219 const PSRAM_IO_MATRIX_DUMMY_40M: u8 = 1;
220 const PSRAM_IO_MATRIX_DUMMY_80M: u8 = 2;
221
222 const _SPI_CACHE_PORT: u8 = 0;
223 const _SPI_FLASH_PORT: u8 = 1;
224 const _SPI_80M_CLK_DIV: u8 = 1;
225 const _SPI_40M_CLK_DIV: u8 = 2;
226
227 const FLASH_ID_GD25LQ32C: u32 = 0xC86016;
228
229 const EFUSE_SPICONFIG_RET_SPICLK_MASK: u32 = 0x3f;
230 const EFUSE_SPICONFIG_RET_SPICLK_SHIFT: u8 = 0;
231 const EFUSE_SPICONFIG_RET_SPIQ_MASK: u32 = 0x3f;
232 const EFUSE_SPICONFIG_RET_SPIQ_SHIFT: u8 = 6;
233 const EFUSE_SPICONFIG_RET_SPID_MASK: u32 = 0x3f;
234 const EFUSE_SPICONFIG_RET_SPID_SHIFT: u8 = 12;
235 const EFUSE_SPICONFIG_RET_SPICS0_MASK: u32 = 0x3f;
236 const EFUSE_SPICONFIG_RET_SPICS0_SHIFT: u8 = 18;
237 const EFUSE_SPICONFIG_RET_SPIHD_MASK: u32 = 0x3f;
238 const EFUSE_SPICONFIG_RET_SPIHD_SHIFT: u8 = 24;
239
240 fn efuse_spiconfig_ret(spi_config: u32, mask: u32, shift: u8) -> u8 {
241 (((spi_config) >> shift) & mask) as u8
242 }
243
244 #[derive(PartialEq, Eq, Debug, Default)]
245 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
246 struct PsramIo {
247 flash_clk_io: u8,
248 flash_cs_io: u8,
249 psram_clk_io: u8,
250 psram_cs_io: u8,
251 psram_spiq_sd0_io: u8,
252 psram_spid_sd1_io: u8,
253 psram_spiwp_sd3_io: u8,
254 psram_spihd_sd2_io: u8,
255 }
256
257 #[derive(PartialEq, Eq, Copy, Clone, Debug)]
258 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
259 enum PsramClkMode {
260 PsramClkModeNorm = 0, PsramClkModeDclk = 1, }
263
264 #[repr(C)]
265 pub(super) struct EspRomSpiflashChip {
266 pub device_id: u32,
267 pub chip_size: u32, pub block_size: u32,
269 pub sector_size: u32,
270 pub page_size: u32,
271 pub status_mask: u32,
272 }
273
274 unsafe extern "C" {
275 fn esp_rom_efuse_get_flash_gpio_info() -> u32;
276
277 fn esp_rom_gpio_connect_out_signal(
278 gpio_num: u32,
279 signal_idx: u32,
280 out_inv: bool,
281 oen_inv: bool,
282 );
283
284 fn esp_rom_gpio_connect_in_signal(gpio_num: u32, signal_idx: u32, inv: bool);
285
286 fn esp_rom_spiflash_config_clk(freqdiv: u8, spi: u8) -> i32;
287
288 static mut g_rom_spiflash_dummy_len_plus: u8;
289
290 pub(super) static g_rom_flashchip: EspRomSpiflashChip;
291
292 fn cache_sram_mmu_set_rom(
293 cpu_no: u32,
294 pid: u32,
295 vaddr: u32,
296 paddr: u32,
297 psize: u32,
298 num: u32,
299 ) -> i32;
300 }
301
302 #[ram]
303 pub(crate) fn psram_init(config: &PsramConfig) {
304 let chip = crate::efuse::chip_type();
305
306 let mode = config.cache_speed;
307 let mut psram_io = PsramIo::default();
308 let clk_mode;
309
310 match chip {
311 crate::efuse::ChipType::Esp32D0wdq6 | crate::efuse::ChipType::Esp32D0wdq5 => {
312 clk_mode = PsramClkMode::PsramClkModeNorm;
313 psram_io.psram_clk_io = D0WD_PSRAM_CLK_IO;
314 psram_io.psram_cs_io = D0WD_PSRAM_CS_IO;
315 }
316 crate::efuse::ChipType::Esp32D2wdq5 => {
317 clk_mode = PsramClkMode::PsramClkModeDclk;
318 psram_io.psram_clk_io = D2WD_PSRAM_CLK_IO;
319 psram_io.psram_cs_io = D2WD_PSRAM_CS_IO;
320 }
321 crate::efuse::ChipType::Esp32Picod2 => {
322 clk_mode = PsramClkMode::PsramClkModeNorm;
323 psram_io.psram_clk_io = PICO_PSRAM_CLK_IO;
324 psram_io.psram_cs_io = PICO_PSRAM_CS_IO;
325 }
326 crate::efuse::ChipType::Esp32Picod4 => {
327 panic!("PSRAM is unsupported on this chip");
328 }
329 crate::efuse::ChipType::Esp32Picov302 => {
330 clk_mode = PsramClkMode::PsramClkModeNorm;
331 psram_io.psram_clk_io = PICO_V3_02_PSRAM_CLK_IO;
332 psram_io.psram_cs_io = PICO_V3_02_PSRAM_CS_IO;
333 }
334 crate::efuse::ChipType::Unknown => {
335 panic!("Unknown chip type. PSRAM is not supported");
336 }
337 }
338
339 let spiconfig = unsafe { esp_rom_efuse_get_flash_gpio_info() };
340 if spiconfig == ESP_ROM_EFUSE_FLASH_DEFAULT_SPI {
341 psram_io.flash_clk_io = SPI_IOMUX_PIN_NUM_CLK;
342 psram_io.flash_cs_io = SPI_IOMUX_PIN_NUM_CS;
343 psram_io.psram_spiq_sd0_io = PSRAM_SPIQ_SD0_IO;
344 psram_io.psram_spid_sd1_io = PSRAM_SPID_SD1_IO;
345 psram_io.psram_spiwp_sd3_io = PSRAM_SPIWP_SD3_IO;
346 psram_io.psram_spihd_sd2_io = PSRAM_SPIHD_SD2_IO;
347 } else if spiconfig == ESP_ROM_EFUSE_FLASH_DEFAULT_HSPI {
348 psram_io.flash_clk_io = FLASH_HSPI_CLK_IO;
349 psram_io.flash_cs_io = FLASH_HSPI_CS_IO;
350 psram_io.psram_spiq_sd0_io = PSRAM_HSPI_SPIQ_SD0_IO;
351 psram_io.psram_spid_sd1_io = PSRAM_HSPI_SPID_SD1_IO;
352 psram_io.psram_spiwp_sd3_io = PSRAM_HSPI_SPIWP_SD3_IO;
353 psram_io.psram_spihd_sd2_io = PSRAM_HSPI_SPIHD_SD2_IO;
354 } else if chip == crate::efuse::ChipType::Esp32Picov302 {
355 psram_io.flash_clk_io = efuse_spiconfig_ret(
356 spiconfig,
357 EFUSE_SPICONFIG_RET_SPICLK_MASK,
358 EFUSE_SPICONFIG_RET_SPICLK_SHIFT,
359 );
360 psram_io.flash_cs_io = efuse_spiconfig_ret(
361 spiconfig,
362 EFUSE_SPICONFIG_RET_SPICS0_MASK,
363 EFUSE_SPICONFIG_RET_SPICS0_SHIFT,
364 );
365 psram_io.psram_spiq_sd0_io = efuse_spiconfig_ret(
366 spiconfig,
367 EFUSE_SPICONFIG_RET_SPIQ_MASK,
368 EFUSE_SPICONFIG_RET_SPIQ_SHIFT,
369 );
370 psram_io.psram_spid_sd1_io = efuse_spiconfig_ret(
371 spiconfig,
372 EFUSE_SPICONFIG_RET_SPID_MASK,
373 EFUSE_SPICONFIG_RET_SPID_SHIFT,
374 );
375 psram_io.psram_spihd_sd2_io = efuse_spiconfig_ret(
376 spiconfig,
377 EFUSE_SPICONFIG_RET_SPIHD_MASK,
378 EFUSE_SPICONFIG_RET_SPIHD_SHIFT,
379 );
380 psram_io.psram_spiwp_sd3_io = PICO_V3_02_PSRAM_SPIWP_SD3_IO;
381 } else {
382 panic!("Getting Flash/PSRAM pins from efuse is not supported");
383 }
391 info!("PS-RAM pins {:?}", &psram_io);
392
393 unsafe {
394 SPI0::regs().ext3().modify(|_, w| w.bits(0x1));
395 SPI1::regs()
396 .user()
397 .modify(|_, w| w.usr_prep_hold().clear_bit());
398 }
399
400 psram_spi_init(mode, clk_mode);
401
402 match mode {
403 PsramCacheSpeed::PsramCacheF80mS80m => unsafe {
404 esp_rom_gpio_connect_out_signal(
405 psram_io.psram_clk_io as u32,
406 SPICLK_OUT_IDX,
407 false,
408 false,
409 );
410 },
411 _ => unsafe {
412 if clk_mode == PsramClkMode::PsramClkModeDclk {
413 esp_rom_gpio_connect_out_signal(
422 PSRAM_INTERNAL_IO_28,
423 SPICLK_OUT_IDX,
424 false,
425 false,
426 );
427 esp_rom_gpio_connect_in_signal(PSRAM_INTERNAL_IO_28, SIG_IN_FUNC224_IDX, false);
428 esp_rom_gpio_connect_out_signal(
429 PSRAM_INTERNAL_IO_29,
430 SIG_IN_FUNC224_IDX,
431 false,
432 false,
433 );
434 esp_rom_gpio_connect_in_signal(PSRAM_INTERNAL_IO_29, SIG_IN_FUNC225_IDX, false);
435 esp_rom_gpio_connect_out_signal(
436 psram_io.psram_clk_io as u32,
437 SIG_IN_FUNC225_IDX,
438 false,
439 false,
440 );
441 } else {
442 esp_rom_gpio_connect_out_signal(
443 psram_io.psram_clk_io as u32,
444 SPICLK_OUT_IDX,
445 false,
446 false,
447 );
448 }
449 },
450 }
451
452 let extra_dummy = psram_gpio_config(&psram_io, mode);
453 info!("extra dummy = {}", extra_dummy);
454
455 unsafe {
458 esp_rom_gpio_connect_out_signal(PSRAM_INTERNAL_IO_28, SIG_GPIO_OUT_IDX, false, false);
459 esp_rom_gpio_connect_out_signal(PSRAM_INTERNAL_IO_29, SIG_GPIO_OUT_IDX, false, false);
460 esp_rom_gpio_connect_out_signal(
461 psram_io.psram_clk_io as u32,
462 SPICLK_OUT_IDX,
463 false,
464 false,
465 );
466 }
467
468 psram_set_cs_timing_spi1(mode, clk_mode);
470 psram_set_cs_timing_spi0(mode, clk_mode); psram_enable_qio_mode_spi1(clk_mode, mode);
472
473 let psram_vaddr_mode = config.psram_vaddr_mode;
474 info!("PS-RAM vaddrmode = {:?}", psram_vaddr_mode);
475
476 psram_cache_init(mode, psram_vaddr_mode, clk_mode, extra_dummy);
477 }
478
479 fn psram_cache_init(
481 psram_cache_mode: PsramCacheSpeed,
482 vaddrmode: PsramVaddrMode,
483 clk_mode: PsramClkMode,
484 extra_dummy: u32,
485 ) {
486 unsafe {
487 let spi = SPI0::regs();
488 info!(
489 "PS-RAM cache_init, psram_cache_mode={:?}, extra_dummy={}, clk_mode={:?}",
490 psram_cache_mode, extra_dummy, clk_mode
491 );
492 match psram_cache_mode {
493 PsramCacheSpeed::PsramCacheF80mS80m => {
494 spi.date().modify(|r, w| {
498 let current_bits = r.bits();
499 let new_bits = current_bits & !((1 << 31) | (1 << 30));
500 w.bits(new_bits)
501 });
502 }
506 PsramCacheSpeed::PsramCacheF80mS40m => {
507 spi.clock().modify(|_, w| w.clk_equ_sysclk().clear_bit());
508 spi.clock().modify(|_, w| w.clkdiv_pre().bits(0));
509 spi.clock().modify(|_, w| w.clkcnt_n().bits(1));
510 spi.clock().modify(|_, w| w.clkcnt_h().bits(0));
511 spi.clock().modify(|_, w| w.clkcnt_l().bits(1));
512
513 spi.date().modify(|r, w| {
514 let current_bits = r.bits();
515 let new_bits = (current_bits | (1 << 31)) & !(1 << 30);
516 w.bits(new_bits)
517 });
518 }
519 _ => {
520 spi.date().modify(|r, w| {
521 let current_bits = r.bits();
522 let new_bits = current_bits & !((1 << 31) | (1 << 30));
523 w.bits(new_bits)
524 });
525 }
526 }
527
528 spi.cache_sctrl()
529 .modify(|_, w| w.usr_sram_dio().clear_bit()); spi.cache_sctrl().modify(|_, w| w.usr_sram_qio().set_bit()); spi.cache_sctrl()
532 .modify(|_, w| w.cache_sram_usr_rcmd().set_bit()); spi.cache_sctrl()
534 .modify(|_, w| w.cache_sram_usr_wcmd().set_bit()); spi.cache_sctrl()
536 .modify(|_, w| w.sram_addr_bitlen().bits(23)); spi.cache_sctrl()
538 .modify(|_, w| w.usr_rd_sram_dummy().set_bit()); spi.sram_drd_cmd()
542 .modify(|_, w| w.cache_sram_usr_rd_cmd_bitlen().bits(7));
543 spi.sram_drd_cmd().modify(|_, w| {
544 w.cache_sram_usr_rd_cmd_value()
545 .bits(PSRAM_FAST_READ_QUAD as u16)
546 });
547 spi.sram_dwr_cmd()
548 .modify(|_, w| w.cache_sram_usr_wr_cmd_bitlen().bits(7));
549 spi.sram_dwr_cmd().modify(|_, w| {
550 w.cache_sram_usr_wr_cmd_value()
551 .bits(PSRAM_QUAD_WRITE as u16)
552 });
553
554 spi.cache_sctrl().modify(|_, w| {
556 w.sram_dummy_cyclelen()
557 .bits((PSRAM_FAST_READ_QUAD_DUMMY + extra_dummy) as u8)
558 });
559
560 match psram_cache_mode {
561 PsramCacheSpeed::PsramCacheF80mS80m => (), _ => {
563 if clk_mode == PsramClkMode::PsramClkModeDclk {
564 spi.sram_drd_cmd()
565 .modify(|_, w| w.cache_sram_usr_rd_cmd_bitlen().bits(15)); spi.sram_drd_cmd().modify(|_, w| {
568 w.cache_sram_usr_rd_cmd_value()
569 .bits((PSRAM_FAST_READ_QUAD << 8) as u16)
570 }); spi.sram_dwr_cmd()
573 .modify(|_, w| w.cache_sram_usr_wr_cmd_bitlen().bits(15)); spi.sram_dwr_cmd().modify(|_, w| {
575 w.cache_sram_usr_wr_cmd_value()
576 .bits((PSRAM_QUAD_WRITE << 8) as u16)
577 }); spi.cache_sctrl().modify(|_, w| {
579 w.sram_dummy_cyclelen()
580 .bits((PSRAM_FAST_READ_QUAD_DUMMY + extra_dummy) as u8)
581 }); }
583 }
584 }
585
586 let dport = DPORT::regs();
587
588 dport
589 .pro_cache_ctrl()
590 .modify(|_, w| w.pro_dram_hl().clear_bit().pro_dram_split().clear_bit());
591 dport
592 .app_cache_ctrl()
593 .modify(|_, w| w.app_dram_hl().clear_bit().app_dram_split().clear_bit());
594 if vaddrmode == PsramVaddrMode::LowHigh {
595 dport
596 .pro_cache_ctrl()
597 .modify(|_, w| w.pro_dram_hl().set_bit());
598 dport
599 .app_cache_ctrl()
600 .modify(|_, w| w.app_dram_hl().set_bit());
601 } else if vaddrmode == PsramVaddrMode::Evenodd {
602 dport
603 .pro_cache_ctrl()
604 .modify(|_, w| w.pro_dram_split().set_bit());
605 dport
606 .app_cache_ctrl()
607 .modify(|_, w| w.app_dram_split().set_bit());
608 }
609
610 dport.pro_cache_ctrl1().modify(|_, w| {
613 w.pro_cache_mask_dram1()
614 .clear_bit()
615 .pro_cache_mask_opsdram()
616 .clear_bit()
617 });
618 dport
619 .pro_cache_ctrl1()
620 .modify(|_, w| w.pro_cmmu_sram_page_mode().bits(0));
621
622 dport.app_cache_ctrl1().modify(|_, w| {
625 w.app_cache_mask_dram1()
626 .clear_bit()
627 .app_cache_mask_opsdram()
628 .clear_bit()
629 });
630 dport
631 .app_cache_ctrl1()
632 .modify(|_, w| w.app_cmmu_sram_page_mode().bits(0));
633
634 spi.pin().modify(|_, w| w.cs1_dis().clear_bit());
636 }
637 }
638
639 #[ram]
641 fn psram_spi_init(
642 mode: PsramCacheSpeed,
644 clk_mode: PsramClkMode,
645 ) {
646 unsafe {
647 let spi = SPI1::regs();
648 spi.slave().modify(|_, w| w.trans_inten().clear_bit());
650 spi.pin().modify(|_, w| w.ck_idle_edge().clear_bit());
652 spi.user().modify(|_, w| w.ck_out_edge().clear_bit());
653 spi.ctrl().modify(|_, w| w.wr_bit_order().clear_bit());
655 spi.ctrl().modify(|_, w| w.rd_bit_order().clear_bit());
656 spi.user().modify(|_, w| w.doutdin().clear_bit());
658 spi.user1().modify(|_, w| w.bits(0));
660 spi.slave().modify(|_, w| w.mode().clear_bit());
662
663 let ptr = SPI1_W0_REG as *mut u32;
664 for i in 0..16 {
665 ptr.offset(i).write_volatile(0);
666 }
667
668 psram_set_cs_timing_spi1(mode, clk_mode);
669 }
670 }
671
672 fn psram_set_cs_timing_spi1(psram_cache_mode: PsramCacheSpeed, clk_mode: PsramClkMode) {
673 unsafe {
674 let spi = SPI1::regs();
675 if clk_mode == PsramClkMode::PsramClkModeNorm {
676 spi.user().modify(|_, w| w.cs_hold().set_bit());
677 spi.user().modify(|_, w| w.cs_setup().set_bit());
678
679 spi.ctrl2().modify(|_, w| {
680 w.hold_time()
681 .bits(psram_cs_hold_time_from_psram_speed(psram_cache_mode) as u8)
682 });
683
684 spi.ctrl2().modify(|_, w| w.setup_time().bits(0));
686 } else {
687 spi.user().modify(|_, w| w.cs_hold().clear_bit());
688 spi.user().modify(|_, w| w.cs_setup().clear_bit());
689 }
690 }
691 }
692
693 fn psram_set_cs_timing_spi0(psram_cache_mode: PsramCacheSpeed, clk_mode: PsramClkMode) {
694 unsafe {
695 let spi = SPI0::regs();
696 if clk_mode == PsramClkMode::PsramClkModeNorm {
697 spi.user().modify(|_, w| w.cs_hold().set_bit());
698 spi.user().modify(|_, w| w.cs_setup().set_bit());
699
700 spi.ctrl2().modify(|_, w| {
701 w.hold_time()
702 .bits(psram_cs_hold_time_from_psram_speed(psram_cache_mode) as u8)
703 });
704
705 spi.ctrl2().modify(|_, w| w.setup_time().bits(0));
707 } else {
708 spi.user().modify(|_, w| w.cs_hold().clear_bit());
709 spi.user().modify(|_, w| w.cs_setup().clear_bit());
710 }
711 }
712 }
713
714 #[derive(Default, Debug, Copy, Clone, PartialEq)]
715 struct PsramCmd {
716 cmd: u16, cmd_bit_len: u16, addr: u32, addr_bit_len: u16, tx_data: *const u32, tx_data_bit_len: u16, rx_data: *mut u32, rx_data_bit_len: u16, dummy_bit_len: u32,
725 }
726
727 const PSRAM_ENTER_QMODE: u32 = 0x35;
728
729 #[ram]
731 fn psram_enable_qio_mode_spi1(clk_mode: PsramClkMode, psram_mode: PsramCacheSpeed) {
732 let mut ps_cmd: PsramCmd = PsramCmd::default();
733 let addr: u32 = PSRAM_ENTER_QMODE << 24;
734
735 ps_cmd.cmd_bit_len = 0;
736 if clk_mode == PsramClkMode::PsramClkModeDclk {
737 match psram_mode {
738 PsramCacheSpeed::PsramCacheF80mS80m => (),
739 _ => {
740 ps_cmd.cmd_bit_len = 2;
741 }
742 }
743 }
744 ps_cmd.cmd = 0;
745 ps_cmd.addr = addr;
746 ps_cmd.addr_bit_len = 8;
747 ps_cmd.tx_data = core::ptr::null();
748 ps_cmd.tx_data_bit_len = 0;
749 ps_cmd.rx_data = core::ptr::null_mut();
750 ps_cmd.rx_data_bit_len = 0;
751 ps_cmd.dummy_bit_len = 0;
752 let (backup_usr, backup_usr1, backup_usr2) = psram_cmd_config_spi1(&ps_cmd);
753 psram_cmd_recv_start_spi1(core::ptr::null_mut(), 0, PsramCmdMode::PsramCmdQpi);
754 psram_cmd_end_spi1(backup_usr, backup_usr1, backup_usr2);
755 }
756
757 #[ram]
758 fn psram_cmd_end_spi1(backup_usr: u32, backup_usr1: u32, backup_usr2: u32) {
759 unsafe {
760 let spi = SPI1::regs();
761 while spi.cmd().read().usr().bit_is_set() {}
762
763 spi.user().write(|w| w.bits(backup_usr));
764 spi.user1().write(|w| w.bits(backup_usr1));
765 spi.user2().write(|w| w.bits(backup_usr2));
766 }
767 }
768
769 #[ram]
771 fn psram_cmd_config_spi1(p_in_data: &PsramCmd) -> (u32, u32, u32) {
772 unsafe {
773 let spi = SPI1::regs();
774 while spi.cmd().read().usr().bit_is_set() {}
775
776 let backup_usr = spi.user().read().bits();
777 let backup_usr1 = spi.user1().read().bits();
778 let backup_usr2 = spi.user2().read().bits();
779
780 if p_in_data.cmd_bit_len != 0 {
782 spi.user2().modify(|_, w| {
784 w.usr_command_bitlen()
785 .bits((p_in_data.cmd_bit_len - 1) as u8)
786 });
787 spi.user().modify(|_, w| w.usr_command().set_bit());
789 spi.user2()
791 .modify(|_, w| w.usr_command_value().bits(p_in_data.cmd));
792 } else {
793 spi.user().modify(|_, w| w.usr_command().clear_bit());
794 spi.user2().modify(|_, w| w.usr_command_bitlen().bits(0));
795 }
796 if p_in_data.addr_bit_len != 0 {
798 spi.user1()
799 .modify(|_, w| w.usr_addr_bitlen().bits((p_in_data.addr_bit_len - 1) as u8));
800 spi.user().modify(|_, w| w.usr_addr().set_bit());
802 spi.addr().modify(|_, w| w.bits(p_in_data.addr));
804 } else {
805 spi.user().modify(|_, w| w.usr_addr().clear_bit());
806 spi.user1().modify(|_, w| w.usr_addr_bitlen().bits(0));
807 }
808 let p_tx_val = p_in_data.tx_data;
810 if p_in_data.tx_data_bit_len != 0 {
811 spi.user().modify(|_, w| w.usr_mosi().set_bit());
813 let len = p_in_data.tx_data_bit_len.div_ceil(32);
815 if !p_tx_val.is_null() {
816 for i in 0..len {
817 spi.w(i as usize)
818 .write(|w| w.bits(p_tx_val.offset(i as isize).read_volatile()));
819 }
820 }
821 spi.mosi_dlen().modify(|_, w| {
823 w.usr_mosi_dbitlen()
824 .bits((p_in_data.tx_data_bit_len - 1) as u32)
825 });
826 } else {
827 spi.user().modify(|_, w| w.usr_mosi().clear_bit());
828 spi.mosi_dlen().modify(|_, w| w.usr_mosi_dbitlen().bits(0));
829 }
830 if p_in_data.rx_data_bit_len != 0 {
832 spi.user().modify(|_, w| w.usr_miso().set_bit());
834 spi.miso_dlen().modify(|_, w| {
836 w.usr_miso_dbitlen()
837 .bits((p_in_data.rx_data_bit_len - 1) as u32)
838 });
839 } else {
840 spi.user().modify(|_, w| w.usr_miso().clear_bit());
841 spi.miso_dlen().modify(|_, w| w.usr_miso_dbitlen().bits(0));
842 }
843 if p_in_data.dummy_bit_len != 0 {
844 spi.user().modify(|_, w| w.usr_dummy().set_bit()); spi.user1().modify(|_, w| {
846 w.usr_dummy_cyclelen()
847 .bits((p_in_data.dummy_bit_len - 1) as u8)
848 }); } else {
850 spi.user().modify(|_, w| w.usr_dummy().clear_bit()); spi.user1().modify(|_, w| w.usr_dummy_cyclelen().bits(0)); }
853
854 (backup_usr, backup_usr1, backup_usr2)
855 }
856 }
857
858 #[derive(Debug, Clone, Copy, PartialEq)]
859 enum PsramCmdMode {
860 PsramCmdQpi,
861 PsramCmdSpi,
862 }
863
864 #[ram]
866 fn psram_cmd_recv_start_spi1(
867 p_rx_data: *mut u32,
868 rx_data_len_words: usize,
869 cmd_mode: PsramCmdMode,
870 ) {
871 unsafe {
872 let spi = SPI1::regs();
873 spi.pin().modify(|_, w| w.cs1_dis().clear_bit());
875 spi.pin().modify(|_, w| w.cs0_dis().set_bit());
876
877 let mode_backup: u32 = (spi.user().read().bits() >> SPI_FWRITE_DUAL_S) & 0xf;
878 let rd_mode_backup: u32 = spi.ctrl().read().bits()
879 & (SPI_FREAD_DIO_M | SPI_FREAD_DUAL_M | SPI_FREAD_QUAD_M | SPI_FREAD_QIO_M);
880
881 if cmd_mode == PsramCmdMode::PsramCmdSpi {
882 psram_set_basic_write_mode_spi1();
883 psram_set_basic_read_mode_spi1();
884 } else if cmd_mode == PsramCmdMode::PsramCmdQpi {
885 psram_set_qio_write_mode_spi1();
886 psram_set_qio_read_mode_spi1();
887 }
888
889 while SPI1::regs().ext2().read().bits() != 0 {}
891
892 DPORT::regs()
894 .host_inf_sel()
895 .modify(|r, w| w.bits(r.bits() | (1 << 14)));
896
897 spi.cmd().modify(|_, w| w.usr().set_bit());
899 while spi.cmd().read().usr().bit_is_set() {}
900
901 DPORT::regs()
903 .host_inf_sel()
904 .modify(|r, w| w.bits(r.bits() & !(1 << 14)));
905
906 set_peri_reg_bits(
909 SPI1_USER_REG,
910 if !p_rx_data.is_null() {
911 SPI_FWRITE_DUAL_M
912 } else {
913 0xf
914 },
915 mode_backup,
916 SPI_FWRITE_DUAL_S,
917 );
918
919 spi.ctrl().modify(|_, w| {
920 w.fread_dio().clear_bit();
921 w.fread_dual().clear_bit();
922 w.fread_quad().clear_bit();
923 w.fread_qio().clear_bit()
924 });
925 spi.ctrl().modify(|r, w| w.bits(r.bits() | rd_mode_backup));
926
927 spi.pin().modify(|_, w| w.cs1_dis().set_bit());
929 spi.pin().modify(|_, w| w.cs0_dis().clear_bit());
930
931 if !p_rx_data.is_null() {
932 for i in 0..rx_data_len_words {
934 p_rx_data.add(i).write_volatile(spi.w(i).read().bits());
935 }
936 }
937 }
938 }
939
940 fn psram_set_basic_write_mode_spi1() {
942 SPI1::regs().user().modify(|_, w| {
943 w.fwrite_qio().clear_bit();
944 w.fwrite_dio().clear_bit();
945 w.fwrite_quad().clear_bit();
946 w.fwrite_dual().clear_bit()
947 });
948 }
949
950 fn psram_set_qio_write_mode_spi1() {
952 SPI1::regs().user().modify(|_, w| {
953 w.fwrite_qio().set_bit();
954 w.fwrite_dio().clear_bit();
955 w.fwrite_quad().clear_bit();
956 w.fwrite_dual().clear_bit()
957 });
958 }
959
960 fn psram_set_qio_read_mode_spi1() {
962 SPI1::regs().ctrl().modify(|_, w| {
963 w.fread_qio().set_bit();
964 w.fread_quad().clear_bit();
965 w.fread_dual().clear_bit();
966 w.fread_dio().clear_bit()
967 });
968 }
969
970 fn psram_set_basic_read_mode_spi1() {
972 SPI1::regs().ctrl().modify(|_, w| {
973 w.fread_qio().clear_bit();
974 w.fread_quad().clear_bit();
975 w.fread_dual().clear_bit();
976 w.fread_dio().clear_bit()
977 });
978 }
979
980 fn psram_gpio_config(psram_io: &PsramIo, mode: PsramCacheSpeed) -> u32 {
982 unsafe {
983 let spi = SPI0::regs();
984 let g_rom_spiflash_dummy_len_plus_ptr = addr_of_mut!(g_rom_spiflash_dummy_len_plus);
985
986 #[derive(Debug, Clone, Copy)]
987 enum Field {
988 McuSel,
989 FunDrv,
990 }
991
992 macro_rules! apply_to_field {
993 ($w:ident, $field:expr, $bits:expr) => {
994 match $field {
995 Field::McuSel => $w.mcu_sel().bits($bits),
996 Field::FunDrv => $w.fun_drv().bits($bits),
997 }
998 };
999 }
1000
1001 fn configure_gpio(gpio: u8, field: Field, bits: u8) {
1002 unsafe {
1003 let ptr = crate::gpio::io_mux_reg(gpio);
1004
1005 ptr.modify(|_, w| apply_to_field!(w, field, bits));
1006 }
1007 }
1008
1009 let spi_cache_dummy;
1010 let rd_mode_reg = spi.ctrl().read().bits();
1011 if (rd_mode_reg & SPI_FREAD_QIO_M) != 0 {
1012 spi_cache_dummy = SPI0_R_QIO_DUMMY_CYCLELEN;
1013 } else if (rd_mode_reg & SPI_FREAD_DIO_M) != 0 {
1014 spi_cache_dummy = SPI0_R_DIO_DUMMY_CYCLELEN;
1015 spi.user1()
1016 .modify(|_, w| w.usr_addr_bitlen().bits(SPI0_R_DIO_ADDR_BITSLEN as u8));
1017 } else {
1018 spi_cache_dummy = SPI0_R_FAST_DUMMY_CYCLELEN;
1019 }
1020
1021 let extra_dummy;
1022
1023 match mode {
1024 PsramCacheSpeed::PsramCacheF80mS40m => {
1025 extra_dummy = PSRAM_IO_MATRIX_DUMMY_40M;
1026
1027 g_rom_spiflash_dummy_len_plus_ptr
1028 .offset(_SPI_CACHE_PORT as isize)
1029 .write_volatile(PSRAM_IO_MATRIX_DUMMY_80M);
1030 g_rom_spiflash_dummy_len_plus_ptr
1031 .offset(_SPI_FLASH_PORT as isize)
1032 .write_volatile(PSRAM_IO_MATRIX_DUMMY_40M);
1033
1034 spi.user1().modify(|_, w| {
1035 w.usr_dummy_cyclelen()
1036 .bits(spi_cache_dummy as u8 + PSRAM_IO_MATRIX_DUMMY_80M)
1037 }); esp_rom_spiflash_config_clk(_SPI_80M_CLK_DIV, _SPI_CACHE_PORT);
1040 esp_rom_spiflash_config_clk(_SPI_40M_CLK_DIV, _SPI_FLASH_PORT);
1041
1042 configure_gpio(psram_io.flash_clk_io, Field::FunDrv, 3);
1045 configure_gpio(psram_io.psram_clk_io, Field::FunDrv, 2);
1046 }
1047 PsramCacheSpeed::PsramCacheF80mS80m => {
1048 extra_dummy = PSRAM_IO_MATRIX_DUMMY_80M;
1049 g_rom_spiflash_dummy_len_plus_ptr
1050 .offset(_SPI_CACHE_PORT as isize)
1051 .write_volatile(PSRAM_IO_MATRIX_DUMMY_80M);
1052 g_rom_spiflash_dummy_len_plus_ptr
1053 .offset(_SPI_FLASH_PORT as isize)
1054 .write_volatile(PSRAM_IO_MATRIX_DUMMY_80M);
1055
1056 spi.user1().modify(|_, w| {
1057 w.usr_dummy_cyclelen()
1058 .bits(spi_cache_dummy as u8 + PSRAM_IO_MATRIX_DUMMY_80M)
1059 }); esp_rom_spiflash_config_clk(_SPI_80M_CLK_DIV, _SPI_CACHE_PORT);
1062 esp_rom_spiflash_config_clk(_SPI_80M_CLK_DIV, _SPI_FLASH_PORT);
1063
1064 configure_gpio(psram_io.flash_clk_io, Field::FunDrv, 3);
1066 configure_gpio(psram_io.psram_clk_io, Field::FunDrv, 3);
1067 }
1068 PsramCacheSpeed::PsramCacheF40mS40m => {
1069 extra_dummy = PSRAM_IO_MATRIX_DUMMY_40M;
1070
1071 g_rom_spiflash_dummy_len_plus_ptr
1072 .offset(_SPI_CACHE_PORT as isize)
1073 .write_volatile(PSRAM_IO_MATRIX_DUMMY_40M);
1074 g_rom_spiflash_dummy_len_plus_ptr
1075 .offset(_SPI_FLASH_PORT as isize)
1076 .write_volatile(PSRAM_IO_MATRIX_DUMMY_40M);
1077
1078 spi.user1().modify(|_, w| {
1079 w.usr_dummy_cyclelen()
1080 .bits(spi_cache_dummy as u8 + PSRAM_IO_MATRIX_DUMMY_40M)
1081 }); esp_rom_spiflash_config_clk(_SPI_40M_CLK_DIV, _SPI_CACHE_PORT);
1084 esp_rom_spiflash_config_clk(_SPI_40M_CLK_DIV, _SPI_FLASH_PORT);
1085
1086 configure_gpio(psram_io.flash_clk_io, Field::FunDrv, 2);
1088 configure_gpio(psram_io.psram_clk_io, Field::FunDrv, 2);
1089 }
1090 }
1091
1092 spi.user().modify(|_, w| w.usr_dummy().set_bit()); esp_rom_gpio_connect_out_signal(
1098 psram_io.flash_cs_io as u32,
1099 SPICS0_OUT_IDX,
1100 false,
1101 false,
1102 );
1103 esp_rom_gpio_connect_out_signal(
1104 psram_io.psram_cs_io as u32,
1105 SPICS1_OUT_IDX,
1106 false,
1107 false,
1108 );
1109 esp_rom_gpio_connect_out_signal(
1110 psram_io.psram_spiq_sd0_io as u32,
1111 SPIQ_OUT_IDX,
1112 false,
1113 false,
1114 );
1115 esp_rom_gpio_connect_in_signal(psram_io.psram_spiq_sd0_io as u32, SPIQ_IN_IDX, false);
1116 esp_rom_gpio_connect_out_signal(
1117 psram_io.psram_spid_sd1_io as u32,
1118 SPID_OUT_IDX,
1119 false,
1120 false,
1121 );
1122 esp_rom_gpio_connect_in_signal(psram_io.psram_spid_sd1_io as u32, SPID_IN_IDX, false);
1123 esp_rom_gpio_connect_out_signal(
1124 psram_io.psram_spiwp_sd3_io as u32,
1125 SPIWP_OUT_IDX,
1126 false,
1127 false,
1128 );
1129 esp_rom_gpio_connect_in_signal(psram_io.psram_spiwp_sd3_io as u32, SPIWP_IN_IDX, false);
1130 esp_rom_gpio_connect_out_signal(
1131 psram_io.psram_spihd_sd2_io as u32,
1132 SPIHD_OUT_IDX,
1133 false,
1134 false,
1135 );
1136 esp_rom_gpio_connect_in_signal(psram_io.psram_spihd_sd2_io as u32, SPIHD_IN_IDX, false);
1137
1138 if (psram_io.flash_clk_io == SPI_IOMUX_PIN_NUM_CLK)
1140 && (psram_io.flash_clk_io != psram_io.psram_clk_io)
1141 {
1142 configure_gpio(
1144 psram_io.flash_clk_io,
1145 Field::McuSel,
1146 FUNC_SD_CLK_SPICLK as u8,
1147 );
1148 } else {
1149 configure_gpio(psram_io.flash_clk_io, Field::McuSel, PIN_FUNC_GPIO as u8);
1151 }
1152 configure_gpio(psram_io.flash_cs_io, Field::McuSel, PIN_FUNC_GPIO as u8);
1153 configure_gpio(psram_io.psram_cs_io, Field::McuSel, PIN_FUNC_GPIO as u8);
1154 configure_gpio(psram_io.psram_clk_io, Field::McuSel, PIN_FUNC_GPIO as u8);
1155 configure_gpio(
1156 psram_io.psram_spiq_sd0_io,
1157 Field::McuSel,
1158 PIN_FUNC_GPIO as u8,
1159 );
1160 configure_gpio(
1161 psram_io.psram_spid_sd1_io,
1162 Field::McuSel,
1163 PIN_FUNC_GPIO as u8,
1164 );
1165 configure_gpio(
1166 psram_io.psram_spihd_sd2_io,
1167 Field::McuSel,
1168 PIN_FUNC_GPIO as u8,
1169 );
1170 configure_gpio(
1171 psram_io.psram_spiwp_sd3_io,
1172 Field::McuSel,
1173 PIN_FUNC_GPIO as u8,
1174 );
1175
1176 let flash_id: u32 = g_rom_flashchip.device_id;
1177 info!("Flash-ID = {}", flash_id);
1178 info!("Flash size = {}", g_rom_flashchip.chip_size);
1179
1180 if flash_id == FLASH_ID_GD25LQ32C {
1181 configure_gpio(psram_io.flash_cs_io, Field::FunDrv, 3);
1183 configure_gpio(psram_io.flash_clk_io, Field::FunDrv, 3);
1184 configure_gpio(psram_io.psram_cs_io, Field::FunDrv, 3);
1185 configure_gpio(psram_io.psram_clk_io, Field::FunDrv, 3);
1186 configure_gpio(psram_io.psram_spiq_sd0_io, Field::FunDrv, 3);
1187 configure_gpio(psram_io.psram_spid_sd1_io, Field::FunDrv, 3);
1188 configure_gpio(psram_io.psram_spihd_sd2_io, Field::FunDrv, 3);
1189 configure_gpio(psram_io.psram_spiwp_sd3_io, Field::FunDrv, 3);
1190 }
1191
1192 extra_dummy as u32
1193 }
1194 }
1195
1196 fn set_peri_reg_bits(reg: u32, bitmap: u32, value: u32, shift: u32) {
1197 unsafe {
1198 (reg as *mut u32).write_volatile(
1199 ((reg as *mut u32).read_volatile() & !(bitmap << shift))
1200 | ((value & bitmap) << shift),
1201 );
1202 }
1203 }
1204}