diff --git a/components/driver/include/driver/sdmmc_defs.h b/components/driver/include/driver/sdmmc_defs.h index 54ead88842..1e336c2d72 100644 --- a/components/driver/include/driver/sdmmc_defs.h +++ b/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) diff --git a/components/sdmmc/sdmmc_common.h b/components/sdmmc/sdmmc_common.h index 8dc049ebc1..a6d7dbbf29 100644 --- a/components/sdmmc/sdmmc_common.h +++ b/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) diff --git a/components/sdmmc/sdmmc_init.c b/components/sdmmc/sdmmc_init.c index 0ef6272118..997dd8ef71 100644 --- a/components/sdmmc/sdmmc_init.c +++ b/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; diff --git a/components/sdmmc/sdmmc_mmc.c b/components/sdmmc/sdmmc_mmc.c index fa83277315..82c978aea6 100644 --- a/components/sdmmc/sdmmc_mmc.c +++ b/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; } - 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); - if (err != ESP_OK) { - ESP_LOGE(TAG, "%s: send_csd returned 0x%x", __func__, err); - return err; + /* 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; } - //Select the card again - err = sdmmc_send_cmd_select_card(card, card->rca); + /* 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: select_card returned 0x%x", __func__, err); - return err; + ESP_LOGE(TAG, "%s: send_status returned 0x%x", __func__, err); + goto out; } - return ESP_OK; + 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; + } + + /* 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: send_ext_csd_data error 0x%x", __func__, err); + goto out; + } + + /* 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; }