Skip to main content

esp_hal/psram/
esp32.rs

1use core::ops::Range;
2
3use super::{EXTMEM_ORIGIN, PsramSize};
4
5/// Cache Speed
6#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
8#[allow(missing_docs)]
9pub enum PsramCacheSpeed {
10    #[default]
11    PsramCacheF80mS40m = 0,
12    PsramCacheF40mS40m,
13    PsramCacheF80mS80m,
14}
15
16/// PSRAM virtual address mode.
17///
18/// Specifies how PSRAM is mapped for the CPU cores.
19#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)]
20#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21pub enum PsramVaddrMode {
22    /// App and pro CPU use their own flash cache for external RAM access.
23    ///
24    /// In this mode both cores access the same physical PSRAM.
25    #[default]
26    Normal = 0,
27    /// App and pro CPU share external RAM caches: pro CPU has low * 2M, app
28    /// CPU has high 2M.
29    ///
30    /// In this mode the two cores will access different parts of PSRAM.
31    LowHigh,
32    /// App and pro CPU share external RAM caches: pro CPU does even 32 byte
33    /// ranges, app does odd ones.
34    ///
35    /// In this mode the two cores will access different parts of PSRAM.
36    Evenodd,
37}
38
39/// PSRAM configuration
40#[derive(Copy, Clone, Debug, Default)]
41#[cfg_attr(feature = "defmt", derive(defmt::Format))]
42pub struct PsramConfig {
43    /// PSRAM size
44    pub size: PsramSize,
45    /// Cache speed
46    pub cache_speed: PsramCacheSpeed,
47    /// PSRAM virtual address mode
48    pub psram_vaddr_mode: PsramVaddrMode,
49}
50
51/// Initializes PSRAM to be used for data.
52#[procmacros::ram]
53pub(crate) fn init_psram(config: &mut PsramConfig) -> bool {
54    utils::psram_init(config);
55
56    if config.size.is_auto() {
57        const MAX_MEM_SIZE: usize = 4 * 1024 * 1024;
58
59        // Reading the device-id turned out to not work as expected (some bits flipped
60        // for unknown reason)
61        //
62        // As a workaround we just map 4m (maximum we can do) and
63        // probe how much memory we can write/read
64        utils::s_mapping(EXTMEM_ORIGIN as u32, MAX_MEM_SIZE as u32);
65
66        let last_correctly_read = unsafe {
67            let ptr = EXTMEM_ORIGIN as *mut u8;
68            for i in (1023..MAX_MEM_SIZE).step_by(1024) {
69                ptr.add(i).write_volatile(0x7f);
70            }
71
72            let mut last_correctly_read = 0;
73            for i in (1023..MAX_MEM_SIZE).step_by(1024) {
74                if ptr.add(i).read_volatile() == 0x7f {
75                    last_correctly_read = i;
76                } else {
77                    break;
78                }
79            }
80
81            last_correctly_read
82        };
83
84        if last_correctly_read == 0 {
85            warn!("No PSRAM found");
86            return false;
87        }
88        let guessed_size = last_correctly_read + 1;
89        info!("Assuming {} bytes of PSRAM", guessed_size);
90        config.size = PsramSize::Size(guessed_size);
91    }
92
93    true
94}
95
96#[procmacros::ram]
97pub(crate) fn map_psram(config: PsramConfig) -> Range<usize> {
98    utils::s_mapping(EXTMEM_ORIGIN as u32, config.size.get() as u32);
99
100    EXTMEM_ORIGIN..EXTMEM_ORIGIN + config.size.get()
101}
102
103pub(crate) mod utils {
104    use procmacros::ram;
105
106    use super::*;
107    use crate::peripherals::{DPORT, SPI0, SPI1};
108
109    #[ram]
110    pub(crate) fn s_mapping(v_start: u32, size: u32) {
111        // Enable external RAM in MMU
112        cache_sram_mmu_set(0, 0, v_start, 0, 32, size / 1024 / 32);
113        // Flush and enable icache for APP CPU
114        DPORT::regs()
115            .app_cache_ctrl1()
116            .modify(|_, w| w.app_cache_mask_dram1().clear_bit());
117
118        cache_sram_mmu_set(1, 0, v_start, 0, 32, size / 1024 / 32);
119    }
120
121    // we can use the ROM version of this: it works well enough and keeps the size
122    // of the binary down.
123    #[ram]
124    fn cache_sram_mmu_set(
125        cpu_no: u32,
126        pid: u32,
127        vaddr: u32,
128        paddr: u32,
129        psize: u32,
130        num: u32,
131    ) -> i32 {
132        unsafe { cache_sram_mmu_set_rom(cpu_no, pid, vaddr, paddr, psize, num) }
133    }
134
135    // PSRAM clock and cs IO should be configured based on hardware design.
136    // For ESP32-WROVER or ESP32-WROVER-B module, the clock IO is IO17, the cs IO is
137    // IO16, they are the default value for these two configs.
138    const D0WD_PSRAM_CLK_IO: u8 = 17;
139    const D0WD_PSRAM_CS_IO: u8 = 16;
140
141    const D2WD_PSRAM_CLK_IO: u8 = 9; // Default value is 9
142    const D2WD_PSRAM_CS_IO: u8 = 10; // Default value is 10
143
144    // For ESP32-PICO chip, the psram share clock with flash. The flash clock pin is
145    // fixed, which is IO6.
146    const PICO_PSRAM_CLK_IO: u8 = 6;
147    const PICO_PSRAM_CS_IO: u8 = 10; // Default value is 10
148
149    const PICO_V3_02_PSRAM_CLK_IO: u8 = 10;
150    const PICO_V3_02_PSRAM_CS_IO: u8 = 9;
151    const PICO_V3_02_PSRAM_SPIWP_SD3_IO: u8 = 18;
152
153    const ESP_ROM_EFUSE_FLASH_DEFAULT_SPI: u32 = 0;
154    const ESP_ROM_EFUSE_FLASH_DEFAULT_HSPI: u32 = 1;
155
156    const SPI_IOMUX_PIN_NUM_CLK: u8 = 6;
157    const SPI_IOMUX_PIN_NUM_CS: u8 = 11;
158
159    // IO-pins for PSRAM.
160    // WARNING: PSRAM shares all but the CS and CLK pins with the flash, so these
161    // defines hardcode the flash pins as well, making this code incompatible
162    // with either a setup that has the flash on non-standard pins or ESP32s
163    // with built-in flash.
164    const PSRAM_SPIQ_SD0_IO: u8 = 7;
165    const PSRAM_SPID_SD1_IO: u8 = 8;
166    const PSRAM_SPIWP_SD3_IO: u8 = 10;
167    const PSRAM_SPIHD_SD2_IO: u8 = 9;
168
169    const FLASH_HSPI_CLK_IO: u8 = 14;
170    const FLASH_HSPI_CS_IO: u8 = 15;
171
172    const PSRAM_HSPI_SPIQ_SD0_IO: u8 = 12;
173    const PSRAM_HSPI_SPID_SD1_IO: u8 = 13;
174    const PSRAM_HSPI_SPIWP_SD3_IO: u8 = 2;
175    const PSRAM_HSPI_SPIHD_SD2_IO: u8 = 4;
176
177    const fn psram_cs_hold_time_from_psram_speed(speed: PsramCacheSpeed) -> u32 {
178        match speed {
179            PsramCacheSpeed::PsramCacheF80mS40m => 0,
180            PsramCacheSpeed::PsramCacheF40mS40m => 0,
181            PsramCacheSpeed::PsramCacheF80mS80m => 1,
182        }
183    }
184
185    const PSRAM_INTERNAL_IO_28: u32 = 28;
186    const PSRAM_INTERNAL_IO_29: u32 = 29;
187    const SIG_GPIO_OUT_IDX: u32 = 256;
188    const SPICLK_OUT_IDX: u32 = 0;
189    const SIG_IN_FUNC224_IDX: u32 = 224;
190    const SIG_IN_FUNC225_IDX: u32 = 225;
191    const SPICS0_OUT_IDX: u32 = 5;
192    const SPICS1_OUT_IDX: u32 = 6;
193    const SPIQ_OUT_IDX: u32 = 1;
194    const SPIQ_IN_IDX: u32 = 1;
195    const SPID_OUT_IDX: u32 = 2;
196    const SPID_IN_IDX: u32 = 2;
197    const SPIWP_OUT_IDX: u32 = 4;
198    const SPIWP_IN_IDX: u32 = 4;
199    const SPIHD_OUT_IDX: u32 = 3;
200    const SPIHD_IN_IDX: u32 = 3;
201    const FUNC_SD_CLK_SPICLK: u32 = 1;
202    const PIN_FUNC_GPIO: u32 = 2;
203
204    const PSRAM_QUAD_WRITE: u32 = 0x38;
205    const PSRAM_FAST_READ_QUAD_DUMMY: u32 = 0x5;
206    const PSRAM_FAST_READ_QUAD: u32 = 0xEB;
207
208    const SPI_FWRITE_DUAL_S: u32 = 12;
209    const SPI_FWRITE_DUAL_M: u32 = 1 << 12;
210
211    const SPI_FREAD_QIO_M: u32 = 1 << 24;
212    const SPI0_R_QIO_DUMMY_CYCLELEN: u32 = 3;
213    const SPI_FREAD_DIO_M: u32 = 1 << 23;
214    const SPI0_R_DIO_DUMMY_CYCLELEN: u32 = 1;
215    const SPI0_R_DIO_ADDR_BITSLEN: u32 = 27;
216    const SPI_FREAD_QUAD_M: u32 = 1 << 20;
217    const SPI_FREAD_DUAL_M: u32 = 1 << 14;
218    const SPI0_R_FAST_DUMMY_CYCLELEN: u32 = 7;
219    const PSRAM_IO_MATRIX_DUMMY_40M: u8 = 1;
220    const PSRAM_IO_MATRIX_DUMMY_80M: u8 = 2;
221
222    const _SPI_CACHE_PORT: u8 = 0;
223    const _SPI_FLASH_PORT: u8 = 1;
224    const _SPI_80M_CLK_DIV: u8 = 1;
225    const _SPI_40M_CLK_DIV: u8 = 2;
226
227    const FLASH_ID_GD25LQ32C: u32 = 0xC86016;
228
229    const EFUSE_SPICONFIG_RET_SPICLK_MASK: u32 = 0x3f;
230    const EFUSE_SPICONFIG_RET_SPICLK_SHIFT: u8 = 0;
231    const EFUSE_SPICONFIG_RET_SPIQ_MASK: u32 = 0x3f;
232    const EFUSE_SPICONFIG_RET_SPIQ_SHIFT: u8 = 6;
233    const EFUSE_SPICONFIG_RET_SPID_MASK: u32 = 0x3f;
234    const EFUSE_SPICONFIG_RET_SPID_SHIFT: u8 = 12;
235    const EFUSE_SPICONFIG_RET_SPICS0_MASK: u32 = 0x3f;
236    const EFUSE_SPICONFIG_RET_SPICS0_SHIFT: u8 = 18;
237    const EFUSE_SPICONFIG_RET_SPIHD_MASK: u32 = 0x3f;
238    const EFUSE_SPICONFIG_RET_SPIHD_SHIFT: u8 = 24;
239
240    fn efuse_spiconfig_ret(spi_config: u32, mask: u32, shift: u8) -> u8 {
241        (((spi_config) >> shift) & mask) as u8
242    }
243
244    #[derive(PartialEq, Eq, Debug, Default)]
245    #[cfg_attr(feature = "defmt", derive(defmt::Format))]
246    struct PsramIo {
247        flash_clk_io: u8,
248        flash_cs_io: u8,
249        psram_clk_io: u8,
250        psram_cs_io: u8,
251        psram_spiq_sd0_io: u8,
252        psram_spid_sd1_io: u8,
253        psram_spiwp_sd3_io: u8,
254        psram_spihd_sd2_io: u8,
255    }
256
257    #[derive(PartialEq, Eq, Copy, Clone, Debug)]
258    #[cfg_attr(feature = "defmt", derive(defmt::Format))]
259    enum PsramClkMode {
260        PsramClkModeNorm = 0, // Normal SPI mode
261        PsramClkModeDclk = 1, // Two extra clock cycles after CS is set high level
262    }
263
264    #[repr(C)]
265    pub(super) struct EspRomSpiflashChip {
266        pub device_id: u32,
267        pub chip_size: u32, // chip size in bytes
268        pub block_size: u32,
269        pub sector_size: u32,
270        pub page_size: u32,
271        pub status_mask: u32,
272    }
273
274    unsafe extern "C" {
275        fn esp_rom_efuse_get_flash_gpio_info() -> u32;
276
277        fn esp_rom_gpio_connect_out_signal(
278            gpio_num: u32,
279            signal_idx: u32,
280            out_inv: bool,
281            oen_inv: bool,
282        );
283
284        fn esp_rom_gpio_connect_in_signal(gpio_num: u32, signal_idx: u32, inv: bool);
285
286        fn esp_rom_spiflash_config_clk(freqdiv: u8, spi: u8) -> i32;
287
288        static mut g_rom_spiflash_dummy_len_plus: u8;
289
290        pub(super) static g_rom_flashchip: EspRomSpiflashChip;
291
292        fn cache_sram_mmu_set_rom(
293            cpu_no: u32,
294            pid: u32,
295            vaddr: u32,
296            paddr: u32,
297            psize: u32,
298            num: u32,
299        ) -> i32;
300    }
301
302    #[ram]
303    pub(crate) fn psram_init(config: &PsramConfig) {
304        let chip = crate::efuse::chip_type();
305
306        let mode = config.cache_speed;
307        let mut psram_io = PsramIo::default();
308        let clk_mode;
309
310        match chip {
311            crate::efuse::ChipType::Esp32D0wdq6 | crate::efuse::ChipType::Esp32D0wdq5 => {
312                clk_mode = PsramClkMode::PsramClkModeNorm;
313                psram_io.psram_clk_io = D0WD_PSRAM_CLK_IO;
314                psram_io.psram_cs_io = D0WD_PSRAM_CS_IO;
315            }
316            crate::efuse::ChipType::Esp32D2wdq5 => {
317                clk_mode = PsramClkMode::PsramClkModeDclk;
318                psram_io.psram_clk_io = D2WD_PSRAM_CLK_IO;
319                psram_io.psram_cs_io = D2WD_PSRAM_CS_IO;
320            }
321            crate::efuse::ChipType::Esp32Picod2 => {
322                clk_mode = PsramClkMode::PsramClkModeNorm;
323                psram_io.psram_clk_io = PICO_PSRAM_CLK_IO;
324                psram_io.psram_cs_io = PICO_PSRAM_CS_IO;
325            }
326            crate::efuse::ChipType::Esp32Picod4 => {
327                panic!("PSRAM is unsupported on this chip");
328            }
329            crate::efuse::ChipType::Esp32Picov302 => {
330                clk_mode = PsramClkMode::PsramClkModeNorm;
331                psram_io.psram_clk_io = PICO_V3_02_PSRAM_CLK_IO;
332                psram_io.psram_cs_io = PICO_V3_02_PSRAM_CS_IO;
333            }
334            crate::efuse::ChipType::Unknown => {
335                panic!("Unknown chip type. PSRAM is not supported");
336            }
337        }
338
339        let spiconfig = unsafe { esp_rom_efuse_get_flash_gpio_info() };
340        if spiconfig == ESP_ROM_EFUSE_FLASH_DEFAULT_SPI {
341            psram_io.flash_clk_io = SPI_IOMUX_PIN_NUM_CLK;
342            psram_io.flash_cs_io = SPI_IOMUX_PIN_NUM_CS;
343            psram_io.psram_spiq_sd0_io = PSRAM_SPIQ_SD0_IO;
344            psram_io.psram_spid_sd1_io = PSRAM_SPID_SD1_IO;
345            psram_io.psram_spiwp_sd3_io = PSRAM_SPIWP_SD3_IO;
346            psram_io.psram_spihd_sd2_io = PSRAM_SPIHD_SD2_IO;
347        } else if spiconfig == ESP_ROM_EFUSE_FLASH_DEFAULT_HSPI {
348            psram_io.flash_clk_io = FLASH_HSPI_CLK_IO;
349            psram_io.flash_cs_io = FLASH_HSPI_CS_IO;
350            psram_io.psram_spiq_sd0_io = PSRAM_HSPI_SPIQ_SD0_IO;
351            psram_io.psram_spid_sd1_io = PSRAM_HSPI_SPID_SD1_IO;
352            psram_io.psram_spiwp_sd3_io = PSRAM_HSPI_SPIWP_SD3_IO;
353            psram_io.psram_spihd_sd2_io = PSRAM_HSPI_SPIHD_SD2_IO;
354        } else if chip == crate::efuse::ChipType::Esp32Picov302 {
355            psram_io.flash_clk_io = efuse_spiconfig_ret(
356                spiconfig,
357                EFUSE_SPICONFIG_RET_SPICLK_MASK,
358                EFUSE_SPICONFIG_RET_SPICLK_SHIFT,
359            );
360            psram_io.flash_cs_io = efuse_spiconfig_ret(
361                spiconfig,
362                EFUSE_SPICONFIG_RET_SPICS0_MASK,
363                EFUSE_SPICONFIG_RET_SPICS0_SHIFT,
364            );
365            psram_io.psram_spiq_sd0_io = efuse_spiconfig_ret(
366                spiconfig,
367                EFUSE_SPICONFIG_RET_SPIQ_MASK,
368                EFUSE_SPICONFIG_RET_SPIQ_SHIFT,
369            );
370            psram_io.psram_spid_sd1_io = efuse_spiconfig_ret(
371                spiconfig,
372                EFUSE_SPICONFIG_RET_SPID_MASK,
373                EFUSE_SPICONFIG_RET_SPID_SHIFT,
374            );
375            psram_io.psram_spihd_sd2_io = efuse_spiconfig_ret(
376                spiconfig,
377                EFUSE_SPICONFIG_RET_SPIHD_MASK,
378                EFUSE_SPICONFIG_RET_SPIHD_SHIFT,
379            );
380            psram_io.psram_spiwp_sd3_io = PICO_V3_02_PSRAM_SPIWP_SD3_IO;
381        } else {
382            panic!("Getting Flash/PSRAM pins from efuse is not supported");
383            // psram_io.flash_clk_io = EFUSE_SPICONFIG_RET_SPICLK(spiconfig);
384            // psram_io.flash_cs_io = EFUSE_SPICONFIG_RET_SPICS0(spiconfig);
385            // psram_io.psram_spiq_sd0_io = EFUSE_SPICONFIG_RET_SPIQ(spiconfig);
386            // psram_io.psram_spid_sd1_io = EFUSE_SPICONFIG_RET_SPID(spiconfig);
387            // psram_io.psram_spihd_sd2_io =
388            // EFUSE_SPICONFIG_RET_SPIHD(spiconfig);
389            // psram_io.psram_spiwp_sd3_io = bootloader_flash_get_wp_pin();
390        }
391        info!("PS-RAM pins {:?}", &psram_io);
392
393        unsafe {
394            SPI0::regs().ext3().modify(|_, w| w.bits(0x1));
395            SPI1::regs()
396                .user()
397                .modify(|_, w| w.usr_prep_hold().clear_bit());
398        }
399
400        psram_spi_init(mode, clk_mode);
401
402        match mode {
403            PsramCacheSpeed::PsramCacheF80mS80m => unsafe {
404                esp_rom_gpio_connect_out_signal(
405                    psram_io.psram_clk_io as u32,
406                    SPICLK_OUT_IDX,
407                    false,
408                    false,
409                );
410            },
411            _ => unsafe {
412                if clk_mode == PsramClkMode::PsramClkModeDclk {
413                    // We need to delay CLK to the PSRAM with respect to the clock signal as output
414                    // by the SPI peripheral. We do this by routing it signal to
415                    // signal 224/225, which are used as a loopback; the extra run through
416                    // the GPIO matrix causes the delay. We use GPIO20 (which is not in any package
417                    // but has pad logic in silicon) as a temporary pad for
418                    // this. So the signal path is: SPI CLK --> GPIO28 -->
419                    // signal224(in then out) --> internal GPIO29 --> signal225(in then out) -->
420                    // GPIO17(PSRAM CLK)
421                    esp_rom_gpio_connect_out_signal(
422                        PSRAM_INTERNAL_IO_28,
423                        SPICLK_OUT_IDX,
424                        false,
425                        false,
426                    );
427                    esp_rom_gpio_connect_in_signal(PSRAM_INTERNAL_IO_28, SIG_IN_FUNC224_IDX, false);
428                    esp_rom_gpio_connect_out_signal(
429                        PSRAM_INTERNAL_IO_29,
430                        SIG_IN_FUNC224_IDX,
431                        false,
432                        false,
433                    );
434                    esp_rom_gpio_connect_in_signal(PSRAM_INTERNAL_IO_29, SIG_IN_FUNC225_IDX, false);
435                    esp_rom_gpio_connect_out_signal(
436                        psram_io.psram_clk_io as u32,
437                        SIG_IN_FUNC225_IDX,
438                        false,
439                        false,
440                    );
441                } else {
442                    esp_rom_gpio_connect_out_signal(
443                        psram_io.psram_clk_io as u32,
444                        SPICLK_OUT_IDX,
445                        false,
446                        false,
447                    );
448                }
449            },
450        }
451
452        let extra_dummy = psram_gpio_config(&psram_io, mode);
453        info!("extra dummy = {}", extra_dummy);
454
455        // psram_is_32mbit_ver0 would need special handling here
456
457        unsafe {
458            esp_rom_gpio_connect_out_signal(PSRAM_INTERNAL_IO_28, SIG_GPIO_OUT_IDX, false, false);
459            esp_rom_gpio_connect_out_signal(PSRAM_INTERNAL_IO_29, SIG_GPIO_OUT_IDX, false, false);
460            esp_rom_gpio_connect_out_signal(
461                psram_io.psram_clk_io as u32,
462                SPICLK_OUT_IDX,
463                false,
464                false,
465            );
466        }
467
468        // Update cs timing according to psram driving method.
469        psram_set_cs_timing_spi0(mode, clk_mode); // SPI_CACHE_PORT
470        psram_enable_qio_mode_spi1(clk_mode, mode);
471
472        let psram_vaddr_mode = config.psram_vaddr_mode;
473        info!("PS-RAM vaddrmode = {:?}", psram_vaddr_mode);
474
475        psram_cache_init(mode, psram_vaddr_mode, clk_mode, extra_dummy);
476    }
477
478    // register initialization for sram cache params and r/w commands
479    fn psram_cache_init(
480        psram_cache_mode: PsramCacheSpeed,
481        vaddrmode: PsramVaddrMode,
482        clk_mode: PsramClkMode,
483        extra_dummy: u32,
484    ) {
485        unsafe {
486            let spi = SPI0::regs();
487            info!(
488                "PS-RAM cache_init, psram_cache_mode={:?}, extra_dummy={}, clk_mode={:?}",
489                psram_cache_mode, extra_dummy, clk_mode
490            );
491            match psram_cache_mode {
492                PsramCacheSpeed::PsramCacheF80mS80m => {
493                    // flash 1 div clk,80+40;
494                    // There's no register on bit 31. No information about it in IDF, nor TRM,
495                    // so just doing it in this way.
496                    spi.date().modify(|r, w| {
497                        let current_bits = r.bits();
498                        let new_bits = current_bits & !((1 << 31) | (1 << 30));
499                        w.bits(new_bits)
500                    });
501                    // pre clk div , ONLY IF SPI/ SRAM@ DIFFERENT SPEED,JUST
502                    // FOR SPI0. FLASH DIV
503                    // 2+SRAM DIV4
504                }
505                PsramCacheSpeed::PsramCacheF80mS40m => {
506                    spi.clock().modify(|_, w| {
507                        w.clk_equ_sysclk().clear_bit();
508                        w.clkdiv_pre().bits(0);
509                        w.clkcnt_n().bits(1);
510                        w.clkcnt_h().bits(0);
511                        w.clkcnt_l().bits(1)
512                    });
513
514                    spi.date().modify(|r, w| {
515                        let current_bits = r.bits();
516                        let new_bits = (current_bits | (1 << 31)) & !(1 << 30);
517                        w.bits(new_bits)
518                    });
519                }
520                _ => {
521                    spi.date().modify(|r, w| {
522                        let current_bits = r.bits();
523                        let new_bits = current_bits & !((1 << 31) | (1 << 30));
524                        w.bits(new_bits)
525                    });
526                }
527            }
528
529            // QIO cache command, 24-bit address, dummy. Dummy: 40 MHz +1, 80 MHz +2.
530            spi.cache_sctrl().modify(|_, w| {
531                w.usr_sram_dio().clear_bit();
532                w.usr_sram_qio().set_bit();
533                w.cache_sram_usr_rcmd().set_bit();
534                w.cache_sram_usr_wcmd().set_bit();
535                w.sram_addr_bitlen().bits(23);
536                w.usr_rd_sram_dummy().set_bit();
537                w.sram_dummy_cyclelen()
538                    .bits((PSRAM_FAST_READ_QUAD_DUMMY + extra_dummy) as u8)
539            });
540
541            spi.sram_drd_cmd().modify(|_, w| {
542                w.cache_sram_usr_rd_cmd_bitlen().bits(7);
543                w.cache_sram_usr_rd_cmd_value()
544                    .bits(PSRAM_FAST_READ_QUAD as u16)
545            });
546            spi.sram_dwr_cmd().modify(|_, w| {
547                w.cache_sram_usr_wr_cmd_bitlen().bits(7);
548                w.cache_sram_usr_wr_cmd_value()
549                    .bits(PSRAM_QUAD_WRITE as u16)
550            });
551
552            match psram_cache_mode {
553                PsramCacheSpeed::PsramCacheF80mS80m => (), // in this mode , no delay is needed
554                _ => {
555                    if clk_mode == PsramClkMode::PsramClkModeDclk {
556                        // Extra command byte (0x00) delays the QIO command in DCLK mode.
557                        spi.sram_drd_cmd().modify(|_, w| {
558                            w.cache_sram_usr_rd_cmd_bitlen().bits(15);
559                            w.cache_sram_usr_rd_cmd_value()
560                                .bits((PSRAM_FAST_READ_QUAD << 8) as u16)
561                        });
562                        spi.sram_dwr_cmd().modify(|_, w| {
563                            w.cache_sram_usr_wr_cmd_bitlen().bits(15);
564                            w.cache_sram_usr_wr_cmd_value()
565                                .bits((PSRAM_QUAD_WRITE << 8) as u16)
566                        });
567                    }
568                }
569            }
570
571            let dport = DPORT::regs();
572
573            dport
574                .pro_cache_ctrl()
575                .modify(|_, w| w.pro_dram_hl().clear_bit().pro_dram_split().clear_bit());
576            dport
577                .app_cache_ctrl()
578                .modify(|_, w| w.app_dram_hl().clear_bit().app_dram_split().clear_bit());
579            if vaddrmode == PsramVaddrMode::LowHigh {
580                dport
581                    .pro_cache_ctrl()
582                    .modify(|_, w| w.pro_dram_hl().set_bit());
583                dport
584                    .app_cache_ctrl()
585                    .modify(|_, w| w.app_dram_hl().set_bit());
586            } else if vaddrmode == PsramVaddrMode::Evenodd {
587                dport
588                    .pro_cache_ctrl()
589                    .modify(|_, w| w.pro_dram_split().set_bit());
590                dport
591                    .app_cache_ctrl()
592                    .modify(|_, w| w.app_dram_split().set_bit());
593            }
594
595            // use Dram1 to visit ext sram. cache page mode : 1 -->16k  4 -->2k
596            // 0-->32k,(accord with the settings in cache_sram_mmu_set)
597            // Dram1 visits ext SRAM. Cache page mode 0 = 32 k (matches cache_sram_mmu_set).
598            dport.pro_cache_ctrl1().modify(|_, w| {
599                w.pro_cache_mask_dram1().clear_bit();
600                w.pro_cache_mask_opsdram().clear_bit();
601                w.pro_cmmu_sram_page_mode().bits(0)
602            });
603            dport.app_cache_ctrl1().modify(|_, w| {
604                w.app_cache_mask_dram1().clear_bit();
605                w.app_cache_mask_opsdram().clear_bit();
606                w.app_cmmu_sram_page_mode().bits(0)
607            });
608
609            // ENABLE SPI0 CS1 TO PSRAM(CS0--FLASH; CS1--SRAM)
610            spi.pin().modify(|_, w| w.cs1_dis().clear_bit());
611        }
612    }
613
614    // spi param init for psram
615    #[ram]
616    fn psram_spi_init(
617        // psram_spi_num_t spi_num = PSRAM_SPI_1,
618        mode: PsramCacheSpeed,
619        clk_mode: PsramClkMode,
620    ) {
621        SPI1::regs().slave().modify(|_, w| {
622            w.trans_inten().clear_bit();
623            w.mode().clear_bit()
624        });
625        SPI1::regs()
626            .pin()
627            .modify(|_, w| w.ck_idle_edge().clear_bit());
628        SPI1::regs().user().modify(|_, w| {
629            w.ck_out_edge().clear_bit();
630            w.doutdin().clear_bit()
631        });
632        SPI1::regs().ctrl().modify(|_, w| {
633            w.wr_bit_order().clear_bit();
634            w.rd_bit_order().clear_bit()
635        });
636        SPI1::regs().user1().modify(|_, w| unsafe { w.bits(0) });
637
638        SPI1::regs().w_iter().for_each(|w| {
639            w.write(|w| unsafe { w.bits(0) });
640        });
641
642        psram_set_cs_timing_spi1(mode, clk_mode);
643    }
644
645    fn psram_set_cs_timing_spi1(psram_cache_mode: PsramCacheSpeed, clk_mode: PsramClkMode) {
646        let spi = SPI1::regs();
647        let normal_mode = clk_mode == PsramClkMode::PsramClkModeNorm;
648        spi.user().modify(|_, w| {
649            w.cs_hold().bit(normal_mode);
650            w.cs_setup().bit(normal_mode)
651        });
652        if normal_mode {
653            spi.ctrl2().modify(|_, w| unsafe {
654                w.hold_time()
655                    .bits(psram_cs_hold_time_from_psram_speed(psram_cache_mode) as u8);
656                w.setup_time().bits(0)
657            });
658        }
659    }
660
661    fn psram_set_cs_timing_spi0(psram_cache_mode: PsramCacheSpeed, clk_mode: PsramClkMode) {
662        let spi = SPI0::regs();
663        let normal_mode = clk_mode == PsramClkMode::PsramClkModeNorm;
664        spi.user().modify(|_, w| {
665            w.cs_hold().bit(normal_mode);
666            w.cs_setup().bit(normal_mode)
667        });
668        if normal_mode {
669            spi.ctrl2().modify(|_, w| unsafe {
670                w.hold_time()
671                    .bits(psram_cs_hold_time_from_psram_speed(psram_cache_mode) as u8);
672                w.setup_time().bits(0)
673            });
674        }
675    }
676
677    #[derive(Default, Debug, PartialEq)]
678    struct PsramCmd<'a> {
679        cmd: u16,           // Command value
680        cmd_bit_len: u16,   // Command byte length
681        addr: u32,          // Address value
682        addr_bit_len: u16,  // Address byte length
683        tx_data: &'a [u32], // Point to send data buffer
684        tx_data_bit_len: u16,
685        rx_data: &'a mut [u32], // Point to recevie data buffer
686        rx_data_bit_len: u16,
687        dummy_bit_len: u32,
688    }
689
690    const PSRAM_ENTER_QMODE: u32 = 0x35;
691
692    // enter QPI mode
693    #[ram]
694    fn psram_enable_qio_mode_spi1(clk_mode: PsramClkMode, psram_mode: PsramCacheSpeed) {
695        let ps_cmd = PsramCmd {
696            cmd_bit_len: if clk_mode == PsramClkMode::PsramClkModeDclk
697                && psram_mode != PsramCacheSpeed::PsramCacheF80mS80m
698            {
699                2
700            } else {
701                0
702            },
703            cmd: 0,
704            addr: PSRAM_ENTER_QMODE << 24,
705            addr_bit_len: 8,
706            tx_data: &[],
707            tx_data_bit_len: 0,
708            rx_data: &mut [],
709            rx_data_bit_len: 0,
710            dummy_bit_len: 0,
711        };
712
713        let (backup_usr, backup_usr1, backup_usr2) = psram_cmd_config_spi1(&ps_cmd);
714        psram_cmd_recv_start_spi1(&mut [], PsramCmdMode::PsramCmdQpi);
715        psram_cmd_end_spi1(backup_usr, backup_usr1, backup_usr2);
716    }
717
718    #[ram]
719    fn psram_cmd_end_spi1(backup_usr: u32, backup_usr1: u32, backup_usr2: u32) {
720        while SPI1::regs().cmd().read().usr().bit_is_set() {}
721        unsafe {
722            SPI1::regs().user().write(|w| w.bits(backup_usr));
723            SPI1::regs().user1().write(|w| w.bits(backup_usr1));
724            SPI1::regs().user2().write(|w| w.bits(backup_usr2));
725        }
726    }
727
728    // setup spi command/addr/data/dummy in user mode
729    #[ram]
730    fn psram_cmd_config_spi1(cmd: &PsramCmd<'_>) -> (u32, u32, u32) {
731        debug_assert_eq!(cmd.tx_data.len(), cmd.tx_data_bit_len.div_ceil(32) as usize);
732        debug_assert_eq!(cmd.rx_data.len(), cmd.rx_data_bit_len.div_ceil(32) as usize);
733        debug_assert!(cmd.tx_data_bit_len <= 64);
734        debug_assert!(cmd.rx_data_bit_len <= 64);
735
736        while SPI1::regs().cmd().read().usr().bit_is_set() {}
737
738        let backup_usr = SPI1::regs().user().read().bits();
739        let backup_usr1 = SPI1::regs().user1().read().bits();
740        let backup_usr2 = SPI1::regs().user2().read().bits();
741
742        // Set command by user.
743        //
744        SPI1::regs().user().modify(|_, w| {
745            w.usr_command().bit(cmd.cmd_bit_len != 0);
746            w.usr_addr().bit(cmd.addr_bit_len != 0);
747            w.usr_mosi().bit(cmd.tx_data_bit_len != 0);
748            w.usr_miso().bit(cmd.rx_data_bit_len != 0);
749            w.usr_dummy().bit(cmd.dummy_bit_len != 0)
750        });
751        SPI1::regs().user1().modify(|_, w| unsafe {
752            w.usr_addr_bitlen()
753                .bits(cmd.addr_bit_len.saturating_sub(1) as u8);
754            w.usr_dummy_cyclelen()
755                .bits(cmd.dummy_bit_len.saturating_sub(1) as u8)
756        });
757        SPI1::regs().user2().modify(|_, w| unsafe {
758            w.usr_command_value().bits(cmd.cmd);
759            w.usr_command_bitlen()
760                .bits(cmd.cmd_bit_len.saturating_sub(1) as u8)
761        });
762
763        // Set data send buffer length. Max data length 64 bytes.
764        SPI1::regs().mosi_dlen().write(|w| unsafe {
765            w.usr_mosi_dbitlen()
766                .bits(cmd.tx_data_bit_len.saturating_sub(1) as u32)
767        });
768
769        // Set data send buffer length. Max data length 64 bytes.
770        SPI1::regs().miso_dlen().write(|w| unsafe {
771            w.usr_miso_dbitlen()
772                .bits(cmd.rx_data_bit_len.saturating_sub(1) as u32)
773        });
774
775        // Set address.
776        if cmd.addr_bit_len != 0 {
777            SPI1::regs().addr().write(|w| unsafe { w.bits(cmd.addr) });
778        }
779
780        // Load TX data.
781        for (i, tx) in cmd.tx_data.iter().enumerate() {
782            SPI1::regs().w(i).write(|w| unsafe { w.bits(*tx) });
783        }
784
785        (backup_usr, backup_usr1, backup_usr2)
786    }
787
788    #[derive(Debug, Clone, Copy, PartialEq)]
789    enum PsramCmdMode {
790        PsramCmdQpi,
791        #[expect(unused)]
792        PsramCmdSpi,
793    }
794
795    // start sending cmd/addr and optionally, receiving data
796    #[ram]
797    fn psram_cmd_recv_start_spi1(rx_data: &mut [u32], cmd_mode: PsramCmdMode) {
798        // get cs1
799        SPI1::regs().pin().modify(|_, w| {
800            w.cs1_dis().clear_bit();
801            w.cs0_dis().set_bit()
802        });
803
804        let mode_backup: u32 = (SPI1::regs().user().read().bits() >> SPI_FWRITE_DUAL_S) & 0xf;
805        let rd_mode_backup: u32 = SPI1::regs().ctrl().read().bits()
806            & (SPI_FREAD_DIO_M | SPI_FREAD_DUAL_M | SPI_FREAD_QUAD_M | SPI_FREAD_QIO_M);
807
808        match cmd_mode {
809            PsramCmdMode::PsramCmdSpi => {
810                psram_set_basic_write_mode_spi1();
811                psram_set_basic_read_mode_spi1();
812            }
813            PsramCmdMode::PsramCmdQpi => {
814                psram_set_qio_write_mode_spi1();
815                psram_set_qio_read_mode_spi1();
816            }
817        }
818
819        // Wait for **SPI0** to idle
820        while SPI0::regs().ext2().read().bits() != 0 {}
821
822        // DPORT_SET_PERI_REG_MASK(DPORT_HOST_INF_SEL_REG, 1 << 14);
823        DPORT::regs()
824            .host_inf_sel()
825            .modify(|r, w| unsafe { w.bits(r.bits() | (1 << 14)) });
826
827        // Start send data
828        SPI1::regs().cmd().modify(|_, w| w.usr().set_bit());
829        while SPI1::regs().cmd().read().usr().bit_is_set() {}
830
831        // DPORT_CLEAR_PERI_REG_MASK(DPORT_HOST_INF_SEL_REG, 1 << 14);
832        DPORT::regs()
833            .host_inf_sel()
834            .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << 14)) });
835
836        // recover spi mode
837        SPI1::regs().user().modify(|r, w| unsafe {
838            let bits = r.bits();
839
840            // TODO: mirrors esp-idf, but looks like a bug
841            let bit_map = if !rx_data.is_empty() {
842                SPI_FWRITE_DUAL_M
843            } else {
844                0xf
845            };
846            let shift = SPI_FWRITE_DUAL_S;
847
848            w.bits((bits & (!bit_map << shift)) | (mode_backup & bit_map) << shift)
849        });
850
851        SPI1::regs().ctrl().modify(|_, w| {
852            w.fread_dio().clear_bit();
853            w.fread_dual().clear_bit();
854            w.fread_quad().clear_bit();
855            w.fread_qio().clear_bit()
856        });
857
858        SPI1::regs()
859            .ctrl()
860            .modify(|r, w| unsafe { w.bits(r.bits() | rd_mode_backup) });
861
862        // return cs to cs0
863        SPI1::regs().pin().modify(|_, w| {
864            w.cs1_dis().set_bit();
865            w.cs0_dis().clear_bit()
866        });
867
868        // Read data out
869        for (i, rx) in rx_data.iter_mut().enumerate() {
870            *rx = SPI1::regs().w(i).read().bits();
871        }
872    }
873
874    // set basic SPI write mode
875    fn psram_set_basic_write_mode_spi1() {
876        SPI1::regs().user().modify(|_, w| {
877            w.fwrite_qio().clear_bit();
878            w.fwrite_dio().clear_bit();
879            w.fwrite_quad().clear_bit();
880            w.fwrite_dual().clear_bit()
881        });
882    }
883
884    // set QPI write mode
885    fn psram_set_qio_write_mode_spi1() {
886        SPI1::regs().user().modify(|_, w| {
887            w.fwrite_qio().set_bit();
888            w.fwrite_dio().clear_bit();
889            w.fwrite_quad().clear_bit();
890            w.fwrite_dual().clear_bit()
891        });
892    }
893
894    // set QPI read mode
895    fn psram_set_qio_read_mode_spi1() {
896        SPI1::regs().ctrl().modify(|_, w| {
897            w.fread_qio().set_bit();
898            w.fread_quad().clear_bit();
899            w.fread_dual().clear_bit();
900            w.fread_dio().clear_bit()
901        });
902    }
903
904    // set SPI read mode
905    fn psram_set_basic_read_mode_spi1() {
906        SPI1::regs().ctrl().modify(|_, w| {
907            w.fread_qio().clear_bit();
908            w.fread_quad().clear_bit();
909            w.fread_dual().clear_bit();
910            w.fread_dio().clear_bit()
911        });
912    }
913
914    // psram gpio init , different working frequency we have different solutions
915    fn psram_gpio_config(psram_io: &PsramIo, mode: PsramCacheSpeed) -> u32 {
916        unsafe {
917            let g_rom_spiflash_dummy_len_plus_ptr = &raw mut g_rom_spiflash_dummy_len_plus;
918
919            #[derive(Debug, Clone, Copy)]
920            enum Field {
921                McuSel,
922                FunDrv,
923            }
924
925            macro_rules! apply_to_field {
926                ($w:ident, $field:expr, $bits:expr) => {
927                    match $field {
928                        Field::McuSel => $w.mcu_sel().bits($bits),
929                        Field::FunDrv => $w.fun_drv().bits($bits),
930                    }
931                };
932            }
933
934            fn configure_gpio(gpio: u8, field: Field, bits: u8) {
935                unsafe {
936                    let ptr = crate::gpio::io_mux_reg(gpio);
937
938                    ptr.modify(|_, w| apply_to_field!(w, field, bits));
939                }
940            }
941
942            let rd_mode_reg = SPI0::regs().ctrl().read();
943            let spi_cache_dummy = if rd_mode_reg.fread_qio().bit_is_set() {
944                SPI0_R_QIO_DUMMY_CYCLELEN
945            } else if rd_mode_reg.fread_dio().bit_is_set() {
946                SPI0::regs()
947                    .user1()
948                    .modify(|_, w| w.usr_addr_bitlen().bits(SPI0_R_DIO_ADDR_BITSLEN as u8));
949                SPI0_R_DIO_DUMMY_CYCLELEN
950            } else {
951                SPI0_R_FAST_DUMMY_CYCLELEN
952            };
953
954            let extra_dummy;
955
956            match mode {
957                PsramCacheSpeed::PsramCacheF80mS40m => {
958                    extra_dummy = PSRAM_IO_MATRIX_DUMMY_40M;
959
960                    g_rom_spiflash_dummy_len_plus_ptr
961                        .offset(_SPI_CACHE_PORT as isize)
962                        .write_volatile(PSRAM_IO_MATRIX_DUMMY_80M);
963                    g_rom_spiflash_dummy_len_plus_ptr
964                        .offset(_SPI_FLASH_PORT as isize)
965                        .write_volatile(PSRAM_IO_MATRIX_DUMMY_40M);
966
967                    SPI0::regs().user1().modify(|_, w| {
968                        w.usr_dummy_cyclelen()
969                            .bits(spi_cache_dummy as u8 + PSRAM_IO_MATRIX_DUMMY_80M)
970                    }); // DUMMY
971
972                    esp_rom_spiflash_config_clk(_SPI_80M_CLK_DIV, _SPI_CACHE_PORT);
973                    esp_rom_spiflash_config_clk(_SPI_40M_CLK_DIV, _SPI_FLASH_PORT);
974
975                    // set drive ability for clock
976
977                    configure_gpio(psram_io.flash_clk_io, Field::FunDrv, 3);
978                    configure_gpio(psram_io.psram_clk_io, Field::FunDrv, 2);
979                }
980                PsramCacheSpeed::PsramCacheF80mS80m => {
981                    extra_dummy = PSRAM_IO_MATRIX_DUMMY_80M;
982                    g_rom_spiflash_dummy_len_plus_ptr
983                        .offset(_SPI_CACHE_PORT as isize)
984                        .write_volatile(PSRAM_IO_MATRIX_DUMMY_80M);
985                    g_rom_spiflash_dummy_len_plus_ptr
986                        .offset(_SPI_FLASH_PORT as isize)
987                        .write_volatile(PSRAM_IO_MATRIX_DUMMY_80M);
988
989                    SPI0::regs().user1().modify(|_, w| {
990                        w.usr_dummy_cyclelen()
991                            .bits(spi_cache_dummy as u8 + PSRAM_IO_MATRIX_DUMMY_80M)
992                    }); // DUMMY
993
994                    esp_rom_spiflash_config_clk(_SPI_80M_CLK_DIV, _SPI_CACHE_PORT);
995                    esp_rom_spiflash_config_clk(_SPI_80M_CLK_DIV, _SPI_FLASH_PORT);
996
997                    // set drive ability for clock
998                    configure_gpio(psram_io.flash_clk_io, Field::FunDrv, 3);
999                    configure_gpio(psram_io.psram_clk_io, Field::FunDrv, 3);
1000                }
1001                PsramCacheSpeed::PsramCacheF40mS40m => {
1002                    extra_dummy = PSRAM_IO_MATRIX_DUMMY_40M;
1003
1004                    g_rom_spiflash_dummy_len_plus_ptr
1005                        .offset(_SPI_CACHE_PORT as isize)
1006                        .write_volatile(PSRAM_IO_MATRIX_DUMMY_40M);
1007                    g_rom_spiflash_dummy_len_plus_ptr
1008                        .offset(_SPI_FLASH_PORT as isize)
1009                        .write_volatile(PSRAM_IO_MATRIX_DUMMY_40M);
1010
1011                    SPI0::regs().user1().modify(|_, w| {
1012                        w.usr_dummy_cyclelen()
1013                            .bits(spi_cache_dummy as u8 + PSRAM_IO_MATRIX_DUMMY_40M)
1014                    }); // DUMMY
1015
1016                    esp_rom_spiflash_config_clk(_SPI_40M_CLK_DIV, _SPI_CACHE_PORT);
1017                    esp_rom_spiflash_config_clk(_SPI_40M_CLK_DIV, _SPI_FLASH_PORT);
1018
1019                    // set drive ability for clock
1020                    configure_gpio(psram_io.flash_clk_io, Field::FunDrv, 2);
1021                    configure_gpio(psram_io.psram_clk_io, Field::FunDrv, 2);
1022                }
1023            }
1024
1025            SPI0::regs().user().modify(|_, w| w.usr_dummy().set_bit()); // dummy enable
1026
1027            // In bootloader, all the signals are already configured,
1028            // We keep the following code in case the bootloader is some older version.
1029
1030            esp_rom_gpio_connect_out_signal(
1031                psram_io.flash_cs_io as u32,
1032                SPICS0_OUT_IDX,
1033                false,
1034                false,
1035            );
1036            esp_rom_gpio_connect_out_signal(
1037                psram_io.psram_cs_io as u32,
1038                SPICS1_OUT_IDX,
1039                false,
1040                false,
1041            );
1042            esp_rom_gpio_connect_out_signal(
1043                psram_io.psram_spiq_sd0_io as u32,
1044                SPIQ_OUT_IDX,
1045                false,
1046                false,
1047            );
1048            esp_rom_gpio_connect_in_signal(psram_io.psram_spiq_sd0_io as u32, SPIQ_IN_IDX, false);
1049            esp_rom_gpio_connect_out_signal(
1050                psram_io.psram_spid_sd1_io as u32,
1051                SPID_OUT_IDX,
1052                false,
1053                false,
1054            );
1055            esp_rom_gpio_connect_in_signal(psram_io.psram_spid_sd1_io as u32, SPID_IN_IDX, false);
1056            esp_rom_gpio_connect_out_signal(
1057                psram_io.psram_spiwp_sd3_io as u32,
1058                SPIWP_OUT_IDX,
1059                false,
1060                false,
1061            );
1062            esp_rom_gpio_connect_in_signal(psram_io.psram_spiwp_sd3_io as u32, SPIWP_IN_IDX, false);
1063            esp_rom_gpio_connect_out_signal(
1064                psram_io.psram_spihd_sd2_io as u32,
1065                SPIHD_OUT_IDX,
1066                false,
1067                false,
1068            );
1069            esp_rom_gpio_connect_in_signal(psram_io.psram_spihd_sd2_io as u32, SPIHD_IN_IDX, false);
1070
1071            // select pin function gpio
1072            if (psram_io.flash_clk_io == SPI_IOMUX_PIN_NUM_CLK)
1073                && (psram_io.flash_clk_io != psram_io.psram_clk_io)
1074            {
1075                // flash clock signal should come from IO MUX.
1076                configure_gpio(
1077                    psram_io.flash_clk_io,
1078                    Field::McuSel,
1079                    FUNC_SD_CLK_SPICLK as u8,
1080                );
1081            } else {
1082                // flash clock signal should come from GPIO matrix.
1083                configure_gpio(psram_io.flash_clk_io, Field::McuSel, PIN_FUNC_GPIO as u8);
1084            }
1085            configure_gpio(psram_io.flash_cs_io, Field::McuSel, PIN_FUNC_GPIO as u8);
1086            configure_gpio(psram_io.psram_cs_io, Field::McuSel, PIN_FUNC_GPIO as u8);
1087            configure_gpio(psram_io.psram_clk_io, Field::McuSel, PIN_FUNC_GPIO as u8);
1088            configure_gpio(
1089                psram_io.psram_spiq_sd0_io,
1090                Field::McuSel,
1091                PIN_FUNC_GPIO as u8,
1092            );
1093            configure_gpio(
1094                psram_io.psram_spid_sd1_io,
1095                Field::McuSel,
1096                PIN_FUNC_GPIO as u8,
1097            );
1098            configure_gpio(
1099                psram_io.psram_spihd_sd2_io,
1100                Field::McuSel,
1101                PIN_FUNC_GPIO as u8,
1102            );
1103            configure_gpio(
1104                psram_io.psram_spiwp_sd3_io,
1105                Field::McuSel,
1106                PIN_FUNC_GPIO as u8,
1107            );
1108
1109            let flash_id: u32 = g_rom_flashchip.device_id;
1110            info!("Flash-ID = {}", flash_id);
1111            info!("Flash size = {}", g_rom_flashchip.chip_size);
1112
1113            if flash_id == FLASH_ID_GD25LQ32C {
1114                // Set drive ability for 1.8v flash in 80Mhz.
1115                configure_gpio(psram_io.flash_cs_io, Field::FunDrv, 3);
1116                configure_gpio(psram_io.flash_clk_io, Field::FunDrv, 3);
1117                configure_gpio(psram_io.psram_cs_io, Field::FunDrv, 3);
1118                configure_gpio(psram_io.psram_clk_io, Field::FunDrv, 3);
1119                configure_gpio(psram_io.psram_spiq_sd0_io, Field::FunDrv, 3);
1120                configure_gpio(psram_io.psram_spid_sd1_io, Field::FunDrv, 3);
1121                configure_gpio(psram_io.psram_spihd_sd2_io, Field::FunDrv, 3);
1122                configure_gpio(psram_io.psram_spiwp_sd3_io, Field::FunDrv, 3);
1123            }
1124
1125            extra_dummy as u32
1126        }
1127    }
1128}