From 421e77d773633526bdc10a4abd1f5aac0dedd656 Mon Sep 17 00:00:00 2001 From: Cao Sen Miao Date: Tue, 23 Aug 2022 18:53:37 +0800 Subject: [PATCH] spi_flash: Add several flash chips HPM(120M) support --- .../spi_flash/include/spi_flash_override.h | 3 +- components/spi_flash/spi_flash_hpm_enable.c | 107 +++++++++++++----- 2 files changed, 82 insertions(+), 28 deletions(-) diff --git a/components/spi_flash/include/spi_flash_override.h b/components/spi_flash/include/spi_flash_override.h index 5e763c9bca..7f01576dee 100644 --- a/components/spi_flash/include/spi_flash_override.h +++ b/components/spi_flash/include/spi_flash_override.h @@ -29,6 +29,7 @@ typedef struct { typedef enum { SPI_FLASH_HPM_CMD_NEEDED, // Means that in the certain condition, flash needs to enter the high performance mode by command. SPI_FLASH_HPM_DUMMY_NEEDED, // Means that in the certain condition, flash needs to enter the high performance mode by adjusting dummy. + SPI_FLASH_HPM_WRITE_SR_NEEDED, // Means that in the certain condition, flash needs to enter the high performance mode by writing status register. SPI_FLASH_HPM_UNNEEDED, // Means that flash doesn't need to enter the high performance mode. SPI_FLASH_HPM_BEYOND_LIMIT, // Means that flash has no capability to meet that condition. } spi_flash_requirement_t; @@ -41,7 +42,7 @@ typedef spi_flash_requirement_t (*spi_flash_hpm_chip_requirement_check_t)(uint32 typedef struct __attribute__((packed)) { - const char *manufacturer; /* Flash vendor */ + const char *method; /* Flash HPM method */ spi_flash_hpm_probe_fn_t probe; spi_flash_hpm_chip_requirement_check_t chip_hpm_requirement_check; spi_flash_hpm_enable_fn_t flash_hpm_enable; diff --git a/components/spi_flash/spi_flash_hpm_enable.c b/components/spi_flash/spi_flash_hpm_enable.c index 9c808c1cff..81659a2e03 100644 --- a/components/spi_flash/spi_flash_hpm_enable.c +++ b/components/spi_flash/spi_flash_hpm_enable.c @@ -48,6 +48,8 @@ extern uint32_t bootloader_flash_execute_command_common( uint8_t mosi_len, uint32_t mosi_data, uint8_t miso_len); +extern uint32_t IRAM_ATTR bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_num); + //-----------------For flash chips which enter HPM via command-----------------------// /** @@ -61,7 +63,14 @@ static esp_err_t spi_flash_hpm_probe_chip_with_cmd(uint32_t flash_id) /* The flash listed here should enter the HPM with command 0xA3 */ case 0xC84016: case 0xC84017: - break; + // Read BYTE4 in SFDP, 0 means C series, 6 means E series + uint32_t gd_sfdp = bootloader_flash_read_sfdp(0x4, 1); + if (gd_sfdp == 0x0) { + break; + } else { + ret = ESP_ERR_NOT_FOUND; + break; + } default: ret = ESP_ERR_NOT_FOUND; break; @@ -75,18 +84,10 @@ static spi_flash_requirement_t spi_flash_hpm_chip_hpm_requirement_check_with_cmd (void)voltage_mv; (void)temperautre; spi_flash_requirement_t chip_cap = SPI_FLASH_HPM_UNNEEDED; - switch (flash_id) { - /* The flash listed here should enter the HPM with command 0xA3 */ - case 0xC84016: - case 0xC84017: - if (freq_mhz > 80) { - chip_cap = SPI_FLASH_HPM_CMD_NEEDED; - } - break; - default: - chip_cap = SPI_FLASH_HPM_UNNEEDED; - break; + if (freq_mhz > 80) { + chip_cap = SPI_FLASH_HPM_CMD_NEEDED; } + ESP_EARLY_LOGD(HPM_TAG, "HPM with command, status is %d", chip_cap); return chip_cap; } @@ -130,6 +131,17 @@ static esp_err_t spi_flash_hpm_probe_chip_with_dummy(uint32_t flash_id) case 0x204017: case 0x204018: break; + // GD chips. + case 0xC84017: + case 0xC84018: + // Read BYTE4 in SFDP, 0 means C series, 6 means E series + uint32_t gd_sfdp = bootloader_flash_read_sfdp(0x4, 1); + if (gd_sfdp == 0x6) { + break; + } else { + ret = ESP_ERR_NOT_FOUND; + break; + } default: ret = ESP_ERR_NOT_FOUND; break; @@ -143,18 +155,11 @@ static spi_flash_requirement_t spi_flash_hpm_chip_hpm_requirement_check_with_dum (void)voltage_mv; (void)temperautre; spi_flash_requirement_t chip_cap = SPI_FLASH_HPM_UNNEEDED; - switch (flash_id) { - /* The flash listed here should enter the HPM with command 0xA3 */ - case 0x204017: - case 0x204018: - if (freq_mhz >= 104) { - chip_cap = SPI_FLASH_HPM_DUMMY_NEEDED; - } - break; - default: - chip_cap = SPI_FLASH_HPM_UNNEEDED; - break; + + if (freq_mhz >= 104) { + chip_cap = SPI_FLASH_HPM_DUMMY_NEEDED; } + ESP_EARLY_LOGD(HPM_TAG, "HPM with dummy, status is %d", chip_cap); return chip_cap; } @@ -194,6 +199,53 @@ static void spi_flash_hpm_get_dummy_xmc(spi_flash_hpm_dummy_conf_t *dummy_conf) dummy_conf->fastrd_dummy = SPI_FLASH_FASTRD_DUMMY_BITLEN; } +//-----------------For flash chips which enter HPM via write status register-----------------------// + +/** + * @brief Probe the chip whether to write status register to enable HPM mode. Take ZB as an example: + * Write status register bits to enable HPM mode of the flash. If ZB works under 80MHz, the register value + * would be 0, but when works under 120MHz, the register value would be 1. + */ +static esp_err_t spi_flash_hpm_probe_chip_with_write_hpf_bit_5(uint32_t flash_id) +{ + esp_err_t ret = ESP_OK; + switch (flash_id) { + /* The flash listed here should enter the HPM by adjusting dummy cycles */ + // ZB chips. + case 0x5E4016: + break; + default: + ret = ESP_ERR_NOT_FOUND; + break; + } + return ret; +} + +static spi_flash_requirement_t spi_flash_hpm_chip_hpm_requirement_check_with_write_hpf_bit_5(uint32_t flash_id, uint32_t freq_mhz, int voltage_mv, int temperautre) +{ + // voltage and temperature are not been used now, to be completed in the future. + (void)voltage_mv; + (void)temperautre; + spi_flash_requirement_t chip_cap = SPI_FLASH_HPM_UNNEEDED; + + if (freq_mhz >= 104) { + chip_cap = SPI_FLASH_HPM_WRITE_SR_NEEDED; + } + ESP_EARLY_LOGD(HPM_TAG, "HPM with dummy, status is %d", chip_cap); + return chip_cap; +} + +/** + * @brief Write bit 5 in status 3 + */ +static void spi_flash_turn_high_performance_write_hpf_bit_5(void) +{ + uint8_t old_status_3 = bootloader_read_status_8b_rdsr3(); + uint8_t new_status = (old_status_3 | 0x10); + bootloader_execute_flash_command(CMD_WRENVSR, 0, 0, 0); + bootloader_write_status_8b_wrsr3(new_status); + esp_rom_spiflash_wait_idle(&g_rom_flashchip); +} //-----------------------generic functions-------------------------------------// @@ -212,8 +264,9 @@ void __attribute__((weak)) spi_flash_hpm_get_dummy_generic(spi_flash_hpm_dummy_c 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 */ - { "GD", 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 }, - { "XMC", 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}, + { "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}, // 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}, }; @@ -250,8 +303,8 @@ esp_err_t spi_flash_enable_high_performance_mode(void) } 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)) { - ESP_EARLY_LOGI(HPM_TAG, "Enabling high speed mode for chip %s", chip_hpm->manufacturer); + 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");