1use core::ops::Range;
2
3use super::{EXTMEM_ORIGIN, PsramSize};
4use crate::peripherals::{EXTMEM, IO_MUX, SPI0, SPI1};
5
6#[derive(Copy, Clone, Debug, Default, PartialEq)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9pub enum PsramMode {
10 #[default]
12 Auto,
13
14 QuadSpi,
16
17 OctalSpi,
19}
20
21#[derive(Copy, Clone, Debug, Default, PartialEq)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24pub enum FlashFreq {
25 FlashFreq20m = 20,
27 FlashFreq40m = 40,
29 #[default]
31 FlashFreq80m = 80,
32 FlashFreq120m = 120,
35}
36
37#[derive(Copy, Clone, Debug, Default, PartialEq)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub enum SpiRamFreq {
41 #[default]
43 Freq40m = 40,
44 Freq80m = 80,
46 Freq120m = 120,
49}
50
51#[derive(Copy, Clone, Debug, Default, PartialEq)]
53#[cfg_attr(feature = "defmt", derive(defmt::Format))]
54pub enum SpiTimingConfigCoreClock {
55 #[default]
57 SpiTimingConfigCoreClock80m = 80,
58 SpiTimingConfigCoreClock120m = 120,
60 SpiTimingConfigCoreClock160m = 160,
62 SpiTimingConfigCoreClock240m = 240,
64}
65
66#[derive(Copy, Clone, Debug, Default, PartialEq)]
68#[cfg_attr(feature = "defmt", derive(defmt::Format))]
69pub struct PsramConfig {
70 pub mode: PsramMode,
72 pub size: PsramSize,
74 pub core_clock: Option<SpiTimingConfigCoreClock>,
76 pub flash_frequency: FlashFreq,
78 pub ram_frequency: SpiRamFreq,
80}
81
82#[procmacros::ram]
84pub(crate) fn init_psram(config: &mut PsramConfig) -> bool {
85 let success = match config.mode {
86 PsramMode::Auto => {
87 let mut success = octal_spi_impl::psram_init(config);
88
89 if !success {
90 success = quad_spi_impl::psram_init(config);
91 }
92
93 success
94 }
95 PsramMode::QuadSpi => quad_spi_impl::psram_init(config),
96 PsramMode::OctalSpi => octal_spi_impl::psram_init(config),
97 };
98
99 if !success {
100 warn!(
101 "Failed to configure PSRAM. This may indicate a missing/inoperable PSRAM chip, or an incorrect PSRAM configuration. Check if the PSRAM chip is present and the configuration is correct."
102 );
103 }
104
105 success
106}
107
108#[procmacros::ram]
109pub(crate) fn map_psram(config: PsramConfig) -> Range<usize> {
110 const MMU_ACCESS_SPIRAM: u32 = 1 << 15;
111 const START_PAGE: u32 = 0;
112
113 unsafe extern "C" {
114 fn Cache_Suspend_DCache();
115
116 fn Cache_Resume_DCache(param: u32);
117
118 fn cache_dbus_mmu_set(
127 ext_ram: u32,
128 vaddr: u32,
129 paddr: u32,
130 psize: u32,
131 num: u32,
132 fixed: u32,
133 ) -> i32;
134 }
135
136 const MMU_PAGE_SIZE: u32 = 0x10000;
137 const ICACHE_MMU_SIZE: usize = 0x800;
138 const FLASH_MMU_TABLE_SIZE: usize = ICACHE_MMU_SIZE / core::mem::size_of::<u32>();
139 const MMU_INVALID: u32 = 1 << 14;
140 const DR_REG_MMU_TABLE: u32 = 0x600C5000;
141
142 let mmu_table_ptr = DR_REG_MMU_TABLE as *const u32;
150 let mut mapped_pages = 0;
151
152 for i in (0..(FLASH_MMU_TABLE_SIZE - 1)).rev() {
155 if unsafe { mmu_table_ptr.add(i).read_volatile() } != MMU_INVALID {
156 mapped_pages = (i + 1) as u32;
157 break;
158 }
159 }
160 let start = EXTMEM_ORIGIN as u32 + (MMU_PAGE_SIZE * mapped_pages);
161 debug!("PSRAM start address = {:x}", start);
162
163 unsafe { Cache_Suspend_DCache() };
165
166 let cache_dbus_mmu_set_res = unsafe {
167 cache_dbus_mmu_set(
168 MMU_ACCESS_SPIRAM,
169 start,
170 START_PAGE << 16,
171 64,
172 config.size.get() as u32 / 1024 / 64, 0,
174 )
175 };
176
177 EXTMEM::regs().dcache_ctrl1().modify(|_, w| {
178 w.dcache_shut_core0_bus().clear_bit();
179 w.dcache_shut_core1_bus().clear_bit()
180 });
181
182 unsafe { Cache_Resume_DCache(0) };
183
184 if cache_dbus_mmu_set_res != 0 {
186 panic!("cache_dbus_mmu_set failed");
187 }
188
189 start as usize..start as usize + config.size.get()
190}
191
192pub(crate) mod quad_spi_impl {
193 use procmacros::ram;
194
195 use super::*;
196
197 const PSRAM_RESET_EN: u16 = 0x66;
198 const PSRAM_RESET: u16 = 0x99;
199 const PSRAM_DEVICE_ID: u16 = 0x9F;
200 const CS_PSRAM_SEL: u8 = 1 << 1;
201
202 #[ram]
203 pub(crate) fn psram_init(config: &mut PsramConfig) -> bool {
204 psram_gpio_config();
205 psram_set_cs_timing();
206
207 if config.size.is_auto() {
208 psram_disable_qio_mode_spi1();
209
210 let mut dev_id = 0u32;
212 psram_exec_cmd(
213 CommandMode::PsramCmdSpi,
214 PSRAM_DEVICE_ID,
215 8, 0,
217 24, 0, core::ptr::null(),
220 0, &mut dev_id as *mut _ as *mut u8,
222 24, CS_PSRAM_SEL, false,
225 );
226 if dev_id == 0xffffff {
227 debug!(
228 "Unknown PSRAM chip ID: {:x}. PSRAM chip not found or not supported. Check if the interface mode is configured correctly.",
229 dev_id
230 );
231 return false;
232 }
233
234 info!("chip id = {:x}", dev_id);
235
236 const PSRAM_ID_EID_S: u32 = 16;
237 const PSRAM_ID_EID_M: u32 = 0xff;
238 const PSRAM_EID_SIZE_M: u32 = 0x07;
239 const PSRAM_EID_SIZE_S: u32 = 5;
240
241 let size_id = ((((dev_id) >> PSRAM_ID_EID_S) & PSRAM_ID_EID_M) >> PSRAM_EID_SIZE_S)
242 & PSRAM_EID_SIZE_M;
243
244 const PSRAM_EID_SIZE_32MBITS: u32 = 1;
245 const PSRAM_EID_SIZE_64MBITS: u32 = 2;
246
247 let size = match size_id {
248 PSRAM_EID_SIZE_64MBITS => 64 / 8 * 1024 * 1024,
249 PSRAM_EID_SIZE_32MBITS => 32 / 8 * 1024 * 1024,
250 _ => 16 / 8 * 1024 * 1024,
251 };
252
253 info!("size is {}", size);
254
255 config.size = PsramSize::Size(size);
256 }
257
258 if config.core_clock.is_none() {
259 config.core_clock = Some(if config.ram_frequency == SpiRamFreq::Freq120m {
260 SpiTimingConfigCoreClock::SpiTimingConfigCoreClock120m
261 } else {
262 SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m
263 });
264 }
265
266 psram_reset_mode_spi1();
268 psram_enable_qio_mode_spi1();
270
271 mspi_timing_psram_tuning();
274
275 config_psram_spi_phases();
277 mspi_timing_enter_high_speed_mode(true, config);
280
281 info!("PSRAM initialized successfully in Quad SPI mode");
282 true
283 }
284
285 const PSRAM_CS_IO: u8 = 26;
286 const SPI_CS1_GPIO_NUM: u8 = 26;
287 const FUNC_SPICS1_SPICS1: u8 = 0;
288 const PIN_FUNC_GPIO: u8 = 2;
289 const PSRAM_SPIWP_SD3_IO: u8 = 10;
290 const ESP_ROM_EFUSE_FLASH_DEFAULT_SPI: u32 = 0;
291 const SPICS1_OUT_IDX: u8 = 6;
292
293 const PSRAM_QUAD_WRITE: u32 = 0x38;
294 const PSRAM_FAST_READ_QUAD: u32 = 0xEB;
295 const PSRAM_FAST_READ_QUAD_DUMMY: u32 = 6;
296 const SPI_MEM_CLKCNT_N_S: u32 = 16;
297 const SPI_MEM_SCLKCNT_N_S: u32 = 16;
298 const SPI_MEM_CLKCNT_H_S: u32 = 8;
299 const SPI_MEM_SCLKCNT_H_S: u32 = 8;
300 const SPI_MEM_CLKCNT_L_S: u32 = 0;
301 const SPI_MEM_SCLKCNT_L_S: u32 = 0;
302
303 unsafe extern "C" {
304 fn esp_rom_efuse_get_flash_gpio_info() -> u32;
305
306 fn esp_rom_efuse_get_flash_wp_gpio() -> u8;
307
308 fn esp_rom_gpio_connect_out_signal(
309 gpio_num: u8,
310 signal_idx: u8,
311 out_inv: bool,
312 oen_inv: bool,
313 );
314
315 fn esp_rom_spiflash_select_qio_pins(wp_gpio_num: u8, spiconfig: u32);
331 }
332
333 #[ram]
336 fn config_psram_spi_phases() {
337 unsafe {
338 let spi = SPI0::regs();
339 spi.cache_sctrl()
341 .modify(|_, w| w.usr_sram_dio().clear_bit()); spi.cache_sctrl().modify(|_, w| w.usr_sram_qio().set_bit()); spi.cache_sctrl()
346 .modify(|_, w| w.cache_sram_usr_rcmd().set_bit()); spi.cache_sctrl()
349 .modify(|_, w| w.cache_sram_usr_wcmd().set_bit()); spi.sram_dwr_cmd()
352 .modify(|_, w| w.cache_sram_usr_wr_cmd_bitlen().bits(7));
353
354 spi.sram_dwr_cmd().modify(|_, w| {
355 w.cache_sram_usr_wr_cmd_value()
356 .bits(PSRAM_QUAD_WRITE as u16)
357 });
358
359 spi.sram_drd_cmd()
360 .modify(|_, w| w.cache_sram_usr_rd_cmd_bitlen().bits(7));
361
362 spi.sram_drd_cmd().modify(|_, w| {
363 w.cache_sram_usr_rd_cmd_value()
364 .bits(PSRAM_FAST_READ_QUAD as u16)
365 });
366
367 spi.cache_sctrl()
369 .modify(|_, w| w.sram_addr_bitlen().bits(23));
370
371 spi.cache_sctrl()
376 .modify(|_, w| w.usr_rd_sram_dummy().set_bit()); spi.cache_sctrl().modify(|_, w| {
379 w.sram_rdummy_cyclelen()
380 .bits((PSRAM_FAST_READ_QUAD_DUMMY - 1) as u8)
381 });
382
383 spi.misc().modify(|_, w| w.cs1_dis().clear_bit());
385 }
386 }
387
388 #[ram]
389 fn mspi_timing_psram_tuning() {
390 }
393
394 #[ram]
403 fn mspi_timing_enter_high_speed_mode(control_spi1: bool, config: &PsramConfig) {
404 let core_clock: SpiTimingConfigCoreClock = mspi_core_clock(config);
405 let flash_div: u32 = flash_clock_divider(config);
406 let psram_div: u32 = psram_clock_divider(config);
407
408 info!(
409 "PSRAM core_clock {:?}, flash_div = {}, psram_div = {}",
410 core_clock, flash_div, psram_div
411 );
412
413 spi0_timing_config_set_core_clock(core_clock);
417
418 spi0_timing_config_set_flash_clock(flash_div);
419 if control_spi1 {
420 spi1_timing_config_set_flash_clock(flash_div);
421 }
422 spi0_timing_config_set_psram_clock(psram_div);
424
425 }
429
430 #[ram]
431 fn spi0_timing_config_set_core_clock(core_clock: SpiTimingConfigCoreClock) {
432 unsafe {
433 SPI0::regs().core_clk_sel().modify(|_, w| {
434 w.core_clk_sel().bits(match core_clock {
435 SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m => 0,
436 SpiTimingConfigCoreClock::SpiTimingConfigCoreClock120m => 1,
437 SpiTimingConfigCoreClock::SpiTimingConfigCoreClock160m => 2,
438 SpiTimingConfigCoreClock::SpiTimingConfigCoreClock240m => 3,
439 })
440 });
441 }
442 }
443
444 #[ram]
445 fn spi0_timing_config_set_flash_clock(freqdiv: u32) {
446 if freqdiv == 1 {
447 SPI0::regs()
448 .clock()
449 .modify(|_, w| w.clk_equ_sysclk().set_bit());
450 } else {
451 let freqbits: u32 = ((freqdiv - 1) << SPI_MEM_CLKCNT_N_S)
452 | ((freqdiv / 2 - 1) << SPI_MEM_CLKCNT_H_S)
453 | ((freqdiv - 1) << SPI_MEM_CLKCNT_L_S);
454 unsafe {
455 SPI0::regs().clock().modify(|_, w| w.bits(freqbits));
456 }
457 }
458 }
459
460 #[ram]
461 fn spi1_timing_config_set_flash_clock(freqdiv: u32) {
462 if freqdiv == 1 {
463 SPI1::regs()
464 .clock()
465 .modify(|_, w| w.clk_equ_sysclk().set_bit());
466 } else {
467 let freqbits: u32 = ((freqdiv - 1) << SPI_MEM_CLKCNT_N_S)
468 | ((freqdiv / 2 - 1) << SPI_MEM_CLKCNT_H_S)
469 | ((freqdiv - 1) << SPI_MEM_CLKCNT_L_S);
470 unsafe {
471 SPI1::regs().clock().modify(|_, w| w.bits(freqbits));
472 }
473 }
474 }
475
476 #[ram]
477 fn spi0_timing_config_set_psram_clock(freqdiv: u32) {
478 if freqdiv == 1 {
479 SPI0::regs()
480 .sram_clk()
481 .modify(|_, w| w.sclk_equ_sysclk().set_bit());
482 } else {
483 let freqbits: u32 = ((freqdiv - 1) << SPI_MEM_SCLKCNT_N_S)
484 | ((freqdiv / 2 - 1) << SPI_MEM_SCLKCNT_H_S)
485 | ((freqdiv - 1) << SPI_MEM_SCLKCNT_L_S);
486 unsafe {
487 SPI0::regs().sram_clk().modify(|_, w| w.bits(freqbits));
488 }
489 }
490 }
491
492 #[ram]
493 fn mspi_core_clock(config: &PsramConfig) -> SpiTimingConfigCoreClock {
494 config.core_clock.unwrap_or_default()
495 }
496
497 #[ram]
498 fn flash_clock_divider(config: &PsramConfig) -> u32 {
499 config.core_clock.unwrap_or_default() as u32 / config.flash_frequency as u32
500 }
501
502 #[ram]
503 fn psram_clock_divider(config: &PsramConfig) -> u32 {
504 config.core_clock.unwrap_or_default() as u32 / config.ram_frequency as u32
505 }
506
507 #[ram]
509 fn psram_reset_mode_spi1() {
510 psram_exec_cmd(
511 CommandMode::PsramCmdSpi,
512 PSRAM_RESET_EN,
513 8, 0,
515 0, 0, core::ptr::null(),
518 0, core::ptr::null_mut(),
520 0, CS_PSRAM_SEL, false,
523 ); psram_exec_cmd(
526 CommandMode::PsramCmdSpi,
527 PSRAM_RESET,
528 8, 0,
530 0, 0, core::ptr::null(),
533 0, core::ptr::null_mut(),
535 0, CS_PSRAM_SEL, false,
538 ); }
540
541 #[derive(PartialEq)]
542 #[allow(unused)]
543 enum CommandMode {
544 PsramCmdQpi = 0,
545 PsramCmdSpi = 1,
546 }
547
548 #[expect(clippy::too_many_arguments)]
549 #[ram]
550 fn psram_exec_cmd(
551 mode: CommandMode,
552 cmd: u16,
553 cmd_bit_len: u16,
554 addr: u32,
555 addr_bit_len: u32,
556 dummy_bits: u32,
557 mosi_data: *const u8,
558 mosi_bit_len: u32,
559 miso_data: *mut u8,
560 miso_bit_len: u32,
561 cs_mask: u8,
562 is_write_erase_operation: bool,
563 ) {
564 unsafe extern "C" {
565 fn esp_rom_spi_cmd_start(
573 spi_num: u32,
574 rx_buf: *const u8,
575 rx_len: u16,
576 cs_en_mask: u8,
577 is_write_erase: bool,
578 );
579 }
580
581 unsafe {
582 let spi1 = SPI1::regs();
583 let backup_usr = spi1.user().read().bits();
584 let backup_usr1 = spi1.user1().read().bits();
585 let backup_usr2 = spi1.user2().read().bits();
586 let backup_ctrl = spi1.ctrl().read().bits();
587 psram_set_op_mode(mode);
588 _psram_exec_cmd(
589 cmd,
590 cmd_bit_len,
591 addr,
592 addr_bit_len,
593 dummy_bits,
594 mosi_data,
595 mosi_bit_len,
596 miso_data,
597 miso_bit_len,
598 );
599 esp_rom_spi_cmd_start(
600 1,
601 miso_data,
602 (miso_bit_len / 8) as u16,
603 cs_mask,
604 is_write_erase_operation,
605 );
606
607 spi1.user().write(|w| w.bits(backup_usr));
608 spi1.user1().write(|w| w.bits(backup_usr1));
609 spi1.user2().write(|w| w.bits(backup_usr2));
610 spi1.ctrl().write(|w| w.bits(backup_ctrl));
611 }
612 }
613
614 #[expect(clippy::too_many_arguments)]
615 #[ram]
616 fn _psram_exec_cmd(
617 cmd: u16,
618 cmd_bit_len: u16,
619 addr: u32,
620 addr_bit_len: u32,
621 dummy_bits: u32,
622 mosi_data: *const u8,
623 mosi_bit_len: u32,
624 miso_data: *mut u8,
625 miso_bit_len: u32,
626 ) {
627 #[repr(C)]
628 struct esp_rom_spi_cmd_t {
629 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,
638 }
639
640 unsafe extern "C" {
641 fn esp_rom_spi_cmd_config(spi_num: u32, pcmd: *const esp_rom_spi_cmd_t);
645 }
646
647 let conf = esp_rom_spi_cmd_t {
648 cmd,
649 cmd_bit_len,
650 addr: &addr,
651 addr_bit_len,
652 tx_data: mosi_data as *const u32,
653 tx_data_bit_len: mosi_bit_len,
654 rx_data: miso_data as *mut u32,
655 rx_data_bit_len: miso_bit_len,
656 dummy_bit_len: dummy_bits,
657 };
658
659 unsafe {
660 esp_rom_spi_cmd_config(1, &conf);
661 }
662 }
663
664 #[ram]
665 fn psram_set_op_mode(mode: CommandMode) {
666 unsafe extern "C" {
667 fn esp_rom_spi_set_op_mode(spi: u32, mode: u32);
668 }
669
670 const ESP_ROM_SPIFLASH_QIO_MODE: u32 = 0;
671 const ESP_ROM_SPIFLASH_SLOWRD_MODE: u32 = 5;
672
673 unsafe {
674 match mode {
675 CommandMode::PsramCmdQpi => {
676 esp_rom_spi_set_op_mode(1, ESP_ROM_SPIFLASH_QIO_MODE);
677 SPI1::regs().ctrl().modify(|_, w| w.fcmd_quad().set_bit());
678 }
679 CommandMode::PsramCmdSpi => {
680 esp_rom_spi_set_op_mode(1, ESP_ROM_SPIFLASH_SLOWRD_MODE);
681 }
682 }
683 }
684 }
685
686 #[ram]
688 fn psram_disable_qio_mode_spi1() {
689 const PSRAM_EXIT_QMODE: u16 = 0xF5;
690 const CS_PSRAM_SEL: u8 = 1 << 1;
691
692 psram_exec_cmd(
693 CommandMode::PsramCmdQpi,
694 PSRAM_EXIT_QMODE,
695 8, 0,
697 0, 0, core::ptr::null(),
700 0, core::ptr::null_mut(),
702 0, CS_PSRAM_SEL, false, );
706 }
707
708 #[ram]
710 fn psram_enable_qio_mode_spi1() {
711 const PSRAM_ENTER_QMODE: u16 = 0x35;
712 const CS_PSRAM_SEL: u8 = 1 << 1;
713
714 psram_exec_cmd(
715 CommandMode::PsramCmdSpi,
716 PSRAM_ENTER_QMODE,
717 8, 0,
719 0, 0, core::ptr::null(),
722 0, core::ptr::null_mut(),
724 0, CS_PSRAM_SEL, false, );
728 }
729
730 #[ram]
731 fn psram_set_cs_timing() {
732 unsafe {
733 SPI0::regs()
736 .spi_smem_ac()
737 .modify(|_, w| w.spi_smem_cs_hold_time().bits(0));
738 SPI0::regs()
739 .spi_smem_ac()
740 .modify(|_, w| w.spi_smem_cs_setup_time().bits(0));
741 SPI0::regs()
742 .spi_smem_ac()
743 .modify(|_, w| w.spi_smem_cs_hold().set_bit());
744 SPI0::regs()
745 .spi_smem_ac()
746 .modify(|_, w| w.spi_smem_cs_setup().set_bit());
747 }
748 }
749
750 #[ram]
751 fn psram_gpio_config() {
752 let cs1_io: u8 = PSRAM_CS_IO;
754 if cs1_io == SPI_CS1_GPIO_NUM {
755 unsafe {
756 IO_MUX::regs()
757 .gpio(cs1_io as usize)
758 .modify(|_, w| w.mcu_sel().bits(FUNC_SPICS1_SPICS1));
759 }
760 } else {
761 unsafe {
762 esp_rom_gpio_connect_out_signal(cs1_io, SPICS1_OUT_IDX, false, false);
763
764 IO_MUX::regs()
765 .gpio(cs1_io as usize)
766 .modify(|_, w| w.mcu_sel().bits(PIN_FUNC_GPIO));
767 }
768 }
769
770 let mut wp_io: u8 = PSRAM_SPIWP_SD3_IO;
772 let spiconfig = unsafe { esp_rom_efuse_get_flash_gpio_info() };
773 if spiconfig == ESP_ROM_EFUSE_FLASH_DEFAULT_SPI {
774 } else {
777 wp_io = unsafe { esp_rom_efuse_get_flash_wp_gpio() };
780 }
781 unsafe {
783 esp_rom_spiflash_select_qio_pins(wp_io, spiconfig);
784 }
785 }
786}
787
788pub(crate) mod octal_spi_impl {
789 use procmacros::ram;
790
791 use super::*;
792
793 const OPI_PSRAM_SYNC_READ: u16 = 0x0000;
794 const OPI_PSRAM_SYNC_WRITE: u16 = 0x8080;
795 const OPI_PSRAM_REG_READ: u16 = 0x4040;
796 const OPI_PSRAM_REG_WRITE: u16 = 0xC0C0;
797 const OCT_PSRAM_RD_CMD_BITLEN: u8 = 16;
798 const OCT_PSRAM_WR_CMD_BITLEN: u8 = 16;
799 const OCT_PSRAM_ADDR_BITLEN: u8 = 32;
800 const OCT_PSRAM_RD_DUMMY_BITLEN: u8 = 2 * (10 - 1);
801 const OCT_PSRAM_WR_DUMMY_BITLEN: u8 = 2 * (5 - 1);
802 const OCT_PSRAM_CS1_IO: u8 = SPI_CS1_GPIO_NUM;
803 const OCT_PSRAM_VENDOR_ID: u8 = 0xD;
804
805 const OCT_PSRAM_CS_SETUP_TIME: u8 = 3;
806 const OCT_PSRAM_CS_HOLD_TIME: u8 = 3;
807 const OCT_PSRAM_CS_HOLD_DELAY: u8 = 2;
808
809 const PSRAM_SIZE_2MB: usize = 2 * 1024 * 1024;
810 const PSRAM_SIZE_4MB: usize = 4 * 1024 * 1024;
811 const PSRAM_SIZE_8MB: usize = 8 * 1024 * 1024;
812 const PSRAM_SIZE_16MB: usize = 16 * 1024 * 1024;
813 const PSRAM_SIZE_32MB: usize = 32 * 1024 * 1024;
814
815 const SPI_CS1_GPIO_NUM: u8 = 26;
816 const FUNC_SPICS1_SPICS1: u8 = 0;
817
818 const SPI_MEM_CLKCNT_N_S: u32 = 16;
819 const SPI_MEM_SCLKCNT_N_S: u32 = 16;
820 const SPI_MEM_CLKCNT_H_S: u32 = 8;
821 const SPI_MEM_SCLKCNT_H_S: u32 = 8;
822 const SPI_MEM_CLKCNT_L_S: u32 = 0;
823 const SPI_MEM_SCLKCNT_L_S: u32 = 0;
824 const ESP_ROM_SPIFLASH_OPI_DTR_MODE: u8 = 7;
825
826 unsafe extern "C" {
827 fn esp_rom_opiflash_exec_cmd(
843 spi_num: u32,
844 mode: u8,
845 cmd: u32,
846 cmd_bit_len: u32,
847 addr: u32,
848 addr_bit_len: u32,
849 dummy_bits: u32,
850 mosi_data: *const u8,
851 mosi_bit_len: u32,
852 miso_data: *mut u8,
853 miso_bit_len: u32,
854 cs_mask: u32,
855 is_write_erase_operation: bool,
856 );
857
858 fn esp_rom_spi_set_dtr_swap_mode(spi: u32, wr_swap: bool, rd_swap: bool);
863
864 fn esp_rom_opiflash_pin_config();
865 }
866
867 #[derive(Default)]
869 #[repr(C)]
870 struct OpiPsramModeReg {
871 pub mr0: u8,
873 pub mr1: u8,
875 pub mr2: u8,
877 pub mr3: u8,
879 pub mr4: u8,
881 pub mr8: u8,
883 }
884
885 #[allow(unused)]
886 impl OpiPsramModeReg {
887 fn drive_str(&self) -> u8 {
888 self.mr0 & 0b11
889 }
890
891 fn set_drive_str(&mut self, value: u8) {
892 self.mr0 &= !0b11;
893 self.mr0 |= value & 0b11;
894 }
895
896 fn read_latency(&self) -> u8 {
897 (self.mr0 >> 2) & 0b111
898 }
899
900 fn set_read_latency(&mut self, value: u8) {
901 self.mr0 &= !(0b111 << 2);
902 self.mr0 |= (value & 0b111) << 2;
903 }
904
905 fn lt(&self) -> u8 {
906 (self.mr0 >> 5) & 0b1
907 }
908
909 fn set_lt(&mut self, value: u8) {
910 self.mr0 &= !(0b1 << 5);
911 self.mr0 |= (value & 0b1) << 5;
912 }
913
914 fn rsvd0_1(&self) -> u8 {
915 (self.mr0 >> 6) & 0b11
916 }
917
918 fn set_rsvd0_1(&mut self, value: u8) {
919 self.mr0 &= !(0b11 << 6);
920 self.mr0 |= (value & 0b11) << 6;
921 }
922
923 fn vendor_id(&self) -> u8 {
924 self.mr1 & 0b11111
925 }
926
927 fn set_vendor_id(&mut self, value: u8) {
928 self.mr1 &= !0b11111;
929 self.mr1 |= value & 0b11111;
930 }
931
932 fn rsvd0_2(&self) -> u8 {
933 (self.mr1 >> 5) & 0b111
934 }
935
936 fn set_rsvd0_2(&mut self, value: u8) {
937 self.mr1 &= !(0b111 << 5);
938 self.mr1 |= (value & 0b111) << 5;
939 }
940
941 fn density(&self) -> u8 {
942 self.mr2 & 0b111
943 }
944
945 fn set_density(&mut self, value: u8) {
946 self.mr2 &= !0b111;
947 self.mr2 |= value & 0b111;
948 }
949
950 fn dev_id(&self) -> u8 {
951 (self.mr2 >> 3) & 0b11
952 }
953
954 fn set_dev_id(&mut self, value: u8) {
955 self.mr2 &= !(0b11 << 3);
956 self.mr2 |= (value & 0b11) << 3;
957 }
958
959 fn rsvd1_2(&self) -> u8 {
960 (self.mr2 >> 5) & 0b11
961 }
962
963 fn set_rsvd1_2(&mut self, value: u8) {
964 self.mr2 &= !(0b11 << 5);
965 self.mr2 |= (value & 0b11) << 5;
966 }
967
968 fn gb(&self) -> u8 {
969 (self.mr2 >> 7) & 0b1
970 }
971
972 fn set_gb(&mut self, value: u8) {
973 self.mr2 &= !(0b1 << 7);
974 self.mr2 |= (value & 0b1) << 7;
975 }
976
977 fn rsvd3_7(&self) -> u8 {
978 self.mr3 & 0b11111
979 }
980
981 fn set_rsvd3_7(&mut self, value: u8) {
982 self.mr3 &= !0b11111;
983 self.mr3 |= value & 0b11111;
984 }
985
986 fn srf(&self) -> u8 {
987 (self.mr3 >> 5) & 0b1
988 }
989
990 fn set_srf(&mut self, value: u8) {
991 self.mr3 &= !(0b1 << 5);
992 self.mr3 |= (value & 0b1) << 5;
993 }
994
995 fn vcc(&self) -> u8 {
996 (self.mr3 >> 6) & 0b1
997 }
998
999 fn set_vcc(&mut self, value: u8) {
1000 self.mr3 &= !(0b1 << 6);
1001 self.mr3 |= (value & 0b1) << 6;
1002 }
1003
1004 fn rsvd0(&self) -> u8 {
1005 (self.mr3 >> 7) & 0b1
1006 }
1007
1008 fn set_rsvd0(&mut self, value: u8) {
1009 self.mr3 &= !(0b1 << 7);
1010 self.mr3 |= (value & 0b1) << 7;
1011 }
1012
1013 fn pasr(&self) -> u8 {
1014 self.mr4 & 0b111
1015 }
1016
1017 fn set_pasr(&mut self, value: u8) {
1018 self.mr4 &= !0b111;
1019 self.mr4 |= value & 0b111;
1020 }
1021
1022 fn rf(&self) -> u8 {
1023 (self.mr4 >> 3) & 0b1
1024 }
1025
1026 fn set_rf(&mut self, value: u8) {
1027 self.mr4 &= !(0b1 << 3);
1028 self.mr4 |= (value & 0b1) << 3;
1029 }
1030
1031 fn rsvd3(&self) -> u8 {
1032 (self.mr4 >> 4) & 0b1
1033 }
1034
1035 fn set_rsvd3(&mut self, value: u8) {
1036 self.mr4 &= !(0b1 << 4);
1037 self.mr4 |= (value & 0b1) << 4;
1038 }
1039
1040 fn wr_latency(&self) -> u8 {
1041 (self.mr4 >> 5) & 0b111
1042 }
1043
1044 fn set_wr_latency(&mut self, value: u8) {
1045 self.mr4 &= !(0b111 << 5);
1046 self.mr4 |= (value & 0b111) << 5;
1047 }
1048
1049 fn bl(&self) -> u8 {
1050 self.mr8 & 0b11
1051 }
1052
1053 fn set_bl(&mut self, value: u8) {
1054 self.mr8 &= !0b11;
1055 self.mr8 |= value & 0b11;
1056 }
1057
1058 fn bt(&self) -> u8 {
1059 (self.mr8 >> 2) & 0b1
1060 }
1061
1062 fn set_bt(&mut self, value: u8) {
1063 self.mr8 &= !(0b1 << 2);
1064 self.mr8 |= (value & 0b1) << 2;
1065 }
1066
1067 fn rsvd0_4(&self) -> u8 {
1068 (self.mr8 >> 3) & 0b11111
1069 }
1070
1071 fn set_rsvd0_4(&mut self, value: u8) {
1072 self.mr8 &= !(0b11111 << 3);
1073 self.mr8 |= (value & 0b11111) << 3;
1074 }
1075 }
1076
1077 #[ram]
1078 pub(crate) fn psram_init(config: &mut PsramConfig) -> bool {
1079 mspi_pin_init();
1080 init_psram_pins();
1081 set_psram_cs_timing();
1082
1083 spi_timing_enter_mspi_low_speed_mode(true);
1088
1089 unsafe {
1090 SPI1::regs()
1092 .ddr()
1093 .modify(|_, w| w.spi_fmem_var_dummy().set_bit());
1094 esp_rom_spi_set_dtr_swap_mode(1, false, false);
1095 }
1096
1097 let mut mode_reg = OpiPsramModeReg::default();
1099 mode_reg.set_lt(1);
1100 mode_reg.set_read_latency(2);
1101 mode_reg.set_drive_str(0);
1102 mode_reg.set_bl(3);
1103 mode_reg.set_bt(0);
1104
1105 init_psram_mode_reg(1, &mode_reg);
1106 psram_mode_reg(1, &mut mode_reg);
1108
1109 print_psram_info(&mode_reg);
1110
1111 if mode_reg.vendor_id() != OCT_PSRAM_VENDOR_ID {
1112 debug!(
1113 "Unknown PSRAM vendor ID: {:x}. PSRAM chip not found or not supported. Check if the interface mode is configured correctly.",
1114 mode_reg.vendor_id()
1115 );
1116 return false;
1117 }
1118
1119 let psram_size = match mode_reg.density() {
1120 0x0 => PSRAM_SIZE_2MB,
1121 0x1 => PSRAM_SIZE_4MB,
1122 0x3 => PSRAM_SIZE_8MB,
1123 0x5 => PSRAM_SIZE_16MB,
1124 0x7 => PSRAM_SIZE_32MB,
1125 _ => 0,
1126 };
1127 info!("{} bytes of PSRAM", psram_size);
1128
1129 if config.core_clock.is_none() {
1130 config.core_clock = Some(if config.ram_frequency == SpiRamFreq::Freq80m {
1131 SpiTimingConfigCoreClock::SpiTimingConfigCoreClock160m
1132 } else if config.ram_frequency == SpiRamFreq::Freq120m {
1133 SpiTimingConfigCoreClock::SpiTimingConfigCoreClock240m
1134 } else {
1135 SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m
1136 });
1137 }
1138 if config.size.is_auto() {
1139 config.size = PsramSize::Size(psram_size);
1140 }
1141
1142 spi_timing_enter_mspi_high_speed_mode(true, config);
1150
1151 spi_flash_set_rom_required_regs();
1154
1155 config_psram_spi_phases();
1160
1161 info!("PSRAM initialized successfully in Octal SPI mode");
1162 true
1163 }
1164
1165 fn config_psram_spi_phases() {
1168 unsafe {
1169 let spi = SPI0::regs();
1170 spi.cache_sctrl()
1172 .modify(|_, w| w.cache_sram_usr_wcmd().set_bit());
1173
1174 spi.sram_dwr_cmd().modify(|_, w| {
1175 w.cache_sram_usr_wr_cmd_bitlen()
1176 .bits(OCT_PSRAM_WR_CMD_BITLEN - 1)
1177 });
1178 spi.sram_dwr_cmd()
1179 .modify(|_, w| w.cache_sram_usr_wr_cmd_value().bits(OPI_PSRAM_SYNC_WRITE));
1180
1181 spi.cache_sctrl()
1183 .modify(|_, w| w.cache_sram_usr_rcmd().set_bit());
1184
1185 spi.sram_drd_cmd().modify(|_, w| {
1186 w.cache_sram_usr_rd_cmd_bitlen()
1187 .bits(OCT_PSRAM_RD_CMD_BITLEN - 1)
1188 });
1189 spi.sram_drd_cmd()
1190 .modify(|_, w| w.cache_sram_usr_rd_cmd_value().bits(OPI_PSRAM_SYNC_READ));
1191
1192 spi.cache_sctrl()
1194 .modify(|_, w| w.sram_addr_bitlen().bits(OCT_PSRAM_ADDR_BITLEN - 1));
1195 spi.cache_sctrl()
1196 .modify(|_, w| w.cache_usr_scmd_4byte().set_bit());
1197
1198 spi.cache_sctrl()
1200 .modify(|_, w| w.usr_rd_sram_dummy().set_bit());
1201 spi.cache_sctrl()
1202 .modify(|_, w| w.usr_wr_sram_dummy().set_bit());
1203 spi.cache_sctrl()
1204 .modify(|_, w| w.sram_rdummy_cyclelen().bits(OCT_PSRAM_RD_DUMMY_BITLEN - 1));
1205 spi.spi_smem_ddr()
1206 .modify(|_, w| w.spi_smem_var_dummy().set_bit());
1207 spi.cache_sctrl()
1208 .modify(|_, w| w.sram_wdummy_cyclelen().bits(OCT_PSRAM_WR_DUMMY_BITLEN - 1));
1209
1210 spi.spi_smem_ddr().modify(|_, w| w.wdat_swp().clear_bit());
1211 spi.spi_smem_ddr().modify(|_, w| w.rdat_swp().clear_bit());
1212 spi.spi_smem_ddr().modify(|_, w| w.en().set_bit());
1213
1214 spi.sram_cmd().modify(|_, w| w.sdummy_out().set_bit());
1215 spi.sram_cmd().modify(|_, w| w.scmd_oct().set_bit());
1216 spi.sram_cmd().modify(|_, w| w.saddr_oct().set_bit());
1217 spi.sram_cmd().modify(|_, w| w.sdout_oct().set_bit());
1218 spi.sram_cmd().modify(|_, w| w.sdin_oct().set_bit());
1219
1220 spi.cache_sctrl().modify(|_, w| w.sram_oct().set_bit());
1221 }
1222 }
1223
1224 #[ram]
1225 fn spi_flash_set_rom_required_regs() {
1226 SPI1::regs()
1228 .ddr()
1229 .modify(|_, w| w.spi_fmem_var_dummy().clear_bit());
1230 }
1236
1237 #[ram]
1238 fn mspi_pin_init() {
1239 unsafe { esp_rom_opiflash_pin_config() };
1240 spi_timing_set_pin_drive_strength();
1241 }
1243
1244 #[ram]
1245 fn spi_timing_set_pin_drive_strength() {
1246 unsafe {
1249 SPI0::regs()
1250 .date()
1251 .modify(|_, w| w.spi_spiclk_pad_drv_ctl_en().set_bit());
1252 SPI0::regs()
1253 .date()
1254 .modify(|_, w| w.spi_smem_spiclk_fun_drv().bits(3));
1255 SPI0::regs()
1256 .date()
1257 .modify(|_, w| w.spi_fmem_spiclk_fun_drv().bits(3));
1258
1259 let pins = [27usize, 28, 31, 32, 33, 34, 35, 36, 37];
1261 for pin in pins {
1262 IO_MUX::regs().gpio(pin).modify(|_, w| w.fun_drv().bits(3));
1263 }
1264 }
1265 }
1266
1267 fn spi_timing_enter_mspi_low_speed_mode(control_spi1: bool) {
1268 spi0_timing_config_set_core_clock(SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m); spi0_timing_config_set_flash_clock(4);
1281 if control_spi1 {
1282 spi1_timing_config_set_flash_clock(4);
1284 }
1285
1286 spi0_timing_config_set_psram_clock(4);
1288
1289 }
1292
1293 fn spi_timing_enter_mspi_high_speed_mode(control_spi1: bool, config: &PsramConfig) {
1301 let flash_div: u32 = flash_clock_divider(config);
1302 let psram_div: u32 = psram_clock_divider(config);
1303
1304 spi0_timing_config_set_core_clock(config.core_clock.unwrap_or_default()); spi0_timing_config_set_flash_clock(flash_div);
1308 if control_spi1 {
1309 spi1_timing_config_set_flash_clock(flash_div);
1310 }
1311 spi0_timing_config_set_psram_clock(psram_div);
1313
1314 }
1317
1318 fn set_psram_cs_timing() {
1319 unsafe {
1320 let spi = SPI0::regs();
1321 spi.spi_smem_ac()
1325 .modify(|_, w| w.spi_smem_cs_hold().set_bit());
1326 spi.spi_smem_ac()
1327 .modify(|_, w| w.spi_smem_cs_setup().set_bit());
1328
1329 spi.spi_smem_ac()
1330 .modify(|_, w| w.spi_smem_cs_hold_time().bits(OCT_PSRAM_CS_HOLD_TIME));
1331 spi.spi_smem_ac()
1332 .modify(|_, w| w.spi_smem_cs_setup_time().bits(OCT_PSRAM_CS_SETUP_TIME));
1333
1334 spi.spi_smem_ac()
1337 .modify(|_, w| w.spi_smem_cs_hold_delay().bits(OCT_PSRAM_CS_HOLD_DELAY));
1338 }
1339 }
1340
1341 fn init_psram_pins() {
1342 unsafe {
1344 IO_MUX::regs()
1345 .gpio(OCT_PSRAM_CS1_IO as usize)
1346 .modify(|_, w| w.mcu_sel().bits(FUNC_SPICS1_SPICS1));
1347 }
1348
1349 unsafe {
1351 IO_MUX::regs()
1352 .gpio(OCT_PSRAM_CS1_IO as usize)
1353 .modify(|_, w| w.fun_drv().bits(3));
1354 }
1355
1356 unsafe {
1358 SPI0::regs()
1359 .date()
1360 .modify(|_, w| w.spi_smem_spiclk_fun_drv().bits(3));
1361 }
1362 }
1363
1364 fn psram_mode_reg(spi_num: u32, out_reg: &mut OpiPsramModeReg) {
1365 let mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE;
1366 let cmd_len: u32 = 16;
1367 let addr_bit_len: u32 = 32;
1368 let dummy: u32 = OCT_PSRAM_RD_DUMMY_BITLEN as u32;
1369 let mut data_bit_len: u32 = 16;
1370
1371 unsafe {
1372 esp_rom_opiflash_exec_cmd(
1374 spi_num,
1375 mode,
1376 OPI_PSRAM_REG_READ as u32,
1377 cmd_len,
1378 0x0,
1379 addr_bit_len,
1380 dummy,
1381 core::ptr::null(),
1382 0,
1383 &mut out_reg.mr0,
1384 data_bit_len,
1385 1 << 1,
1386 false,
1387 );
1388 esp_rom_opiflash_exec_cmd(
1390 spi_num,
1391 mode,
1392 OPI_PSRAM_REG_READ as u32,
1393 cmd_len,
1394 0x2,
1395 addr_bit_len,
1396 dummy,
1397 core::ptr::null(),
1398 0,
1399 &mut out_reg.mr2,
1400 data_bit_len,
1401 1 << 1,
1402 false,
1403 );
1404 data_bit_len = 8;
1405 esp_rom_opiflash_exec_cmd(
1407 spi_num,
1408 mode,
1409 OPI_PSRAM_REG_READ as u32,
1410 cmd_len,
1411 0x4,
1412 addr_bit_len,
1413 dummy,
1414 core::ptr::null(),
1415 0,
1416 &mut out_reg.mr4,
1417 data_bit_len,
1418 1 << 1,
1419 false,
1420 );
1421 esp_rom_opiflash_exec_cmd(
1423 spi_num,
1424 mode,
1425 OPI_PSRAM_REG_READ as u32,
1426 cmd_len,
1427 0x8,
1428 addr_bit_len,
1429 dummy,
1430 core::ptr::null(),
1431 0,
1432 &mut out_reg.mr8,
1433 data_bit_len,
1434 1 << 1,
1435 false,
1436 );
1437 }
1438 }
1439
1440 fn init_psram_mode_reg(spi_num: u32, mode_reg_config: &OpiPsramModeReg) {
1442 let mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE;
1443 let cmd_len: u32 = 16;
1444 let addr: u32 = 0x0; let addr_bit_len: u32 = 32;
1446 let dummy = OCT_PSRAM_RD_DUMMY_BITLEN as u32;
1447 let mut mode_reg = OpiPsramModeReg::default();
1448 let data_bit_len: u32 = 16;
1449
1450 unsafe {
1452 esp_rom_opiflash_exec_cmd(
1453 spi_num,
1454 mode,
1455 OPI_PSRAM_REG_READ as u32,
1456 cmd_len,
1457 addr,
1458 addr_bit_len,
1459 dummy,
1460 core::ptr::null(),
1461 0,
1462 &mut mode_reg.mr0,
1463 data_bit_len,
1464 1 << 1,
1465 false,
1466 );
1467 }
1468
1469 mode_reg.set_lt(mode_reg_config.lt());
1471 mode_reg.set_read_latency(mode_reg_config.read_latency());
1472 mode_reg.set_drive_str(mode_reg_config.drive_str());
1473
1474 unsafe {
1476 esp_rom_opiflash_exec_cmd(
1477 spi_num,
1478 mode,
1479 OPI_PSRAM_REG_WRITE as u32,
1480 cmd_len,
1481 addr,
1482 addr_bit_len,
1483 0,
1484 &mode_reg.mr0,
1485 16,
1486 core::ptr::null_mut(),
1487 0,
1488 1 << 1,
1489 false,
1490 );
1491 }
1492
1493 }
1495
1496 fn print_psram_info(reg_val: &OpiPsramModeReg) {
1497 info!(
1498 "vendor id : {:02x} ({})",
1499 reg_val.vendor_id(),
1500 if reg_val.vendor_id() == 0x0d {
1501 "AP"
1502 } else {
1503 "UNKNOWN"
1504 }
1505 );
1506 info!(
1507 "dev id : {:02x} (generation {})",
1508 reg_val.dev_id(),
1509 reg_val.dev_id() + 1
1510 );
1511 info!(
1512 "density : {:02x} ({} Mbit)",
1513 reg_val.density(),
1514 if reg_val.density() == 0x1 {
1515 32
1516 } else if reg_val.density() == 0x3 {
1517 64
1518 } else if reg_val.density() == 0x5 {
1519 128
1520 } else if reg_val.density() == 0x7 {
1521 256
1522 } else {
1523 0
1524 }
1525 );
1526 info!(
1527 "good-die : {:02x} ({})",
1528 reg_val.gb(),
1529 if reg_val.gb() == 1 { "Pass" } else { "Fail" }
1530 );
1531 info!(
1532 "Latency : {:02x} ({})",
1533 reg_val.lt(),
1534 if reg_val.lt() == 1 {
1535 "Fixed"
1536 } else {
1537 "Variable"
1538 }
1539 );
1540 info!(
1541 "VCC : {:02x} ({})",
1542 reg_val.vcc(),
1543 if reg_val.vcc() == 1 { "3V" } else { "1.8V" }
1544 );
1545 info!(
1546 "SRF : {:02x} ({} Refresh)",
1547 reg_val.srf(),
1548 if reg_val.srf() == 0x1 { "Fast" } else { "Slow" }
1549 );
1550 info!(
1551 "BurstType : {:02x} ({} Wrap)",
1552 reg_val.bt(),
1553 if reg_val.bt() == 1 && reg_val.bl() != 3 {
1554 "Hybrid"
1555 } else {
1556 ""
1557 }
1558 );
1559 info!(
1560 "BurstLen : {:02x} ({} Byte)",
1561 reg_val.bl(),
1562 if reg_val.bl() == 0x00 {
1563 16
1564 } else if reg_val.bl() == 0x01 {
1565 32
1566 } else if reg_val.bl() == 0x10 {
1567 64
1568 } else {
1569 1024
1570 }
1571 );
1572 info!(
1573 "Readlatency : {:02x} ({} cycles@{})",
1574 reg_val.read_latency(),
1575 reg_val.read_latency() * 2 + 6,
1576 if reg_val.lt() == 1 {
1577 "Fixed"
1578 } else {
1579 "Variable"
1580 }
1581 );
1582 info!(
1583 "DriveStrength: {:02x} (1/{})",
1584 reg_val.drive_str(),
1585 if reg_val.drive_str() == 0x00 {
1586 1
1587 } else if reg_val.drive_str() == 0x01 {
1588 2
1589 } else if reg_val.drive_str() == 0x02 {
1590 4
1591 } else {
1592 8
1593 }
1594 );
1595 }
1596
1597 #[ram]
1598 fn spi0_timing_config_set_core_clock(core_clock: SpiTimingConfigCoreClock) {
1599 unsafe {
1600 SPI0::regs().core_clk_sel().modify(|_, w| {
1601 w.core_clk_sel().bits(match core_clock {
1602 SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m => 0,
1603 SpiTimingConfigCoreClock::SpiTimingConfigCoreClock120m => 1,
1604 SpiTimingConfigCoreClock::SpiTimingConfigCoreClock160m => 2,
1605 SpiTimingConfigCoreClock::SpiTimingConfigCoreClock240m => 3,
1606 })
1607 });
1608 }
1609 }
1610
1611 #[ram]
1612 fn spi0_timing_config_set_flash_clock(freqdiv: u32) {
1613 if freqdiv == 1 {
1614 SPI0::regs()
1615 .clock()
1616 .modify(|_, w| w.clk_equ_sysclk().set_bit());
1617 } else {
1618 let freqbits: u32 = ((freqdiv - 1) << SPI_MEM_CLKCNT_N_S)
1619 | ((freqdiv / 2 - 1) << SPI_MEM_CLKCNT_H_S)
1620 | ((freqdiv - 1) << SPI_MEM_CLKCNT_L_S);
1621 unsafe {
1622 SPI0::regs().clock().modify(|_, w| w.bits(freqbits));
1623 }
1624 }
1625 }
1626
1627 #[ram]
1628 fn spi1_timing_config_set_flash_clock(freqdiv: u32) {
1629 if freqdiv == 1 {
1630 SPI1::regs()
1631 .clock()
1632 .modify(|_, w| w.clk_equ_sysclk().set_bit());
1633 } else {
1634 let freqbits: u32 = ((freqdiv - 1) << SPI_MEM_CLKCNT_N_S)
1635 | ((freqdiv / 2 - 1) << SPI_MEM_CLKCNT_H_S)
1636 | ((freqdiv - 1) << SPI_MEM_CLKCNT_L_S);
1637 unsafe {
1638 SPI1::regs().clock().modify(|_, w| w.bits(freqbits));
1639 }
1640 }
1641 }
1642
1643 #[ram]
1644 fn spi0_timing_config_set_psram_clock(freqdiv: u32) {
1645 if freqdiv == 1 {
1646 SPI0::regs()
1647 .sram_clk()
1648 .modify(|_, w| w.sclk_equ_sysclk().set_bit());
1649 } else {
1650 let freqbits: u32 = ((freqdiv - 1) << SPI_MEM_SCLKCNT_N_S)
1651 | ((freqdiv / 2 - 1) << SPI_MEM_SCLKCNT_H_S)
1652 | ((freqdiv - 1) << SPI_MEM_SCLKCNT_L_S);
1653 unsafe {
1654 SPI0::regs().sram_clk().modify(|_, w| w.bits(freqbits));
1655 }
1656 }
1657 }
1658
1659 #[ram]
1660 fn flash_clock_divider(config: &PsramConfig) -> u32 {
1661 config.core_clock.unwrap_or_default() as u32 / config.flash_frequency as u32
1662 }
1663
1664 #[ram]
1665 fn psram_clock_divider(config: &PsramConfig) -> u32 {
1666 config.core_clock.unwrap_or_default() as u32 / config.ram_frequency as u32
1667 }
1668}