mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-30 19:19:21 +00:00
spi_flash: fixed issue that enabling HPM-DC by default may cause app unable to restart
This commit is contained in:
@@ -29,14 +29,28 @@
|
||||
* 4. Some flash chips do nothing.
|
||||
******************************************************************************/
|
||||
|
||||
#if CONFIG_ESPTOOLPY_FLASHFREQ_120M
|
||||
#define FLASH_FREQUENCY 120
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_80M
|
||||
#define FLASH_FREQUENCY 80
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_40M
|
||||
#define FLASH_FREQUENCY 40
|
||||
#elif CONFIG_ESPTOOLPY_FLASHFREQ_20M
|
||||
#define FLASH_FREQUENCY 20
|
||||
/*
|
||||
* Note: This file should only be compiled when HPM_ON, which is only available when !CONFIG_ESPTOOLPY_OCT_FLASH.
|
||||
* However when HPM_ON, there are still some cases this file is not actually used:
|
||||
*
|
||||
* - !CONFIG_SPI_FLASH_UNDER_HIGH_FREQ:
|
||||
* It mean that the flash not running under frequency requires HPM. spi_flash_enable_high_performance_mode() still
|
||||
* called because caller shouldn't take care of the frequency.
|
||||
*
|
||||
* - bootloader_flash_is_octal_mode_enabled() == true:
|
||||
* This is possible when `CONFIG_ESPTOOLPY_FLASH_MODE_AUTO_DETECT` selected
|
||||
*
|
||||
* Octal Flash for now all support 120M. No need to enable HPM. The file is compiled, but will not actually run
|
||||
* into spi_flash_enable_high_performance_mode().
|
||||
*/
|
||||
|
||||
void spi_flash_hpm_get_dummy_generic(spi_flash_hpm_dummy_conf_t *dummy_conf);
|
||||
|
||||
#if CONFIG_SPI_FLASH_UNDER_HIGH_FREQ
|
||||
|
||||
#if CONFIG_SPI_FLASH_HPM_AUTO
|
||||
// This only happens on S3, where HPM_AUTO leads to HPM_ON
|
||||
#warning High Performance Mode (QSPI Flash > 80MHz) is optional feature that depends on flash model. Read Docs First!
|
||||
#endif
|
||||
|
||||
const static char *HPM_TAG = "flash HPM";
|
||||
@@ -120,6 +134,7 @@ static esp_err_t spi_flash_high_performance_check_hpf_bit_5(void)
|
||||
|
||||
//-----------------For flash chips which enter HPM via adjust dummy-----------------------//
|
||||
|
||||
#if CONFIG_SPI_FLASH_HPM_DC_ON
|
||||
/**
|
||||
* @brief Probe the chip whether adjust dummy to enable HPM mode. Take XMC as an example:
|
||||
* Adjust dummy bits to enable HPM mode of the flash. If XMC works under 80MHz, the dummy bits
|
||||
@@ -203,6 +218,14 @@ static void spi_flash_hpm_get_dummy_xmc(spi_flash_hpm_dummy_conf_t *dummy_conf)
|
||||
dummy_conf->qout_dummy = SPI_FLASH_QOUT_DUMMY_BITLEN;
|
||||
dummy_conf->fastrd_dummy = SPI_FLASH_FASTRD_DUMMY_BITLEN;
|
||||
}
|
||||
#elif !CONFIG_SPI_FLASH_HPM_DC_DISABLE
|
||||
|
||||
//This is because bootloader doesn't support this
|
||||
#warning HPM-DC, which helps to run some flash > 80MHz by adjusting dummy cycles, is no longer enabled by default.
|
||||
#warning To enable this feature, your bootloader needs to have the support for it (by explicitly selecting BOOTLOADER_FLASH_DC_AWARE).
|
||||
#warning If your bootloader does not support it, select SPI_FLASH_HPM_DC_DISABLE to suppress the warning. READ DOCS FIRST!
|
||||
|
||||
#endif //CONFIG_SPI_FLASH_HPM_DC_ON
|
||||
|
||||
//-----------------For flash chips which enter HPM via write status register-----------------------//
|
||||
|
||||
@@ -284,6 +307,127 @@ static spi_flash_requirement_t spi_flash_hpm_chip_hpm_requirement_check_with_doi
|
||||
return chip_cap;
|
||||
}
|
||||
|
||||
const spi_flash_hpm_info_t __attribute__((weak)) spi_flash_hpm_enable_list[] = {
|
||||
/* vendor, chip_id, freq_threshold, temperature threshold, operation for setting high performance, reading HPF status, get dummy */
|
||||
{ "command", spi_flash_hpm_probe_chip_with_cmd, spi_flash_hpm_chip_hpm_requirement_check_with_cmd, spi_flash_enable_high_performance_send_cmd, spi_flash_high_performance_check_hpf_bit_5, spi_flash_hpm_get_dummy_generic },
|
||||
#if CONFIG_SPI_FLASH_HPM_DC_ON
|
||||
{ "dummy", spi_flash_hpm_probe_chip_with_dummy, spi_flash_hpm_chip_hpm_requirement_check_with_dummy, spi_flash_turn_high_performance_reconfig_dummy, spi_flash_high_performance_check_dummy_sr, spi_flash_hpm_get_dummy_xmc},
|
||||
#endif //CONFIG_SPI_FLASH_HPM_DC_ON
|
||||
{ "write sr3-bit5", spi_flash_hpm_probe_chip_with_write_hpf_bit_5, spi_flash_hpm_chip_hpm_requirement_check_with_write_hpf_bit_5, spi_flash_turn_high_performance_write_hpf_bit_5, spi_flash_high_performance_check_hpf_bit_5, spi_flash_hpm_get_dummy_generic},
|
||||
{ "noting-to-do", spi_flash_hpm_probe_chip_with_doing_nothing, spi_flash_hpm_chip_hpm_requirement_check_with_doing_nothing, NULL, NULL, spi_flash_hpm_get_dummy_generic},
|
||||
// default: do nothing, but keep the dummy get function. The first item with NULL as its probe will be the fallback.
|
||||
{ "NULL", NULL, NULL, NULL, NULL, spi_flash_hpm_get_dummy_generic},
|
||||
};
|
||||
|
||||
static const spi_flash_hpm_info_t *chip_hpm = NULL;
|
||||
|
||||
#if CONFIG_SPI_FLASH_HPM_DC_ON
|
||||
static bool s_hpm_dummy_changed = false;
|
||||
static spi_flash_hpm_dummy_conf_t s_dummy_conf;
|
||||
|
||||
const spi_flash_hpm_dummy_conf_t *spi_flash_hpm_get_dummy(void)
|
||||
{
|
||||
chip_hpm->flash_get_dummy(&s_dummy_conf);
|
||||
return &s_dummy_conf;
|
||||
}
|
||||
|
||||
bool spi_flash_hpm_dummy_adjust(void)
|
||||
{
|
||||
return s_hpm_dummy_changed;
|
||||
}
|
||||
#endif //CONFIG_SPI_FLASH_HPM_DC_ON
|
||||
|
||||
#if CONFIG_ESPTOOLPY_FLASHFREQ_120M
|
||||
#define FLASH_FREQUENCY 120
|
||||
#endif
|
||||
|
||||
esp_err_t spi_flash_enable_high_performance_mode(void)
|
||||
{
|
||||
uint32_t flash_chip_id = g_rom_flashchip.device_id;
|
||||
uint32_t flash_freq = FLASH_FREQUENCY;
|
||||
spi_flash_requirement_t hpm_requirement_check;
|
||||
// voltage and temperature has not been implemented, just leave an interface here. Complete in the future.
|
||||
int voltage = 0;
|
||||
int temperature = 0;
|
||||
|
||||
#if CONFIG_SPI_FLASH_HPM_AUTO
|
||||
ESP_EARLY_LOGW(HPM_TAG, "HPM mode is optional feature that depends on flash model. Read Docs First!");
|
||||
#endif
|
||||
|
||||
#if CONFIG_SPI_FLASH_HPM_DC_DISABLE
|
||||
// case 1: force disabled
|
||||
ESP_EARLY_LOGI(HPM_TAG, "w/o HPM-DC support");
|
||||
#elif CONFIG_SPI_FLASH_HPM_DC_ON
|
||||
// case 2: auto, and actually enabled
|
||||
ESP_EARLY_LOGI(HPM_TAG, "with HPM-DC support");
|
||||
#else
|
||||
// case 3: auto, but disabled (not supported by bootloader)
|
||||
ESP_EARLY_LOGW(HPM_TAG, "HPM mode with DC adjustment is disabled. Some flash models may not be supported. Read Docs First!");
|
||||
#endif
|
||||
|
||||
const spi_flash_hpm_info_t *chip = spi_flash_hpm_enable_list;
|
||||
esp_err_t ret = ESP_OK;
|
||||
while (chip->probe) {
|
||||
ret = chip->probe(flash_chip_id);
|
||||
if (ret == ESP_OK) {
|
||||
break;
|
||||
}
|
||||
chip++;
|
||||
}
|
||||
chip_hpm = chip;
|
||||
|
||||
/* When > 80 MHz, flash chips usually need special HPM support to run normally. The support is chip-specific. When
|
||||
* the chip is not in the known flash list, nothing will be done and there will be an warning.
|
||||
* When <= 80 MHz, it's assumed that all flash chips can run without chip-specific HPM support. This function will not be called and there will be no warning.
|
||||
*/
|
||||
if (ret != ESP_OK) {
|
||||
ESP_EARLY_LOGW(HPM_TAG, "High performance mode of this flash model hasn't been supported.");
|
||||
return ret;
|
||||
}
|
||||
|
||||
hpm_requirement_check = chip_hpm->chip_hpm_requirement_check(flash_chip_id, flash_freq, voltage, temperature);
|
||||
if ((hpm_requirement_check == SPI_FLASH_HPM_CMD_NEEDED) || (hpm_requirement_check == SPI_FLASH_HPM_DUMMY_NEEDED) || (hpm_requirement_check == SPI_FLASH_HPM_WRITE_SR_NEEDED)) {
|
||||
ESP_EARLY_LOGI(HPM_TAG, "Enabling flash high speed mode by %s", chip_hpm->method);
|
||||
chip_hpm->flash_hpm_enable();
|
||||
ESP_EARLY_LOGD(HPM_TAG, "Checking whether HPM has been executed");
|
||||
|
||||
if (chip_hpm->flash_hpf_check() != ESP_OK) {
|
||||
ESP_EARLY_LOGE(HPM_TAG, "Flash high performance mode hasn't been executed successfully");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#if CONFIG_SPI_FLASH_HPM_DC_ON
|
||||
s_hpm_dummy_changed = (hpm_requirement_check == SPI_FLASH_HPM_DUMMY_NEEDED) ? true : false;
|
||||
#else
|
||||
assert(hpm_requirement_check != SPI_FLASH_HPM_DUMMY_NEEDED);
|
||||
#endif
|
||||
} else if (hpm_requirement_check == SPI_FLASH_HPM_BEYOND_LIMIT) {
|
||||
ESP_EARLY_LOGE(HPM_TAG, "Flash does not have the ability to raise to that frequency");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
#else
|
||||
//!CONFIG_SPI_FLASH_UNDER_HIGH_FREQ
|
||||
|
||||
static spi_flash_hpm_dummy_conf_t s_dummy_conf;
|
||||
|
||||
esp_err_t spi_flash_enable_high_performance_mode(void)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
const spi_flash_hpm_dummy_conf_t *spi_flash_hpm_get_dummy(void)
|
||||
{
|
||||
spi_flash_hpm_get_dummy_generic(&s_dummy_conf);
|
||||
return &s_dummy_conf;
|
||||
}
|
||||
|
||||
bool spi_flash_hpm_dummy_adjust(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif //CONFIG_SPI_FLASH_UNDER_HIGH_FREQ
|
||||
|
||||
//-----------------------generic functions-------------------------------------//
|
||||
|
||||
/**
|
||||
@@ -298,73 +442,3 @@ void __attribute__((weak)) spi_flash_hpm_get_dummy_generic(spi_flash_hpm_dummy_c
|
||||
dummy_conf->qout_dummy = SPI_FLASH_QOUT_DUMMY_BITLEN;
|
||||
dummy_conf->fastrd_dummy = SPI_FLASH_FASTRD_DUMMY_BITLEN;
|
||||
}
|
||||
|
||||
const spi_flash_hpm_info_t __attribute__((weak)) spi_flash_hpm_enable_list[] = {
|
||||
/* vendor, chip_id, freq_threshold, temperature threshold, operation for setting high performance, reading HPF status, get dummy */
|
||||
{ "command", spi_flash_hpm_probe_chip_with_cmd, spi_flash_hpm_chip_hpm_requirement_check_with_cmd, spi_flash_enable_high_performance_send_cmd, spi_flash_high_performance_check_hpf_bit_5, spi_flash_hpm_get_dummy_generic },
|
||||
{ "dummy", spi_flash_hpm_probe_chip_with_dummy, spi_flash_hpm_chip_hpm_requirement_check_with_dummy, spi_flash_turn_high_performance_reconfig_dummy, spi_flash_high_performance_check_dummy_sr, spi_flash_hpm_get_dummy_xmc},
|
||||
{ "write sr3-bit5", spi_flash_hpm_probe_chip_with_write_hpf_bit_5, spi_flash_hpm_chip_hpm_requirement_check_with_write_hpf_bit_5, spi_flash_turn_high_performance_write_hpf_bit_5, spi_flash_high_performance_check_hpf_bit_5, spi_flash_hpm_get_dummy_generic},
|
||||
{ "noting-to-do", spi_flash_hpm_probe_chip_with_doing_nothing, spi_flash_hpm_chip_hpm_requirement_check_with_doing_nothing, NULL, NULL, spi_flash_hpm_get_dummy_generic},
|
||||
// default: do nothing, but keep the dummy get function. The first item with NULL as its probe will be the fallback.
|
||||
{ "NULL", NULL, NULL, NULL, NULL, spi_flash_hpm_get_dummy_generic},
|
||||
};
|
||||
|
||||
static const spi_flash_hpm_info_t *chip_hpm = NULL;
|
||||
static spi_flash_hpm_dummy_conf_t dummy_conf;
|
||||
static bool hpm_dummy_changed = false;
|
||||
|
||||
esp_err_t spi_flash_enable_high_performance_mode(void)
|
||||
{
|
||||
uint32_t flash_chip_id = g_rom_flashchip.device_id;
|
||||
uint32_t flash_freq = FLASH_FREQUENCY;
|
||||
spi_flash_requirement_t hpm_requirement_check;
|
||||
// voltage and temperature has not been implemented, just leave an interface here. Complete in the future.
|
||||
int voltage = 0;
|
||||
int temperature = 0;
|
||||
|
||||
const spi_flash_hpm_info_t *chip = spi_flash_hpm_enable_list;
|
||||
esp_err_t ret = ESP_OK;
|
||||
while (chip->probe) {
|
||||
ret = chip->probe(flash_chip_id);
|
||||
if (ret == ESP_OK) {
|
||||
break;
|
||||
}
|
||||
chip++;
|
||||
}
|
||||
chip_hpm = chip;
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
#if (FLASH_FREQUENCY == 120)
|
||||
ESP_EARLY_LOGW(HPM_TAG, "Flash high performance mode hasn't been supported");
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
hpm_requirement_check = chip_hpm->chip_hpm_requirement_check(flash_chip_id, flash_freq, voltage, temperature);
|
||||
if ((hpm_requirement_check == SPI_FLASH_HPM_CMD_NEEDED) || (hpm_requirement_check == SPI_FLASH_HPM_DUMMY_NEEDED) || (hpm_requirement_check == SPI_FLASH_HPM_WRITE_SR_NEEDED)) {
|
||||
ESP_EARLY_LOGI(HPM_TAG, "Enabling flash high speed mode by %s", chip_hpm->method);
|
||||
chip_hpm->flash_hpm_enable();
|
||||
ESP_EARLY_LOGD(HPM_TAG, "Checking whether HPM has been executed");
|
||||
|
||||
if (chip_hpm->flash_hpf_check() != ESP_OK) {
|
||||
ESP_EARLY_LOGE(HPM_TAG, "Flash high performance mode hasn't been executed successfully");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
hpm_dummy_changed = (hpm_requirement_check == SPI_FLASH_HPM_DUMMY_NEEDED) ? true : false;
|
||||
} else if (hpm_requirement_check == SPI_FLASH_HPM_BEYOND_LIMIT) {
|
||||
ESP_EARLY_LOGE(HPM_TAG, "Flash does not have the ability to raise to that frequency");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
const spi_flash_hpm_dummy_conf_t *spi_flash_hpm_get_dummy(void)
|
||||
{
|
||||
chip_hpm->flash_get_dummy(&dummy_conf);
|
||||
return &dummy_conf;
|
||||
}
|
||||
|
||||
bool spi_flash_hpm_dummy_adjust(void)
|
||||
{
|
||||
return hpm_dummy_changed;
|
||||
}
|
||||
|
Reference in New Issue
Block a user