Explorar el Código

Merge branch 'feature/mmc_validate_hs_mode' into 'master'

Add high speed mode switch validation check for mmc.

See merge request espressif/esp-idf!17545
Martin Vychodil hace 3 años
padre
commit
aa1200607a

+ 3 - 0
components/driver/include/driver/sdmmc_defs.h

@@ -103,6 +103,9 @@
 #define MMC_R1_READY_FOR_DATA           (1<<8)  /* ready for next transfer */
 #define MMC_R1_APP_CMD                  (1<<5)  /* app. commands supported */
 #define MMC_R1_SWITCH_ERROR             (1<<7)  /* switch command did not succeed */
+#define MMC_R1_CURRENT_STATE_POS        (9)
+#define MMC_R1_CURRENT_STATE_MASK       (0x1E00)/* card current state */
+#define MMC_R1_CURRENT_STATE_TRAN       (4)
 
 /* SPI mode R1 response type bits */
 #define SD_SPI_R1_IDLE_STATE            (1<<0)

+ 1 - 1
components/sdmmc/sdmmc_common.h

@@ -126,7 +126,7 @@ esp_err_t sdmmc_init_io_bus_width(sdmmc_card_t* card);
 esp_err_t sdmmc_init_mmc_bus_width(sdmmc_card_t* card);
 esp_err_t sdmmc_init_card_hs_mode(sdmmc_card_t* card);
 esp_err_t sdmmc_init_host_frequency(sdmmc_card_t* card);
-esp_err_t sdmmc_init_mmc_check_csd(sdmmc_card_t* card);
+esp_err_t sdmmc_init_mmc_check_ext_csd(sdmmc_card_t* card);
 
 /* Various helper functions */
 static inline bool host_is_spi(const sdmmc_card_t* card)

+ 2 - 2
components/sdmmc/sdmmc_init.c

@@ -120,8 +120,8 @@ esp_err_t sdmmc_card_init(const sdmmc_host_t* config, sdmmc_card_t* card)
 
     /* Sanity check after switching the bus mode and frequency */
     SDMMC_INIT_STEP(is_sdmem, sdmmc_check_scr);
-    /* TODO: this is CMD line only, add data checks for eMMC */
-    SDMMC_INIT_STEP(is_mmc, sdmmc_init_mmc_check_csd);
+    /* Sanity check after eMMC switch to HS mode */
+    SDMMC_INIT_STEP(is_mmc, sdmmc_init_mmc_check_ext_csd);
     /* TODO: add similar checks for SDIO */
 
     return ESP_OK;

+ 43 - 22
components/sdmmc/sdmmc_mmc.c

@@ -47,7 +47,6 @@ esp_err_t sdmmc_init_mmc_read_ext_csd(sdmmc_card_t* card)
         goto out;
     }
     card_type = ext_csd[EXT_CSD_CARD_TYPE];
-
     card->is_ddr = 0;
     if (card_type & EXT_CSD_CARD_TYPE_F_52M_1_8V) {
         card->max_freq_khz = SDMMC_FREQ_52M;
@@ -237,33 +236,55 @@ esp_err_t sdmmc_mmc_switch(sdmmc_card_t* card, uint8_t set, uint8_t index, uint8
     return err;
 }
 
-esp_err_t sdmmc_init_mmc_check_csd(sdmmc_card_t* card)
+esp_err_t sdmmc_init_mmc_check_ext_csd(sdmmc_card_t* card)
 {
-    esp_err_t err;
-    assert(card->is_mem == 1);
-    assert(card->rca != 0);
-    //The card will not respond to send_csd command in the transfer state.
-    //Deselect it first.
-    err = sdmmc_send_cmd_select_card(card, 0);
-    if (err != ESP_OK) {
-        ESP_LOGE(TAG, "%s: select_card returned 0x%x", __func__, err);
-        return err;
+    assert(card->is_mem == 1 && card->rca != 0);
+
+    /*
+     * Integrity check required if card switched to HS mode
+     * card->max_freq_khz = MIN(card->max_freq_khz, card->host.max_freq_khz)
+     * For 26MHz limit background see sdmmc_mmc_enable_hs_mode()
+     */
+    if (card->max_freq_khz <= SDMMC_FREQ_26M) {
+        return ESP_OK;
+    }
+
+    /* ensure EXT_CSD buffer is available before starting any SD-card operation */
+    uint8_t* ext_csd = heap_caps_malloc(EXT_CSD_MMC_SIZE, MALLOC_CAP_DMA);
+    if (!ext_csd) {
+        ESP_LOGE(TAG, "%s: could not allocate ext_csd", __func__);
+        return ESP_ERR_NO_MEM;
     }
 
-    sdmmc_csd_t csd;
-    /* Get the contents of CSD register to verify the communication over CMD line
-       is OK. */
-    err = sdmmc_send_cmd_send_csd(card, &csd);
+    /* ensure card is in transfer state before read ext_csd */
+    uint32_t status;
+    esp_err_t err = sdmmc_send_cmd_send_status(card, &status);
     if (err != ESP_OK) {
-        ESP_LOGE(TAG, "%s: send_csd returned 0x%x", __func__, err);
-        return err;
+        ESP_LOGE(TAG, "%s: send_status returned 0x%x", __func__, err);
+        goto out;
+    }
+    status = ((status & MMC_R1_CURRENT_STATE_MASK) >> MMC_R1_CURRENT_STATE_POS);
+    if (status != MMC_R1_CURRENT_STATE_TRAN) {
+        ESP_LOGE(TAG, "%s: card not in transfer state", __func__);
+        err = ESP_ERR_INVALID_STATE;
+        goto out;
     }
 
-    //Select the card again
-    err = sdmmc_send_cmd_select_card(card, card->rca);
+    /* read EXT_CSD to ensure device works fine in HS mode */
+    err = sdmmc_mmc_send_ext_csd_data(card, ext_csd, EXT_CSD_MMC_SIZE);
     if (err != ESP_OK) {
-        ESP_LOGE(TAG, "%s: select_card returned 0x%x", __func__, err);
-        return err;
+        ESP_LOGE(TAG, "%s: send_ext_csd_data error 0x%x", __func__, err);
+        goto out;
     }
-    return ESP_OK;
+
+    /* EXT_CSD static fields should match the previous read values in sdmmc_card_init */
+    if ((card->ext_csd.rev != ext_csd[EXT_CSD_REV]) ||
+            (card->ext_csd.sec_feature != ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT])) {
+        ESP_LOGE(TAG, "%s: Data integrity test fail in HS mode", __func__);
+        err = ESP_FAIL;
+    }
+
+out:
+    free(ext_csd);
+    return err;
 }