Przeglądaj źródła

spi_flash: re-enable the HPM mode on several XMC chips

Cao Sen Miao 3 lat temu
rodzic
commit
ec6a56ed0c

+ 11 - 0
components/bootloader_support/bootloader_flash/include/bootloader_flash_priv.h

@@ -42,6 +42,7 @@ extern "C" {
 #define CMD_WRSR2      0x31 /* Not all SPI flash uses this command */
 #define CMD_WRSR3      0x11 /* Not all SPI flash uses this command */
 #define CMD_WREN       0x06
+#define CMD_WRENVSR    0x50 /* Flash write enable for volatile SR bits */
 #define CMD_WRDI       0x04
 #define CMD_RDSR       0x05
 #define CMD_RDSR2      0x35 /* Not all SPI flash uses this command */
@@ -50,6 +51,8 @@ extern "C" {
 #define CMD_RDSFDP     0x5A /* Read the SFDP of the flash */
 #define CMD_WRAP       0x77 /* Set burst with wrap command */
 #define CMD_RESUME     0x7A /* Resume command to clear flash suspend bit */
+#define CMD_RESETEN    0x66
+#define CMD_RESET      0x99
 
 
 /* Provide a Flash API for bootloader_support code,
@@ -172,6 +175,14 @@ uint32_t bootloader_flash_read_sfdp(uint32_t sfdp_addr, unsigned int miso_byte_n
  */
 void bootloader_enable_wp(void);
 
+/**
+ * @brief Once this function is called,
+ * any on-going internal operations will be terminated and the device will return to its default power-on
+ * state and lose all the current volatile settings, such as Volatile Status Register bits, Write Enable Latch
+ * (WEL) status, Program/Erase Suspend status, etc.
+ */
+void bootloader_spi_flash_reset(void);
+
 #ifdef __cplusplus
 }
 #endif

+ 6 - 0
components/bootloader_support/bootloader_flash/src/bootloader_flash.c

@@ -603,6 +603,12 @@ uint32_t IRAM_ATTR bootloader_read_flash_id(void)
     return id;
 }
 
+void bootloader_spi_flash_reset(void)
+{
+    bootloader_execute_flash_command(CMD_RESETEN, 0, 0, 0);
+    bootloader_execute_flash_command(CMD_RESET, 0, 0, 0);
+}
+
 #if SOC_CACHE_SUPPORT_WRAP
 esp_err_t bootloader_flash_wrap_set(spi_flash_wrap_mode_t mode)
 {

+ 5 - 0
components/bootloader_support/src/esp32s3/bootloader_esp32s3.c

@@ -210,6 +210,11 @@ static esp_err_t bootloader_init_spi_flash(void)
     }
 #endif
 
+#if CONFIG_SPI_FLASH_HPM_ENABLE
+    // Reset flash, clear volatile bits DC[0:1]. Make it work under default mode to boot.
+    bootloader_spi_flash_reset();
+#endif
+
     bootloader_flash_unlock();
 
 #if CONFIG_ESPTOOLPY_FLASHMODE_QIO || CONFIG_ESPTOOLPY_FLASHMODE_QOUT

+ 1 - 0
components/esptool_py/Kconfig.projbuild

@@ -74,6 +74,7 @@ menu "Serial flasher config"
         default ESPTOOLPY_FLASHFREQ_48M if IDF_TARGET_ESP32H2
         config ESPTOOLPY_FLASHFREQ_120M
             bool "120 MHz"
+            select SPI_FLASH_HPM_ENABLE
             depends on SOC_MEMSPI_SRC_FREQ_120M && ESPTOOLPY_FLASH_SAMPLE_MODE_STR
         config ESPTOOLPY_FLASHFREQ_80M
             bool "80 MHz"

+ 11 - 1
components/esptool_py/project_include.cmake

@@ -20,7 +20,17 @@ set(ESPSECUREPY ${python} "${CMAKE_CURRENT_LIST_DIR}/esptool/espsecure.py")
 set(ESPEFUSEPY ${python} "${CMAKE_CURRENT_LIST_DIR}/esptool/espefuse.py")
 set(ESPMONITOR ${python} "${idf_path}/tools/idf_monitor.py")
 
