esp_hal/psram/
esp32.rs

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