Skip to main content

esp_hal/psram/
esp32s3.rs

1use core::ops::Range;
2
3use super::{EXTMEM_ORIGIN, PsramSize};
4use crate::peripherals::{EXTMEM, IO_MUX, SPI0, SPI1};
5
6/// PSRAM interface mode
7#[derive(Copy, Clone, Debug, Default, PartialEq)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9pub enum PsramMode {
10    /// Try to detect the PSRAM mode. While convenient, not entirely reliable.
11    #[default]
12    Auto,
13
14    /// The PSRAM is connected via Quad SPI.
15    QuadSpi,
16
17    /// The PSRAM is connected via Octal SPI.
18    OctalSpi,
19}
20
21/// Frequency of flash memory
22#[derive(Copy, Clone, Debug, Default, PartialEq)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24pub enum FlashFreq {
25    /// Flash frequency 20 MHz
26    FlashFreq20m  = 20,
27    /// Flash frequency 40 MHz
28    FlashFreq40m  = 40,
29    /// Flash frequency 80 MHz
30    #[default]
31    FlashFreq80m  = 80,
32    /// Flash frequency 120 MHz
33    /// This is not recommended, see <https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-guides/flash_psram_config.html>
34    FlashFreq120m = 120,
35}
36
37/// Frequency of PSRAM memory
38#[derive(Copy, Clone, Debug, Default, PartialEq)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub enum SpiRamFreq {
41    /// PSRAM frequency 40 MHz
42    #[default]
43    Freq40m  = 40,
44    /// PSRAM frequency 80 MHz
45    Freq80m  = 80,
46    /// PSRAM frequency 120 MHz
47    /// This is not recommended, see <https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-guides/flash_psram_config.html>
48    Freq120m = 120,
49}
50
51/// Core timing configuration
52#[derive(Copy, Clone, Debug, Default, PartialEq)]
53#[cfg_attr(feature = "defmt", derive(defmt::Format))]
54pub enum SpiTimingConfigCoreClock {
55    /// Core clock 80 MHz
56    #[default]
57    SpiTimingConfigCoreClock80m  = 80,
58    /// Core clock 120 MHz
59    SpiTimingConfigCoreClock120m = 120,
60    /// Core clock 160 MHz
61    SpiTimingConfigCoreClock160m = 160,
62    /// Core clock 240 MHz
63    SpiTimingConfigCoreClock240m = 240,
64}
65
66/// PSRAM configuration
67#[derive(Copy, Clone, Debug, Default, PartialEq)]
68#[cfg_attr(feature = "defmt", derive(defmt::Format))]
69pub struct PsramConfig {
70    /// PSRAM interface mode
71    pub mode: PsramMode,
72    /// PSRAM size
73    pub size: PsramSize,
74    /// Core timing configuration
75    pub core_clock: Option<SpiTimingConfigCoreClock>,
76    /// Frequency of flash memory
77    pub flash_frequency: FlashFreq,
78    /// Frequency of PSRAM memory
79    pub ram_frequency: SpiRamFreq,
80}
81
82/// Initialize PSRAM to be used for data.
83#[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        /// Set DCache mmu mapping.
119        ///
120        /// [`ext_ram`]: u32 DPORT_MMU_ACCESS_FLASH for flash, DPORT_MMU_ACCESS_SPIRAM for spiram, DPORT_MMU_INVALID for invalid.
121        /// [`vaddr`]: u32 Virtual address in CPU address space.
122        /// [`paddr`]: u32 Physical address in external memory. Should be aligned by psize.
123        /// [`psize`]: u32 Page size of DCache, in kilobytes. Should be 64 here.
124        /// [`num`]: u32 Pages to be set.
125        /// [`fixes`]: u32 0 for physical pages grow with virtual pages, other for virtual pages map to same physical page.
126        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    // calculate the PSRAM start address to map
143    // the linker scripts can produce a gap between mapped IROM and DROM segments
144    // bigger than a flash page - i.e. we will see an unmapped memory slot
145    // start from the end and find the last mapped flash page
146    //
147    // More general information about the MMU can be found here:
148    // https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-reference/system/mm.html#introduction
149    let mmu_table_ptr = DR_REG_MMU_TABLE as *const u32;
150    let mut mapped_pages = 0;
151
152    // the bootloader is using the last page to access flash internally
153    // (e.g. to read the app descriptor) so we just skip that
154    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    // If we need use SPIRAM, we should use data cache.
164    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, // number of pages to map
173            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    // panic AFTER resuming the cache
185    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            // read chip id
211            let mut dev_id = 0u32;
212            psram_exec_cmd(
213                CommandMode::PsramCmdSpi,
214                PSRAM_DEVICE_ID,
215                8, // command and command bit len
216                0,
217                24, // address and address bit len
218                0,  // dummy bit len
219                core::ptr::null(),
220                0, // tx data and tx bit len
221                &mut dev_id as *mut _ as *mut u8,
222                24,           // rx data and rx bit len
223                CS_PSRAM_SEL, // cs bit mask
224                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        // SPI1: send psram reset command
267        psram_reset_mode_spi1();
268        // SPI1: send QPI enable command
269        psram_enable_qio_mode_spi1();
270
271        // Do PSRAM timing tuning, we use SPI1 to do the tuning, and set the SPI0 PSRAM
272        // timing related registers accordingly
273        mspi_timing_psram_tuning();
274
275        // Configure SPI0 PSRAM related SPI Phases
276        config_psram_spi_phases();
277        // Back to the high speed mode. Flash/PSRAM clocks are set to the clock that
278        // user selected. SPI0/1 registers are all set correctly
279        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        /// Enable Quad I/O pin functions
316        ///
317        /// Sets the HD & WP pin functions for Quad I/O modes, based on the
318        /// efuse SPI pin configuration.
319        ///
320        /// [`wp_gpio_num`]: u8 Number of the WP pin to reconfigure for quad I/O
321        /// [`spiconfig`]: u32 Pin configuration, as returned from ets_efuse_get_spiconfig().
322        /// - If this parameter is 0, default SPI pins are used and wp_gpio_num parameter is
323        ///   ignored.
324        /// - If this parameter is 1, default HSPI pins are used and wp_gpio_num parameter is
325        ///   ignored.
326        /// - For other values, this parameter encodes the HD pin number and also the CLK pin
327        ///   number. CLK pin selection is used to determine if HSPI or SPI peripheral will be used
328        ///   (use HSPI if CLK pin is the HSPI clock pin, otherwise use SPI).
329        //   Both HD & WP pins are configured via GPIO matrix to map to the selected peripheral.
330        fn esp_rom_spiflash_select_qio_pins(wp_gpio_num: u8, spiconfig: u32);
331    }
332
333    // Configure PSRAM SPI0 phase related registers here according to the PSRAM chip
334    // requirement
335    #[ram]
336    fn config_psram_spi_phases() {
337        unsafe {
338            let spi = SPI0::regs();
339            // Config CMD phase
340            spi.cache_sctrl()
341                .modify(|_, w| w.usr_sram_dio().clear_bit()); // disable dio mode for cache command
342
343            spi.cache_sctrl().modify(|_, w| w.usr_sram_qio().set_bit()); // enable qio mode for cache command
344
345            spi.cache_sctrl()
346                .modify(|_, w| w.cache_sram_usr_rcmd().set_bit()); // enable cache read command
347
348            spi.cache_sctrl()
349                .modify(|_, w| w.cache_sram_usr_wcmd().set_bit()); // enable cache write command
350
351            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            // Config ADDR phase
368            spi.cache_sctrl()
369                .modify(|_, w| w.sram_addr_bitlen().bits(23));
370
371            // Dummy
372            // We set the PSRAM chip required dummy here. If timing tuning is
373            // needed, the dummy length will be updated in
374            // `mspi_timing_enter_high_speed_mode()`
375            spi.cache_sctrl()
376                .modify(|_, w| w.usr_rd_sram_dummy().set_bit()); // enable cache read dummy
377
378            spi.cache_sctrl().modify(|_, w| {
379                w.sram_rdummy_cyclelen()
380                    .bits((PSRAM_FAST_READ_QUAD_DUMMY - 1) as u8)
381            });
382
383            // ENABLE SPI0 CS1 TO PSRAM(CS0--FLASH; CS1--SRAM)
384            spi.misc().modify(|_, w| w.cs1_dis().clear_bit());
385        }
386    }
387
388    #[ram]
389    fn mspi_timing_psram_tuning() {
390        // currently we only support !SPI_TIMING_PSRAM_NEEDS_TUNING
391        // see https://github.com/espressif/esp-idf/blob/4e24516ee2731eb55687182d4e061b5b93a9e33f/components/esp_hw_support/mspi_timing_tuning.c#L391-L415
392    }
393
394    /// Set SPI0 FLASH and PSRAM module clock, din_num, din_mode and extra
395    /// dummy, according to the configuration got from timing tuning
396    /// function (`calculate_best_flash_tuning_config`). iF control_spi1 ==
397    /// 1, will also update SPI1 timing registers. Should only be set to 1 when
398    /// do tuning.
399    ///
400    /// This function should always be called after `mspi_timing_flash_tuning`
401    /// or `calculate_best_flash_tuning_config`
402    #[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        // Set SPI01 core clock
414        // SPI0 and SPI1 share the register for core clock. So we only set SPI0 here.
415        // Set FLASH module clock
416        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        // Set PSRAM module clock
423        spi0_timing_config_set_psram_clock(psram_div);
424
425        // #if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING
426        //     set_timing_tuning_regs_as_required(true);
427        // #endif
428    }
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    // send reset command to psram, in spi mode
508    #[ram]
509    fn psram_reset_mode_spi1() {
510        psram_exec_cmd(
511            CommandMode::PsramCmdSpi,
512            PSRAM_RESET_EN,
513            8, // command and command bit len
514            0,
515            0, // address and address bit len
516            0, // dummy bit len
517            core::ptr::null(),
518            0, // tx data and tx bit len
519            core::ptr::null_mut(),
520            0,            // rx data and rx bit len
521            CS_PSRAM_SEL, // cs bit mask
522            false,
523        ); // whether is program/erase operation
524
525        psram_exec_cmd(
526            CommandMode::PsramCmdSpi,
527            PSRAM_RESET,
528            8, // command and command bit len
529            0,
530            0, // address and address bit len
531            0, // dummy bit len
532            core::ptr::null(),
533            0, // tx data and tx bit len
534            core::ptr::null_mut(),
535            0,            // rx data and rx bit len
536            CS_PSRAM_SEL, // cs bit mask
537            false,
538        ); // whether is program/erase operation
539    }
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            ///  Start a spi user command sequence
566            ///  [`spi_num`] spi port
567            ///  [`rx_buf`] buffer pointer to receive data
568            ///  [`rx_len`] receive data length in byte
569            ///  [`cs_en_mask`] decide which cs to use, 0 for cs0, 1 for cs1
570            ///  [`is_write_erase`] to indicate whether this is a write or erase
571            /// operation, since the CPU would check permission
572            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,             // Command value
630            cmd_bit_len: u16,     // Command byte length
631            addr: *const u32,     // Point to address value
632            addr_bit_len: u32,    // Address byte length
633            tx_data: *const u32,  // Point to send data buffer
634            tx_data_bit_len: u32, // Send data byte length.
635            rx_data: *mut u32,    // Point to recevie data buffer
636            rx_data_bit_len: u32, // Recevie Data byte length.
637            dummy_bit_len: u32,
638        }
639
640        unsafe extern "C" {
641            /// Config the spi user command
642            /// [`spi_num`] spi port
643            /// [`pcmd`] pointer to accept the spi command struct
644            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    /// Exit QPI mode
687    #[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, // command and command bit len
696            0,
697            0, // address and address bit len
698            0, // dummy bit len
699            core::ptr::null(),
700            0, // tx data and tx bit len
701            core::ptr::null_mut(),
702            0,            // rx data and rx bit len
703            CS_PSRAM_SEL, // cs bit mask
704            false,        // whether is program/erase operation
705        );
706    }
707
708    /// Enter QPI mode
709    #[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, // command and command bit len
718            0,
719            0, // address and address bit len
720            0, // dummy bit len
721            core::ptr::null(),
722            0, // tx data and tx bit len
723            core::ptr::null_mut(),
724            0,            // rx data and rx bit len
725            CS_PSRAM_SEL, // cs bit mask
726            false,        // whether is program/erase operation
727        );
728    }
729
730    #[ram]
731    fn psram_set_cs_timing() {
732        unsafe {
733            // SPI0/1 share the cs_hold / cs_setup, cd_hold_time / cd_setup_time registers
734            // for PSRAM, so we only need to set SPI0 related registers here
735            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        // CS1
753        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        // WP HD
771        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            // MSPI pins (except wp / hd) are all configured via IO_MUX in 1st
775            // bootloader.
776        } else {
777            // MSPI pins (except wp / hd) are all configured via GPIO matrix in 1st
778            // bootloader.
779            wp_io = unsafe { esp_rom_efuse_get_flash_wp_gpio() };
780        }
781        // This ROM function will init both WP and HD pins.
782        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        // @brief To execute a flash operation command
828        // @param spi_num spi port
829        // @param mode Flash Read Mode
830        // @param cmd data to send in command field
831        // @param cmd_bit_len bit length of command field
832        // @param addr data to send in address field
833        // @param addr_bit_len bit length of address field
834        // @param dummy_bits bit length of dummy field
835        // @param mosi_data data buffer to be sent in mosi field
836        // @param mosi_bit_len bit length of data buffer to be sent in mosi field
837        // @param miso_data data buffer to accept data in miso field
838        // @param miso_bit_len bit length of data buffer to accept data in miso field
839        // @param cs_mark decide which cs pin to use. 0: cs0, 1: cs1
840        // @param is_write_erase_operation to indicate whether this a write or erase
841        // flash operation
842        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        // @brief Set data swap mode in DTR(DDR) mode
859        // @param spi_num spi port
860        // @param wr_swap to decide whether to swap fifo data in dtr write operation
861        // @param rd_swap to decide whether to swap fifo data in dtr read operation
862        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    /// Represents the operational mode registers of an OPI PSRAM.
868    #[derive(Default)]
869    #[repr(C)]
870    struct OpiPsramModeReg {
871        // Mode register 0 (MR0).
872        pub mr0: u8,
873        // Mode register 1 (MR1).
874        pub mr1: u8,
875        // Mode register 2 (MR2).
876        pub mr2: u8,
877        // Mode register 3 (MR3).
878        pub mr3: u8,
879        // Mode register 4 (MR4).
880        pub mr4: u8,
881        // Mode register 8 (MR8).
882        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        // for now we don't support ECC
1084        // "s_configure_psram_ecc();"
1085
1086        // enter MSPI slow mode to init PSRAM device registers
1087        spi_timing_enter_mspi_low_speed_mode(true);
1088
1089        unsafe {
1090            // set to variable dummy mode
1091            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        // Set PSRAM read latency and drive strength
1098        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        // Print PSRAM info
1107        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        // Do PSRAM timing tuning, we use SPI1 to do the tuning, and set the
1143        // SPI0 PSRAM timing related registers accordingly
1144        // this is unsupported for now
1145        // spi_timing_psram_tuning();
1146
1147        // Back to the high speed mode. Flash/PSRAM clocks are set to the clock
1148        // that user selected. SPI0/1 registers are all set correctly
1149        spi_timing_enter_mspi_high_speed_mode(true, config);
1150
1151        // Tuning may change SPI1 regs, whereas legacy spi_flash APIs rely on
1152        // these regs. This function is to restore SPI1 init state.
1153        spi_flash_set_rom_required_regs();
1154
1155        // Flash chip requires MSPI specifically, call this function to set them
1156        // this is unsupported for now
1157        // spi_flash_set_vendor_required_regs();
1158
1159        config_psram_spi_phases();
1160
1161        info!("PSRAM initialized successfully in Octal SPI mode");
1162        true
1163    }
1164
1165    // Configure PSRAM SPI0 phase related registers here according to the PSRAM chip
1166    // requirement
1167    fn config_psram_spi_phases() {
1168        unsafe {
1169            let spi = SPI0::regs();
1170            // Config Write CMD phase for SPI0 to access PSRAM
1171            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            // Config Read CMD phase for SPI0 to access PSRAM
1182            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            // Config ADDR phase
1193            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            // Config RD/WR Dummy phase
1199            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        // Disable the variable dummy mode when doing timing tuning
1227        SPI1::regs()
1228            .ddr()
1229            .modify(|_, w| w.spi_fmem_var_dummy().clear_bit());
1230        // STR /DTR mode setting is done every time when
1231        // `esp_rom_opiflash_exec_cmd` is called
1232        //
1233        // Add any registers that are not set in ROM SPI flash functions here in
1234        // the future
1235    }
1236
1237    #[ram]
1238    fn mspi_pin_init() {
1239        unsafe { esp_rom_opiflash_pin_config() };
1240        spi_timing_set_pin_drive_strength();
1241        // Set F4R4 board pin drive strength. TODO: IDF-3663
1242    }
1243
1244    #[ram]
1245    fn spi_timing_set_pin_drive_strength() {
1246        // For now, set them all to 3. Need to check after QVL test results are out.
1247        // TODO: IDF-3663 Set default clk
1248        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            // Set default mspi d0 ~ d7, dqs pin drive strength
1260            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        // Here we are going to slow the SPI1 frequency to 20Mhz, so we need to
1269        // set SPI1 din_num and din_mode regs.
1270        //
1271        // Because SPI0 and SPI1 share the din_num and din_mode regs, so if we
1272        // clear SPI1 din_num and din_mode to 0, if the SPI0 flash
1273        // module clock is still in high freq, it may not work correctly.
1274        //
1275        // Therefore, here we need to slow both the SPI0 and SPI1 and related
1276        // timing tuning regs to 20Mhz configuration.
1277        // Switch SPI1 and SPI0 clock as 20MHz, set its SPIMEM core clock as 80M and set
1278        // clock division as 4
1279        spi0_timing_config_set_core_clock(SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m); // SPI0 and SPI1 share the register for core clock. So we only set SPI0 here.
1280        spi0_timing_config_set_flash_clock(4);
1281        if control_spi1 {
1282            // After tuning, won't touch SPI1 again
1283            spi1_timing_config_set_flash_clock(4);
1284        }
1285
1286        // Set PSRAM module clock
1287        spi0_timing_config_set_psram_clock(4);
1288
1289        // for now we don't support tuning the timing
1290        // "clear_timing_tuning_regs(control_spi1);"
1291    }
1292
1293    // Set SPI0 FLASH and PSRAM module clock, din_num, din_mode and extra dummy,
1294    // according to the configuration got from timing tuning function
1295    // (`calculate_best_flash_tuning_config`). iF control_spi1 == 1, will also
1296    // update SPI1 timing registers. Should only be set to 1 when do tuning.
1297    //
1298    // This function should always be called after `spi_timing_flash_tuning` or
1299    // `calculate_best_flash_tuning_config`
1300    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        // Set SPI01 core clock
1305        spi0_timing_config_set_core_clock(config.core_clock.unwrap_or_default()); // SPI0 and SPI1 share the register for core clock. So we only set SPI0 here.
1306        // Set FLASH module clock
1307        spi0_timing_config_set_flash_clock(flash_div);
1308        if control_spi1 {
1309            spi1_timing_config_set_flash_clock(flash_div);
1310        }
1311        // Set PSRAM module clock
1312        spi0_timing_config_set_psram_clock(psram_div);
1313
1314        // for now we don't support tuning the timing
1315        // "set_timing_tuning_regs_as_required(true);"
1316    }
1317
1318    fn set_psram_cs_timing() {
1319        unsafe {
1320            let spi = SPI0::regs();
1321            // SPI0/1 share the cs_hold / cs_setup, cd_hold_time / cd_setup_time,
1322            // cs_hold_delay registers for PSRAM, so we only need to set SPI0 related
1323            // registers here
1324            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            // CONFIG_SPIRAM_ECC_ENABLE unsupported for now
1335            // CS1 high time
1336            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        // Set cs1 pin function
1343        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        // Set mspi cs1 drive strength
1350        unsafe {
1351            IO_MUX::regs()
1352                .gpio(OCT_PSRAM_CS1_IO as usize)
1353                .modify(|_, w| w.fun_drv().bits(3));
1354        }
1355
1356        // Set psram clock pin drive strength
1357        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            // Read MR0~1 register
1373            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            // Read MR2~3 register
1389            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            // Read MR4 register
1406            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            // Read MR8 register
1422            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    // Initialise mode registers of the PSRAM
1441    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; // 0x0 is the MR0 register
1445        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        // read
1451        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        // modify
1470        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        // write
1475        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        // CONFIG_SPIRAM_ECC_ENABLE not yet supported
1494    }
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}