-set(ESPFLASHMODE ${CONFIG_ESPTOOLPY_FLASHMODE})
+if(CONFIG_SPI_FLASH_HPM_ENABLE)
+# When set flash frequency to 120M, must keep 1st bootloader work under ``DOUT`` mode
+# because on some flash chips, 120M will modify the status register,
+# which will make ROM won't work.
+# This change intends to be for esptool only and the bootloader should keep use
+# ``DOUT`` mode.
+    set(ESPFLASHMODE "dout")
+    message("Note: HPM is enabled for the flash, force the ROM bootloader into DOUT mode for stable boot on")
+else()
+    set(ESPFLASHMODE ${CONFIG_ESPTOOLPY_FLASHMODE})
+endif()
 set(ESPFLASHFREQ ${CONFIG_ESPTOOLPY_FLASHFREQ})
 set(ESPFLASHSIZE ${CONFIG_ESPTOOLPY_FLASHSIZE})
 

+ 7 - 0
components/spi_flash/Kconfig

@@ -300,4 +300,11 @@ menu "SPI Flash driver"
             application is not using flash encryption feature and is in need of some additional
             memory from IRAM region (~1KB) then this config can be disabled.
 
+    config SPI_FLASH_HPM_ENABLE
+        bool
+        default n
+        help
+            This option is invisible, and will be selected automatically
+            when ``ESPTOOLPY_FLASHFREQ_120M`` is selected.
+
 endmenu

+ 9 - 5
components/spi_flash/esp32s3/spi_timing_config.c

@@ -13,6 +13,7 @@
 #include "esp_log.h"
 #include "soc/spi_mem_reg.h"
 #include "spi_timing_config.h"
+#include "esp_private/spi_flash_os.h"
 
 #define OPI_PSRAM_SYNC_READ           0x0000
 #define OPI_PSRAM_SYNC_WRITE          0x8080
@@ -164,21 +165,24 @@ void spi_timing_config_flash_set_extra_dummy(uint8_t spi_num, uint8_t extra_dumm
     if (ctrl_reg & MULTI_LINE_MASK_OCT_FLASH) {
         abort();
     }
+    // Only Quad Flash will run into this branch.
+    // So simply get the hpm dummy here by calling `spi_flash_hpm_get_dummy()`
+    const spi_flash_hpm_dummy_conf_t *dummy_cycle = spi_flash_hpm_get_dummy();
     switch (ctrl_reg & MULTI_LINE_MASK_QUAD_FLASH) {
         case SPI_FLASH_QIO_MODE:
-            dummy = SPI1_R_QIO_DUMMY_CYCLELEN;
+            dummy = dummy_cycle->qio_dummy - 1;
             break;
         case SPI_FLASH_QUAD_MODE:
-            dummy = SPI1_R_FAST_DUMMY_CYCLELEN;
+            dummy = dummy_cycle->qout_dummy - 1;
             break;
         case SPI_FLASH_DIO_MODE:
-            dummy = SPI1_R_DIO_DUMMY_CYCLELEN;
+            dummy = dummy_cycle->dio_dummy - 1;
             break;
         case SPI_FLASH_DUAL_MODE:
-            dummy = SPI1_R_FAST_DUMMY_CYCLELEN;
+            dummy = dummy_cycle->dout_dummy - 1;
             break;
         case SPI_FLASH_FAST_MODE:
-            dummy = SPI1_R_FAST_DUMMY_CYCLELEN;
+            dummy = dummy_cycle->fastrd_dummy - 1;
             break;
         case SPI_FLASH_SLOW_MODE:
             dummy = 0;

+ 7 - 0
components/spi_flash/esp_flash_spi_init.c

@@ -381,6 +381,13 @@ esp_err_t esp_flash_init_default_chip(void)
         return err;
     }
 #endif
+
+#if CONFIG_SPI_FLASH_HPM_ENABLE
+    if (spi_flash_hpm_dummy_adjust()) {
+        default_chip.hpm_dummy_ena = 1;
+    }
+#endif
+
     return ESP_OK;
 }
 

+ 2 - 1
components/spi_flash/include/esp_flash.h

@@ -100,7 +100,8 @@ struct esp_flash_t {
     uint32_t size;                   ///< Size of SPI flash in bytes. If 0, size will be detected during initialisation.
     uint32_t chip_id;               ///< Detected chip id.
     uint32_t busy             :1;   ///< This flag is used to verify chip's status.
-    uint32_t reserved_flags   :31;  ///< reserved.
+    uint32_t hpm_dummy_ena    :1;   ///< This flag is used to verify whether flash works under HPM status.
+    uint32_t reserved_flags   :30;  ///< reserved.
 };
 
 

