2021-05-09 22:35:07 -04:00
|
|
|
/*
|
|
|
|
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
2017-01-29 22:29:50 -05:00
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdint.h>
|
2020-07-07 00:35:52 -04:00
|
|
|
#include "bootloader_flash_config.h"
|
2017-01-29 22:29:50 -05:00
|
|
|
#include "flash_qio_mode.h"
|
2020-07-29 10:03:46 -04:00
|
|
|
#include "sdkconfig.h"
|
2020-07-12 15:23:12 -04:00
|
|
|
#include "bootloader_flash_priv.h"
|
2017-01-29 22:29:50 -05:00
|
|
|
#include "esp_log.h"
|
2017-06-19 20:56:29 -04:00
|
|
|
#include "esp_err.h"
|
2020-07-13 09:57:24 -04:00
|
|
|
#include "esp_rom_efuse.h"
|
2020-07-29 10:03:46 -04:00
|
|
|
#include "flash_qio_mode.h"
|
2019-05-27 02:29:43 -04:00
|
|
|
#if CONFIG_IDF_TARGET_ESP32
|
2019-03-14 05:29:32 -04:00
|
|
|
#include "esp32/rom/spi_flash.h"
|
2020-01-16 22:47:08 -05:00
|
|
|
#elif CONFIG_IDF_TARGET_ESP32S2
|
|
|
|
#include "esp32s2/rom/spi_flash.h"
|
bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
This commit helps to clear WEL when flash configuration is done.
**RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0 | WIP | WIP |
| 1 | WEL | WEL |
| 2 | BP0 | BP0 |
| 3 | BP1 | BP1 |
| 4 | BP2 | BP2 |
| 5 | BP3 | BP3 |
| 6 | QE | BP4 |
| 7 | SRWD | SRP0 |
| 8 | | SRP1 |
| 9 | | QE |
| 10 | | SUS2 |
| 11 | | LB1 |
| 12 | | LB2 |
| 13 | | LB3 |
| 14 | | CMP |
| 15 | | SUS1 |
QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
2020-03-12 06:20:31 -04:00
|
|
|
#elif CONFIG_IDF_TARGET_ESP32S3
|
|
|
|
#include "esp32s3/rom/spi_flash.h"
|
2020-11-26 03:56:13 -05:00
|
|
|
#elif CONFIG_IDF_TARGET_ESP32C3
|
|
|
|
#include "esp32c3/rom/spi_flash.h"
|
2021-06-10 07:28:18 -04:00
|
|
|
#elif CONFIG_IDF_TARGET_ESP32H2
|
|
|
|
#include "esp32h2/rom/spi_flash.h"
|
2019-05-27 02:29:43 -04:00
|
|
|
#endif
|
2019-05-13 06:02:45 -04:00
|
|
|
#include "soc/efuse_periph.h"
|
2019-05-27 02:29:43 -04:00
|
|
|
#include "soc/io_mux_reg.h"
|
2017-01-29 22:29:50 -05:00
|
|
|
|
|
|
|
|
|
|
|
static const char *TAG = "qio_mode";
|
|
|
|
|
|
|
|
/* Array of known flash chips and data to enable Quad I/O mode
|
|
|
|
|
|
|
|
Manufacturer & flash ID can be tested by running "esptool.py
|
|
|
|
flash_id"
|
|
|
|
|
|
|
|
If manufacturer ID matches, and flash ID ORed with flash ID mask
|
|
|
|
matches, enable_qio_mode() will execute "Read Cmd", test if bit
|
|
|
|
number "QIE Bit" is set, and if not set it will call "Write Cmd"
|
|
|
|
with this bit set.
|
|
|
|
|
|
|
|
Searching of this table stops when the first match is found.
|
|
|
|
*/
|
2021-09-24 00:03:03 -04:00
|
|
|
const bootloader_qio_info_t __attribute__((weak)) bootloader_flash_qe_support_list[] = {
|
2019-05-27 02:29:43 -04:00
|
|
|
/* Manufacturer, mfg_id, flash_id, id mask, Read Status, Write Status, QIE Bit */
|
2021-09-24 00:03:03 -04:00
|
|
|
{ "MXIC", 0xC2, 0x2000, 0xFF00, bootloader_read_status_8b_rdsr, bootloader_write_status_8b_wrsr, 6 },
|
|
|
|
{ "ISSI", 0x9D, 0x4000, 0xCF00, bootloader_read_status_8b_rdsr, bootloader_write_status_8b_wrsr, 6 }, /* IDs 0x40xx, 0x70xx */
|
|
|
|
{ "WinBond", 0xEF, 0x4000, 0xFF00, bootloader_read_status_16b_rdsr_rdsr2, bootloader_write_status_16b_wrsr, 9 },
|
|
|
|
{ "GD", 0xC8, 0x6000, 0xFF00, bootloader_read_status_16b_rdsr_rdsr2, bootloader_write_status_16b_wrsr, 9 },
|
|
|
|
{ "XM25QU64A", 0x20, 0x3817, 0xFFFF, bootloader_read_status_8b_xmc25qu64a, bootloader_write_status_8b_xmc25qu64a, 6 },
|
|
|
|
{ "TH", 0xcd, 0x6000, 0xFF00, bootloader_read_status_16b_rdsr_rdsr2, bootloader_write_status_16b_wrsr, 9 },
|
2017-01-29 22:29:50 -05:00
|
|
|
|
|
|
|
/* Final entry is default entry, if no other IDs have matched.
|
|
|
|
|
|
|
|
This approach works for chips including:
|
|
|
|
GigaDevice (mfg ID 0xC8, flash IDs including 4016),
|
2017-01-31 21:14:09 -05:00
|
|
|
FM25Q32 (QOUT mode only, mfg ID 0xA1, flash IDs including 4016)
|
2021-02-01 23:39:38 -05:00
|
|
|
BY25Q32 (mfg ID 0x68, flash IDs including 4016)
|
2017-01-29 22:29:50 -05:00
|
|
|
*/
|
2021-09-24 00:03:03 -04:00
|
|
|
{ NULL, 0xFF, 0xFFFF, 0xFFFF, bootloader_read_status_8b_rdsr2, bootloader_write_status_8b_wrsr2, 1 },
|
2017-01-29 22:29:50 -05:00
|
|
|
};
|
|
|
|
|
2021-09-24 00:03:03 -04:00
|
|
|
#define NUM_CHIPS (sizeof(bootloader_flash_qe_support_list) / sizeof(bootloader_qio_info_t))
|
2017-01-29 22:29:50 -05:00
|
|
|
|
2021-09-24 00:03:03 -04:00
|
|
|
static esp_err_t enable_qio_mode(bootloader_flash_read_status_fn_t read_status_fn,
|
|
|
|
bootloader_flash_write_status_fn_t write_status_fn,
|
2019-05-27 02:29:43 -04:00
|
|
|
uint8_t status_qio_bit);
|
2017-01-29 22:29:50 -05:00
|
|
|
|
|
|
|
/* Generic function to use the "user command" SPI controller functionality
|
|
|
|
to send commands to the SPI flash and read the respopnse.
|
|
|
|
|
|
|
|
The command passed here is always the on-the-wire command given to the SPI flash unit.
|
|
|
|
*/
|
|
|
|
|
|
|
|
void bootloader_enable_qio_mode(void)
|
|
|
|
{
|
|
|
|
uint32_t raw_flash_id;
|
|
|
|
uint8_t mfg_id;
|
|
|
|
uint16_t flash_id;
|
2020-11-16 23:48:35 -05:00
|
|
|
size_t i;
|
2017-01-29 22:29:50 -05:00
|
|
|
|
|
|
|
ESP_LOGD(TAG, "Probing for QIO mode enable...");
|
2017-03-09 02:29:00 -05:00
|
|
|
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
2017-01-29 22:29:50 -05:00
|
|
|
|
2018-04-20 04:59:25 -04:00
|
|
|
raw_flash_id = g_rom_flashchip.device_id;
|
2017-01-29 22:29:50 -05:00
|
|
|
ESP_LOGD(TAG, "Raw SPI flash chip id 0x%x", raw_flash_id);
|
|
|
|
|
2018-04-20 04:59:25 -04:00
|
|
|
mfg_id = (raw_flash_id >> 16) & 0xFF;
|
|
|
|
flash_id = raw_flash_id & 0xFFFF;
|
2017-01-29 22:29:50 -05:00
|
|
|
ESP_LOGD(TAG, "Manufacturer ID 0x%02x chip ID 0x%04x", mfg_id, flash_id);
|
|
|
|
|
2019-05-27 02:29:43 -04:00
|
|
|
for (i = 0; i < NUM_CHIPS - 1; i++) {
|
2021-09-24 00:03:03 -04:00
|
|
|
const bootloader_qio_info_t *chip = &bootloader_flash_qe_support_list[i];
|
2017-01-29 22:29:50 -05:00
|
|
|
if (mfg_id == chip->mfg_id && (flash_id & chip->id_mask) == (chip->flash_id & chip->id_mask)) {
|
2021-09-24 00:03:03 -04:00
|
|
|
ESP_LOGI(TAG, "Enabling QIO for flash chip %s", bootloader_flash_qe_support_list[i].manufacturer);
|
2017-01-29 22:29:50 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == NUM_CHIPS - 1) {
|
|
|
|
ESP_LOGI(TAG, "Enabling default flash chip QIO");
|
|
|
|
}
|
2021-09-24 00:03:03 -04:00
|
|
|
enable_qio_mode(bootloader_flash_qe_support_list[i].read_status_fn,
|
|
|
|
bootloader_flash_qe_support_list[i].write_status_fn,
|
|
|
|
bootloader_flash_qe_support_list[i].status_qio_bit);
|
bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
This commit helps to clear WEL when flash configuration is done.
**RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0 | WIP | WIP |
| 1 | WEL | WEL |
| 2 | BP0 | BP0 |
| 3 | BP1 | BP1 |
| 4 | BP2 | BP2 |
| 5 | BP3 | BP3 |
| 6 | QE | BP4 |
| 7 | SRWD | SRP0 |
| 8 | | SRP1 |
| 9 | | QE |
| 10 | | SUS2 |
| 11 | | LB1 |
| 12 | | LB2 |
| 13 | | LB3 |
| 14 | | CMP |
| 15 | | SUS1 |
QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
2020-03-12 06:20:31 -04:00
|
|
|
#if SOC_CACHE_SUPPORT_WRAP
|
|
|
|
bootloader_flash_wrap_set(FLASH_WRAP_MODE_DISABLE);
|
2019-11-05 00:04:50 -05:00
|
|
|
#endif
|
2017-01-29 22:29:50 -05:00
|
|
|
}
|
|
|
|
|
2021-09-24 00:03:03 -04:00
|
|
|
static esp_err_t enable_qio_mode(bootloader_flash_read_status_fn_t read_status_fn,
|
|
|
|
bootloader_flash_write_status_fn_t write_status_fn,
|
2019-05-27 02:29:43 -04:00
|
|
|
uint8_t status_qio_bit)
|
2017-01-29 22:29:50 -05:00
|
|
|
{
|
|
|
|
uint32_t status;
|
2020-07-13 09:57:24 -04:00
|
|
|
const uint32_t spiconfig = esp_rom_efuse_get_flash_gpio_info();
|
2017-04-13 03:08:53 -04:00
|
|
|
|
2017-03-09 02:29:00 -05:00
|
|
|
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
2017-01-29 22:29:50 -05:00
|
|
|
|
2017-01-31 21:14:09 -05:00
|
|
|
status = read_status_fn();
|
2017-01-29 22:29:50 -05:00
|
|
|
ESP_LOGD(TAG, "Initial flash chip status 0x%x", status);
|
|
|
|
|
2019-05-27 02:29:43 -04:00
|
|
|
if ((status & (1 << status_qio_bit)) == 0) {
|
bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
This commit helps to clear WEL when flash configuration is done.
**RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0 | WIP | WIP |
| 1 | WEL | WEL |
| 2 | BP0 | BP0 |
| 3 | BP1 | BP1 |
| 4 | BP2 | BP2 |
| 5 | BP3 | BP3 |
| 6 | QE | BP4 |
| 7 | SRWD | SRP0 |
| 8 | | SRP1 |
| 9 | | QE |
| 10 | | SUS2 |
| 11 | | LB1 |
| 12 | | LB2 |
| 13 | | LB3 |
| 14 | | CMP |
| 15 | | SUS1 |
QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
2020-03-12 06:20:31 -04:00
|
|
|
bootloader_execute_flash_command(CMD_WREN, 0, 0, 0);
|
2019-05-27 02:29:43 -04:00
|
|
|
write_status_fn(status | (1 << status_qio_bit));
|
2017-01-29 22:29:50 -05:00
|
|
|
|
2017-03-09 02:29:00 -05:00
|
|
|
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
2017-01-29 22:29:50 -05:00
|
|
|
|
2017-01-31 21:14:09 -05:00
|
|
|
status = read_status_fn();
|
2017-01-29 22:29:50 -05:00
|
|
|
ESP_LOGD(TAG, "Updated flash chip status 0x%x", status);
|
2019-05-27 02:29:43 -04:00
|
|
|
if ((status & (1 << status_qio_bit)) == 0) {
|
2017-01-29 22:29:50 -05:00
|
|
|
ESP_LOGE(TAG, "Failed to set QIE bit, not enabling QIO mode");
|
2017-06-19 20:56:29 -04:00
|
|
|
return ESP_FAIL;
|
2017-01-29 22:29:50 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
ESP_LOGD(TAG, "QIO mode already enabled in flash");
|
|
|
|
}
|
|
|
|
|
|
|
|
ESP_LOGD(TAG, "Enabling QIO mode...");
|
|
|
|
|
2017-03-09 02:29:00 -05:00
|
|
|
esp_rom_spiflash_read_mode_t mode;
|
2019-05-09 07:39:30 -04:00
|
|
|
#if CONFIG_ESPTOOLPY_FLASHMODE_QOUT
|
2017-03-09 02:29:00 -05:00
|
|
|
mode = ESP_ROM_SPIFLASH_QOUT_MODE;
|
2017-01-29 22:29:50 -05:00
|
|
|
#else
|
2017-03-09 02:29:00 -05:00
|
|
|
mode = ESP_ROM_SPIFLASH_QIO_MODE;
|
2017-01-29 22:29:50 -05:00
|
|
|
#endif
|
2017-04-13 03:08:53 -04:00
|
|
|
|
2017-04-11 21:31:26 -04:00
|
|
|
esp_rom_spiflash_config_readmode(mode);
|
|
|
|
|
2019-05-27 02:29:43 -04:00
|
|
|
#if CONFIG_IDF_TARGET_ESP32
|
2020-07-07 00:35:52 -04:00
|
|
|
int wp_pin = bootloader_flash_get_wp_pin();
|
|
|
|
esp_rom_spiflash_select_qio_pins(wp_pin, spiconfig);
|
2020-11-26 03:56:13 -05:00
|
|
|
#else
|
2020-07-07 00:35:52 -04:00
|
|
|
esp_rom_spiflash_select_qio_pins(esp_rom_efuse_get_flash_wp_gpio(), spiconfig);
|
2019-05-27 02:29:43 -04:00
|
|
|
#endif
|
2017-06-19 20:56:29 -04:00
|
|
|
return ESP_OK;
|
2017-01-29 22:29:50 -05:00
|
|
|
}
|
|
|
|
|
2021-09-24 00:03:03 -04:00
|
|
|
unsigned bootloader_read_status_8b_rdsr(void)
|
2017-01-31 21:14:09 -05:00
|
|
|
{
|
bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
This commit helps to clear WEL when flash configuration is done.
**RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0 | WIP | WIP |
| 1 | WEL | WEL |
| 2 | BP0 | BP0 |
| 3 | BP1 | BP1 |
| 4 | BP2 | BP2 |
| 5 | BP3 | BP3 |
| 6 | QE | BP4 |
| 7 | SRWD | SRP0 |
| 8 | | SRP1 |
| 9 | | QE |
| 10 | | SUS2 |
| 11 | | LB1 |
| 12 | | LB2 |
| 13 | | LB3 |
| 14 | | CMP |
| 15 | | SUS1 |
QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
2020-03-12 06:20:31 -04:00
|
|
|
return bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8);
|
2017-01-31 21:14:09 -05:00
|
|
|
}
|
|
|
|
|
2021-09-24 00:03:03 -04:00
|
|
|
unsigned bootloader_read_status_8b_rdsr2(void)
|
2017-01-31 21:14:09 -05:00
|
|
|
{
|
bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
This commit helps to clear WEL when flash configuration is done.
**RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0 | WIP | WIP |
| 1 | WEL | WEL |
| 2 | BP0 | BP0 |
| 3 | BP1 | BP1 |
| 4 | BP2 | BP2 |
| 5 | BP3 | BP3 |
| 6 | QE | BP4 |
| 7 | SRWD | SRP0 |
| 8 | | SRP1 |
| 9 | | QE |
| 10 | | SUS2 |
| 11 | | LB1 |
| 12 | | LB2 |
| 13 | | LB3 |
| 14 | | CMP |
| 15 | | SUS1 |
QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
2020-03-12 06:20:31 -04:00
|
|
|
return bootloader_execute_flash_command(CMD_RDSR2, 0, 0, 8);
|
2017-01-31 21:14:09 -05:00
|
|
|
}
|
|
|
|
|
2022-02-25 04:03:45 -05:00
|
|
|
unsigned bootloader_read_status_8b_rdsr3(void)
|
|
|
|
{
|
|
|
|
return bootloader_execute_flash_command(CMD_RDSR3, 0, 0, 8);
|
|
|
|
}
|
|
|
|
|
2022-03-14 05:06:30 -04:00
|
|
|
unsigned bootloader_read_status_16b_rdsr_rdsr2(void)
|
2017-01-31 21:14:09 -05:00
|
|
|
{
|
bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
This commit helps to clear WEL when flash configuration is done.
**RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0 | WIP | WIP |
| 1 | WEL | WEL |
| 2 | BP0 | BP0 |
| 3 | BP1 | BP1 |
| 4 | BP2 | BP2 |
| 5 | BP3 | BP3 |
| 6 | QE | BP4 |
| 7 | SRWD | SRP0 |
| 8 | | SRP1 |
| 9 | | QE |
| 10 | | SUS2 |
| 11 | | LB1 |
| 12 | | LB2 |
| 13 | | LB3 |
| 14 | | CMP |
| 15 | | SUS1 |
QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
2020-03-12 06:20:31 -04:00
|
|
|
return bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8) | (bootloader_execute_flash_command(CMD_RDSR2, 0, 0, 8) << 8);
|
2017-01-31 21:14:09 -05:00
|
|
|
}
|
|
|
|
|
2021-09-24 00:03:03 -04:00
|
|
|
void bootloader_write_status_8b_wrsr(unsigned new_status)
|
2017-01-31 21:14:09 -05:00
|
|
|
{
|
bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
This commit helps to clear WEL when flash configuration is done.
**RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0 | WIP | WIP |
| 1 | WEL | WEL |
| 2 | BP0 | BP0 |
| 3 | BP1 | BP1 |
| 4 | BP2 | BP2 |
| 5 | BP3 | BP3 |
| 6 | QE | BP4 |
| 7 | SRWD | SRP0 |
| 8 | | SRP1 |
| 9 | | QE |
| 10 | | SUS2 |
| 11 | | LB1 |
| 12 | | LB2 |
| 13 | | LB3 |
| 14 | | CMP |
| 15 | | SUS1 |
QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
2020-03-12 06:20:31 -04:00
|
|
|
bootloader_execute_flash_command(CMD_WRSR, new_status, 8, 0);
|
2017-01-31 21:14:09 -05:00
|
|
|
}
|
|
|
|
|
2021-09-24 00:03:03 -04:00
|
|
|
void bootloader_write_status_8b_wrsr2(unsigned new_status)
|
2017-01-31 21:14:09 -05:00
|
|
|
{
|
bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
This commit helps to clear WEL when flash configuration is done.
**RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0 | WIP | WIP |
| 1 | WEL | WEL |
| 2 | BP0 | BP0 |
| 3 | BP1 | BP1 |
| 4 | BP2 | BP2 |
| 5 | BP3 | BP3 |
| 6 | QE | BP4 |
| 7 | SRWD | SRP0 |
| 8 | | SRP1 |
| 9 | | QE |
| 10 | | SUS2 |
| 11 | | LB1 |
| 12 | | LB2 |
| 13 | | LB3 |
| 14 | | CMP |
| 15 | | SUS1 |
QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
2020-03-12 06:20:31 -04:00
|
|
|
bootloader_execute_flash_command(CMD_WRSR2, new_status, 8, 0);
|
2017-01-31 21:14:09 -05:00
|
|
|
}
|
|
|
|
|
2022-02-25 04:03:45 -05:00
|
|
|
void bootloader_write_status_8b_wrsr3(unsigned new_status)
|
|
|
|
{
|
|
|
|
bootloader_execute_flash_command(CMD_WRSR3, new_status, 8, 0);
|
|
|
|
}
|
|
|
|
|
2021-09-24 00:03:03 -04:00
|
|
|
void bootloader_write_status_16b_wrsr(unsigned new_status)
|
2017-01-31 21:14:09 -05:00
|
|
|
{
|
bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
This commit helps to clear WEL when flash configuration is done.
**RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0 | WIP | WIP |
| 1 | WEL | WEL |
| 2 | BP0 | BP0 |
| 3 | BP1 | BP1 |
| 4 | BP2 | BP2 |
| 5 | BP3 | BP3 |
| 6 | QE | BP4 |
| 7 | SRWD | SRP0 |
| 8 | | SRP1 |
| 9 | | QE |
| 10 | | SUS2 |
| 11 | | LB1 |
| 12 | | LB2 |
| 13 | | LB3 |
| 14 | | CMP |
| 15 | | SUS1 |
QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
2020-03-12 06:20:31 -04:00
|
|
|
bootloader_execute_flash_command(CMD_WRSR, new_status, 16, 0);
|
2017-01-31 21:14:09 -05:00
|
|
|
}
|
|
|
|
|
2021-09-24 00:03:03 -04:00
|
|
|
unsigned bootloader_read_status_8b_xmc25qu64a(void)
|
2018-07-11 09:36:35 -04:00
|
|
|
{
|
bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
This commit helps to clear WEL when flash configuration is done.
**RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0 | WIP | WIP |
| 1 | WEL | WEL |
| 2 | BP0 | BP0 |
| 3 | BP1 | BP1 |
| 4 | BP2 | BP2 |
| 5 | BP3 | BP3 |
| 6 | QE | BP4 |
| 7 | SRWD | SRP0 |
| 8 | | SRP1 |
| 9 | | QE |
| 10 | | SUS2 |
| 11 | | LB1 |
| 12 | | LB2 |
| 13 | | LB3 |
| 14 | | CMP |
| 15 | | SUS1 |
QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
2020-03-12 06:20:31 -04:00
|
|
|
bootloader_execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */
|
2018-07-11 09:36:35 -04:00
|
|
|
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
This commit helps to clear WEL when flash configuration is done.
**RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0 | WIP | WIP |
| 1 | WEL | WEL |
| 2 | BP0 | BP0 |
| 3 | BP1 | BP1 |
| 4 | BP2 | BP2 |
| 5 | BP3 | BP3 |
| 6 | QE | BP4 |
| 7 | SRWD | SRP0 |
| 8 | | SRP1 |
| 9 | | QE |
| 10 | | SUS2 |
| 11 | | LB1 |
| 12 | | LB2 |
| 13 | | LB3 |
| 14 | | CMP |
| 15 | | SUS1 |
QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
2020-03-12 06:20:31 -04:00
|
|
|
uint32_t read_status = bootloader_execute_flash_command(CMD_RDSR, 0, 0, 8);
|
|
|
|
bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */
|
2018-07-11 09:36:35 -04:00
|
|
|
return read_status;
|
|
|
|
}
|
|
|
|
|
2021-09-24 00:03:03 -04:00
|
|
|
void bootloader_write_status_8b_xmc25qu64a(unsigned new_status)
|
2018-07-11 09:36:35 -04:00
|
|
|
{
|
bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
This commit helps to clear WEL when flash configuration is done.
**RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0 | WIP | WIP |
| 1 | WEL | WEL |
| 2 | BP0 | BP0 |
| 3 | BP1 | BP1 |
| 4 | BP2 | BP2 |
| 5 | BP3 | BP3 |
| 6 | QE | BP4 |
| 7 | SRWD | SRP0 |
| 8 | | SRP1 |
| 9 | | QE |
| 10 | | SUS2 |
| 11 | | LB1 |
| 12 | | LB2 |
| 13 | | LB3 |
| 14 | | CMP |
| 15 | | SUS1 |
QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
2020-03-12 06:20:31 -04:00
|
|
|
bootloader_execute_flash_command(CMD_OTPEN, 0, 0, 0); /* Enter OTP mode */
|
2018-07-11 09:36:35 -04:00
|
|
|
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
This commit helps to clear WEL when flash configuration is done.
**RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0 | WIP | WIP |
| 1 | WEL | WEL |
| 2 | BP0 | BP0 |
| 3 | BP1 | BP1 |
| 4 | BP2 | BP2 |
| 5 | BP3 | BP3 |
| 6 | QE | BP4 |
| 7 | SRWD | SRP0 |
| 8 | | SRP1 |
| 9 | | QE |
| 10 | | SUS2 |
| 11 | | LB1 |
| 12 | | LB2 |
| 13 | | LB3 |
| 14 | | CMP |
| 15 | | SUS1 |
QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
2020-03-12 06:20:31 -04:00
|
|
|
bootloader_execute_flash_command(CMD_WRSR, new_status, 8, 0);
|
2018-07-11 09:36:35 -04:00
|
|
|
esp_rom_spiflash_wait_idle(&g_rom_flashchip);
|
bootloader: fix the WRSR format for ISSI flash chips
1. The 2nd bootloader always call `rom_spiflash_unlock()`, but never help to clear the WEL bit when exit. This may cause system unstability.
This commit helps to clear WEL when flash configuration is done.
**RISK:** When the app starts, it didn't have to clear the WEL before it actually write/erase. But now the very first write/erase operation should be done after a WEL clear. Though the risk is little (all the following write/erase also need to clear the WEL), we still have to test this carefully, especially for those functions used by the OTA.
2. The `rom_spiflash_unlock()` function in the patch of ESP32 may (1) trigger the QPI, (2) clear the QE or (3) fail to unlock the ISSI chips.
Status register bitmap of ISSI chip and GD chip:
| SR | ISSI | GD25LQ32C |
| -- | ---- | --------- |
| 0 | WIP | WIP |
| 1 | WEL | WEL |
| 2 | BP0 | BP0 |
| 3 | BP1 | BP1 |
| 4 | BP2 | BP2 |
| 5 | BP3 | BP3 |
| 6 | QE | BP4 |
| 7 | SRWD | SRP0 |
| 8 | | SRP1 |
| 9 | | QE |
| 10 | | SUS2 |
| 11 | | LB1 |
| 12 | | LB2 |
| 13 | | LB3 |
| 14 | | CMP |
| 15 | | SUS1 |
QE bit of other chips are at the bit 9 of the status register (i.e. bit 1 of SR2), which should be read by RDSR2 command.
However, the RDSR2 (35H, Read Status 2) command for chip of other vendors happens to be the QIOEN (Enter QPI mode) command of ISSI chips. When the `rom_spiflash_unlock()` function trys to read SR2, it may trigger the QPI of ISSI chips.
Moreover, when `rom_spiflash_unlock()` try to clear the BP4 bit in the status register, QE (bit 6) of ISSI chip may be cleared by accident. Or if the ISSI chip doesn't accept WRSR command with argument of two bytes (since it only have status register of one byte), it may fail to clear the other protect bits (BP0~BP3) as expected.
This commit makes the `rom_spiflash_unlock()` check whether the vendor is issi. if so, `rom_spiflash_unlock()` only send RDSR to read the status register, send WRSR with only 1 byte argument, and also avoid clearing the QE bit (bit 6).
3. `rom_spiflash_unlock()` always send WRSR command to clear protection bits even when there is no protection bit active. And the execution of clearing status registers, which takes about 700us, will also happen even when there's no bits cleared.
This commit skips the clearing of status register if there is no protection bits active.
Also move the execute_flash_command to be a bootloader API; move
implementation of spi_flash_wrap_set to the bootloader
2020-03-12 06:20:31 -04:00
|
|
|
bootloader_execute_flash_command(CMD_WRDI, 0, 0, 0); /* Exit OTP mode */
|
2017-01-29 22:29:50 -05:00
|
|
|
}
|