diff --git a/components/bootloader/src/main/bootloader_start.c b/components/bootloader/src/main/bootloader_start.c index 536077af4f..28446c2647 100644 --- a/components/bootloader/src/main/bootloader_start.c +++ b/components/bootloader/src/main/bootloader_start.c @@ -19,6 +19,7 @@ #include "esp_log.h" #include "rom/cache.h" +#include "rom/efuse.h" #include "rom/ets_sys.h" #include "rom/spi_flash.h" #include "rom/crc.h" @@ -258,6 +259,15 @@ void bootloader_main() /* disable watch dog here */ REG_CLR_BIT( RTC_CNTL_WDTCONFIG0_REG, RTC_CNTL_WDT_FLASHBOOT_MOD_EN ); REG_CLR_BIT( TIMG_WDTCONFIG0_REG(0), TIMG_WDT_FLASHBOOT_MOD_EN ); + +#ifndef CONFIG_SPI_FLASH_ROM_DRIVER_PATCH + const uint32_t spiconfig = ets_efuse_get_spiconfig(); + if(spiconfig != EFUSE_SPICONFIG_SPI_DEFAULTS && spiconfig != EFUSE_SPICONFIG_HSPI_DEFAULTS) { + ESP_LOGE(TAG, "SPI flash pins are overridden. \"Enable SPI flash ROM driver patched functions\" must be enabled in menuconfig"); + return; + } +#endif + esp_rom_spiflash_unlock(); ESP_LOGI(TAG, "Enabling RNG early entropy source..."); diff --git a/components/bootloader/src/main/flash_qio_mode.c b/components/bootloader/src/main/flash_qio_mode.c index 55c618654b..cd288290cb 100644 --- a/components/bootloader/src/main/flash_qio_mode.c +++ b/components/bootloader/src/main/flash_qio_mode.c @@ -16,7 +16,9 @@ #include "flash_qio_mode.h" #include "esp_log.h" #include "rom/spi_flash.h" +#include "rom/efuse.h" #include "soc/spi_struct.h" +#include "soc/efuse_reg.h" #include "sdkconfig.h" /* SPI flash controller */ @@ -33,6 +35,9 @@ #define CMD_RDSR 0x05 #define CMD_RDSR2 0x35 /* Not all SPI flash uses this command */ + +#define ESP32_D2WD_WP_GPIO 7 /* ESP32-D2WD has this GPIO wired to WP pin of flash */ + static const char *TAG = "qio_mode"; typedef unsigned (*read_status_fn_t)(); @@ -77,7 +82,7 @@ static void write_status_16b_wrsr(unsigned new_status); const static qio_info_t chip_data[] = { /* Manufacturer, mfg_id, flash_id, id mask, Read Status, Write Status, QIE Bit */ { "MXIC", 0xC2, 0x2000, 0xFF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 }, - { "ISSI", 0x9D, 0x4000, 0xFF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 }, + { "ISSI", 0x9D, 0x4000, 0xCF00, read_status_8b_rdsr, write_status_8b_wrsr, 6 }, /* IDs 0x40xx, 0x70xx */ { "WinBond", 0xEF, 0x4000, 0xFF00, read_status_16b_rdsr_rdsr2, write_status_16b_wrsr, 9 }, /* Final entry is default entry, if no other IDs have matched. @@ -102,6 +107,9 @@ static void enable_qio_mode(read_status_fn_t read_status_fn, */ static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len); +/* dummy_len_plus values defined in ROM for SPI flash configuration */ +extern uint8_t g_rom_spiflash_dummy_len_plus[]; + void bootloader_enable_qio_mode(void) { uint32_t raw_flash_id; @@ -149,6 +157,20 @@ static void enable_qio_mode(read_status_fn_t read_status_fn, uint8_t status_qio_bit) { uint32_t status; + const uint32_t spiconfig = ets_efuse_get_spiconfig(); + + if (spiconfig != EFUSE_SPICONFIG_SPI_DEFAULTS && spiconfig != EFUSE_SPICONFIG_HSPI_DEFAULTS) { + // spiconfig specifies a custom efuse pin configuration. This config defines all pins -except- WP. + // + // For now, in this situation we only support Quad I/O mode for ESP32-D2WD where WP pin is known. + uint32_t chip_ver = REG_GET_FIELD(EFUSE_BLK0_RDATA3_REG, EFUSE_RD_CHIP_VER_RESERVE); + uint32_t pkg_ver = chip_ver & 0x7; + const uint32_t PKG_VER_ESP32_D2WD = 2; // TODO: use chip detection API once available + if (pkg_ver != PKG_VER_ESP32_D2WD) { + ESP_LOGE(TAG, "Quad I/O is only supported for standard pin numbers or ESP32-D2WD. Falling back to Dual I/O."); + return; + } + } esp_rom_spiflash_wait_idle(&g_rom_flashchip); @@ -180,8 +202,10 @@ static void enable_qio_mode(read_status_fn_t read_status_fn, #else mode = ESP_ROM_SPIFLASH_QIO_MODE; #endif + esp_rom_spiflash_config_readmode(mode); + esp_rom_spiflash_select_qio_pins(ESP32_D2WD_WP_GPIO, spiconfig); } static unsigned read_status_8b_rdsr() @@ -223,6 +247,17 @@ static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8 SPIFLASH.mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0; SPIFLASH.data_buf[0] = mosi_data; + if (g_rom_spiflash_dummy_len_plus[1]) { + /* When flash pins are mapped via GPIO matrix, need a dummy cycle before reading via MISO */ + if (miso_len > 0) { + SPIFLASH.user.usr_dummy = 1; + SPIFLASH.user1.usr_dummy_cyclelen = g_rom_spiflash_dummy_len_plus[1] - 1; + } else { + SPIFLASH.user.usr_dummy = 0; + SPIFLASH.user1.usr_dummy_cyclelen = 0; + } + } + SPIFLASH.cmd.usr = 1; while(SPIFLASH.cmd.usr != 0) { } diff --git a/components/esp32/include/rom/efuse.h b/components/esp32/include/rom/efuse.h index 58cfdb20bc..337227ab0d 100644 --- a/components/esp32/include/rom/efuse.h +++ b/components/esp32/include/rom/efuse.h @@ -60,15 +60,20 @@ void ets_efuse_program_op(void); uint32_t ets_efuse_get_8M_clock(void); /** - * @brief Read spi pad configuration, show gpio number of flash pad, includes 5 pads. + * @brief Read spi flash pin configuration from Efuse * - * @param null - * - * @return uint32_t: 0, invalid, flash pad decided by strapping - * else, bit[5:0] spiclk, bit[11:6] spiq, bit[17:12] spid, bit[23:18] spics0, bit[29:24] spihd + * @return + * - 0 for default SPI pins. + * - 1 for default HSPI pins. + * - Other values define a custom pin configuration mask. Pins are encoded as per the EFUSE_SPICONFIG_RET_SPICLK, + * EFUSE_SPICONFIG_RET_SPIQ, EFUSE_SPICONFIG_RET_SPID, EFUSE_SPICONFIG_RET_SPICS0, EFUSE_SPICONFIG_RET_SPIHD macros. + * WP pin (for quad I/O modes) is not saved in efuse and not returned by this function. */ uint32_t ets_efuse_get_spiconfig(void); +#define EFUSE_SPICONFIG_SPI_DEFAULTS 0 +#define EFUSE_SPICONFIG_HSPI_DEFAULTS 1 + #define EFUSE_SPICONFIG_RET_SPICLK_MASK 0x3f #define EFUSE_SPICONFIG_RET_SPICLK_SHIFT 0 #define EFUSE_SPICONFIG_RET_SPICLK(ret) (((ret) >> EFUSE_SPICONFIG_RET_SPICLK_SHIFT) & EFUSE_SPICONFIG_RET_SPICLK_MASK) diff --git a/components/esp32/include/rom/spi_flash.h b/components/esp32/include/rom/spi_flash.h index 97efccc368..35d010d797 100644 --- a/components/esp32/include/rom/spi_flash.h +++ b/components/esp32/include/rom/spi_flash.h @@ -512,6 +512,24 @@ esp_rom_spiflash_result_t esp_rom_spiflash_write_encrypted(uint32_t flash_addr, esp_rom_spiflash_result_t esp_rom_spiflash_wait_idle(esp_rom_spiflash_chip_t *spi); +/** @brief Enable Quad I/O pin functions + * + * @note Please do not call this function in SDK. + * + * Sets the HD & WP pin functions for Quad I/O modes, based on the + * efuse SPI pin configuration. + * + * @param wp_gpio_num - Number of the WP pin to reconfigure for quad I/O. + * + * @param spiconfig - Pin configuration, as returned from ets_efuse_get_spiconfig(). + * - If this parameter is 0, default SPI pins are used and wp_gpio_num parameter is ignored. + * - If this parameter is 1, default HSPI pins are used and wp_gpio_num parameter is ignored. + * - For other values, this parameter encodes the HD pin number and also the CLK pin number. CLK pin selection is used + * to determine if HSPI or SPI peripheral will be used (use HSPI if CLK pin is the HSPI clock pin, otherwise use SPI). + * Both HD & WP pins are configured via GPIO matrix to map to the selected peripheral. + */ +void esp_rom_spiflash_select_qio_pins(uint8_t wp_gpio_num, uint32_t spiconfig); + /** @brief Global esp_rom_spiflash_chip_t structure used by ROM functions * */ diff --git a/components/esp32/ld/esp32.rom.ld b/components/esp32/ld/esp32.rom.ld index 6529e31dfa..3b81f2cecf 100644 --- a/components/esp32/ld/esp32.rom.ld +++ b/components/esp32/ld/esp32.rom.ld @@ -1537,6 +1537,7 @@ PROVIDE ( esp_rom_spiflash_read_user_cmd = 0x400621b0 ); PROVIDE ( esp_rom_spiflash_write_encrypted_disable = 0x40062e60 ); PROVIDE ( esp_rom_spiflash_write_encrypted_enable = 0x40062df4 ); PROVIDE ( esp_rom_spiflash_prepare_encrypted_data = 0x40062e1c ); +PROVIDE ( esp_rom_spiflash_select_qio_pins = 0x40061ddc ); PROVIDE ( g_rom_spiflash_chip = 0x3ffae270 ); /*