mirror of
https://github.com/espressif/esp-idf
synced 2025-03-09 17:19:09 -04:00
feat(sdmmc): support for voltage switching in protocol layer
This commit is contained in:
parent
a03cbdba2e
commit
31dc34a909
@ -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 */
|
||||
|
@ -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) */
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user