Kaynağa Gözat

spi_flash: Add several flash chips HPM(120M) support

Cao Sen Miao 3 yıl önce
ebeveyn
işleme
421e77d773

+ 2 - 1
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;

+ 80 - 27
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");