spi_flash: move the unlock patch to bootloader and add support for GD (backport v4.0)

This commit is contained in:
Cao Sen Miao 2021-09-18 04:28:03 +08:00 committed by zhaokeke
parent 6b79d1c206
commit 04a730c80c
5 changed files with 98 additions and 2 deletions

View File

@ -17,6 +17,8 @@
extern "C" {
#endif
#include "esp_err.h"
/** @brief Enable Quad I/O mode in bootloader (if configured)
*
* Queries attached SPI flash ID and sends correct SPI flash
@ -32,6 +34,14 @@ void bootloader_enable_qio_mode(void);
*/
uint32_t bootloader_read_flash_id();
/**
* @brief Unlock Flash write protect.
* Please do not call this function in SDK.
*
* @note This can be overridden because it's attribute weak.
*/
esp_err_t bootloader_flash_unlock(void);
/**
* @brief Read the SFDP of the flash
*

View File

@ -17,6 +17,7 @@
#include <esp_log.h>
#include <esp_spi_flash.h> /* including in bootloader for error values */
#include <esp_flash_encrypt.h>
#include "flash_qio_mode.h"
#ifndef BOOTLOADER_BUILD
/* Normal app version maps to esp_spi_flash.h operations...
@ -249,7 +250,7 @@ esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool
return ESP_FAIL;
}
err = spi_to_esp_err(esp_rom_spiflash_unlock());
err = bootloader_flash_unlock();
if (err != ESP_OK) {
return err;
}

View File

@ -183,7 +183,7 @@ static esp_err_t bootloader_main()
}
#endif
esp_rom_spiflash_unlock();
bootloader_flash_unlock();
ESP_LOGI(TAG, "Enabling RNG early entropy source...");
bootloader_random_enable();

View File

@ -41,7 +41,16 @@
#define CMD_RDSFDP 0x5A /* Read the SFDP of the flash */
#define BYTESHIFT(VAR, IDX) (((VAR) >> ((IDX) * 8)) & 0xFF)
#define ISSI_ID 0x9D
#define GD_Q_ID_HIGH 0xC8
#define GD_Q_ID_MID 0x40
#define GD_Q_ID_LOW 0x16
#define ESP_BOOTLOADER_SPIFLASH_BP_MASK_ISSI (BIT7 | BIT5 | BIT4 | BIT3 | BIT2)
#define ESP_BOOTLOADER_SPIFLASH_QE_16B BIT9 // QE position when you write 16 bits at one time.
#define ESP_BOOTLOADER_SPIFLASH_QE_8B BIT1 // QE position when you write 8 bits(for SR2) at one time.
#define ESP_BOOTLOADER_SPIFLASH_WRITE_8B (8)
#define ESP_BOOTLOADER_SPIFLASH_WRITE_16B (16)
static DRAM_ATTR char TAG[] = "qio_mode";
@ -462,3 +471,77 @@ esp_err_t IRAM_ATTR bootloader_flash_xmc_startup(void)
#endif //XMC_SUPPORT
static inline IRAM_ATTR bool is_issi_chip(const esp_rom_spiflash_chip_t* chip)
{
return BYTESHIFT(chip->device_id, 2) == ISSI_ID;
}
// For GD25Q32, GD25Q64, GD25Q127C, GD25Q128, which use single command to read/write different SR.
static inline IRAM_ATTR bool is_gd_q_chip(const esp_rom_spiflash_chip_t* chip)
{
return BYTESHIFT(chip->device_id, 2) == GD_Q_ID_HIGH && BYTESHIFT(chip->device_id, 1) == GD_Q_ID_MID && BYTESHIFT(chip->device_id, 0) >= GD_Q_ID_LOW;
}
esp_err_t IRAM_ATTR __attribute__((weak)) bootloader_flash_unlock(void)
{
uint16_t status = 0; // status for SR1 or SR1+SR2 if writing SR with 01H + 2Bytes.
uint16_t new_status = 0;
uint8_t status_sr2 = 0; // status_sr2 for SR2.
uint8_t new_status_sr2 = 0;
uint8_t write_sr_bit = 0;
esp_err_t err = ESP_OK;
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
if (is_issi_chip(&g_rom_flashchip)) {
write_sr_bit = ESP_BOOTLOADER_SPIFLASH_WRITE_8B;
// ISSI chips have different QE position
status = execute_flash_command(CMD_RDSR, 0, 0, 8);
/* 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_BOOTLOADER_SPIFLASH_BP_MASK_ISSI);
// Skip if nothing needs to be cleared. Otherwise will waste time waiting for the flash to clear nothing.
} else if (is_gd_q_chip(&g_rom_flashchip)) {
/* The GD chips behaviour is to clear all bits in SR1 and clear bits in SR2 except QE bit.
Use 01H to write SR1 and 31H to write SR2.
*/
write_sr_bit = ESP_BOOTLOADER_SPIFLASH_WRITE_8B;
status = execute_flash_command(CMD_RDSR, 0, 0, 8);
new_status = 0;
status_sr2 = execute_flash_command(CMD_RDSR2, 0, 0, 8);
new_status_sr2 = status_sr2 & ESP_BOOTLOADER_SPIFLASH_QE_8B;
} else {
/* For common behaviour, like XMC chips, Use 01H+2Bytes to write both SR1 and SR2*/
write_sr_bit = ESP_BOOTLOADER_SPIFLASH_WRITE_16B;
status = execute_flash_command(CMD_RDSR, 0, 0, 8) | (execute_flash_command(CMD_RDSR2, 0, 0, 8) << 8);
/* 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_BOOTLOADER_SPIFLASH_QE_16B;
}
if (status != new_status) {
/* if the status in SR not equal to the ideal status, the status need to be updated */
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
execute_flash_command(CMD_WREN, 0, 0, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
execute_flash_command(CMD_WRSR, new_status, write_sr_bit, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
}
if (status_sr2 != new_status_sr2) {
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
execute_flash_command(CMD_WREN, 0, 0, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
execute_flash_command(CMD_WRSR2, new_status_sr2, write_sr_bit, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
}
execute_flash_command(CMD_WRDI, 0, 0, 0);
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
return err;
}

View File

@ -88,6 +88,7 @@ static void do_global_ctors(void);
static void main_task(void* args);
extern void app_main(void);
extern esp_err_t esp_pthread_init(void);
extern esp_err_t bootloader_flash_unlock(void);
extern int _bss_start;
extern int _bss_end;
@ -458,6 +459,7 @@ void start_cpu0_default(void)
#endif
bootloader_flash_update_id();
bootloader_flash_unlock();
#if !CONFIG_SPIRAM_BOOT_INIT
// If psram is uninitialized, we need to improve some flash configuration.
bootloader_flash_clock_config(&fhdr);