diff --git a/components/bootloader_support/src/flash_qio_mode.c b/components/bootloader_support/src/flash_qio_mode.c index db486c73e3..431c395eb6 100644 --- a/components/bootloader_support/src/flash_qio_mode.c +++ b/components/bootloader_support/src/flash_qio_mode.c @@ -66,10 +66,10 @@ static void write_status_8b_wrsr2(unsigned new_status); /* Write 16 bit status using WRSR */ static void write_status_16b_wrsr(unsigned new_status); -/* Read 8 bit status of XM25QU64A */ -static unsigned read_status_8b_xmc25qu64a(); -/* Write 8 bit status of XM25QU64A */ -static void write_status_8b_xmc25qu64a(unsigned new_status); +/* Read 8 bit status using RDSR command in otp mode */ +static unsigned read_status_8b_rdsr_otp(void); +/* Write 8 bit status using WRSR command in otp mode */ +static void write_status_8b_wrsr_otp(unsigned new_status); #define ESP32_D2WD_WP_GPIO 7 /* ESP32-D2WD has this GPIO wired to WP pin of flash */ @@ -95,7 +95,8 @@ const static qio_info_t chip_data[] = { { "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 }, { "GD", 0xC8, 0x6000, 0xFF00, read_status_16b_rdsr_rdsr2, write_status_16b_wrsr, 9 }, - { "XM25QU64A", 0x20, 0x3817, 0xFFFF, read_status_8b_xmc25qu64a, write_status_8b_xmc25qu64a, 6 }, + { "XM25QU64A", 0x20, 0x3817, 0xFFFF, read_status_8b_rdsr_otp, write_status_8b_wrsr_otp, 6 }, + { "EON", 0x1C, 0x7000, 0xFF00, read_status_8b_rdsr_otp, write_status_8b_wrsr_otp, 6 }, /* EN25QH sereils: IDs 0x70xx */ /* Final entry is default entry, if no other IDs have matched. @@ -253,7 +254,7 @@ static void write_status_16b_wrsr(unsigned new_status) execute_flash_command(CMD_WRSR, new_status, 16, 0); } -static unsigned read_status_8b_xmc25qu64a() +static unsigned read_status_8b_rdsr_otp(void) { execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */ esp_rom_spiflash_wait_idle(&g_rom_flashchip); @@ -262,7 +263,7 @@ static unsigned read_status_8b_xmc25qu64a() return read_status; } -static void write_status_8b_xmc25qu64a(unsigned new_status) +static void write_status_8b_wrsr_otp(unsigned new_status) { execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */ esp_rom_spiflash_wait_idle(&g_rom_flashchip); diff --git a/components/esp_rom/include/esp32/rom/spi_flash.h b/components/esp_rom/include/esp32/rom/spi_flash.h index b78a6130aa..4534afee7c 100644 --- a/components/esp_rom/include/esp32/rom/spi_flash.h +++ b/components/esp_rom/include/esp32/rom/spi_flash.h @@ -121,6 +121,7 @@ extern "C" { #define ESP_ROM_SPIFLASH_BP2 BIT4 #define ESP_ROM_SPIFLASH_WR_PROTECT (ESP_ROM_SPIFLASH_BP0|ESP_ROM_SPIFLASH_BP1|ESP_ROM_SPIFLASH_BP2) #define ESP_ROM_SPIFLASH_QE BIT9 +#define ESP_ROM_SPIFLASH_BP_MASK_EON (BIT7 | BIT6 | BIT5 | BIT4 | BIT3 | BIT2) //Extra dummy for flash read #define ESP_ROM_SPIFLASH_DUMMY_LEN_PLUS_20M 0 diff --git a/components/spi_flash/spi_flash_rom_patch.c b/components/spi_flash/spi_flash_rom_patch.c index adf62fa572..a1cf70932d 100644 --- a/components/spi_flash/spi_flash_rom_patch.c +++ b/components/spi_flash/spi_flash_rom_patch.c @@ -24,6 +24,11 @@ extern esp_rom_spiflash_chip_t g_rom_spiflash_chip; +static inline bool is_eon_chip(const esp_rom_spiflash_chip_t* chip) +{ + return ((((chip->device_id >> 16)&0xff)) == 0x1C && (((chip->device_id >> 8)&0xff) == 0x70)); +} + esp_rom_spiflash_result_t esp_rom_spiflash_wait_idle(esp_rom_spiflash_chip_t *spi) { uint32_t status; @@ -53,33 +58,52 @@ esp_rom_spiflash_result_t esp_rom_spiflash_wait_idle(esp_rom_spiflash_chip_t *sp about interrupts, CPU coordination, flash mapping. However some of the functions in esp_spi_flash.c call it. */ -esp_rom_spiflash_result_t esp_rom_spiflash_unlock() +esp_rom_spiflash_result_t esp_rom_spiflash_unlock(void) { uint32_t status; + uint32_t new_status; esp_rom_spiflash_wait_idle(&g_rom_spiflash_chip); - if (esp_rom_spiflash_read_statushigh(&g_rom_spiflash_chip, &status) != ESP_ROM_SPIFLASH_RESULT_OK) { - return ESP_ROM_SPIFLASH_RESULT_ERR; - } + if (is_eon_chip(&g_rom_spiflash_chip)) { + // Eon chips have different QE position - /* Clear all bits except QIE, if it is set. - (This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.) - */ - status &= ESP_ROM_SPIFLASH_QE; + if (esp_rom_spiflash_read_status(&g_rom_spiflash_chip, &status) != ESP_ROM_SPIFLASH_RESULT_OK) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + /* Clear all bits in the mask. + (This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.) + */ + new_status = status & (~ESP_ROM_SPIFLASH_BP_MASK_EON); + // Skip if nothing needs to be cleared. Otherwise will waste time waiting for the flash to clear nothing. + if (new_status == status) return ESP_ROM_SPIFLASH_RESULT_OK; + + CLEAR_PERI_REG_MASK(SPI_CTRL_REG(SPI_IDX), SPI_WRSR_2B); + } else { + if (esp_rom_spiflash_read_statushigh(&g_rom_spiflash_chip, &status) != ESP_ROM_SPIFLASH_RESULT_OK) { + return ESP_ROM_SPIFLASH_RESULT_ERR; + } + + /* Clear all bits except QE, if it is set. + (This is different from ROM esp_rom_spiflash_unlock, which keeps all bits as-is.) + */ + new_status = status & ESP_ROM_SPIFLASH_QE; + SET_PERI_REG_MASK(SPI_CTRL_REG(SPI_IDX), SPI_WRSR_2B); + } esp_rom_spiflash_wait_idle(&g_rom_spiflash_chip); REG_WRITE(SPI_CMD_REG(SPI_IDX), SPI_FLASH_WREN); while (REG_READ(SPI_CMD_REG(SPI_IDX)) != 0) { } esp_rom_spiflash_wait_idle(&g_rom_spiflash_chip); - - SET_PERI_REG_MASK(SPI_CTRL_REG(SPI_IDX), SPI_WRSR_2B); - if (esp_rom_spiflash_write_status(&g_rom_spiflash_chip, status) != ESP_ROM_SPIFLASH_RESULT_OK) { - return ESP_ROM_SPIFLASH_RESULT_ERR; + esp_rom_spiflash_result_t ret = esp_rom_spiflash_write_status(&g_rom_spiflash_chip, new_status); + // WEL bit should be cleared after operations regardless of writing succeed or not. + esp_rom_spiflash_wait_idle(&g_rom_spiflash_chip); + REG_WRITE(SPI_CMD_REG(SPI_IDX), SPI_FLASH_WRDI); + while (REG_READ(SPI_CMD_REG(SPI_IDX)) != 0) { } - - return ESP_ROM_SPIFLASH_RESULT_OK; + return ret; }