spi_flash: fix xm25qh32c flash overerase

customer/maintain_v4.0_xiaomi_tsf_issue
chenjianqiang 2021-05-08 11:39:35 +08:00 zatwierdzone przez Michael (XIAO Xufeng)
rodzic 937ce5dfd5
commit e3f975b5a8
4 zmienionych plików z 136 dodań i 0 usunięć

Wyświetl plik

@ -219,6 +219,22 @@ menu "Bootloader config"
It allow to test anti-rollback implemention without permanent write eFuse bits.
In partition table should be exist this partition `emul_efuse, data, 5, , 0x2000`.
choice BOOTLOADER_FLASH_XMC_OVERERASE_PATCH
bool "Patch strategy for XMC over-erase issue"
default BOOTLOADER_FLASH_XMC_OVERERASE_PATCH_DEFAULT
help
Specify the patch strategy for XMC chips. The over-erase issue may exist on
XM25QH16C, XM25QH32C and XM25QH128C.
config BOOTLOADER_FLASH_XMC_OVERERASE_PATCH_ALL
bool "Run the patch for all XMC chips. This can completely avoid over-erase issue. But may cost some time."
config BOOTLOADER_FLASH_XMC_OVERERASE_PATCH_DEFAULT
bool "Run the patch on XMC chips when there are clues indicating the flash is running incorrectly."
config BOOTLOADER_FLASH_XMC_OVERERASE_PATCH_BYPASS
bool "Not using the patch"
endchoice # BOOTLOADER_FLASH_XMC_OVERERASE_PATCH
endmenu # Bootloader

Wyświetl plik

@ -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,8 @@ void bootloader_enable_qio_mode(void);
*/
uint32_t bootloader_read_flash_id();
esp_err_t bootloader_xmc_flash_overerase_fix();
#ifdef __cplusplus
}
#endif

Wyświetl plik

@ -120,8 +120,16 @@ esp_err_t bootloader_init()
static esp_err_t bootloader_main()
{
bootloader_common_vddsdio_configure();
/* Read and keep flash ID, for further use. */
g_rom_flashchip.device_id = bootloader_read_flash_id();
#if CONFIG_BOOTLOADER_FLASH_XMC_OVERERASE_PATCH_ALL || CONFIG_BOOTLOADER_FLASH_XMC_OVERERASE_PATCH_DEFAULT
if (bootloader_xmc_flash_overerase_fix() != ESP_OK) {
ESP_LOGE(TAG, "failed to fix XMC flash overerase, reboot!");
return ESP_FAIL;
}
#endif
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!");

Wyświetl plik

@ -306,3 +306,111 @@ static uint32_t execute_flash_command(uint8_t command, uint32_t mosi_data, uint8
SPIFLASH.ctrl.val = old_ctrl_reg;
return SPIFLASH.data_buf[0];
}
// cmd(0x5A) + 24bit address + 8 cycles dummy
static uint32_t bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num)
{
assert(miso_byte_num <= 4);
uint8_t command = 0x5A;
uint8_t miso_len = miso_byte_num * 8;
uint8_t mosi_len = 0;
uint32_t mosi_data = 0;
uint32_t old_ctrl_reg = SPIFLASH.ctrl.val;
SPIFLASH.ctrl.val = SPI_WP_REG_M; // keep WP high while idle, otherwise leave DIO mode
SPIFLASH.user.usr_dummy = 1;
SPIFLASH.user1.usr_dummy_cyclelen = 7 + g_rom_spiflash_dummy_len_plus[1];
SPIFLASH.user.usr_addr = 1;
SPIFLASH.addr = (sfdp_addr<<8);
SPIFLASH.user1.usr_addr_bitlen = 23;
SPIFLASH.user.usr_command = 1;
SPIFLASH.user2.usr_command_bitlen = 7;
SPIFLASH.user2.usr_command_value = command;
SPIFLASH.user.usr_miso = miso_len > 0;
SPIFLASH.miso_dlen.usr_miso_dbitlen = miso_len ? (miso_len - 1) : 0;
SPIFLASH.user.usr_mosi = mosi_len > 0;
SPIFLASH.mosi_dlen.usr_mosi_dbitlen = mosi_len ? (mosi_len - 1) : 0;
SPIFLASH.data_buf[0] = mosi_data;
SPIFLASH.cmd.usr = 1;
while(SPIFLASH.cmd.usr != 0)
{ }
SPIFLASH.ctrl.val = old_ctrl_reg;
uint32_t ret = SPIFLASH.data_buf[0];
if (miso_len < 32) {
//set unused bits to 0
ret &= ~(UINT32_MAX << miso_len);
}
return ret;
}
#define XMC_VENDOR_ID 0x20
//use strict model checking for over-erase issue
static bool is_xmc_chip_strict(uint32_t rdid)
{
uint32_t vendor_id = (rdid >> 16) & 0xFF;
uint32_t mfid = (rdid >> 8) & 0xFF;
uint32_t cpid = rdid & 0xFF;
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;
}
esp_err_t bootloader_xmc_flash_overerase_fix()
{
#if CONFIG_BOOTLOADER_FLASH_XMC_OVERERASE_PATCH_DEFAULT
//correct RDID value means the issue doesn't occur
if (is_xmc_chip_strict(g_rom_flashchip.device_id)) {
return ESP_OK;
}
#endif
// Check vendor ID in SFDP registers. If not XMC chip, no need to run the patch
uint8_t mf_id = (bootloader_flash_read_sfdp(0x10, 1) & 0xff);
if (mf_id != XMC_VENDOR_ID) {
return ESP_OK;
}
ESP_LOGI(TAG, "XM25QHxxC flash overerase fix");
// Enter DPD
execute_flash_command(0xB9, 0, 0, 0);
// Enter UDPD
execute_flash_command(0x79, 0, 0, 0);
// Exit UDPD
execute_flash_command(0xFF, 0, 0, 0);
// Delay tXUDPD
ets_delay_us(2000);
// Release Power-down
execute_flash_command(0xAB, 0, 0, 0);
ets_delay_us(20);
// Read flash ID and check
g_rom_flashchip.device_id = bootloader_read_flash_id();
if (!is_xmc_chip_strict(g_rom_flashchip.device_id)) {
// fail
ESP_LOGE(TAG, "XM25QH32C flash overerase fix fail");
return ESP_FAIL;
}
return ESP_OK;
}