diff --git a/components/sdmmc/include/sd_protocol_defs.h b/components/sdmmc/include/sd_protocol_defs.h index 8eb52ca6b0..8fbaa2c2cf 100644 --- a/components/sdmmc/include/sd_protocol_defs.h +++ b/components/sdmmc/include/sd_protocol_defs.h @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: ISC * - * SPDX-FileContributor: 2016-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileContributor: 2016-2024 Espressif Systems (Shanghai) CO LTD */ /* * Copyright (c) 2006 Uwe Stuehler @@ -59,6 +59,7 @@ extern "C" { #define SD_SEND_RELATIVE_ADDR 3 /* R6 */ #define SD_SEND_SWITCH_FUNC 6 /* R1 */ #define SD_SEND_IF_COND 8 /* R7 */ +#define SD_SWITCH_VOLTAGE 11 /* R1 */ #define SD_ERASE_GROUP_START 32 /* R1 */ #define SD_ERASE_GROUP_END 33 /* R1 */ #define SD_READ_OCR 58 /* R3 */ @@ -98,8 +99,20 @@ extern "C" { #define MMC_OCR_2_0V_2_1V (1<<8) #define MMC_OCR_1_65V_1_95V (1<<7) -#define SD_OCR_SDHC_CAP (1<<30) -#define SD_OCR_VOL_MASK 0xFF8000 /* bits 23:15 */ +#define SD_OCR_CARD_READY MMC_OCR_MEM_READY /* bit-31: power-up status */ +#define SD_OCR_SDHC_CAP (1<<30) /* HCS bit */ +#define SD_OCR_XPC (1<<28) /* SDXC Power Control (bit 28) */ +#define SD_OCR_S18_RA (1<<24) /* S18R/A bit: 1.8V voltage support, UHS-I only */ +#define SD_OCR_VOL_MASK 0xFF8000 /* SD OCR voltage bits 23:15 */ +#define SD_OCR_3_5V_3_6V MMC_OCR_3_5V_3_6V /* bit-23 */ +#define SD_OCR_3_4V_3_5V MMC_OCR_3_4V_3_5V /* bit-22 */ +#define SD_OCR_3_3V_3_4V MMC_OCR_3_3V_3_4V /* ... */ +#define SD_OCR_3_2V_3_3V MMC_OCR_3_2V_3_3V +#define SD_OCR_3_1V_3_2V MMC_OCR_3_1V_3_2V +#define SD_OCR_3_0V_3_1V MMC_OCR_3_0V_3_1V +#define SD_OCR_2_9V_3_0V MMC_OCR_2_9V_3_0V +#define SD_OCR_2_8V_2_9V MMC_OCR_2_8V_2_9V /* ... */ +#define SD_OCR_2_7V_2_8V MMC_OCR_2_7V_2_8V /* bit-15 */ /* SD mode R1 response type bits */ #define MMC_R1_READY_FOR_DATA (1<<8) /* ready for next transfer */ diff --git a/components/sdmmc/include/sd_protocol_types.h b/components/sdmmc/include/sd_protocol_types.h index effe3b4a0f..3f3a29d1e4 100644 --- a/components/sdmmc/include/sd_protocol_types.h +++ b/components/sdmmc/include/sd_protocol_types.h @@ -149,6 +149,8 @@ typedef struct { /** @endcond */ esp_err_t error; /*!< error returned from transfer */ uint32_t timeout_ms; /*!< response timeout, in milliseconds */ + esp_err_t (*volt_switch_cb)(void*, int); /*!< callback to be called during CMD11 to switch voltage */ + void* volt_switch_cb_arg; /*!< argument to be passed to the CMD11 callback */ } sdmmc_command_t; /** @@ -183,6 +185,7 @@ typedef struct { Currently this is only used by the SDIO driver. Set this flag when using SDIO CMD53 byte mode, with user buffer that is behind the cache or not aligned to 4 byte boundary. */ +#define SDMMC_HOST_FLAG_UHS1 BIT(7) /*!< host supports UHS-I mode */ int slot; /*!< slot number, to be passed to host functions */ int max_freq_khz; /*!< max frequency supported by the host */ #define SDMMC_FREQ_DEFAULT 20000 /*!< SD/MMC Default speed (limited by clock divider) */ diff --git a/components/sdmmc/sdmmc_common.c b/components/sdmmc/sdmmc_common.c index 8135e593e2..c59f879b01 100644 --- a/components/sdmmc/sdmmc_common.c +++ b/components/sdmmc/sdmmc_common.c @@ -42,6 +42,12 @@ esp_err_t sdmmc_init_ocr(sdmmc_card_t* card) acmd41_arg |= SD_OCR_SDHC_CAP; } + if ((card->host.flags & SDMMC_HOST_FLAG_UHS1) != 0) { + acmd41_arg |= SD_OCR_S18_RA; + acmd41_arg |= SD_OCR_XPC; + } + ESP_LOGV(TAG, "%s: acmd41_arg=0x%08" PRIx32, __func__, card->ocr); + /* Send SEND_OP_COND (ACMD41) command to the card until it becomes ready. */ err = sdmmc_send_cmd_send_op_cond(card, acmd41_arg, &card->ocr); @@ -278,7 +284,15 @@ void sdmmc_card_print_info(FILE* stream, const sdmmc_card_t* card) type = "MMC"; print_csd = true; } else { - type = (card->ocr & SD_OCR_SDHC_CAP) ? "SDHC/SDXC" : "SDSC"; + if ((card->ocr & SD_OCR_SDHC_CAP) == 0) { + type = "SDSC"; + } else { + if (card->ocr & SD_OCR_S18_RA) { + type = "SDHC/SDXC (UHS-I)"; + } else { + type = "SDHC"; + } + } print_csd = true; } fprintf(stream, "Type: %s\n", type); diff --git a/components/sdmmc/sdmmc_common.h b/components/sdmmc/sdmmc_common.h index 2753d3d681..64b48e6062 100644 --- a/components/sdmmc/sdmmc_common.h +++ b/components/sdmmc/sdmmc_common.h @@ -77,6 +77,7 @@ esp_err_t sdmmc_send_cmd_send_scr(sdmmc_card_t* card, sdmmc_scr_t *out_scr); esp_err_t sdmmc_send_cmd_set_bus_width(sdmmc_card_t* card, int width); esp_err_t sdmmc_send_cmd_send_status(sdmmc_card_t* card, uint32_t* out_status); esp_err_t sdmmc_send_cmd_crc_on_off(sdmmc_card_t* card, bool crc_enable); +esp_err_t sdmmc_send_cmd_voltage_switch(sdmmc_card_t* card); /* Higher level functions */ esp_err_t sdmmc_enable_hs_mode(sdmmc_card_t* card); @@ -139,6 +140,7 @@ 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_ext_csd(sdmmc_card_t* card); +esp_err_t sdmmc_init_sd_uhs1(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 41d1ac6fc0..45528f6785 100644 --- a/components/sdmmc/sdmmc_init.c +++ b/components/sdmmc/sdmmc_init.c @@ -95,6 +95,10 @@ esp_err_t sdmmc_card_init(const sdmmc_host_t* config, sdmmc_card_t* card) ESP_LOGD(TAG, "%s: card type is %s", __func__, is_sdio ? "SDIO" : is_mmc ? "MMC" : "SD"); + /* switch to 1.8V if supported (UHS-I) */ + bool is_uhs1 = is_sdmem && (card->ocr & SD_OCR_S18_RA) && (card->ocr & SD_OCR_SDHC_CAP); + SDMMC_INIT_STEP(is_uhs1, sdmmc_init_sd_uhs1); + /* Read the contents of CID register*/ SDMMC_INIT_STEP(is_mem, sdmmc_init_cid); diff --git a/components/sdmmc/sdmmc_sd.c b/components/sdmmc/sdmmc_sd.c index 3fbebc67cb..41700965d7 100644 --- a/components/sdmmc/sdmmc_sd.c +++ b/components/sdmmc/sdmmc_sd.c @@ -322,6 +322,31 @@ esp_err_t sdmmc_enable_hs_mode_and_check(sdmmc_card_t* card) return ESP_OK; } +static esp_err_t sdmmc_init_sd_uhs1_volt_sw_cb(void* arg, int voltage_mv) +{ + sdmmc_card_t* card = (sdmmc_card_t*)arg; + ESP_LOGV(TAG, "%s: Voltage switch callback (%umv)", __func__, voltage_mv); + return sd_pwr_ctrl_set_io_voltage(card->host.pwr_ctrl_handle, voltage_mv); +} + +esp_err_t sdmmc_init_sd_uhs1(sdmmc_card_t* card) +{ + sdmmc_command_t cmd = { + .opcode = SD_SWITCH_VOLTAGE, + .arg = 0, + .flags = SCF_CMD_AC | SCF_RSP_R1, + .volt_switch_cb = &sdmmc_init_sd_uhs1_volt_sw_cb, + .volt_switch_cb_arg = card + }; + esp_err_t err = sdmmc_send_cmd(card, &cmd); + if (err != ESP_OK) { + ESP_LOGE(TAG, "%s: send_cmd returned 0x%x", __func__, err); + return err; + } + + return ESP_OK; +} + esp_err_t sdmmc_check_scr(sdmmc_card_t* card) { /* If frequency switch has been performed, read SCR register one more time