+ 9 - 2
components/spi_flash/include/esp_private/spi_flash_os.h

@@ -165,9 +165,16 @@ esp_err_t spi_flash_enable_high_performance_mode(void);
  *        This can be used when one flash has several dummy configurations to enable the high performance mode.
  * @note Don't forget to subtract one when assign to the register of mspi e.g. if the value you get is 4, (4-1=3) should be assigned to the register.
  *
- * @return Pointer to bootlaoder_flash_dummy_conf_t.
+ * @return Pointer to spi_flash_hpm_dummy_conf_t.
  */
-const spi_flash_hpm_dummy_conf_t *spi_flash_get_dummy(void);
+const spi_flash_hpm_dummy_conf_t *spi_flash_hpm_get_dummy(void);
+
+/**
+ * @brief Used to judge whether flash works under HPM mode with dummy adjustment.
+ *
+ * @return true Yes, and work under HPM with adjusting dummy. Otherwise, false.
+ */
+bool spi_flash_hpm_dummy_adjust(void);
 
 typedef enum {
     FLASH_WRAP_MODE_8B = 0,

+ 2 - 0
components/spi_flash/include/spi_flash/spi_flash_defs.h

@@ -67,3 +67,5 @@
 #define SPI_FLASH_OPISTR_DUMMY_BITLEN   20
 #define SPI_FLASH_OPIDTR_ADDR_BITLEN    32
 #define SPI_FLASH_OPIDTR_DUMMY_BITLEN   40
+#define SPI_FLASH_QIO_HPM_DUMMY_BITLEN  10
+#define SPI_FLASH_DIO_HPM_DUMMY_BITLEN  8

+ 2 - 1
components/spi_flash/include/spi_flash_override.h

@@ -27,7 +27,8 @@ typedef struct {
 } spi_flash_hpm_dummy_conf_t;
 
 typedef enum {
-    SPI_FLASH_HPM_NEEDED,             // Means that in the certain condition, flash needs to enter the high performance mode.
+    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_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;

+ 20 - 8
components/spi_flash/spi_flash_chip_generic.c

@@ -33,6 +33,20 @@ DRAM_ATTR const static flash_chip_dummy_t default_flash_chip_dummy = {
     .slowrd_dummy_bitlen = SPI_FLASH_SLOWRD_DUMMY_BITLEN,
 };
 
+DRAM_ATTR const static flash_chip_dummy_t hpm_flash_chip_dummy = {
+    .dio_dummy_bitlen = SPI_FLASH_DIO_HPM_DUMMY_BITLEN,
+    .qio_dummy_bitlen = SPI_FLASH_QIO_HPM_DUMMY_BITLEN,
+    .qout_dummy_bitlen = SPI_FLASH_QOUT_DUMMY_BITLEN,
+    .dout_dummy_bitlen = SPI_FLASH_DOUT_DUMMY_BITLEN,
+    .fastrd_dummy_bitlen = SPI_FLASH_FASTRD_DUMMY_BITLEN,
+    .slowrd_dummy_bitlen = SPI_FLASH_SLOWRD_DUMMY_BITLEN,
+};
+
+
+DRAM_ATTR flash_chip_dummy_t *rom_flash_chip_dummy = (flash_chip_dummy_t *)&default_flash_chip_dummy;
+
+DRAM_ATTR flash_chip_dummy_t *rom_flash_chip_dummy_hpm = (flash_chip_dummy_t *)&hpm_flash_chip_dummy;
+
 // These are the pointer to HW flash encryption. Default using hardware encryption.
 DRAM_ATTR static spi_flash_encryption_t esp_flash_encryption_default __attribute__((__unused__)) = {
     .flash_encryption_enable = spi_flash_encryption_hal_enable,
@@ -43,8 +57,6 @@ DRAM_ATTR static spi_flash_encryption_t esp_flash_encryption_default __attribute
     .flash_encryption_check = spi_flash_encryption_hal_check,
 };
 
-DRAM_ATTR flash_chip_dummy_t *rom_flash_chip_dummy = (flash_chip_dummy_t *)&default_flash_chip_dummy;
-
 #define SPI_FLASH_DEFAULT_IDLE_TIMEOUT_MS           200
 #define SPI_FLASH_GENERIC_CHIP_ERASE_TIMEOUT_MS     4000
 #define SPI_FLASH_GENERIC_SECTOR_ERASE_TIMEOUT_MS   600  //according to GD25Q127(125°) + 100ms
@@ -467,35 +479,35 @@ esp_err_t spi_flash_chip_generic_config_host_io_mode(esp_flash_t *chip, uint32_t
     case SPI_FLASH_QIO:
         //for QIO mode, the 4 bit right after the address are used for continuous mode, should be set to 0 to avoid that.
         addr_bitlen = SPI_FLASH_QIO_ADDR_BITLEN;
-        dummy_cyclelen_base = rom_flash_chip_dummy->qio_dummy_bitlen;
+        dummy_cyclelen_base = (chip->hpm_dummy_ena ? rom_flash_chip_dummy_hpm->qio_dummy_bitlen : rom_flash_chip_dummy->qio_dummy_bitlen);
         read_command = (addr_32bit? CMD_FASTRD_QIO_4B: CMD_FASTRD_QIO);
         conf_required = true;
         break;
     case SPI_FLASH_QOUT:
         addr_bitlen = SPI_FLASH_QOUT_ADDR_BITLEN;
-        dummy_cyclelen_base = rom_flash_chip_dummy->qout_dummy_bitlen;
+        dummy_cyclelen_base = (chip->hpm_dummy_ena ? rom_flash_chip_dummy_hpm->qout_dummy_bitlen : rom_flash_chip_dummy->qout_dummy_bitlen);
         read_command = (addr_32bit? CMD_FASTRD_QUAD_4B: CMD_FASTRD_QUAD);
         break;
     case SPI_FLASH_DIO:
         //for DIO mode, the 4 bit right after the address are used for continuous mode, should be set to 0 to avoid that.
         addr_bitlen = SPI_FLASH_DIO_ADDR_BITLEN;
-        dummy_cyclelen_base = rom_flash_chip_dummy->dio_dummy_bitlen;
+        dummy_cyclelen_base = (chip->hpm_dummy_ena ? rom_flash_chip_dummy_hpm->dio_dummy_bitlen : rom_flash_chip_dummy->dio_dummy_bitlen);
         read_command = (addr_32bit? CMD_FASTRD_DIO_4B: CMD_FASTRD_DIO);
         conf_required = true;
         break;
     case SPI_FLASH_DOUT:
         addr_bitlen = SPI_FLASH_DOUT_ADDR_BITLEN;
-        dummy_cyclelen_base = rom_flash_chip_dummy->dout_dummy_bitlen;
+        dummy_cyclelen_base = (chip->hpm_dummy_ena ? rom_flash_chip_dummy_hpm->dout_dummy_bitlen : rom_flash_chip_dummy->dout_dummy_bitlen);
         read_command = (addr_32bit? CMD_FASTRD_DUAL_4B: CMD_FASTRD_DUAL);
         break;
     case SPI_FLASH_FASTRD:
         addr_bitlen = SPI_FLASH_FASTRD_ADDR_BITLEN;
-        dummy_cyclelen_base = rom_flash_chip_dummy->fastrd_dummy_bitlen;
+        dummy_cyclelen_base = (chip->hpm_dummy_ena ? rom_flash_chip_dummy_hpm->fastrd_dummy_bitlen : rom_flash_chip_dummy->fastrd_dummy_bitlen);
         read_command = (addr_32bit? CMD_FASTRD_4B: CMD_FASTRD);
         break;
     case SPI_FLASH_SLOWRD:
         addr_bitlen = SPI_FLASH_SLOWRD_ADDR_BITLEN;
-        dummy_cyclelen_base = rom_flash_chip_dummy->slowrd_dummy_bitlen;
+        dummy_cyclelen_base = (chip->hpm_dummy_ena ? rom_flash_chip_dummy_hpm->slowrd_dummy_bitlen : rom_flash_chip_dummy->slowrd_dummy_bitlen);
         read_command = (addr_32bit? CMD_READ_4B: CMD_READ);
         break;
     default:

+ 29 - 15
components/spi_flash/spi_flash_hpm_enable.c

@@ -80,7 +80,7 @@ static spi_flash_requirement_t spi_flash_hpm_chip_hpm_requirement_check_with_cmd
     case 0xC84016:
     case 0xC84017:
         if (freq_mhz > 80) {
-            chip_cap = SPI_FLASH_HPM_NEEDED;
+            chip_cap = SPI_FLASH_HPM_CMD_NEEDED;
         }
         break;
     default:
@@ -126,6 +126,10 @@ static esp_err_t spi_flash_hpm_probe_chip_with_dummy(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 */
+    // XMC chips.
+    case 0x204017:
+    case 0x204018:
+        break;
     default:
         ret = ESP_ERR_NOT_FOUND;
         break;
@@ -142,8 +146,9 @@ static spi_flash_requirement_t spi_flash_hpm_chip_hpm_requirement_check_with_dum
     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_NEEDED;
+            chip_cap = SPI_FLASH_HPM_DUMMY_NEEDED;
         }
         break;
     default:
@@ -164,7 +169,7 @@ static void spi_flash_turn_high_performance_reconfig_dummy(void)
 {
     uint8_t old_status_3 = bootloader_read_status_8b_rdsr3();
     uint8_t new_status = (old_status_3 | 0x03);
-    bootloader_execute_flash_command(CMD_WREN, 0, 0, 0);
+    bootloader_execute_flash_command(CMD_WRENVSR, 0, 0, 0);
     bootloader_write_status_8b_wrsr3(new_status);
     esp_rom_spiflash_wait_idle(&g_rom_flashchip);
 }
@@ -182,11 +187,11 @@ static esp_err_t spi_flash_high_performance_check_dummy_sr(void)
 
 static void spi_flash_hpm_get_dummy_xmc(spi_flash_hpm_dummy_conf_t *dummy_conf)
 {
-    dummy_conf->dio_dummy = 8;
-    dummy_conf->dout_dummy = 8;
-    dummy_conf->qio_dummy = 10;
-    dummy_conf->qout_dummy = 8;
-    dummy_conf->fastrd_dummy = 8;
+    dummy_conf->dio_dummy = SPI_FLASH_DIO_HPM_DUMMY_BITLEN;
+    dummy_conf->dout_dummy = SPI_FLASH_DOUT_DUMMY_BITLEN;
+    dummy_conf->qio_dummy = SPI_FLASH_QIO_HPM_DUMMY_BITLEN;
+    dummy_conf->qout_dummy = SPI_FLASH_QOUT_DUMMY_BITLEN;
+    dummy_conf->fastrd_dummy = SPI_FLASH_FASTRD_DUMMY_BITLEN;
 }
 
 
@@ -198,11 +203,11 @@ static void spi_flash_hpm_get_dummy_xmc(spi_flash_hpm_dummy_conf_t *dummy_conf)
  */
 void __attribute__((weak)) spi_flash_hpm_get_dummy_generic(spi_flash_hpm_dummy_conf_t *dummy_conf)
 {
-    dummy_conf->dio_dummy = 4;
-    dummy_conf->dout_dummy = 8;
-    dummy_conf->qio_dummy = 6;
-    dummy_conf->qout_dummy = 8;
-    dummy_conf->fastrd_dummy = 8;
+    dummy_conf->dio_dummy = SPI_FLASH_DIO_DUMMY_BITLEN;
+    dummy_conf->dout_dummy = SPI_FLASH_DOUT_DUMMY_BITLEN;
+    dummy_conf->qio_dummy = SPI_FLASH_QIO_DUMMY_BITLEN;
+    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[] = {
@@ -215,11 +220,13 @@ const spi_flash_hpm_info_t __attribute__((weak)) spi_flash_hpm_enable_list[] = {
 
 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;
@@ -242,7 +249,8 @@ esp_err_t spi_flash_enable_high_performance_mode(void)
         return ret;
     }
 
-    if (chip_hpm->chip_hpm_requirement_check(flash_chip_id, flash_freq, voltage, temperature) == SPI_FLASH_HPM_NEEDED) {
+    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);
         chip_hpm->flash_hpm_enable();
         ESP_EARLY_LOGD(HPM_TAG, "Checking whether HPM has been executed");
@@ -251,7 +259,8 @@ esp_err_t spi_flash_enable_high_performance_mode(void)
             ESP_EARLY_LOGE(HPM_TAG, "Flash high performance mode hasn't been executed successfully");
             return ESP_FAIL;
         }
-    } else if (chip_hpm->chip_hpm_requirement_check(flash_chip_id, flash_freq, voltage, temperature) == SPI_FLASH_HPM_BEYOND_LIMIT) {
+        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;
     }
@@ -263,3 +272,8 @@ 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;
+}