mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-05-17 07:06:41 +08:00
feat(bootloader): add xmc spi_flash startup flow to improve reliability
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
|
||||
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
|
||||
|
||||
|
||||
|
@ -8,4 +8,5 @@ PROVIDE ( gpio_input_get = 0x40004cf0 );
|
||||
|
||||
PROVIDE ( xthal_get_ccount = 0x4000dd38 );
|
||||
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 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,
|
||||
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);
|
||||
|
||||
/**
|
||||
* @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
|
||||
|
@ -263,9 +263,13 @@ esp_err_t bootloader_flash_erase_sector(size_t sector)
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp8266/rom_functions.h"
|
||||
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
#include "esp_spi_flash.h"
|
||||
#else
|
||||
#include "bootloader_flash.h"
|
||||
#include "priv/esp_spi_flash_raw.h"
|
||||
#endif
|
||||
|
||||
#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
|
||||
#endif
|
||||
|
||||
extern void Cache_Read_Disable();
|
||||
extern void Cache_Read_Enable(uint8_t map, uint8_t p, uint8_t v);
|
||||
#define XMC_SUPPORT CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT
|
||||
|
||||
#define BYTESHIFT(VAR, IDX) (((VAR) >> ((IDX) * 8)) & 0xFF)
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#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
|
||||
|
@ -642,6 +642,8 @@ esp_err_t bootloader_init()
|
||||
|
||||
static esp_err_t bootloader_main()
|
||||
{
|
||||
esp_err_t ret;
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_DISABLE_JTAG_IO
|
||||
/* Set GPIO 12-15 to be normal GPIO */
|
||||
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12);
|
||||
@ -655,6 +657,11 @@ static esp_err_t bootloader_main()
|
||||
|
||||
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;
|
||||
if (bootloader_flash_read(ESP_BOOTLOADER_OFFSET, &fhdr, sizeof(esp_image_header_t), true) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "failed to load bootloader header!");
|
||||
|
Reference in New Issue
Block a user