mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-07-03 23:48:59 +08:00
Merge branch 'bugfix/xmc_overerase' into 'master'
feat(bootloader): add xmc spi_flash startup flow to improve reliability See merge request sdk/ESP8266_RTOS_SDK!1661
This commit is contained in:
@ -174,6 +174,15 @@ config BOOTLOADER_STORE_OFFSET
|
|||||||
bootloader of the SDK's bootloader, you can set the option to store SDK's bootloader
|
bootloader of the SDK's bootloader, you can set the option to store SDK's bootloader
|
||||||
to other space in the flash instead of "0x0".
|
to other space in the flash instead of "0x0".
|
||||||
|
|
||||||
|
config BOOTLOADER_FLASH_XMC_SUPPORT
|
||||||
|
bool "Enable the support for flash chips of XMC (READ HELP FIRST)"
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Perform the startup flow recommended by XMC. Please consult XMC for the details of this flow.
|
||||||
|
XMC chips will be forbidden to be used, when this option is disabled.
|
||||||
|
|
||||||
|
DON'T DISABLE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.
|
||||||
|
|
||||||
endmenu # Bootloader
|
endmenu # Bootloader
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,3 +9,4 @@ PROVIDE ( gpio_input_get = 0x40004cf0 );
|
|||||||
PROVIDE ( xthal_get_ccount = 0x4000dd38 );
|
PROVIDE ( xthal_get_ccount = 0x4000dd38 );
|
||||||
PROVIDE ( uart_div_modify = 0x400039d8 );
|
PROVIDE ( uart_div_modify = 0x400039d8 );
|
||||||
PROVIDE ( ets_io_vprintf = 0x40001f00 );
|
PROVIDE ( ets_io_vprintf = 0x40001f00 );
|
||||||
|
PROVIDE ( ets_rom_delay_us = 0x40002ecc );
|
@ -22,6 +22,11 @@
|
|||||||
|
|
||||||
#define FLASH_SECTOR_SIZE 0x1000
|
#define FLASH_SECTOR_SIZE 0x1000
|
||||||
|
|
||||||
|
#define CMD_RDSFDP 0x5A /* Read the SFDP of the flash */
|
||||||
|
#define CMD_RDJEDECID 0x9F /* Read the JEDEC ID of the flash */
|
||||||
|
|
||||||
|
#define XMC_VENDOR_ID 0x20
|
||||||
|
|
||||||
/* Provide a Flash API for bootloader_support code,
|
/* Provide a Flash API for bootloader_support code,
|
||||||
that can be used from bootloader or app code.
|
that can be used from bootloader or app code.
|
||||||
|
|
||||||
@ -100,4 +105,20 @@ esp_err_t bootloader_flash_write(size_t dest_addr, void *src, size_t size, bool
|
|||||||
*/
|
*/
|
||||||
esp_err_t bootloader_flash_erase_sector(size_t sector);
|
esp_err_t bootloader_flash_erase_sector(size_t sector);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read the SFDP of the flash
|
||||||
|
*
|
||||||
|
* @param sfdp_addr Address of the parameter to read
|
||||||
|
* @param miso_byte_num Bytes to read
|
||||||
|
* @return The read SFDP, little endian, 4 bytes at most
|
||||||
|
*/
|
||||||
|
uint32_t bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Startup flow recommended by XMC. Call at startup before any erase/write operation.
|
||||||
|
*
|
||||||
|
* @return ESP_OK When startup successfully, otherwise ESP_FAIL (indiciating you should reboot before erase/write).
|
||||||
|
*/
|
||||||
|
esp_err_t bootloader_flash_xmc_startup(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -263,9 +263,13 @@ esp_err_t bootloader_flash_erase_sector(size_t sector)
|
|||||||
|
|
||||||
#include "esp_err.h"
|
#include "esp_err.h"
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "esp8266/rom_functions.h"
|
||||||
|
|
||||||
#ifndef BOOTLOADER_BUILD
|
#ifndef BOOTLOADER_BUILD
|
||||||
#include "esp_spi_flash.h"
|
#include "esp_spi_flash.h"
|
||||||
|
#else
|
||||||
|
#include "bootloader_flash.h"
|
||||||
|
#include "priv/esp_spi_flash_raw.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_SOC_FULL_ICACHE
|
#ifdef CONFIG_SOC_FULL_ICACHE
|
||||||
@ -274,19 +278,12 @@ esp_err_t bootloader_flash_erase_sector(size_t sector)
|
|||||||
#define SOC_CACHE_SIZE 0 // 16KB
|
#define SOC_CACHE_SIZE 0 // 16KB
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern void Cache_Read_Disable();
|
#define XMC_SUPPORT CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT
|
||||||
extern void Cache_Read_Enable(uint8_t map, uint8_t p, uint8_t v);
|
|
||||||
|
#define BYTESHIFT(VAR, IDX) (((VAR) >> ((IDX) * 8)) & 0xFF)
|
||||||
|
|
||||||
static const char *TAG = "bootloader_flash";
|
static const char *TAG = "bootloader_flash";
|
||||||
|
|
||||||
typedef enum { SPI_FLASH_RESULT_OK = 0,
|
|
||||||
SPI_FLASH_RESULT_ERR = 1,
|
|
||||||
SPI_FLASH_RESULT_TIMEOUT = 2 } SpiFlashOpResult;
|
|
||||||
|
|
||||||
SpiFlashOpResult SPIRead(uint32_t addr, void *dst, uint32_t size);
|
|
||||||
SpiFlashOpResult SPIWrite(uint32_t addr, const uint8_t *src, uint32_t size);
|
|
||||||
SpiFlashOpResult SPIEraseSector(uint32_t sector_num);
|
|
||||||
|
|
||||||
static bool mapped;
|
static bool mapped;
|
||||||
|
|
||||||
const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
|
const void *bootloader_mmap(uint32_t src_addr, uint32_t size)
|
||||||
@ -406,4 +403,150 @@ esp_err_t bootloader_flash_erase_sector(size_t sector)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef BOOTLOADER_BUILD
|
||||||
|
uint32_t bootloader_read_flash_id(void)
|
||||||
|
{
|
||||||
|
uint32_t id = spi_flash_get_id_raw(&g_rom_flashchip);
|
||||||
|
id = ((id & 0xff) << 16) | ((id >> 16) & 0xff) | (id & 0xff00);
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if XMC_SUPPORT
|
||||||
|
static bool is_xmc_chip_strict(uint32_t rdid)
|
||||||
|
{
|
||||||
|
uint32_t vendor_id = BYTESHIFT(rdid, 2);
|
||||||
|
uint32_t mfid = BYTESHIFT(rdid, 1);
|
||||||
|
uint32_t cpid = BYTESHIFT(rdid, 0);
|
||||||
|
|
||||||
|
if (vendor_id != XMC_VENDOR_ID) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matched = false;
|
||||||
|
if (mfid == 0x40) {
|
||||||
|
if (cpid >= 0x13 && cpid <= 0x20) {
|
||||||
|
matched = true;
|
||||||
|
}
|
||||||
|
} else if (mfid == 0x41) {
|
||||||
|
if (cpid >= 0x17 && cpid <= 0x20) {
|
||||||
|
matched = true;
|
||||||
|
}
|
||||||
|
} else if (mfid == 0x50) {
|
||||||
|
if (cpid >= 0x15 && cpid <= 0x16) {
|
||||||
|
matched = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return matched;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bootloader_execute_flash_command(uint8_t command, uint32_t mosi_data, uint8_t mosi_len, uint8_t miso_len)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
spi_cmd_t cmd;
|
||||||
|
|
||||||
|
cmd.cmd = command;
|
||||||
|
cmd.cmd_len = 1;
|
||||||
|
cmd.addr = NULL;
|
||||||
|
cmd.addr_len = 0;
|
||||||
|
cmd.dummy_bits = 0;
|
||||||
|
cmd.data = NULL;
|
||||||
|
cmd.data_len = 0;
|
||||||
|
|
||||||
|
ret = spi_user_cmd_raw(&g_rom_flashchip, SPI_TX, &cmd);
|
||||||
|
if (!ret) {
|
||||||
|
ESP_LOGE(TAG, "failed to write cmd=%02x", command);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
spi_cmd_t cmd;
|
||||||
|
uint32_t data = 0;
|
||||||
|
uint32_t addr = sfdp_addr << 8;
|
||||||
|
|
||||||
|
cmd.cmd = CMD_RDSFDP;
|
||||||
|
cmd.cmd_len = 1;
|
||||||
|
cmd.addr = &addr;
|
||||||
|
cmd.addr_len = 3;
|
||||||
|
cmd.dummy_bits = 8;
|
||||||
|
cmd.data = &data;
|
||||||
|
cmd.data_len = miso_byte_num;
|
||||||
|
|
||||||
|
ret = spi_user_cmd_raw(&g_rom_flashchip, SPI_RX, &cmd);
|
||||||
|
if (!ret) {
|
||||||
|
ESP_LOGE(TAG, "failed to read sfdp");
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t bootloader_flash_xmc_startup(void)
|
||||||
|
{
|
||||||
|
extern void ets_rom_delay_us(uint16_t us);
|
||||||
|
|
||||||
|
uint32_t id = bootloader_read_flash_id();
|
||||||
|
|
||||||
|
// If the RDID value is a valid XMC one, may skip the flow
|
||||||
|
const bool fast_check = true;
|
||||||
|
if (fast_check && is_xmc_chip_strict(id)) {
|
||||||
|
ESP_LOGD(TAG, "XMC chip detected by RDID (%08X), skip.", id);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the Manufacturer ID in SFDP registers (JEDEC standard). If not XMC chip, no need to run the flow
|
||||||
|
const int sfdp_mfid_addr = 0x10;
|
||||||
|
uint8_t mf_id = (bootloader_flash_read_sfdp(sfdp_mfid_addr, 1) & 0xff);
|
||||||
|
if (mf_id != XMC_VENDOR_ID) {
|
||||||
|
ESP_LOGD(TAG, "non-XMC chip detected by SFDP Read (%02X), skip.", mf_id);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGI(TAG, "XM25QHxxC startup flow");
|
||||||
|
// Enter DPD
|
||||||
|
bootloader_execute_flash_command(0xB9, 0, 0, 0);
|
||||||
|
// Enter UDPD
|
||||||
|
bootloader_execute_flash_command(0x79, 0, 0, 0);
|
||||||
|
// Exit UDPD
|
||||||
|
bootloader_execute_flash_command(0xFF, 0, 0, 0);
|
||||||
|
// Delay tXUDPD
|
||||||
|
ets_rom_delay_us(2000);
|
||||||
|
// Release Power-down
|
||||||
|
bootloader_execute_flash_command(0xAB, 0, 0, 0);
|
||||||
|
ets_rom_delay_us(20);
|
||||||
|
// Read flash ID and check again
|
||||||
|
id = bootloader_read_flash_id();
|
||||||
|
if (!is_xmc_chip_strict(id)) {
|
||||||
|
ESP_LOGE(TAG, "XMC flash startup fail");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static bool is_xmc_chip(uint32_t rdid)
|
||||||
|
{
|
||||||
|
uint32_t vendor_id = (rdid >> 16) &0xff;
|
||||||
|
|
||||||
|
return vendor_id == XMC_VENDOR_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t bootloader_flash_xmc_startup(void)
|
||||||
|
{
|
||||||
|
uint32_t id = bootloader_read_flash_id();
|
||||||
|
|
||||||
|
if (is_xmc_chip(id)) {
|
||||||
|
ESP_LOGE(TAG, "XMC chip detected(%08X) while support disable.", id);
|
||||||
|
return ESP_FAIL;
|
||||||
|
} else {
|
||||||
|
ESP_LOGI(TAG, "flash chip is %08X", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -642,6 +642,8 @@ esp_err_t bootloader_init()
|
|||||||
|
|
||||||
static esp_err_t bootloader_main()
|
static esp_err_t bootloader_main()
|
||||||
{
|
{
|
||||||
|
esp_err_t ret;
|
||||||
|
|
||||||
#ifdef CONFIG_BOOTLOADER_DISABLE_JTAG_IO
|
#ifdef CONFIG_BOOTLOADER_DISABLE_JTAG_IO
|
||||||
/* Set GPIO 12-15 to be normal GPIO */
|
/* Set GPIO 12-15 to be normal GPIO */
|
||||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12);
|
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12);
|
||||||
@ -655,6 +657,11 @@ static esp_err_t bootloader_main()
|
|||||||
|
|
||||||
uart_console_configure();
|
uart_console_configure();
|
||||||
|
|
||||||
|
if ((ret = bootloader_flash_xmc_startup()) != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "failed when running XMC startup flow, reboot!");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
esp_image_header_t fhdr;
|
esp_image_header_t fhdr;
|
||||||
if (bootloader_flash_read(ESP_BOOTLOADER_OFFSET, &fhdr, sizeof(esp_image_header_t), true) != ESP_OK) {
|
if (bootloader_flash_read(ESP_BOOTLOADER_OFFSET, &fhdr, sizeof(esp_image_header_t), true) != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "failed to load bootloader header!");
|
ESP_LOGE(TAG, "failed to load bootloader header!");
|
||||||
|
Reference in New Issue
Block a user