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
56 if config.size.is_auto() {
57 const MAX_MEM_SIZE: usize = 4 * 1024 * 1024;
58
59 utils::s_mapping(EXTMEM_ORIGIN as u32, MAX_MEM_SIZE as u32);
65
66 let last_correctly_read = unsafe {
67 let ptr = EXTMEM_ORIGIN as *mut u8;
68 for i in (1023..MAX_MEM_SIZE).step_by(1024) {
69 ptr.add(i).write_volatile(0x7f);
70 }
71
72 let mut last_correctly_read = 0;
73 for i in (1023..MAX_MEM_SIZE).step_by(1024) {
74 if ptr.add(i).read_volatile() == 0x7f {
75 last_correctly_read = i;
76 } else {
77 break;
78 }
79 }
80
81 last_correctly_read
82 };
83
84 if last_correctly_read == 0 {
85 warn!("No PSRAM found");
86 return false;
87 }
88 let guessed_size = last_correctly_read + 1;
89 info!("Assuming {} bytes of PSRAM", guessed_size);
90 config.size = PsramSize::Size(guessed_size);
91 }
92
93 true
94}
95
96#[procmacros::ram]
97pub(crate) fn map_psram(config: PsramConfig) -> Range<usize> {
98 utils::s_mapping(EXTMEM_ORIGIN as u32, config.size.get() as u32);
99
100 EXTMEM_ORIGIN..EXTMEM_ORIGIN + config.size.get()
101}
102
103pub(crate) mod utils {
104 use procmacros::ram;
105
106 use super::*;
107 use crate::peripherals::{DPORT, SPI0, SPI1};
108
109 #[ram]
110 pub(crate) fn s_mapping(v_start: u32, size: u32) {
111 cache_sram_mmu_set(0, 0, v_start, 0, 32, size / 1024 / 32);
113 DPORT::regs()
115 .app_cache_ctrl1()
116 .modify(|_, w| w.app_cache_mask_dram1().clear_bit());
117
118 cache_sram_mmu_set(1, 0, v_start, 0, 32, size / 1024 / 32);
119 }
120
121 #[ram]
124 fn cache_sram_mmu_set(
125 cpu_no: u32,
126 pid: u32,
127 vaddr: u32,
128 paddr: u32,
129 psize: u32,
130 num: u32,
131 ) -> i32 {
132 unsafe { cache_sram_mmu_set_rom(cpu_no, pid, vaddr, paddr, psize, num) }
133 }
134
135 const D0WD_PSRAM_CLK_IO: u8 = 17;
139 const D0WD_PSRAM_CS_IO: u8 = 16;
140
141 const D2WD_PSRAM_CLK_IO: u8 = 9; const D2WD_PSRAM_CS_IO: u8 = 10; const PICO_PSRAM_CLK_IO: u8 = 6;
147 const PICO_PSRAM_CS_IO: u8 = 10; const PICO_V3_02_PSRAM_CLK_IO: u8 = 10;
150 const PICO_V3_02_PSRAM_CS_IO: u8 = 9;
151 const PICO_V3_02_PSRAM_SPIWP_SD3_IO: u8 = 18;
152
153 const ESP_ROM_EFUSE_FLASH_DEFAULT_SPI: u32 = 0;
154 const ESP_ROM_EFUSE_FLASH_DEFAULT_HSPI: u32 = 1;
155
156 const SPI_IOMUX_PIN_NUM_CLK: u8 = 6;
157 const SPI_IOMUX_PIN_NUM_CS: u8 = 11;
158
159 const PSRAM_SPIQ_SD0_IO: u8 = 7;
165 const PSRAM_SPID_SD1_IO: u8 = 8;
166 const PSRAM_SPIWP_SD3_IO: u8 = 10;
167 const PSRAM_SPIHD_SD2_IO: u8 = 9;
168
169 const FLASH_HSPI_CLK_IO: u8 = 14;
170 const FLASH_HSPI_CS_IO: u8 = 15;
171
172 const PSRAM_HSPI_SPIQ_SD0_IO: u8 = 12;
173 const PSRAM_HSPI_SPID_SD1_IO: u8 = 13;
174 const PSRAM_HSPI_SPIWP_SD3_IO: u8 = 2;
175 const PSRAM_HSPI_SPIHD_SD2_IO: u8 = 4;
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_spi0(mode, clk_mode); psram_enable_qio_mode_spi1(clk_mode, mode);
471
472 let psram_vaddr_mode = config.psram_vaddr_mode;
473 info!("PS-RAM vaddrmode = {:?}", psram_vaddr_mode);
474
475 psram_cache_init(mode, psram_vaddr_mode, clk_mode, extra_dummy);
476 }
477
478 fn psram_cache_init(
480 psram_cache_mode: PsramCacheSpeed,
481 vaddrmode: PsramVaddrMode,
482 clk_mode: PsramClkMode,
483 extra_dummy: u32,
484 ) {
485 unsafe {
486 let spi = SPI0::regs();
487 info!(
488 "PS-RAM cache_init, psram_cache_mode={:?}, extra_dummy={}, clk_mode={:?}",
489 psram_cache_mode, extra_dummy, clk_mode
490 );
491 match psram_cache_mode {
492 PsramCacheSpeed::PsramCacheF80mS80m => {
493 spi.date().modify(|r, w| {
497 let current_bits = r.bits();
498 let new_bits = current_bits & !((1 << 31) | (1 << 30));
499 w.bits(new_bits)
500 });
501 }
505 PsramCacheSpeed::PsramCacheF80mS40m => {
506 spi.clock().modify(|_, w| {
507 w.clk_equ_sysclk().clear_bit();
508 w.clkdiv_pre().bits(0);
509 w.clkcnt_n().bits(1);
510 w.clkcnt_h().bits(0);
511 w.clkcnt_l().bits(1)
512 });
513
514 spi.date().modify(|r, w| {
515 let current_bits = r.bits();
516 let new_bits = (current_bits | (1 << 31)) & !(1 << 30);
517 w.bits(new_bits)
518 });
519 }
520 _ => {
521 spi.date().modify(|r, w| {
522 let current_bits = r.bits();
523 let new_bits = current_bits & !((1 << 31) | (1 << 30));
524 w.bits(new_bits)
525 });
526 }
527 }
528
529 spi.cache_sctrl().modify(|_, w| {
531 w.usr_sram_dio().clear_bit();
532 w.usr_sram_qio().set_bit();
533 w.cache_sram_usr_rcmd().set_bit();
534 w.cache_sram_usr_wcmd().set_bit();
535 w.sram_addr_bitlen().bits(23);
536 w.usr_rd_sram_dummy().set_bit();
537 w.sram_dummy_cyclelen()
538 .bits((PSRAM_FAST_READ_QUAD_DUMMY + extra_dummy) as u8)
539 });
540
541 spi.sram_drd_cmd().modify(|_, w| {
542 w.cache_sram_usr_rd_cmd_bitlen().bits(7);
543 w.cache_sram_usr_rd_cmd_value()
544 .bits(PSRAM_FAST_READ_QUAD as u16)
545 });
546 spi.sram_dwr_cmd().modify(|_, w| {
547 w.cache_sram_usr_wr_cmd_bitlen().bits(7);
548 w.cache_sram_usr_wr_cmd_value()
549 .bits(PSRAM_QUAD_WRITE as u16)
550 });
551
552 match psram_cache_mode {
553 PsramCacheSpeed::PsramCacheF80mS80m => (), _ => {
555 if clk_mode == PsramClkMode::PsramClkModeDclk {
556 spi.sram_drd_cmd().modify(|_, w| {
558 w.cache_sram_usr_rd_cmd_bitlen().bits(15);
559 w.cache_sram_usr_rd_cmd_value()
560 .bits((PSRAM_FAST_READ_QUAD << 8) as u16)
561 });
562 spi.sram_dwr_cmd().modify(|_, w| {
563 w.cache_sram_usr_wr_cmd_bitlen().bits(15);
564 w.cache_sram_usr_wr_cmd_value()
565 .bits((PSRAM_QUAD_WRITE << 8) as u16)
566 });
567 }
568 }
569 }
570
571 let dport = DPORT::regs();
572
573 dport
574 .pro_cache_ctrl()
575 .modify(|_, w| w.pro_dram_hl().clear_bit().pro_dram_split().clear_bit());
576 dport
577 .app_cache_ctrl()
578 .modify(|_, w| w.app_dram_hl().clear_bit().app_dram_split().clear_bit());
579 if vaddrmode == PsramVaddrMode::LowHigh {
580 dport
581 .pro_cache_ctrl()
582 .modify(|_, w| w.pro_dram_hl().set_bit());
583 dport
584 .app_cache_ctrl()
585 .modify(|_, w| w.app_dram_hl().set_bit());
586 } else if vaddrmode == PsramVaddrMode::Evenodd {
587 dport
588 .pro_cache_ctrl()
589 .modify(|_, w| w.pro_dram_split().set_bit());
590 dport
591 .app_cache_ctrl()
592 .modify(|_, w| w.app_dram_split().set_bit());
593 }
594
595 dport.pro_cache_ctrl1().modify(|_, w| {
599 w.pro_cache_mask_dram1().clear_bit();
600 w.pro_cache_mask_opsdram().clear_bit();
601 w.pro_cmmu_sram_page_mode().bits(0)
602 });
603 dport.app_cache_ctrl1().modify(|_, w| {
604 w.app_cache_mask_dram1().clear_bit();
605 w.app_cache_mask_opsdram().clear_bit();
606 w.app_cmmu_sram_page_mode().bits(0)
607 });
608
609 spi.pin().modify(|_, w| w.cs1_dis().clear_bit());
611 }
612 }
613
614 #[ram]
616 fn psram_spi_init(
617 mode: PsramCacheSpeed,
619 clk_mode: PsramClkMode,
620 ) {
621 SPI1::regs().slave().modify(|_, w| {
622 w.trans_inten().clear_bit();
623 w.mode().clear_bit()
624 });
625 SPI1::regs()
626 .pin()
627 .modify(|_, w| w.ck_idle_edge().clear_bit());
628 SPI1::regs().user().modify(|_, w| {
629 w.ck_out_edge().clear_bit();
630 w.doutdin().clear_bit()
631 });
632 SPI1::regs().ctrl().modify(|_, w| {
633 w.wr_bit_order().clear_bit();
634 w.rd_bit_order().clear_bit()
635 });
636 SPI1::regs().user1().modify(|_, w| unsafe { w.bits(0) });
637
638 SPI1::regs().w_iter().for_each(|w| {
639 w.write(|w| unsafe { w.bits(0) });
640 });
641
642 psram_set_cs_timing_spi1(mode, clk_mode);
643 }
644
645 fn psram_set_cs_timing_spi1(psram_cache_mode: PsramCacheSpeed, clk_mode: PsramClkMode) {
646 let spi = SPI1::regs();
647 let normal_mode = clk_mode == PsramClkMode::PsramClkModeNorm;
648 spi.user().modify(|_, w| {
649 w.cs_hold().bit(normal_mode);
650 w.cs_setup().bit(normal_mode)
651 });
652 if normal_mode {
653 spi.ctrl2().modify(|_, w| unsafe {
654 w.hold_time()
655 .bits(psram_cs_hold_time_from_psram_speed(psram_cache_mode) as u8);
656 w.setup_time().bits(0)
657 });
658 }
659 }
660
661 fn psram_set_cs_timing_spi0(psram_cache_mode: PsramCacheSpeed, clk_mode: PsramClkMode) {
662 let spi = SPI0::regs();
663 let normal_mode = clk_mode == PsramClkMode::PsramClkModeNorm;
664 spi.user().modify(|_, w| {
665 w.cs_hold().bit(normal_mode);
666 w.cs_setup().bit(normal_mode)
667 });
668 if normal_mode {
669 spi.ctrl2().modify(|_, w| unsafe {
670 w.hold_time()
671 .bits(psram_cs_hold_time_from_psram_speed(psram_cache_mode) as u8);
672 w.setup_time().bits(0)
673 });
674 }
675 }
676
677 #[derive(Default, Debug, PartialEq)]
678 struct PsramCmd<'a> {
679 cmd: u16, cmd_bit_len: u16, addr: u32, addr_bit_len: u16, tx_data: &'a [u32], tx_data_bit_len: u16,
685 rx_data: &'a mut [u32], rx_data_bit_len: u16,
687 dummy_bit_len: u32,
688 }
689
690 const PSRAM_ENTER_QMODE: u32 = 0x35;
691
692 #[ram]
694 fn psram_enable_qio_mode_spi1(clk_mode: PsramClkMode, psram_mode: PsramCacheSpeed) {
695 let ps_cmd = PsramCmd {
696 cmd_bit_len: if clk_mode == PsramClkMode::PsramClkModeDclk
697 && psram_mode != PsramCacheSpeed::PsramCacheF80mS80m
698 {
699 2
700 } else {
701 0
702 },
703 cmd: 0,
704 addr: PSRAM_ENTER_QMODE << 24,
705 addr_bit_len: 8,
706 tx_data: &[],
707 tx_data_bit_len: 0,
708 rx_data: &mut [],
709 rx_data_bit_len: 0,
710 dummy_bit_len: 0,
711 };
712
713 let (backup_usr, backup_usr1, backup_usr2) = psram_cmd_config_spi1(&ps_cmd);
714 psram_cmd_recv_start_spi1(&mut [], PsramCmdMode::PsramCmdQpi);
715 psram_cmd_end_spi1(backup_usr, backup_usr1, backup_usr2);
716 }
717
718 #[ram]
719 fn psram_cmd_end_spi1(backup_usr: u32, backup_usr1: u32, backup_usr2: u32) {
720 while SPI1::regs().cmd().read().usr().bit_is_set() {}
721 unsafe {
722 SPI1::regs().user().write(|w| w.bits(backup_usr));
723 SPI1::regs().user1().write(|w| w.bits(backup_usr1));
724 SPI1::regs().user2().write(|w| w.bits(backup_usr2));
725 }
726 }
727
728 #[ram]
730 fn psram_cmd_config_spi1(cmd: &PsramCmd<'_>) -> (u32, u32, u32) {
731 debug_assert_eq!(cmd.tx_data.len(), cmd.tx_data_bit_len.div_ceil(32) as usize);
732 debug_assert_eq!(cmd.rx_data.len(), cmd.rx_data_bit_len.div_ceil(32) as usize);
733 debug_assert!(cmd.tx_data_bit_len <= 64);
734 debug_assert!(cmd.rx_data_bit_len <= 64);
735
736 while SPI1::regs().cmd().read().usr().bit_is_set() {}
737
738 let backup_usr = SPI1::regs().user().read().bits();
739 let backup_usr1 = SPI1::regs().user1().read().bits();
740 let backup_usr2 = SPI1::regs().user2().read().bits();
741
742 SPI1::regs().user().modify(|_, w| {
745 w.usr_command().bit(cmd.cmd_bit_len != 0);
746 w.usr_addr().bit(cmd.addr_bit_len != 0);
747 w.usr_mosi().bit(cmd.tx_data_bit_len != 0);
748 w.usr_miso().bit(cmd.rx_data_bit_len != 0);
749 w.usr_dummy().bit(cmd.dummy_bit_len != 0)
750 });
751 SPI1::regs().user1().modify(|_, w| unsafe {
752 w.usr_addr_bitlen()
753 .bits(cmd.addr_bit_len.saturating_sub(1) as u8);
754 w.usr_dummy_cyclelen()
755 .bits(cmd.dummy_bit_len.saturating_sub(1) as u8)
756 });
757 SPI1::regs().user2().modify(|_, w| unsafe {
758 w.usr_command_value().bits(cmd.cmd);
759 w.usr_command_bitlen()
760 .bits(cmd.cmd_bit_len.saturating_sub(1) as u8)
761 });
762
763 SPI1::regs().mosi_dlen().write(|w| unsafe {
765 w.usr_mosi_dbitlen()
766 .bits(cmd.tx_data_bit_len.saturating_sub(1) as u32)
767 });
768
769 SPI1::regs().miso_dlen().write(|w| unsafe {
771 w.usr_miso_dbitlen()
772 .bits(cmd.rx_data_bit_len.saturating_sub(1) as u32)
773 });
774
775 if cmd.addr_bit_len != 0 {
777 SPI1::regs().addr().write(|w| unsafe { w.bits(cmd.addr) });
778 }
779
780 for (i, tx) in cmd.tx_data.iter().enumerate() {
782 SPI1::regs().w(i).write(|w| unsafe { w.bits(*tx) });
783 }
784
785 (backup_usr, backup_usr1, backup_usr2)
786 }
787
788 #[derive(Debug, Clone, Copy, PartialEq)]
789 enum PsramCmdMode {
790 PsramCmdQpi,
791 #[expect(unused)]
792 PsramCmdSpi,
793 }
794
795 #[ram]
797 fn psram_cmd_recv_start_spi1(rx_data: &mut [u32], cmd_mode: PsramCmdMode) {
798 SPI1::regs().pin().modify(|_, w| {
800 w.cs1_dis().clear_bit();
801 w.cs0_dis().set_bit()
802 });
803
804 let mode_backup: u32 = (SPI1::regs().user().read().bits() >> SPI_FWRITE_DUAL_S) & 0xf;
805 let rd_mode_backup: u32 = SPI1::regs().ctrl().read().bits()
806 & (SPI_FREAD_DIO_M | SPI_FREAD_DUAL_M | SPI_FREAD_QUAD_M | SPI_FREAD_QIO_M);
807
808 match cmd_mode {
809 PsramCmdMode::PsramCmdSpi => {
810 psram_set_basic_write_mode_spi1();
811 psram_set_basic_read_mode_spi1();
812 }
813 PsramCmdMode::PsramCmdQpi => {
814 psram_set_qio_write_mode_spi1();
815 psram_set_qio_read_mode_spi1();
816 }
817 }
818
819 while SPI0::regs().ext2().read().bits() != 0 {}
821
822 DPORT::regs()
824 .host_inf_sel()
825 .modify(|r, w| unsafe { w.bits(r.bits() | (1 << 14)) });
826
827 SPI1::regs().cmd().modify(|_, w| w.usr().set_bit());
829 while SPI1::regs().cmd().read().usr().bit_is_set() {}
830
831 DPORT::regs()
833 .host_inf_sel()
834 .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << 14)) });
835
836 SPI1::regs().user().modify(|r, w| unsafe {
838 let bits = r.bits();
839
840 let bit_map = if !rx_data.is_empty() {
842 SPI_FWRITE_DUAL_M
843 } else {
844 0xf
845 };
846 let shift = SPI_FWRITE_DUAL_S;
847
848 w.bits((bits & (!bit_map << shift)) | (mode_backup & bit_map) << shift)
849 });
850
851 SPI1::regs().ctrl().modify(|_, w| {
852 w.fread_dio().clear_bit();
853 w.fread_dual().clear_bit();
854 w.fread_quad().clear_bit();
855 w.fread_qio().clear_bit()
856 });
857
858 SPI1::regs()
859 .ctrl()
860 .modify(|r, w| unsafe { w.bits(r.bits() | rd_mode_backup) });
861
862 SPI1::regs().pin().modify(|_, w| {
864 w.cs1_dis().set_bit();
865 w.cs0_dis().clear_bit()
866 });
867
868 for (i, rx) in rx_data.iter_mut().enumerate() {
870 *rx = SPI1::regs().w(i).read().bits();
871 }
872 }
873
874 fn psram_set_basic_write_mode_spi1() {
876 SPI1::regs().user().modify(|_, w| {
877 w.fwrite_qio().clear_bit();
878 w.fwrite_dio().clear_bit();
879 w.fwrite_quad().clear_bit();
880 w.fwrite_dual().clear_bit()
881 });
882 }
883
884 fn psram_set_qio_write_mode_spi1() {
886 SPI1::regs().user().modify(|_, w| {
887 w.fwrite_qio().set_bit();
888 w.fwrite_dio().clear_bit();
889 w.fwrite_quad().clear_bit();
890 w.fwrite_dual().clear_bit()
891 });
892 }
893
894 fn psram_set_qio_read_mode_spi1() {
896 SPI1::regs().ctrl().modify(|_, w| {
897 w.fread_qio().set_bit();
898 w.fread_quad().clear_bit();
899 w.fread_dual().clear_bit();
900 w.fread_dio().clear_bit()
901 });
902 }
903
904 fn psram_set_basic_read_mode_spi1() {
906 SPI1::regs().ctrl().modify(|_, w| {
907 w.fread_qio().clear_bit();
908 w.fread_quad().clear_bit();
909 w.fread_dual().clear_bit();
910 w.fread_dio().clear_bit()
911 });
912 }
913
914 fn psram_gpio_config(psram_io: &PsramIo, mode: PsramCacheSpeed) -> u32 {
916 unsafe {
917 let g_rom_spiflash_dummy_len_plus_ptr = &raw mut g_rom_spiflash_dummy_len_plus;
918
919 #[derive(Debug, Clone, Copy)]
920 enum Field {
921 McuSel,
922 FunDrv,
923 }
924
925 macro_rules! apply_to_field {
926 ($w:ident, $field:expr, $bits:expr) => {
927 match $field {
928 Field::McuSel => $w.mcu_sel().bits($bits),
929 Field::FunDrv => $w.fun_drv().bits($bits),
930 }
931 };
932 }
933
934 fn configure_gpio(gpio: u8, field: Field, bits: u8) {
935 unsafe {
936 let ptr = crate::gpio::io_mux_reg(gpio);
937
938 ptr.modify(|_, w| apply_to_field!(w, field, bits));
939 }
940 }
941
942 let rd_mode_reg = SPI0::regs().ctrl().read();
943 let spi_cache_dummy = if rd_mode_reg.fread_qio().bit_is_set() {
944 SPI0_R_QIO_DUMMY_CYCLELEN
945 } else if rd_mode_reg.fread_dio().bit_is_set() {
946 SPI0::regs()
947 .user1()
948 .modify(|_, w| w.usr_addr_bitlen().bits(SPI0_R_DIO_ADDR_BITSLEN as u8));
949 SPI0_R_DIO_DUMMY_CYCLELEN
950 } else {
951 SPI0_R_FAST_DUMMY_CYCLELEN
952 };
953
954 let extra_dummy;
955
956 match mode {
957 PsramCacheSpeed::PsramCacheF80mS40m => {
958 extra_dummy = PSRAM_IO_MATRIX_DUMMY_40M;
959
960 g_rom_spiflash_dummy_len_plus_ptr
961 .offset(_SPI_CACHE_PORT as isize)
962 .write_volatile(PSRAM_IO_MATRIX_DUMMY_80M);
963 g_rom_spiflash_dummy_len_plus_ptr
964 .offset(_SPI_FLASH_PORT as isize)
965 .write_volatile(PSRAM_IO_MATRIX_DUMMY_40M);
966
967 SPI0::regs().user1().modify(|_, w| {
968 w.usr_dummy_cyclelen()
969 .bits(spi_cache_dummy as u8 + PSRAM_IO_MATRIX_DUMMY_80M)
970 }); esp_rom_spiflash_config_clk(_SPI_80M_CLK_DIV, _SPI_CACHE_PORT);
973 esp_rom_spiflash_config_clk(_SPI_40M_CLK_DIV, _SPI_FLASH_PORT);
974
975 configure_gpio(psram_io.flash_clk_io, Field::FunDrv, 3);
978 configure_gpio(psram_io.psram_clk_io, Field::FunDrv, 2);
979 }
980 PsramCacheSpeed::PsramCacheF80mS80m => {
981 extra_dummy = PSRAM_IO_MATRIX_DUMMY_80M;
982 g_rom_spiflash_dummy_len_plus_ptr
983 .offset(_SPI_CACHE_PORT as isize)
984 .write_volatile(PSRAM_IO_MATRIX_DUMMY_80M);
985 g_rom_spiflash_dummy_len_plus_ptr
986 .offset(_SPI_FLASH_PORT as isize)
987 .write_volatile(PSRAM_IO_MATRIX_DUMMY_80M);
988
989 SPI0::regs().user1().modify(|_, w| {
990 w.usr_dummy_cyclelen()
991 .bits(spi_cache_dummy as u8 + PSRAM_IO_MATRIX_DUMMY_80M)
992 }); esp_rom_spiflash_config_clk(_SPI_80M_CLK_DIV, _SPI_CACHE_PORT);
995 esp_rom_spiflash_config_clk(_SPI_80M_CLK_DIV, _SPI_FLASH_PORT);
996
997 configure_gpio(psram_io.flash_clk_io, Field::FunDrv, 3);
999 configure_gpio(psram_io.psram_clk_io, Field::FunDrv, 3);
1000 }
1001 PsramCacheSpeed::PsramCacheF40mS40m => {
1002 extra_dummy = PSRAM_IO_MATRIX_DUMMY_40M;
1003
1004 g_rom_spiflash_dummy_len_plus_ptr
1005 .offset(_SPI_CACHE_PORT as isize)
1006 .write_volatile(PSRAM_IO_MATRIX_DUMMY_40M);
1007 g_rom_spiflash_dummy_len_plus_ptr
1008 .offset(_SPI_FLASH_PORT as isize)
1009 .write_volatile(PSRAM_IO_MATRIX_DUMMY_40M);
1010
1011 SPI0::regs().user1().modify(|_, w| {
1012 w.usr_dummy_cyclelen()
1013 .bits(spi_cache_dummy as u8 + PSRAM_IO_MATRIX_DUMMY_40M)
1014 }); esp_rom_spiflash_config_clk(_SPI_40M_CLK_DIV, _SPI_CACHE_PORT);
1017 esp_rom_spiflash_config_clk(_SPI_40M_CLK_DIV, _SPI_FLASH_PORT);
1018
1019 configure_gpio(psram_io.flash_clk_io, Field::FunDrv, 2);
1021 configure_gpio(psram_io.psram_clk_io, Field::FunDrv, 2);
1022 }
1023 }
1024
1025 SPI0::regs().user().modify(|_, w| w.usr_dummy().set_bit()); esp_rom_gpio_connect_out_signal(
1031 psram_io.flash_cs_io as u32,
1032 SPICS0_OUT_IDX,
1033 false,
1034 false,
1035 );
1036 esp_rom_gpio_connect_out_signal(
1037 psram_io.psram_cs_io as u32,
1038 SPICS1_OUT_IDX,
1039 false,
1040 false,
1041 );
1042 esp_rom_gpio_connect_out_signal(
1043 psram_io.psram_spiq_sd0_io as u32,
1044 SPIQ_OUT_IDX,
1045 false,
1046 false,
1047 );
1048 esp_rom_gpio_connect_in_signal(psram_io.psram_spiq_sd0_io as u32, SPIQ_IN_IDX, false);
1049 esp_rom_gpio_connect_out_signal(
1050 psram_io.psram_spid_sd1_io as u32,
1051 SPID_OUT_IDX,
1052 false,
1053 false,
1054 );
1055 esp_rom_gpio_connect_in_signal(psram_io.psram_spid_sd1_io as u32, SPID_IN_IDX, false);
1056 esp_rom_gpio_connect_out_signal(
1057 psram_io.psram_spiwp_sd3_io as u32,
1058 SPIWP_OUT_IDX,
1059 false,
1060 false,
1061 );
1062 esp_rom_gpio_connect_in_signal(psram_io.psram_spiwp_sd3_io as u32, SPIWP_IN_IDX, false);
1063 esp_rom_gpio_connect_out_signal(
1064 psram_io.psram_spihd_sd2_io as u32,
1065 SPIHD_OUT_IDX,
1066 false,
1067 false,
1068 );
1069 esp_rom_gpio_connect_in_signal(psram_io.psram_spihd_sd2_io as u32, SPIHD_IN_IDX, false);
1070
1071 if (psram_io.flash_clk_io == SPI_IOMUX_PIN_NUM_CLK)
1073 && (psram_io.flash_clk_io != psram_io.psram_clk_io)
1074 {
1075 configure_gpio(
1077 psram_io.flash_clk_io,
1078 Field::McuSel,
1079 FUNC_SD_CLK_SPICLK as u8,
1080 );
1081 } else {
1082 configure_gpio(psram_io.flash_clk_io, Field::McuSel, PIN_FUNC_GPIO as u8);
1084 }
1085 configure_gpio(psram_io.flash_cs_io, Field::McuSel, PIN_FUNC_GPIO as u8);
1086 configure_gpio(psram_io.psram_cs_io, Field::McuSel, PIN_FUNC_GPIO as u8);
1087 configure_gpio(psram_io.psram_clk_io, Field::McuSel, PIN_FUNC_GPIO as u8);
1088 configure_gpio(
1089 psram_io.psram_spiq_sd0_io,
1090 Field::McuSel,
1091 PIN_FUNC_GPIO as u8,
1092 );
1093 configure_gpio(
1094 psram_io.psram_spid_sd1_io,
1095 Field::McuSel,
1096 PIN_FUNC_GPIO as u8,
1097 );
1098 configure_gpio(
1099 psram_io.psram_spihd_sd2_io,
1100 Field::McuSel,
1101 PIN_FUNC_GPIO as u8,
1102 );
1103 configure_gpio(
1104 psram_io.psram_spiwp_sd3_io,
1105 Field::McuSel,
1106 PIN_FUNC_GPIO as u8,
1107 );
1108
1109 let flash_id: u32 = g_rom_flashchip.device_id;
1110 info!("Flash-ID = {}", flash_id);
1111 info!("Flash size = {}", g_rom_flashchip.chip_size);
1112
1113 if flash_id == FLASH_ID_GD25LQ32C {
1114 configure_gpio(psram_io.flash_cs_io, Field::FunDrv, 3);
1116 configure_gpio(psram_io.flash_clk_io, Field::FunDrv, 3);
1117 configure_gpio(psram_io.psram_cs_io, Field::FunDrv, 3);
1118 configure_gpio(psram_io.psram_clk_io, Field::FunDrv, 3);
1119 configure_gpio(psram_io.psram_spiq_sd0_io, Field::FunDrv, 3);
1120 configure_gpio(psram_io.psram_spid_sd1_io, Field::FunDrv, 3);
1121 configure_gpio(psram_io.psram_spihd_sd2_io, Field::FunDrv, 3);
1122 configure_gpio(psram_io.psram_spiwp_sd3_io, Field::FunDrv, 3);
1123 }
1124
1125 extra_dummy as u32
1126 }
1127 }
1128}