esp_hal/psram/
esp32s3.rs

1use super::PsramSize;
2use crate::peripherals::{EXTMEM, IO_MUX, SPI0, SPI1};
3
4const EXTMEM_ORIGIN: u32 = 0x3C000000;
5
6/// Frequency of flash memory
7#[derive(Copy, Clone, Debug, Default, PartialEq)]
8#[cfg_attr(feature = "defmt", derive(defmt::Format))]
9pub enum FlashFreq {
10    /// Flash frequency 20 MHz
11    FlashFreq20m  = 20,
12    /// Flash frequency 40 MHz
13    FlashFreq40m  = 40,
14    /// Flash frequency 80 MHz
15    #[default]
16    FlashFreq80m  = 80,
17    /// Flash frequency 120 MHz
18    /// This is not recommended, see <https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-guides/flash_psram_config.html>
19    FlashFreq120m = 120,
20}
21
22/// Frequency of PSRAM memory
23#[derive(Copy, Clone, Debug, Default, PartialEq)]
24#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25#[allow(missing_docs)]
26pub enum SpiRamFreq {
27    /// PSRAM frequency 40 MHz
28    #[default]
29    Freq40m  = 40,
30    /// PSRAM frequency 80 MHz
31    Freq80m  = 80,
32    /// PSRAM 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    Freq120m = 120,
35}
36
37/// Core timing configuration
38#[derive(Copy, Clone, Debug, Default, PartialEq)]
39#[cfg_attr(feature = "defmt", derive(defmt::Format))]
40pub enum SpiTimingConfigCoreClock {
41    /// Core clock 80 MHz
42    #[default]
43    SpiTimingConfigCoreClock80m  = 80,
44    /// Core clock 120 MHz
45    SpiTimingConfigCoreClock120m = 120,
46    /// Core clock 160 MHz
47    SpiTimingConfigCoreClock160m = 160,
48    /// Core clock 240 MHz
49    SpiTimingConfigCoreClock240m = 240,
50}
51
52/// PSRAM configuration
53#[derive(Copy, Clone, Debug, Default, PartialEq)]
54#[cfg_attr(feature = "defmt", derive(defmt::Format))]
55pub struct PsramConfig {
56    /// PSRAM size
57    pub size: PsramSize,
58    /// Core timing configuration
59    pub core_clock: Option<SpiTimingConfigCoreClock>,
60    /// Frequency of flash memory
61    pub flash_frequency: FlashFreq,
62    /// Frequency of PSRAM memory
63    pub ram_frequency: SpiRamFreq,
64}
65
66/// Initialize PSRAM to be used for data.
67///
68/// Returns the start of the mapped memory and the size
69#[procmacros::ram]
70pub(crate) fn init_psram(config: PsramConfig) {
71    let mut config = config;
72
73    if config.core_clock.is_none() {
74        cfg_if::cfg_if! {
75            if #[cfg(psram_mode_octal)] {
76                config.core_clock = Some(if config.ram_frequency == SpiRamFreq::Freq80m {
77                    SpiTimingConfigCoreClock::SpiTimingConfigCoreClock160m
78                } else if config.ram_frequency == SpiRamFreq::Freq120m {
79                    SpiTimingConfigCoreClock::SpiTimingConfigCoreClock240m
80                } else {
81                    SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m
82                });
83            } else {
84                config.core_clock = Some( if config.ram_frequency == SpiRamFreq::Freq120m {
85                    SpiTimingConfigCoreClock::SpiTimingConfigCoreClock120m
86                } else {
87                    SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m
88                });
89            }
90        }
91    }
92
93    utils::psram_init(&mut config);
94
95    const MMU_ACCESS_SPIRAM: u32 = 1 << 15;
96    const START_PAGE: u32 = 0;
97
98    unsafe extern "C" {
99        fn Cache_Suspend_DCache();
100
101        fn Cache_Resume_DCache(param: u32);
102
103        /// Set DCache mmu mapping.
104        ///
105        /// [`ext_ram`]: u32 DPORT_MMU_ACCESS_FLASH for flash, DPORT_MMU_ACCESS_SPIRAM for spiram, DPORT_MMU_INVALID for invalid.
106        /// [`vaddr`]: u32 Virtual address in CPU address space.
107        /// [`paddr`]: u32 Physical address in external memory. Should be aligned by psize.
108        /// [`psize`]: u32 Page size of DCache, in kilobytes. Should be 64 here.
109        /// [`num`]: u32 Pages to be set.
110        /// [`fixes`]: u32 0 for physical pages grow with virtual pages, other for virtual pages map to same physical page.
111        fn cache_dbus_mmu_set(
112            ext_ram: u32,
113            vaddr: u32,
114            paddr: u32,
115            psize: u32,
116            num: u32,
117            fixed: u32,
118        ) -> i32;
119    }
120
121    let start = unsafe {
122        const MMU_PAGE_SIZE: u32 = 0x10000;
123        const ICACHE_MMU_SIZE: usize = 0x800;
124        const FLASH_MMU_TABLE_SIZE: usize = ICACHE_MMU_SIZE / core::mem::size_of::<u32>();
125        const MMU_INVALID: u32 = 1 << 14;
126        const DR_REG_MMU_TABLE: u32 = 0x600C5000;
127
128        // calculate the PSRAM start address to map
129        // the linker scripts can produce a gap between mapped IROM and DROM segments
130        // bigger than a flash page - i.e. we will see an unmapped memory slot
131        // start from the end and find the last mapped flash page
132        //
133        // More general information about the MMU can be found here:
134        // https://docs.espressif.com/projects/esp-idf/en/stable/esp32s3/api-reference/system/mm.html#introduction
135        let mmu_table_ptr = DR_REG_MMU_TABLE as *const u32;
136        let mut mapped_pages = 0;
137
138        // the bootloader is using the last page to access flash internally
139        // (e.g. to read the app descriptor) so we just skip that
140        for i in (0..(FLASH_MMU_TABLE_SIZE - 1)).rev() {
141            if mmu_table_ptr.add(i).read_volatile() != MMU_INVALID {
142                mapped_pages = (i + 1) as u32;
143                break;
144            }
145        }
146        let start = EXTMEM_ORIGIN + (MMU_PAGE_SIZE * mapped_pages);
147        debug!("PSRAM start address = {:x}", start);
148
149        // If we need use SPIRAM, we should use data cache.
150        Cache_Suspend_DCache();
151
152        let cache_dbus_mmu_set_res = cache_dbus_mmu_set(
153            MMU_ACCESS_SPIRAM,
154            start,
155            START_PAGE << 16,
156            64,
157            config.size.get() as u32 / 1024 / 64, // number of pages to map
158            0,
159        );
160
161        EXTMEM::regs().dcache_ctrl1().modify(|_, w| {
162            w.dcache_shut_core0_bus()
163                .clear_bit()
164                .dcache_shut_core1_bus()
165                .clear_bit()
166        });
167
168        Cache_Resume_DCache(0);
169
170        // panic AFTER resuming the cache
171        if cache_dbus_mmu_set_res != 0 {
172            panic!("cache_dbus_mmu_set failed");
173        }
174
175        start
176    };
177
178    unsafe {
179        super::MAPPED_PSRAM.memory_range = start as usize..start as usize + config.size.get();
180    }
181}
182
183#[cfg(psram_mode_quad)]
184pub(crate) mod utils {
185    use procmacros::ram;
186
187    use super::*;
188
189    const PSRAM_RESET_EN: u16 = 0x66;
190    const PSRAM_RESET: u16 = 0x99;
191    const PSRAM_DEVICE_ID: u16 = 0x9F;
192    const CS_PSRAM_SEL: u8 = 1 << 1;
193
194    #[ram]
195    pub(crate) fn psram_init(config: &mut super::PsramConfig) {
196        psram_gpio_config();
197        psram_set_cs_timing();
198
199        if config.size.is_auto() {
200            psram_disable_qio_mode_spi1();
201
202            // read chip id
203            let mut dev_id = 0u32;
204            psram_exec_cmd(
205                CommandMode::PsramCmdSpi,
206                PSRAM_DEVICE_ID,
207                8, // command and command bit len
208                0,
209                24, // address and address bit len
210                0,  // dummy bit len
211                core::ptr::null(),
212                0, // tx data and tx bit len
213                &mut dev_id as *mut _ as *mut u8,
214                24,           // rx data and rx bit len
215                CS_PSRAM_SEL, // cs bit mask
216                false,
217            );
218            info!("chip id = {:x}", dev_id);
219
220            let size = if dev_id != 0xffffff {
221                const PSRAM_ID_EID_S: u32 = 16;
222                const PSRAM_ID_EID_M: u32 = 0xff;
223                const PSRAM_EID_SIZE_M: u32 = 0x07;
224                const PSRAM_EID_SIZE_S: u32 = 5;
225
226                let size_id = ((((dev_id) >> PSRAM_ID_EID_S) & PSRAM_ID_EID_M) >> PSRAM_EID_SIZE_S)
227                    & PSRAM_EID_SIZE_M;
228
229                const PSRAM_EID_SIZE_32MBITS: u32 = 1;
230                const PSRAM_EID_SIZE_64MBITS: u32 = 2;
231
232                match size_id {
233                    PSRAM_EID_SIZE_64MBITS => 64 / 8 * 1024 * 1024,
234                    PSRAM_EID_SIZE_32MBITS => 32 / 8 * 1024 * 1024,
235                    _ => 16 / 8 * 1024 * 1024,
236                }
237            } else {
238                0
239            };
240
241            info!("size is {}", size);
242
243            config.size = PsramSize::Size(size);
244        }
245
246        // SPI1: send psram reset command
247        psram_reset_mode_spi1();
248        // SPI1: send QPI enable command
249        psram_enable_qio_mode_spi1();
250
251        // Do PSRAM timing tuning, we use SPI1 to do the tuning, and set the SPI0 PSRAM
252        // timing related registers accordingly
253        mspi_timing_psram_tuning();
254
255        // Configure SPI0 PSRAM related SPI Phases
256        config_psram_spi_phases();
257        // Back to the high speed mode. Flash/PSRAM clocks are set to the clock that
258        // user selected. SPI0/1 registers are all set correctly
259        mspi_timing_enter_high_speed_mode(true, config);
260    }
261
262    const PSRAM_CS_IO: u8 = 26;
263    const SPI_CS1_GPIO_NUM: u8 = 26;
264    const FUNC_SPICS1_SPICS1: u8 = 0;
265    const PIN_FUNC_GPIO: u8 = 2;
266    const PSRAM_SPIWP_SD3_IO: u8 = 10;
267    const ESP_ROM_EFUSE_FLASH_DEFAULT_SPI: u32 = 0;
268    const SPICS1_OUT_IDX: u8 = 6;
269
270    const PSRAM_QUAD_WRITE: u32 = 0x38;
271    const PSRAM_FAST_READ_QUAD: u32 = 0xEB;
272    const PSRAM_FAST_READ_QUAD_DUMMY: u32 = 6;
273    const SPI_MEM_CLKCNT_N_S: u32 = 16;
274    const SPI_MEM_SCLKCNT_N_S: u32 = 16;
275    const SPI_MEM_CLKCNT_H_S: u32 = 8;
276    const SPI_MEM_SCLKCNT_H_S: u32 = 8;
277    const SPI_MEM_CLKCNT_L_S: u32 = 0;
278    const SPI_MEM_SCLKCNT_L_S: u32 = 0;
279
280    unsafe extern "C" {
281        fn esp_rom_efuse_get_flash_gpio_info() -> u32;
282
283        fn esp_rom_efuse_get_flash_wp_gpio() -> u8;
284
285        fn esp_rom_gpio_connect_out_signal(
286            gpio_num: u8,
287            signal_idx: u8,
288            out_inv: bool,
289            oen_inv: bool,
290        );
291
292        /// Enable Quad I/O pin functions
293        ///
294        /// Sets the HD & WP pin functions for Quad I/O modes, based on the
295        /// efuse SPI pin configuration.
296        ///
297        /// [`wp_gpio_num`]: u8 Number of the WP pin to reconfigure for quad I/O
298        /// [`spiconfig`]: u32 Pin configuration, as returned from ets_efuse_get_spiconfig().
299        /// - If this parameter is 0, default SPI pins are used and wp_gpio_num parameter is
300        ///   ignored.
301        /// - If this parameter is 1, default HSPI pins are used and wp_gpio_num parameter is
302        ///   ignored.
303        /// - For other values, this parameter encodes the HD pin number and also the CLK pin
304        ///   number. CLK pin selection is used to determine if HSPI or SPI peripheral will be used
305        ///   (use HSPI if CLK pin is the HSPI clock pin, otherwise use SPI).
306        //   Both HD & WP pins are configured via GPIO matrix to map to the selected peripheral.
307        fn esp_rom_spiflash_select_qio_pins(wp_gpio_num: u8, spiconfig: u32);
308    }
309
310    // Configure PSRAM SPI0 phase related registers here according to the PSRAM chip
311    // requirement
312    #[ram]
313    fn config_psram_spi_phases() {
314        unsafe {
315            let spi = SPI0::regs();
316            // Config CMD phase
317            spi.cache_sctrl()
318                .modify(|_, w| w.usr_sram_dio().clear_bit()); // disable dio mode for cache command
319
320            spi.cache_sctrl().modify(|_, w| w.usr_sram_qio().set_bit()); // enable qio mode for cache command
321
322            spi.cache_sctrl()
323                .modify(|_, w| w.cache_sram_usr_rcmd().set_bit()); // enable cache read command
324
325            spi.cache_sctrl()
326                .modify(|_, w| w.cache_sram_usr_wcmd().set_bit()); // enable cache write command
327
328            spi.sram_dwr_cmd()
329                .modify(|_, w| w.cache_sram_usr_wr_cmd_bitlen().bits(7));
330
331            spi.sram_dwr_cmd().modify(|_, w| {
332                w.cache_sram_usr_wr_cmd_value()
333                    .bits(PSRAM_QUAD_WRITE as u16)
334            });
335
336            spi.sram_drd_cmd()
337                .modify(|_, w| w.cache_sram_usr_rd_cmd_bitlen().bits(7));
338
339            spi.sram_drd_cmd().modify(|_, w| {
340                w.cache_sram_usr_rd_cmd_value()
341                    .bits(PSRAM_FAST_READ_QUAD as u16)
342            });
343
344            // Config ADDR phase
345            spi.cache_sctrl()
346                .modify(|_, w| w.sram_addr_bitlen().bits(23));
347
348            // Dummy
349            // We set the PSRAM chip required dummy here. If timing tuning is
350            // needed, the dummy length will be updated in
351            // `mspi_timing_enter_high_speed_mode()`
352            spi.cache_sctrl()
353                .modify(|_, w| w.usr_rd_sram_dummy().set_bit()); // enable cache read dummy
354
355            spi.cache_sctrl().modify(|_, w| {
356                w.sram_rdummy_cyclelen()
357                    .bits((PSRAM_FAST_READ_QUAD_DUMMY - 1) as u8)
358            });
359
360            // ENABLE SPI0 CS1 TO PSRAM(CS0--FLASH; CS1--SRAM)
361            spi.misc().modify(|_, w| w.cs1_dis().clear_bit());
362        }
363    }
364
365    #[ram]
366    fn mspi_timing_psram_tuning() {
367        // currently we only support !SPI_TIMING_PSRAM_NEEDS_TUNING
368        // see https://github.com/espressif/esp-idf/blob/4e24516ee2731eb55687182d4e061b5b93a9e33f/components/esp_hw_support/mspi_timing_tuning.c#L391-L415
369    }
370
371    /// Set SPI0 FLASH and PSRAM module clock, din_num, din_mode and extra
372    /// dummy, according to the configuration got from timing tuning
373    /// function (`calculate_best_flash_tuning_config`). iF control_spi1 ==
374    /// 1, will also update SPI1 timing registers. Should only be set to 1 when
375    /// do tuning.
376    ///
377    /// This function should always be called after `mspi_timing_flash_tuning`
378    /// or `calculate_best_flash_tuning_config`
379    #[ram]
380    fn mspi_timing_enter_high_speed_mode(control_spi1: bool, config: &PsramConfig) {
381        let core_clock: SpiTimingConfigCoreClock = mspi_core_clock(config);
382        let flash_div: u32 = flash_clock_divider(config);
383        let psram_div: u32 = psram_clock_divider(config);
384
385        info!(
386            "PSRAM core_clock {:?}, flash_div = {}, psram_div = {}",
387            core_clock, flash_div, psram_div
388        );
389
390        // Set SPI01 core clock
391        // SPI0 and SPI1 share the register for core clock. So we only set SPI0 here.
392        // Set FLASH module clock
393        spi0_timing_config_set_core_clock(core_clock);
394
395        spi0_timing_config_set_flash_clock(flash_div);
396        if control_spi1 {
397            spi1_timing_config_set_flash_clock(flash_div);
398        }
399        // Set PSRAM module clock
400        spi0_timing_config_set_psram_clock(psram_div);
401
402        // #if SPI_TIMING_FLASH_NEEDS_TUNING || SPI_TIMING_PSRAM_NEEDS_TUNING
403        //     set_timing_tuning_regs_as_required(true);
404        // #endif
405    }
406
407    #[ram]
408    fn spi0_timing_config_set_core_clock(core_clock: SpiTimingConfigCoreClock) {
409        unsafe {
410            SPI0::regs().core_clk_sel().modify(|_, w| {
411                w.core_clk_sel().bits(match core_clock {
412                    SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m => 0,
413                    SpiTimingConfigCoreClock::SpiTimingConfigCoreClock120m => 1,
414                    SpiTimingConfigCoreClock::SpiTimingConfigCoreClock160m => 2,
415                    SpiTimingConfigCoreClock::SpiTimingConfigCoreClock240m => 3,
416                })
417            });
418        }
419    }
420
421    #[ram]
422    fn spi0_timing_config_set_flash_clock(freqdiv: u32) {
423        if freqdiv == 1 {
424            SPI0::regs()
425                .clock()
426                .modify(|_, w| w.clk_equ_sysclk().set_bit());
427        } else {
428            let freqbits: u32 = ((freqdiv - 1) << SPI_MEM_CLKCNT_N_S)
429                | ((freqdiv / 2 - 1) << SPI_MEM_CLKCNT_H_S)
430                | ((freqdiv - 1) << SPI_MEM_CLKCNT_L_S);
431            unsafe {
432                SPI0::regs().clock().modify(|_, w| w.bits(freqbits));
433            }
434        }
435    }
436
437    #[ram]
438    fn spi1_timing_config_set_flash_clock(freqdiv: u32) {
439        if freqdiv == 1 {
440            SPI1::regs()
441                .clock()
442                .modify(|_, w| w.clk_equ_sysclk().set_bit());
443        } else {
444            let freqbits: u32 = ((freqdiv - 1) << SPI_MEM_CLKCNT_N_S)
445                | ((freqdiv / 2 - 1) << SPI_MEM_CLKCNT_H_S)
446                | ((freqdiv - 1) << SPI_MEM_CLKCNT_L_S);
447            unsafe {
448                SPI1::regs().clock().modify(|_, w| w.bits(freqbits));
449            }
450        }
451    }
452
453    #[ram]
454    fn spi0_timing_config_set_psram_clock(freqdiv: u32) {
455        if freqdiv == 1 {
456            SPI0::regs()
457                .sram_clk()
458                .modify(|_, w| w.sclk_equ_sysclk().set_bit());
459        } else {
460            let freqbits: u32 = ((freqdiv - 1) << SPI_MEM_SCLKCNT_N_S)
461                | ((freqdiv / 2 - 1) << SPI_MEM_SCLKCNT_H_S)
462                | ((freqdiv - 1) << SPI_MEM_SCLKCNT_L_S);
463            unsafe {
464                SPI0::regs().sram_clk().modify(|_, w| w.bits(freqbits));
465            }
466        }
467    }
468
469    #[ram]
470    fn mspi_core_clock(config: &PsramConfig) -> SpiTimingConfigCoreClock {
471        config.core_clock.unwrap_or_default()
472    }
473
474    #[ram]
475    fn flash_clock_divider(config: &PsramConfig) -> u32 {
476        config.core_clock.unwrap_or_default() as u32 / config.flash_frequency as u32
477    }
478
479    #[ram]
480    fn psram_clock_divider(config: &PsramConfig) -> u32 {
481        config.core_clock.unwrap_or_default() as u32 / config.ram_frequency as u32
482    }
483
484    // send reset command to psram, in spi mode
485    #[ram]
486    fn psram_reset_mode_spi1() {
487        psram_exec_cmd(
488            CommandMode::PsramCmdSpi,
489            PSRAM_RESET_EN,
490            8, // command and command bit len
491            0,
492            0, // address and address bit len
493            0, // dummy bit len
494            core::ptr::null(),
495            0, // tx data and tx bit len
496            core::ptr::null_mut(),
497            0,            // rx data and rx bit len
498            CS_PSRAM_SEL, // cs bit mask
499            false,
500        ); // whether is program/erase operation
501
502        psram_exec_cmd(
503            CommandMode::PsramCmdSpi,
504            PSRAM_RESET,
505            8, // command and command bit len
506            0,
507            0, // address and address bit len
508            0, // dummy bit len
509            core::ptr::null(),
510            0, // tx data and tx bit len
511            core::ptr::null_mut(),
512            0,            // rx data and rx bit len
513            CS_PSRAM_SEL, // cs bit mask
514            false,
515        ); // whether is program/erase operation
516    }
517
518    #[derive(PartialEq)]
519    #[allow(unused)]
520    enum CommandMode {
521        PsramCmdQpi = 0,
522        PsramCmdSpi = 1,
523    }
524
525    #[expect(clippy::too_many_arguments)]
526    #[ram]
527    fn psram_exec_cmd(
528        mode: CommandMode,
529        cmd: u16,
530        cmd_bit_len: u16,
531        addr: u32,
532        addr_bit_len: u32,
533        dummy_bits: u32,
534        mosi_data: *const u8,
535        mosi_bit_len: u32,
536        miso_data: *mut u8,
537        miso_bit_len: u32,
538        cs_mask: u8,
539        is_write_erase_operation: bool,
540    ) {
541        unsafe extern "C" {
542            ///  Start a spi user command sequence
543            ///  [`spi_num`] spi port
544            ///  [`rx_buf`] buffer pointer to receive data
545            ///  [`rx_len`] receive data length in byte
546            ///  [`cs_en_mask`] decide which cs to use, 0 for cs0, 1 for cs1
547            ///  [`is_write_erase`] to indicate whether this is a write or erase
548            /// operation, since the CPU would check permission
549            fn esp_rom_spi_cmd_start(
550                spi_num: u32,
551                rx_buf: *const u8,
552                rx_len: u16,
553                cs_en_mask: u8,
554                is_write_erase: bool,
555            );
556        }
557
558        unsafe {
559            let spi1 = SPI1::regs();
560            let backup_usr = spi1.user().read().bits();
561            let backup_usr1 = spi1.user1().read().bits();
562            let backup_usr2 = spi1.user2().read().bits();
563            let backup_ctrl = spi1.ctrl().read().bits();
564            psram_set_op_mode(mode);
565            _psram_exec_cmd(
566                cmd,
567                cmd_bit_len,
568                addr,
569                addr_bit_len,
570                dummy_bits,
571                mosi_data,
572                mosi_bit_len,
573                miso_data,
574                miso_bit_len,
575            );
576            esp_rom_spi_cmd_start(
577                1,
578                miso_data,
579                (miso_bit_len / 8) as u16,
580                cs_mask,
581                is_write_erase_operation,
582            );
583
584            spi1.user().write(|w| w.bits(backup_usr));
585            spi1.user1().write(|w| w.bits(backup_usr1));
586            spi1.user2().write(|w| w.bits(backup_usr2));
587            spi1.ctrl().write(|w| w.bits(backup_ctrl));
588        }
589    }
590
591    #[expect(clippy::too_many_arguments)]
592    #[ram]
593    fn _psram_exec_cmd(
594        cmd: u16,
595        cmd_bit_len: u16,
596        addr: u32,
597        addr_bit_len: u32,
598        dummy_bits: u32,
599        mosi_data: *const u8,
600        mosi_bit_len: u32,
601        miso_data: *mut u8,
602        miso_bit_len: u32,
603    ) {
604        #[repr(C)]
605        struct esp_rom_spi_cmd_t {
606            cmd: u16,             // Command value
607            cmd_bit_len: u16,     // Command byte length
608            addr: *const u32,     // Point to address value
609            addr_bit_len: u32,    // Address byte length
610            tx_data: *const u32,  // Point to send data buffer
611            tx_data_bit_len: u32, // Send data byte length.
612            rx_data: *mut u32,    // Point to recevie data buffer
613            rx_data_bit_len: u32, // Recevie Data byte length.
614            dummy_bit_len: u32,
615        }
616
617        unsafe extern "C" {
618            /// Config the spi user command
619            /// [`spi_num`] spi port
620            /// [`pcmd`] pointer to accept the spi command struct
621            fn esp_rom_spi_cmd_config(spi_num: u32, pcmd: *const esp_rom_spi_cmd_t);
622        }
623
624        let conf = esp_rom_spi_cmd_t {
625            cmd,
626            cmd_bit_len,
627            addr: &addr,
628            addr_bit_len,
629            tx_data: mosi_data as *const u32,
630            tx_data_bit_len: mosi_bit_len,
631            rx_data: miso_data as *mut u32,
632            rx_data_bit_len: miso_bit_len,
633            dummy_bit_len: dummy_bits,
634        };
635
636        unsafe {
637            esp_rom_spi_cmd_config(1, &conf);
638        }
639    }
640
641    #[ram]
642    fn psram_set_op_mode(mode: CommandMode) {
643        unsafe extern "C" {
644            fn esp_rom_spi_set_op_mode(spi: u32, mode: u32);
645        }
646
647        const ESP_ROM_SPIFLASH_QIO_MODE: u32 = 0;
648        const ESP_ROM_SPIFLASH_SLOWRD_MODE: u32 = 5;
649
650        unsafe {
651            match mode {
652                CommandMode::PsramCmdQpi => {
653                    esp_rom_spi_set_op_mode(1, ESP_ROM_SPIFLASH_QIO_MODE);
654                    SPI1::regs().ctrl().modify(|_, w| w.fcmd_quad().set_bit());
655                }
656                CommandMode::PsramCmdSpi => {
657                    esp_rom_spi_set_op_mode(1, ESP_ROM_SPIFLASH_SLOWRD_MODE);
658                }
659            }
660        }
661    }
662
663    /// Exit QPI mode
664    #[ram]
665    fn psram_disable_qio_mode_spi1() {
666        const PSRAM_EXIT_QMODE: u16 = 0xF5;
667        const CS_PSRAM_SEL: u8 = 1 << 1;
668
669        psram_exec_cmd(
670            CommandMode::PsramCmdQpi,
671            PSRAM_EXIT_QMODE,
672            8, // command and command bit len
673            0,
674            0, // address and address bit len
675            0, // dummy bit len
676            core::ptr::null(),
677            0, // tx data and tx bit len
678            core::ptr::null_mut(),
679            0,            // rx data and rx bit len
680            CS_PSRAM_SEL, // cs bit mask
681            false,        // whether is program/erase operation
682        );
683    }
684
685    /// Enter QPI mode
686    #[ram]
687    fn psram_enable_qio_mode_spi1() {
688        const PSRAM_ENTER_QMODE: u16 = 0x35;
689        const CS_PSRAM_SEL: u8 = 1 << 1;
690
691        psram_exec_cmd(
692            CommandMode::PsramCmdSpi,
693            PSRAM_ENTER_QMODE,
694            8, // command and command bit len
695            0,
696            0, // address and address bit len
697            0, // dummy bit len
698            core::ptr::null(),
699            0, // tx data and tx bit len
700            core::ptr::null_mut(),
701            0,            // rx data and rx bit len
702            CS_PSRAM_SEL, // cs bit mask
703            false,        // whether is program/erase operation
704        );
705    }
706
707    #[ram]
708    fn psram_set_cs_timing() {
709        unsafe {
710            // SPI0/1 share the cs_hold / cs_setup, cd_hold_time / cd_setup_time registers
711            // for PSRAM, so we only need to set SPI0 related registers here
712            SPI0::regs()
713                .spi_smem_ac()
714                .modify(|_, w| w.spi_smem_cs_hold_time().bits(0));
715            SPI0::regs()
716                .spi_smem_ac()
717                .modify(|_, w| w.spi_smem_cs_setup_time().bits(0));
718            SPI0::regs()
719                .spi_smem_ac()
720                .modify(|_, w| w.spi_smem_cs_hold().set_bit());
721            SPI0::regs()
722                .spi_smem_ac()
723                .modify(|_, w| w.spi_smem_cs_setup().set_bit());
724        }
725    }
726
727    #[ram]
728    fn psram_gpio_config() {
729        // CS1
730        let cs1_io: u8 = PSRAM_CS_IO;
731        if cs1_io == SPI_CS1_GPIO_NUM {
732            unsafe {
733                IO_MUX::regs()
734                    .gpio(cs1_io as usize)
735                    .modify(|_, w| w.mcu_sel().bits(FUNC_SPICS1_SPICS1));
736            }
737        } else {
738            unsafe {
739                esp_rom_gpio_connect_out_signal(cs1_io, SPICS1_OUT_IDX, false, false);
740
741                IO_MUX::regs()
742                    .gpio(cs1_io as usize)
743                    .modify(|_, w| w.mcu_sel().bits(PIN_FUNC_GPIO));
744            }
745        }
746
747        // WP HD
748        let mut wp_io: u8 = PSRAM_SPIWP_SD3_IO;
749        let spiconfig = unsafe { esp_rom_efuse_get_flash_gpio_info() };
750        if spiconfig == ESP_ROM_EFUSE_FLASH_DEFAULT_SPI {
751            // MSPI pins (except wp / hd) are all configured via IO_MUX in 1st
752            // bootloader.
753        } else {
754            // MSPI pins (except wp / hd) are all configured via GPIO matrix in 1st
755            // bootloader.
756            wp_io = unsafe { esp_rom_efuse_get_flash_wp_gpio() };
757        }
758        // This ROM function will init both WP and HD pins.
759        unsafe {
760            esp_rom_spiflash_select_qio_pins(wp_io, spiconfig);
761        }
762    }
763}
764
765#[cfg(psram_mode_octal)]
766pub(crate) mod utils {
767    use procmacros::ram;
768
769    use super::*;
770
771    const OPI_PSRAM_SYNC_READ: u16 = 0x0000;
772    const OPI_PSRAM_SYNC_WRITE: u16 = 0x8080;
773    const OPI_PSRAM_REG_READ: u16 = 0x4040;
774    const OPI_PSRAM_REG_WRITE: u16 = 0xC0C0;
775    const OCT_PSRAM_RD_CMD_BITLEN: u8 = 16;
776    const OCT_PSRAM_WR_CMD_BITLEN: u8 = 16;
777    const OCT_PSRAM_ADDR_BITLEN: u8 = 32;
778    const OCT_PSRAM_RD_DUMMY_BITLEN: u8 = 2 * (10 - 1);
779    const OCT_PSRAM_WR_DUMMY_BITLEN: u8 = 2 * (5 - 1);
780    const OCT_PSRAM_CS1_IO: u8 = SPI_CS1_GPIO_NUM;
781    const OCT_PSRAM_VENDOR_ID: u8 = 0xD;
782
783    const OCT_PSRAM_CS_SETUP_TIME: u8 = 3;
784    const OCT_PSRAM_CS_HOLD_TIME: u8 = 3;
785    const OCT_PSRAM_CS_HOLD_DELAY: u8 = 2;
786
787    const PSRAM_SIZE_2MB: usize = 2 * 1024 * 1024;
788    const PSRAM_SIZE_4MB: usize = 4 * 1024 * 1024;
789    const PSRAM_SIZE_8MB: usize = 8 * 1024 * 1024;
790    const PSRAM_SIZE_16MB: usize = 16 * 1024 * 1024;
791    const PSRAM_SIZE_32MB: usize = 32 * 1024 * 1024;
792
793    const SPI_CS1_GPIO_NUM: u8 = 26;
794    const FUNC_SPICS1_SPICS1: u8 = 0;
795
796    const SPI_MEM_CLKCNT_N_S: u32 = 16;
797    const SPI_MEM_SCLKCNT_N_S: u32 = 16;
798    const SPI_MEM_CLKCNT_H_S: u32 = 8;
799    const SPI_MEM_SCLKCNT_H_S: u32 = 8;
800    const SPI_MEM_CLKCNT_L_S: u32 = 0;
801    const SPI_MEM_SCLKCNT_L_S: u32 = 0;
802    const ESP_ROM_SPIFLASH_OPI_DTR_MODE: u8 = 7;
803
804    unsafe extern "C" {
805        // @brief To execute a flash operation command
806        // @param spi_num spi port
807        // @param mode Flash Read Mode
808        // @param cmd data to send in command field
809        // @param cmd_bit_len bit length of command field
810        // @param addr data to send in address field
811        // @param addr_bit_len bit length of address field
812        // @param dummy_bits bit length of dummy field
813        // @param mosi_data data buffer to be sent in mosi field
814        // @param mosi_bit_len bit length of data buffer to be sent in mosi field
815        // @param miso_data data buffer to accept data in miso field
816        // @param miso_bit_len bit length of data buffer to accept data in miso field
817        // @param cs_mark decide which cs pin to use. 0: cs0, 1: cs1
818        // @param is_write_erase_operation to indicate whether this a write or erase
819        // flash operation
820        fn esp_rom_opiflash_exec_cmd(
821            spi_num: u32,
822            mode: u8,
823            cmd: u32,
824            cmd_bit_len: u32,
825            addr: u32,
826            addr_bit_len: u32,
827            dummy_bits: u32,
828            mosi_data: *const u8,
829            mosi_bit_len: u32,
830            miso_data: *mut u8,
831            miso_bit_len: u32,
832            cs_mask: u32,
833            is_write_erase_operation: bool,
834        );
835
836        // @brief Set data swap mode in DTR(DDR) mode
837        // @param spi_num spi port
838        // @param wr_swap to decide whether to swap fifo data in dtr write operation
839        // @param rd_swap to decide whether to swap fifo data in dtr read operation
840        fn esp_rom_spi_set_dtr_swap_mode(spi: u32, wr_swap: bool, rd_swap: bool);
841
842        fn esp_rom_opiflash_pin_config();
843    }
844
845    /// Represents the operational mode registers of an OPI PSRAM.
846    #[derive(Default)]
847    #[repr(C)]
848    struct OpiPsramModeReg {
849        // Mode register 0 (MR0).
850        pub mr0: u8,
851        // Mode register 1 (MR1).
852        pub mr1: u8,
853        // Mode register 2 (MR2).
854        pub mr2: u8,
855        // Mode register 3 (MR3).
856        pub mr3: u8,
857        // Mode register 4 (MR4).
858        pub mr4: u8,
859        // Mode register 8 (MR8).
860        pub mr8: u8,
861    }
862
863    #[allow(unused)]
864    impl OpiPsramModeReg {
865        fn drive_str(&self) -> u8 {
866            self.mr0 & 0b11
867        }
868
869        fn set_drive_str(&mut self, value: u8) {
870            self.mr0 &= !0b11;
871            self.mr0 |= value & 0b11;
872        }
873
874        fn read_latency(&self) -> u8 {
875            (self.mr0 >> 2) & 0b111
876        }
877
878        fn set_read_latency(&mut self, value: u8) {
879            self.mr0 &= !(0b111 << 2);
880            self.mr0 |= (value & 0b111) << 2;
881        }
882
883        fn lt(&self) -> u8 {
884            (self.mr0 >> 5) & 0b1
885        }
886
887        fn set_lt(&mut self, value: u8) {
888            self.mr0 &= !(0b1 << 5);
889            self.mr0 |= (value & 0b1) << 5;
890        }
891
892        fn rsvd0_1(&self) -> u8 {
893            (self.mr0 >> 6) & 0b11
894        }
895
896        fn set_rsvd0_1(&mut self, value: u8) {
897            self.mr0 &= !(0b11 << 6);
898            self.mr0 |= (value & 0b11) << 6;
899        }
900
901        fn vendor_id(&self) -> u8 {
902            self.mr1 & 0b11111
903        }
904
905        fn set_vendor_id(&mut self, value: u8) {
906            self.mr1 &= !0b11111;
907            self.mr1 |= value & 0b11111;
908        }
909
910        fn rsvd0_2(&self) -> u8 {
911            (self.mr1 >> 5) & 0b111
912        }
913
914        fn set_rsvd0_2(&mut self, value: u8) {
915            self.mr1 &= !(0b111 << 5);
916            self.mr1 |= (value & 0b111) << 5;
917        }
918
919        fn density(&self) -> u8 {
920            self.mr2 & 0b111
921        }
922
923        fn set_density(&mut self, value: u8) {
924            self.mr2 &= !0b111;
925            self.mr2 |= value & 0b111;
926        }
927
928        fn dev_id(&self) -> u8 {
929            (self.mr2 >> 3) & 0b11
930        }
931
932        fn set_dev_id(&mut self, value: u8) {
933            self.mr2 &= !(0b11 << 3);
934            self.mr2 |= (value & 0b11) << 3;
935        }
936
937        fn rsvd1_2(&self) -> u8 {
938            (self.mr2 >> 5) & 0b11
939        }
940
941        fn set_rsvd1_2(&mut self, value: u8) {
942            self.mr2 &= !(0b11 << 5);
943            self.mr2 |= (value & 0b11) << 5;
944        }
945
946        fn gb(&self) -> u8 {
947            (self.mr2 >> 7) & 0b1
948        }
949
950        fn set_gb(&mut self, value: u8) {
951            self.mr2 &= !(0b1 << 7);
952            self.mr2 |= (value & 0b1) << 7;
953        }
954
955        fn rsvd3_7(&self) -> u8 {
956            self.mr3 & 0b11111
957        }
958
959        fn set_rsvd3_7(&mut self, value: u8) {
960            self.mr3 &= !0b11111;
961            self.mr3 |= value & 0b11111;
962        }
963
964        fn srf(&self) -> u8 {
965            (self.mr3 >> 5) & 0b1
966        }
967
968        fn set_srf(&mut self, value: u8) {
969            self.mr3 &= !(0b1 << 5);
970            self.mr3 |= (value & 0b1) << 5;
971        }
972
973        fn vcc(&self) -> u8 {
974            (self.mr3 >> 6) & 0b1
975        }
976
977        fn set_vcc(&mut self, value: u8) {
978            self.mr3 &= !(0b1 << 6);
979            self.mr3 |= (value & 0b1) << 6;
980        }
981
982        fn rsvd0(&self) -> u8 {
983            (self.mr3 >> 7) & 0b1
984        }
985
986        fn set_rsvd0(&mut self, value: u8) {
987            self.mr3 &= !(0b1 << 7);
988            self.mr3 |= (value & 0b1) << 7;
989        }
990
991        fn pasr(&self) -> u8 {
992            self.mr4 & 0b111
993        }
994
995        fn set_pasr(&mut self, value: u8) {
996            self.mr4 &= !0b111;
997            self.mr4 |= value & 0b111;
998        }
999
1000        fn rf(&self) -> u8 {
1001            (self.mr4 >> 3) & 0b1
1002        }
1003
1004        fn set_rf(&mut self, value: u8) {
1005            self.mr4 &= !(0b1 << 3);
1006            self.mr4 |= (value & 0b1) << 3;
1007        }
1008
1009        fn rsvd3(&self) -> u8 {
1010            (self.mr4 >> 4) & 0b1
1011        }
1012
1013        fn set_rsvd3(&mut self, value: u8) {
1014            self.mr4 &= !(0b1 << 4);
1015            self.mr4 |= (value & 0b1) << 4;
1016        }
1017
1018        fn wr_latency(&self) -> u8 {
1019            (self.mr4 >> 5) & 0b111
1020        }
1021
1022        fn set_wr_latency(&mut self, value: u8) {
1023            self.mr4 &= !(0b111 << 5);
1024            self.mr4 |= (value & 0b111) << 5;
1025        }
1026
1027        fn bl(&self) -> u8 {
1028            self.mr8 & 0b11
1029        }
1030
1031        fn set_bl(&mut self, value: u8) {
1032            self.mr8 &= !0b11;
1033            self.mr8 |= value & 0b11;
1034        }
1035
1036        fn bt(&self) -> u8 {
1037            (self.mr8 >> 2) & 0b1
1038        }
1039
1040        fn set_bt(&mut self, value: u8) {
1041            self.mr8 &= !(0b1 << 2);
1042            self.mr8 |= (value & 0b1) << 2;
1043        }
1044
1045        fn rsvd0_4(&self) -> u8 {
1046            (self.mr8 >> 3) & 0b11111
1047        }
1048
1049        fn set_rsvd0_4(&mut self, value: u8) {
1050            self.mr8 &= !(0b11111 << 3);
1051            self.mr8 |= (value & 0b11111) << 3;
1052        }
1053    }
1054
1055    #[ram]
1056    pub(crate) fn psram_init(config: &mut PsramConfig) {
1057        mspi_pin_init();
1058        init_psram_pins();
1059        set_psram_cs_timing();
1060
1061        // for now we don't support ECC
1062        // "s_configure_psram_ecc();"
1063
1064        // enter MSPI slow mode to init PSRAM device registers
1065        spi_timing_enter_mspi_low_speed_mode(true);
1066
1067        unsafe {
1068            // set to variable dummy mode
1069            SPI1::regs()
1070                .ddr()
1071                .modify(|_, w| w.spi_fmem_var_dummy().set_bit());
1072            esp_rom_spi_set_dtr_swap_mode(1, false, false);
1073        }
1074
1075        // Set PSRAM read latency and drive strength
1076        let mut mode_reg = OpiPsramModeReg::default();
1077        mode_reg.set_lt(1);
1078        mode_reg.set_read_latency(2);
1079        mode_reg.set_drive_str(0);
1080        mode_reg.set_bl(3);
1081        mode_reg.set_bt(0);
1082
1083        init_psram_mode_reg(1, &mode_reg);
1084        // Print PSRAM info
1085        psram_mode_reg(1, &mut mode_reg);
1086
1087        print_psram_info(&mode_reg);
1088
1089        if mode_reg.vendor_id() != OCT_PSRAM_VENDOR_ID {
1090            warn!(
1091                "PSRAM ID read error: {:x}, PSRAM chip not found or not supported, or wrong PSRAM line mode",
1092                mode_reg.vendor_id()
1093            );
1094            return;
1095        }
1096
1097        let psram_size = match mode_reg.density() {
1098            0x0 => PSRAM_SIZE_2MB,
1099            0x1 => PSRAM_SIZE_4MB,
1100            0x3 => PSRAM_SIZE_8MB,
1101            0x5 => PSRAM_SIZE_16MB,
1102            0x7 => PSRAM_SIZE_32MB,
1103            _ => 0,
1104        };
1105        info!("{} bytes of PSRAM", psram_size);
1106
1107        if config.size.is_auto() {
1108            config.size = PsramSize::Size(psram_size);
1109        }
1110
1111        // Do PSRAM timing tuning, we use SPI1 to do the tuning, and set the
1112        // SPI0 PSRAM timing related registers accordingly
1113        // this is unsupported for now
1114        // spi_timing_psram_tuning();
1115
1116        // Back to the high speed mode. Flash/PSRAM clocks are set to the clock
1117        // that user selected. SPI0/1 registers are all set correctly
1118        spi_timing_enter_mspi_high_speed_mode(true, config);
1119
1120        // Tuning may change SPI1 regs, whereas legacy spi_flash APIs rely on
1121        // these regs. This function is to restore SPI1 init state.
1122        spi_flash_set_rom_required_regs();
1123
1124        // Flash chip requires MSPI specifically, call this function to set them
1125        // this is unsupported for now
1126        // spi_flash_set_vendor_required_regs();
1127
1128        config_psram_spi_phases();
1129    }
1130
1131    // Configure PSRAM SPI0 phase related registers here according to the PSRAM chip
1132    // requirement
1133    fn config_psram_spi_phases() {
1134        unsafe {
1135            let spi = SPI0::regs();
1136            // Config Write CMD phase for SPI0 to access PSRAM
1137            spi.cache_sctrl()
1138                .modify(|_, w| w.cache_sram_usr_wcmd().set_bit());
1139
1140            spi.sram_dwr_cmd().modify(|_, w| {
1141                w.cache_sram_usr_wr_cmd_bitlen()
1142                    .bits(OCT_PSRAM_WR_CMD_BITLEN - 1)
1143            });
1144            spi.sram_dwr_cmd()
1145                .modify(|_, w| w.cache_sram_usr_wr_cmd_value().bits(OPI_PSRAM_SYNC_WRITE));
1146
1147            // Config Read CMD phase for SPI0 to access PSRAM
1148            spi.cache_sctrl()
1149                .modify(|_, w| w.cache_sram_usr_rcmd().set_bit());
1150
1151            spi.sram_drd_cmd().modify(|_, w| {
1152                w.cache_sram_usr_rd_cmd_bitlen()
1153                    .bits(OCT_PSRAM_RD_CMD_BITLEN - 1)
1154            });
1155            spi.sram_drd_cmd()
1156                .modify(|_, w| w.cache_sram_usr_rd_cmd_value().bits(OPI_PSRAM_SYNC_READ));
1157
1158            // Config ADDR phase
1159            spi.cache_sctrl()
1160                .modify(|_, w| w.sram_addr_bitlen().bits(OCT_PSRAM_ADDR_BITLEN - 1));
1161            spi.cache_sctrl()
1162                .modify(|_, w| w.cache_usr_scmd_4byte().set_bit());
1163
1164            // Config RD/WR Dummy phase
1165            spi.cache_sctrl()
1166                .modify(|_, w| w.usr_rd_sram_dummy().set_bit());
1167            spi.cache_sctrl()
1168                .modify(|_, w| w.usr_wr_sram_dummy().set_bit());
1169            spi.cache_sctrl()
1170                .modify(|_, w| w.sram_rdummy_cyclelen().bits(OCT_PSRAM_RD_DUMMY_BITLEN - 1));
1171            spi.spi_smem_ddr()
1172                .modify(|_, w| w.spi_smem_var_dummy().set_bit());
1173            spi.cache_sctrl()
1174                .modify(|_, w| w.sram_wdummy_cyclelen().bits(OCT_PSRAM_WR_DUMMY_BITLEN - 1));
1175
1176            spi.spi_smem_ddr().modify(|_, w| w.wdat_swp().clear_bit());
1177            spi.spi_smem_ddr().modify(|_, w| w.rdat_swp().clear_bit());
1178            spi.spi_smem_ddr().modify(|_, w| w.en().set_bit());
1179
1180            spi.sram_cmd().modify(|_, w| w.sdummy_out().set_bit());
1181            spi.sram_cmd().modify(|_, w| w.scmd_oct().set_bit());
1182            spi.sram_cmd().modify(|_, w| w.saddr_oct().set_bit());
1183            spi.sram_cmd().modify(|_, w| w.sdout_oct().set_bit());
1184            spi.sram_cmd().modify(|_, w| w.sdin_oct().set_bit());
1185
1186            spi.cache_sctrl().modify(|_, w| w.sram_oct().set_bit());
1187        }
1188    }
1189
1190    #[ram]
1191    fn spi_flash_set_rom_required_regs() {
1192        // Disable the variable dummy mode when doing timing tuning
1193        SPI1::regs()
1194            .ddr()
1195            .modify(|_, w| w.spi_fmem_var_dummy().clear_bit());
1196        // STR /DTR mode setting is done every time when
1197        // `esp_rom_opiflash_exec_cmd` is called
1198        //
1199        // Add any registers that are not set in ROM SPI flash functions here in
1200        // the future
1201    }
1202
1203    #[ram]
1204    fn mspi_pin_init() {
1205        unsafe { esp_rom_opiflash_pin_config() };
1206        spi_timing_set_pin_drive_strength();
1207        // Set F4R4 board pin drive strength. TODO: IDF-3663
1208    }
1209
1210    #[ram]
1211    fn spi_timing_set_pin_drive_strength() {
1212        // For now, set them all to 3. Need to check after QVL test results are out.
1213        // TODO: IDF-3663 Set default clk
1214        unsafe {
1215            SPI0::regs()
1216                .date()
1217                .modify(|_, w| w.spi_spiclk_pad_drv_ctl_en().set_bit());
1218            SPI0::regs()
1219                .date()
1220                .modify(|_, w| w.spi_smem_spiclk_fun_drv().bits(3));
1221            SPI0::regs()
1222                .date()
1223                .modify(|_, w| w.spi_fmem_spiclk_fun_drv().bits(3));
1224
1225            // Set default mspi d0 ~ d7, dqs pin drive strength
1226            let pins = [27usize, 28, 31, 32, 33, 34, 35, 36, 37];
1227            for pin in pins {
1228                IO_MUX::regs().gpio(pin).modify(|_, w| w.fun_drv().bits(3));
1229            }
1230        }
1231    }
1232
1233    fn spi_timing_enter_mspi_low_speed_mode(control_spi1: bool) {
1234        // Here we are going to slow the SPI1 frequency to 20Mhz, so we need to
1235        // set SPI1 din_num and din_mode regs.
1236        //
1237        // Because SPI0 and SPI1 share the din_num and din_mode regs, so if we
1238        // clear SPI1 din_num and din_mode to 0, if the SPI0 flash
1239        // module clock is still in high freq, it may not work correctly.
1240        //
1241        // Therefore, here we need to slow both the SPI0 and SPI1 and related
1242        // timing tuning regs to 20Mhz configuration.
1243        // Switch SPI1 and SPI0 clock as 20MHz, set its SPIMEM core clock as 80M and set
1244        // clock division as 4
1245        spi0_timing_config_set_core_clock(SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m); // SPI0 and SPI1 share the register for core clock. So we only set SPI0 here.
1246        spi0_timing_config_set_flash_clock(4);
1247        if control_spi1 {
1248            // After tuning, won't touch SPI1 again
1249            spi1_timing_config_set_flash_clock(4);
1250        }
1251
1252        // Set PSRAM module clock
1253        spi0_timing_config_set_psram_clock(4);
1254
1255        // for now we don't support tuning the timing
1256        // "clear_timing_tuning_regs(control_spi1);"
1257    }
1258
1259    // Set SPI0 FLASH and PSRAM module clock, din_num, din_mode and extra dummy,
1260    // according to the configuration got from timing tuning function
1261    // (`calculate_best_flash_tuning_config`). iF control_spi1 == 1, will also
1262    // update SPI1 timing registers. Should only be set to 1 when do tuning.
1263    //
1264    // This function should always be called after `spi_timing_flash_tuning` or
1265    // `calculate_best_flash_tuning_config`
1266    fn spi_timing_enter_mspi_high_speed_mode(control_spi1: bool, config: &PsramConfig) {
1267        let flash_div: u32 = flash_clock_divider(config);
1268        let psram_div: u32 = psram_clock_divider(config);
1269
1270        // Set SPI01 core clock
1271        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.
1272        // Set FLASH module clock
1273        spi0_timing_config_set_flash_clock(flash_div);
1274        if control_spi1 {
1275            spi1_timing_config_set_flash_clock(flash_div);
1276        }
1277        // Set PSRAM module clock
1278        spi0_timing_config_set_psram_clock(psram_div);
1279
1280        // for now we don't support tuning the timing
1281        // "set_timing_tuning_regs_as_required(true);"
1282    }
1283
1284    fn set_psram_cs_timing() {
1285        unsafe {
1286            let spi = SPI0::regs();
1287            // SPI0/1 share the cs_hold / cs_setup, cd_hold_time / cd_setup_time,
1288            // cs_hold_delay registers for PSRAM, so we only need to set SPI0 related
1289            // registers here
1290            spi.spi_smem_ac()
1291                .modify(|_, w| w.spi_smem_cs_hold().set_bit());
1292            spi.spi_smem_ac()
1293                .modify(|_, w| w.spi_smem_cs_setup().set_bit());
1294
1295            spi.spi_smem_ac()
1296                .modify(|_, w| w.spi_smem_cs_hold_time().bits(OCT_PSRAM_CS_HOLD_TIME));
1297            spi.spi_smem_ac()
1298                .modify(|_, w| w.spi_smem_cs_setup_time().bits(OCT_PSRAM_CS_SETUP_TIME));
1299
1300            // CONFIG_SPIRAM_ECC_ENABLE unsupported for now
1301            // CS1 high time
1302            spi.spi_smem_ac()
1303                .modify(|_, w| w.spi_smem_cs_hold_delay().bits(OCT_PSRAM_CS_HOLD_DELAY));
1304        }
1305    }
1306
1307    fn init_psram_pins() {
1308        // Set cs1 pin function
1309        unsafe {
1310            IO_MUX::regs()
1311                .gpio(OCT_PSRAM_CS1_IO as usize)
1312                .modify(|_, w| w.mcu_sel().bits(FUNC_SPICS1_SPICS1));
1313        }
1314
1315        // Set mspi cs1 drive strength
1316        unsafe {
1317            IO_MUX::regs()
1318                .gpio(OCT_PSRAM_CS1_IO as usize)
1319                .modify(|_, w| w.fun_drv().bits(3));
1320        }
1321
1322        // Set psram clock pin drive strength
1323        unsafe {
1324            SPI0::regs()
1325                .date()
1326                .modify(|_, w| w.spi_smem_spiclk_fun_drv().bits(3));
1327        }
1328    }
1329
1330    fn psram_mode_reg(spi_num: u32, out_reg: &mut OpiPsramModeReg) {
1331        let mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE;
1332        let cmd_len: u32 = 16;
1333        let addr_bit_len: u32 = 32;
1334        let dummy: u32 = OCT_PSRAM_RD_DUMMY_BITLEN as u32;
1335        let mut data_bit_len: u32 = 16;
1336
1337        unsafe {
1338            // Read MR0~1 register
1339            esp_rom_opiflash_exec_cmd(
1340                spi_num,
1341                mode,
1342                OPI_PSRAM_REG_READ as u32,
1343                cmd_len,
1344                0x0,
1345                addr_bit_len,
1346                dummy,
1347                core::ptr::null(),
1348                0,
1349                &mut out_reg.mr0,
1350                data_bit_len,
1351                1 << 1,
1352                false,
1353            );
1354            // Read MR2~3 register
1355            esp_rom_opiflash_exec_cmd(
1356                spi_num,
1357                mode,
1358                OPI_PSRAM_REG_READ as u32,
1359                cmd_len,
1360                0x2,
1361                addr_bit_len,
1362                dummy,
1363                core::ptr::null(),
1364                0,
1365                &mut out_reg.mr2,
1366                data_bit_len,
1367                1 << 1,
1368                false,
1369            );
1370            data_bit_len = 8;
1371            // Read MR4 register
1372            esp_rom_opiflash_exec_cmd(
1373                spi_num,
1374                mode,
1375                OPI_PSRAM_REG_READ as u32,
1376                cmd_len,
1377                0x4,
1378                addr_bit_len,
1379                dummy,
1380                core::ptr::null(),
1381                0,
1382                &mut out_reg.mr4,
1383                data_bit_len,
1384                1 << 1,
1385                false,
1386            );
1387            // Read MR8 register
1388            esp_rom_opiflash_exec_cmd(
1389                spi_num,
1390                mode,
1391                OPI_PSRAM_REG_READ as u32,
1392                cmd_len,
1393                0x8,
1394                addr_bit_len,
1395                dummy,
1396                core::ptr::null(),
1397                0,
1398                &mut out_reg.mr8,
1399                data_bit_len,
1400                1 << 1,
1401                false,
1402            );
1403        }
1404    }
1405
1406    // Initialise mode registers of the PSRAM
1407    fn init_psram_mode_reg(spi_num: u32, mode_reg_config: &OpiPsramModeReg) {
1408        let mode = ESP_ROM_SPIFLASH_OPI_DTR_MODE;
1409        let cmd_len: u32 = 16;
1410        let addr: u32 = 0x0; // 0x0 is the MR0 register
1411        let addr_bit_len: u32 = 32;
1412        let dummy = OCT_PSRAM_RD_DUMMY_BITLEN as u32;
1413        let mut mode_reg = OpiPsramModeReg::default();
1414        let data_bit_len: u32 = 16;
1415
1416        // read
1417        unsafe {
1418            esp_rom_opiflash_exec_cmd(
1419                spi_num,
1420                mode,
1421                OPI_PSRAM_REG_READ as u32,
1422                cmd_len,
1423                addr,
1424                addr_bit_len,
1425                dummy,
1426                core::ptr::null(),
1427                0,
1428                &mut mode_reg.mr0,
1429                data_bit_len,
1430                1 << 1,
1431                false,
1432            );
1433        }
1434
1435        // modify
1436        mode_reg.set_lt(mode_reg_config.lt());
1437        mode_reg.set_read_latency(mode_reg_config.read_latency());
1438        mode_reg.set_drive_str(mode_reg_config.drive_str());
1439
1440        // write
1441        unsafe {
1442            esp_rom_opiflash_exec_cmd(
1443                spi_num,
1444                mode,
1445                OPI_PSRAM_REG_WRITE as u32,
1446                cmd_len,
1447                addr,
1448                addr_bit_len,
1449                0,
1450                &mode_reg.mr0,
1451                16,
1452                core::ptr::null_mut(),
1453                0,
1454                1 << 1,
1455                false,
1456            );
1457        }
1458
1459        // CONFIG_SPIRAM_ECC_ENABLE not yet supported
1460    }
1461
1462    fn print_psram_info(reg_val: &OpiPsramModeReg) {
1463        info!(
1464            "vendor id    : {:02x} ({})",
1465            reg_val.vendor_id(),
1466            if reg_val.vendor_id() == 0x0d {
1467                "AP"
1468            } else {
1469                "UNKNOWN"
1470            }
1471        );
1472        info!(
1473            "dev id       : {:02x} (generation {})",
1474            reg_val.dev_id(),
1475            reg_val.dev_id() + 1
1476        );
1477        info!(
1478            "density      : {:02x} ({} Mbit)",
1479            reg_val.density(),
1480            if reg_val.density() == 0x1 {
1481                32
1482            } else if reg_val.density() == 0x3 {
1483                64
1484            } else if reg_val.density() == 0x5 {
1485                128
1486            } else if reg_val.density() == 0x7 {
1487                256
1488            } else {
1489                0
1490            }
1491        );
1492        info!(
1493            "good-die     : {:02x} ({})",
1494            reg_val.gb(),
1495            if reg_val.gb() == 1 { "Pass" } else { "Fail" }
1496        );
1497        info!(
1498            "Latency      : {:02x} ({})",
1499            reg_val.lt(),
1500            if reg_val.lt() == 1 {
1501                "Fixed"
1502            } else {
1503                "Variable"
1504            }
1505        );
1506        info!(
1507            "VCC          : {:02x} ({})",
1508            reg_val.vcc(),
1509            if reg_val.vcc() == 1 { "3V" } else { "1.8V" }
1510        );
1511        info!(
1512            "SRF          : {:02x} ({} Refresh)",
1513            reg_val.srf(),
1514            if reg_val.srf() == 0x1 { "Fast" } else { "Slow" }
1515        );
1516        info!(
1517            "BurstType    : {:02x} ({} Wrap)",
1518            reg_val.bt(),
1519            if reg_val.bt() == 1 && reg_val.bl() != 3 {
1520                "Hybrid"
1521            } else {
1522                ""
1523            }
1524        );
1525        info!(
1526            "BurstLen     : {:02x} ({} Byte)",
1527            reg_val.bl(),
1528            if reg_val.bl() == 0x00 {
1529                16
1530            } else if reg_val.bl() == 0x01 {
1531                32
1532            } else if reg_val.bl() == 0x10 {
1533                64
1534            } else {
1535                1024
1536            }
1537        );
1538        info!(
1539            "Readlatency  : {:02x} ({} cycles@{})",
1540            reg_val.read_latency(),
1541            reg_val.read_latency() * 2 + 6,
1542            if reg_val.lt() == 1 {
1543                "Fixed"
1544            } else {
1545                "Variable"
1546            }
1547        );
1548        info!(
1549            "DriveStrength: {:02x} (1/{})",
1550            reg_val.drive_str(),
1551            if reg_val.drive_str() == 0x00 {
1552                1
1553            } else if reg_val.drive_str() == 0x01 {
1554                2
1555            } else if reg_val.drive_str() == 0x02 {
1556                4
1557            } else {
1558                8
1559            }
1560        );
1561    }
1562
1563    #[ram]
1564    fn spi0_timing_config_set_core_clock(core_clock: SpiTimingConfigCoreClock) {
1565        unsafe {
1566            SPI0::regs().core_clk_sel().modify(|_, w| {
1567                w.core_clk_sel().bits(match core_clock {
1568                    SpiTimingConfigCoreClock::SpiTimingConfigCoreClock80m => 0,
1569                    SpiTimingConfigCoreClock::SpiTimingConfigCoreClock120m => 1,
1570                    SpiTimingConfigCoreClock::SpiTimingConfigCoreClock160m => 2,
1571                    SpiTimingConfigCoreClock::SpiTimingConfigCoreClock240m => 3,
1572                })
1573            });
1574        }
1575    }
1576
1577    #[ram]
1578    fn spi0_timing_config_set_flash_clock(freqdiv: u32) {
1579        if freqdiv == 1 {
1580            SPI0::regs()
1581                .clock()
1582                .modify(|_, w| w.clk_equ_sysclk().set_bit());
1583        } else {
1584            let freqbits: u32 = ((freqdiv - 1) << SPI_MEM_CLKCNT_N_S)
1585                | ((freqdiv / 2 - 1) << SPI_MEM_CLKCNT_H_S)
1586                | ((freqdiv - 1) << SPI_MEM_CLKCNT_L_S);
1587            unsafe {
1588                SPI0::regs().clock().modify(|_, w| w.bits(freqbits));
1589            }
1590        }
1591    }
1592
1593    #[ram]
1594    fn spi1_timing_config_set_flash_clock(freqdiv: u32) {
1595        if freqdiv == 1 {
1596            SPI1::regs()
1597                .clock()
1598                .modify(|_, w| w.clk_equ_sysclk().set_bit());
1599        } else {
1600            let freqbits: u32 = ((freqdiv - 1) << SPI_MEM_CLKCNT_N_S)
1601                | ((freqdiv / 2 - 1) << SPI_MEM_CLKCNT_H_S)
1602                | ((freqdiv - 1) << SPI_MEM_CLKCNT_L_S);
1603            unsafe {
1604                SPI1::regs().clock().modify(|_, w| w.bits(freqbits));
1605            }
1606        }
1607    }
1608
1609    #[ram]
1610    fn spi0_timing_config_set_psram_clock(freqdiv: u32) {
1611        if freqdiv == 1 {
1612            SPI0::regs()
1613                .sram_clk()
1614                .modify(|_, w| w.sclk_equ_sysclk().set_bit());
1615        } else {
1616            let freqbits: u32 = ((freqdiv - 1) << SPI_MEM_SCLKCNT_N_S)
1617                | ((freqdiv / 2 - 1) << SPI_MEM_SCLKCNT_H_S)
1618                | ((freqdiv - 1) << SPI_MEM_SCLKCNT_L_S);
1619            unsafe {
1620                SPI0::regs().sram_clk().modify(|_, w| w.bits(freqbits));
1621            }
1622        }
1623    }
1624
1625    #[ram]
1626    fn flash_clock_divider(config: &PsramConfig) -> u32 {
1627        config.core_clock.unwrap_or_default() as u32 / config.flash_frequency as u32
1628    }
1629
1630    #[ram]
1631    fn psram_clock_divider(config: &PsramConfig) -> u32 {
1632        config.core_clock.unwrap_or_default() as u32 / config.ram_frequency as u32
1633    }
1634}