Procházet zdrojové kódy

esp_flash: fix the regression of non-quad mode by default chip driver

Armando před 5 roky
rodič
revize
aa5b4fb372

+ 8 - 7
components/spi_flash/esp_flash_spi_init.c

@@ -70,17 +70,17 @@ static IRAM_ATTR NOINLINE_ATTR void cs_initialize(esp_flash_t *chip, const esp_f
     int cs_io_num = config->cs_io_num;
     int spics_in = spi_periph_signal[config->host_id].spics_in;
     int spics_out = spi_periph_signal[config->host_id].spics_out[config->cs_id];
+    int spics_func = spi_periph_signal[config->host_id].func;
     uint32_t iomux_reg = GPIO_PIN_MUX_REG[cs_io_num];
 
     //To avoid the panic caused by flash data line conflicts during cs line
     //initialization, disable the cache temporarily
     chip->os_func->start(chip->os_func_data);
     if (use_iomux) {
-        GPIO.func_in_sel_cfg[spics_in].sig_in_sel = 0;
-        PIN_INPUT_ENABLE(iomux_reg);
-        GPIO.func_out_sel_cfg[spics_out].oen_sel = 0;
-        GPIO.func_out_sel_cfg[spics_out].oen_inv_sel = false;
-        PIN_FUNC_SELECT(iomux_reg, 1);
+        // This requires `gpio_iomux_in` and `gpio_iomux_out` to be in the IRAM.
+        // `linker.lf` is used fulfill this requirement.
+        gpio_iomux_in(cs_io_num, spics_in);
+        gpio_iomux_out(cs_io_num, spics_func, false);
     } else {
         PIN_INPUT_ENABLE(iomux_reg);
         if (cs_io_num < 32) {
@@ -180,9 +180,10 @@ static DRAM_ATTR esp_flash_t default_chip = {
     .os_func = &esp_flash_noos_functions,
 };
 
-esp_err_t esp_flash_init_default_chip()
+esp_err_t esp_flash_init_default_chip(void)
 {
     memspi_host_config_t cfg = ESP_FLASH_HOST_CONFIG_DEFAULT();
+
     //the host is already initialized, only do init for the data and load it to the host
     spi_flash_hal_init(&default_driver_data, &cfg);
     default_chip.host->driver_data = &default_driver_data;
@@ -206,7 +207,7 @@ esp_err_t esp_flash_init_default_chip()
     return ESP_OK;
 }
 
-esp_err_t esp_flash_app_init()
+esp_err_t esp_flash_app_init(void)
 {
     return esp_flash_app_init_os_functions(&default_chip);
 }

+ 2 - 0
components/spi_flash/spi_flash_chip_drivers.c

@@ -35,6 +35,8 @@ static const spi_flash_chip_t *default_registered_chips[] = {
 #ifdef CONFIG_SPI_FLASH_SUPPORT_GD_CHIP
     &esp_flash_chip_gd,
 #endif
+    // Default chip drivers that will accept all chip ID.
+    // FM, Winbond and XMC chips are supposed to be supported by this chip driver.
     &esp_flash_chip_generic,
     NULL,
 };

+ 9 - 6
components/spi_flash/spi_flash_chip_generic.c

@@ -451,12 +451,15 @@ esp_err_t spi_flash_common_set_io_mode(esp_flash_t *chip, esp_flash_wrsr_func_t
     esp_err_t ret = ESP_OK;
     const bool is_quad_mode = esp_flash_is_quad_mode(chip);
     bool update_config = false;
-    const bool force_check = true; //in case some chips doesn't support erase QE
-
-    bool need_check = is_quad_mode;
-    if (force_check) {
-        need_check = true;
-    }
+    /*
+     * By default, we don't clear the QE bit even the flash mode is not QIO or QOUT. Force clearing
+     * QE bit by the generic chip driver (command 01H with 2 bytes) may cause the output of some
+     * chips (MXIC) no longer valid.
+     * Enable this option when testing a new flash chip for clearing of QE.
+     */
+    const bool force_check = false;
+
+    bool need_check = is_quad_mode || force_check;
 
     uint32_t sr_update;
     if (need_check) {

+ 22 - 7
components/spi_flash/test/test_esp_flash.c

@@ -49,6 +49,9 @@ typedef void (*flash_test_func_t)(esp_flash_t* chip);
 #define FLASH_TEST_CASE(STR, FUNC_TO_RUN) \
     TEST_CASE(STR, "[esp_flash]") {flash_test_func(FUNC_TO_RUN, 1 /* first index reserved for main flash */ );}
 
+#define FLASH_TEST_CASE_IGNORE(STR, FUNC_TO_RUN) \
+    TEST_CASE(STR, "[esp_flash][ignore]") {flash_test_func(FUNC_TO_RUN, 1 /* first index reserved for main flash */ );}
+
 /* Use FLASH_TEST_CASE_3 for tests which also run on external flash, which sits in the place of PSRAM
    (these tests are incompatible with PSRAM)
 
@@ -56,9 +59,13 @@ typedef void (*flash_test_func_t)(esp_flash_t* chip);
  */
 #if defined(CONFIG_SPIRAM_SUPPORT)
 #define FLASH_TEST_CASE_3(STR, FUNCT_TO_RUN)
+#define FLASH_TEST_CASE_3_IGNORE(STR, FUNCT_TO_RUN)
 #else
 #define FLASH_TEST_CASE_3(STR, FUNC_TO_RUN) \
     TEST_CASE(STR", 3 chips", "[esp_flash][test_env=UT_T1_ESP_FLASH]") {flash_test_func(FUNC_TO_RUN, TEST_CONFIG_NUM);}
+
+#define FLASH_TEST_CASE_3_IGNORE(STR, FUNC_TO_RUN) \
+    TEST_CASE(STR", 3 chips", "[esp_flash][test_env=UT_T1_ESP_FLASH][ignore]") {flash_test_func(FUNC_TO_RUN, TEST_CONFIG_NUM);}
 #endif
 
 //currently all the configs are the same with esp_flash_spi_device_config_t, no more information required
@@ -408,7 +415,7 @@ esp_err_t esp_flash_set_io_mode(esp_flash_t* chip, bool qe);
 esp_err_t esp_flash_get_io_mode(esp_flash_t* chip, bool* qe);
 esp_err_t esp_flash_read_chip_id(esp_flash_t* chip, uint32_t* flash_id);
 
-static bool check_winbond_chip(esp_flash_t* chip)
+static bool is_winbond_chip(esp_flash_t* chip)
 {
     uint32_t flash_id;
     esp_err_t ret = esp_flash_read_chip_id(chip, &flash_id);
@@ -430,14 +437,15 @@ static void test_toggle_qe(esp_flash_t* chip)
     esp_err_t ret = esp_flash_get_io_mode(chip, &qe);
     TEST_ESP_OK(ret);
 
-    bool is_winbond_chip = check_winbond_chip(chip);
+    bool allow_failure = is_winbond_chip(chip);
+
 
     for (int i = 0; i < 4; i ++) {
         ESP_LOGI(TAG, "write qe: %d->%d", qe, !qe);
         qe = !qe;
         chip->read_mode = qe? SPI_FLASH_QOUT: SPI_FLASH_SLOWRD;
         ret = esp_flash_set_io_mode(chip, qe);
-        if (is_winbond_chip && !qe && ret == ESP_ERR_FLASH_NO_RESPONSE) {
+        if (allow_failure && !qe && ret == ESP_ERR_FLASH_NO_RESPONSE) {
             //allows clear qe failure for Winbond chips
             ret = ESP_OK;
         }
@@ -447,8 +455,12 @@ static void test_toggle_qe(esp_flash_t* chip)
         ret = esp_flash_get_io_mode(chip, &qe_read);
         TEST_ESP_OK(ret);
         ESP_LOGD(TAG, "qe read: %d", qe_read);
-        if (qe != qe_read && !qe && is_winbond_chip) {
-            ESP_LOGE(TAG, "cannot clear QE bit, this may be normal for Winbond chips.");
+        if (!qe && qe_read) {
+            if (allow_failure) {
+                ESP_LOGW(TAG, "cannot clear QE bit for known permanent QE (Winbond) chips.");
+            } else {
+                ESP_LOGE(TAG, "cannot clear QE bit, please make sure force clearing QE option is enabled in `spi_flash_common_set_io_mode`, and this chip is not a permanent QE one.");
+            }     
             chip->read_mode = io_mode_before;
             return;
         }
@@ -458,8 +470,11 @@ static void test_toggle_qe(esp_flash_t* chip)
     chip->read_mode = io_mode_before;
 }
 
-FLASH_TEST_CASE("Test esp_flash_write can toggle QE bit", test_toggle_qe);
-FLASH_TEST_CASE_3("Test esp_flash_write can toggle QE bit", test_toggle_qe);
+// These tests show whether the QE is permanent or not for the chip tested.
+// To test the behaviour of a new SPI flash chip, enable force_check flag in generic driver
+// `spi_flash_common_set_io_mode` and then run this test.
+FLASH_TEST_CASE_IGNORE("Test esp_flash_write can toggle QE bit", test_toggle_qe);
+FLASH_TEST_CASE_3_IGNORE("Test esp_flash_write can toggle QE bit", test_toggle_qe);
 
 
 void test_permutations(flashtest_config_t* config)