feat(sdmmc): support for voltage switching in protocol layer

This commit is contained in:
Ivan Grokhotkov 2024-10-04 18:48:06 +02:00 committed by Armando
parent a03cbdba2e
commit 31dc34a909
6 changed files with 65 additions and 4 deletions

View File

@ -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 <uwe@openbsd.org>
@ -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 */

View File

@ -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) */

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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