diff --git a/components/sdmmc/sdmmc_common.h b/components/sdmmc/sdmmc_common.h index d5da45d4fd..2753d3d681 100644 --- a/components/sdmmc/sdmmc_common.h +++ b/components/sdmmc/sdmmc_common.h @@ -124,6 +124,8 @@ esp_err_t sdmmc_init_mmc_decode_cid(sdmmc_card_t* card); esp_err_t sdmmc_init_ocr(sdmmc_card_t* card); esp_err_t sdmmc_init_spi_crc(sdmmc_card_t* card); esp_err_t sdmmc_init_io(sdmmc_card_t* card); +esp_err_t sdmmc_io_init_read_card_cap(sdmmc_card_t* card, uint8_t* card_cap); +esp_err_t sdmmc_io_init_check_card_cap(sdmmc_card_t* card, uint8_t* card_cap); esp_err_t sdmmc_init_sd_blocklen(sdmmc_card_t* card); esp_err_t sdmmc_init_sd_scr(sdmmc_card_t* card); esp_err_t sdmmc_init_sd_ssr(sdmmc_card_t* card); diff --git a/components/sdmmc/sdmmc_init.c b/components/sdmmc/sdmmc_init.c index 2bb09389b8..41d1ac6fc0 100644 --- a/components/sdmmc/sdmmc_init.c +++ b/components/sdmmc/sdmmc_init.c @@ -32,6 +32,16 @@ static const char* TAG = "sdmmc_init"; } \ } while(0); +#define SDMMC_INIT_STEP_PARAM(condition, function, param) \ + do { \ + if ((condition)) { \ + esp_err_t err = (function)(card, param); \ + if (err != ESP_OK) { \ + ESP_LOGD(TAG, "%s: %s returned 0x%x", __func__, #function, err); \ + return err; \ + } \ + } \ + } while(0); esp_err_t sdmmc_card_init(const sdmmc_host_t* config, sdmmc_card_t* card) { @@ -115,6 +125,10 @@ esp_err_t sdmmc_card_init(const sdmmc_host_t* config, sdmmc_card_t* card) /* MMC cards: read CXD */ SDMMC_INIT_STEP(is_mmc, sdmmc_init_mmc_read_ext_csd); + /* SDIO cards: read CCCR card capabilities */ + uint8_t card_cap = 0; + SDMMC_INIT_STEP_PARAM(is_sdio, sdmmc_io_init_read_card_cap, &card_cap); + /* Try to switch card to HS mode if the card supports it. * Set card->max_freq_khz value accordingly. */ @@ -138,7 +152,8 @@ esp_err_t sdmmc_card_init(const sdmmc_host_t* config, sdmmc_card_t* card) SDMMC_INIT_STEP(is_sdmem, sdmmc_check_scr); /* 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 */ + /* Sanity check for SDIO after switching the frequency */ + SDMMC_INIT_STEP_PARAM(is_sdio, sdmmc_io_init_check_card_cap, &card_cap); return ESP_OK; } diff --git a/components/sdmmc/sdmmc_io.c b/components/sdmmc/sdmmc_io.c index 376cebc9e5..86f471b8ac 100644 --- a/components/sdmmc/sdmmc_io.c +++ b/components/sdmmc/sdmmc_io.c @@ -120,6 +120,48 @@ esp_err_t sdmmc_init_io(sdmmc_card_t* card) return ESP_OK; } +esp_err_t sdmmc_io_init_read_card_cap(sdmmc_card_t* card, uint8_t *card_cap) +{ + esp_err_t err = ESP_OK; + + err = sdmmc_io_rw_direct(card, 0, SD_IO_CCCR_CARD_CAP, + SD_ARG_CMD52_READ, card_cap); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: sdmmc_io_rw_direct (read SD_IO_CCCR_CARD_CAP) returned 0x%0x", __func__, err); + return err; + } + + return ESP_OK; +} + +esp_err_t sdmmc_io_init_check_card_cap(sdmmc_card_t* card, uint8_t *card_cap) +{ + esp_err_t err = ESP_OK; + /* + * Integrity check required if card is switched to HS mode + * For frequency less than SDMMC_FREQ_HIGHSPEED, see sdmmc_io_enable_hs_mode() + */ + if (card->max_freq_khz < SDMMC_FREQ_HIGHSPEED) { + return ESP_OK; + } + + /* If frequency switch has been performed, read card capabilities from CCCR to confirm + * that data can be read correctly at the new frequency. + */ + uint8_t temp_card_cap = 0; + err = sdmmc_io_rw_direct(card, 0, SD_IO_CCCR_CARD_CAP, + SD_ARG_CMD52_READ, &temp_card_cap); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: sdmmc_io_rw_direct (read SD_IO_CCCR_CARD_CAP) returned 0x%0x", __func__, err); + return err; + } + if (*card_cap != temp_card_cap) { + ESP_LOGE(TAG, "%s: got corrupted data after increasing clock frequency", __func__); + return ESP_ERR_INVALID_RESPONSE; + } + return ESP_OK; +} + esp_err_t sdmmc_init_io_bus_width(sdmmc_card_t* card) { esp_err_t err;