feat(sdmmc): supported UHS-I SDR50 (100Mhz) and DDR50 mode

This commit is contained in:
Armando
2024-11-06 12:09:25 +08:00
parent 31dc34a909
commit 04cd469e4a
26 changed files with 650 additions and 131 deletions

View File

@ -31,6 +31,8 @@ extern "C" {
.slot = SDMMC_HOST_SLOT_1, \ .slot = SDMMC_HOST_SLOT_1, \
.max_freq_khz = SDMMC_FREQ_DEFAULT, \ .max_freq_khz = SDMMC_FREQ_DEFAULT, \
.io_voltage = 3.3f, \ .io_voltage = 3.3f, \
.driver_strength = SDMMC_DRIVER_STRENGTH_B, \
.current_limit = SDMMC_CURRENT_LIMIT_200MA, \
.init = &sdmmc_host_init, \ .init = &sdmmc_host_init, \
.set_bus_width = &sdmmc_host_set_bus_width, \ .set_bus_width = &sdmmc_host_set_bus_width, \
.get_bus_width = &sdmmc_host_get_slot_width, \ .get_bus_width = &sdmmc_host_get_slot_width, \
@ -48,29 +50,35 @@ extern "C" {
.dma_aligned_buffer = NULL, \ .dma_aligned_buffer = NULL, \
.pwr_ctrl_handle = NULL, \ .pwr_ctrl_handle = NULL, \
.get_dma_info = &sdmmc_host_get_dma_info, \ .get_dma_info = &sdmmc_host_get_dma_info, \
.is_slot_set_to_uhs1 = &sdmmc_host_is_slot_set_to_uhs1, \
} }
#define SDMMC_SLOT_NO_CD GPIO_NUM_NC ///< indicates that card detect line is not used #define SDMMC_SLOT_NO_CD GPIO_NUM_NC ///< indicates that card detect line is not used
#define SDMMC_SLOT_NO_WP GPIO_NUM_NC ///< indicates that write protect line is not used #define SDMMC_SLOT_NO_WP GPIO_NUM_NC ///< indicates that write protect line is not used
#define SDMMC_SLOT_WIDTH_DEFAULT 0 ///< use the maximum possible width for the slot #define SDMMC_SLOT_WIDTH_DEFAULT 0 ///< use the maximum possible width for the slot
#if SOC_SDMMC_USE_IOMUX && !SOC_SDMMC_USE_GPIO_MATRIX
/** /**
* Macro defining default configuration of SDMMC host slot * Macro defining default configuration of SDMMC host slot
*/ */
#if CONFIG_IDF_TARGET_ESP32
#define SDMMC_SLOT_CONFIG_DEFAULT() {\ #define SDMMC_SLOT_CONFIG_DEFAULT() {\
.clk = GPIO_NUM_6, \
.cmd = GPIO_NUM_11, \
.d0 = GPIO_NUM_7, \
.d1 = GPIO_NUM_8, \
.d2 = GPIO_NUM_9, \
.d3 = GPIO_NUM_10, \
.d4 = GPIO_NUM_16, \
.d5 = GPIO_NUM_17, \
.d6 = GPIO_NUM_5, \
.d7 = GPIO_NUM_18, \
.cd = SDMMC_SLOT_NO_CD, \ .cd = SDMMC_SLOT_NO_CD, \
.wp = SDMMC_SLOT_NO_WP, \ .wp = SDMMC_SLOT_NO_WP, \
.width = SDMMC_SLOT_WIDTH_DEFAULT, \ .width = SDMMC_SLOT_WIDTH_DEFAULT, \
.flags = 0, \ .flags = 0, \
} }
#else #elif CONFIG_IDF_TARGET_ESP32P4
/**
* Macro defining default configuration of SDMMC host slot
*/
#if CONFIG_IDF_TARGET_ESP32P4
#define SDMMC_SLOT_CONFIG_DEFAULT() {\ #define SDMMC_SLOT_CONFIG_DEFAULT() {\
.clk = GPIO_NUM_43, \ .clk = GPIO_NUM_43, \
.cmd = GPIO_NUM_44, \ .cmd = GPIO_NUM_44, \
@ -107,8 +115,6 @@ extern "C" {
} }
#endif // GPIO Matrix chips #endif // GPIO Matrix chips
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -24,7 +24,6 @@ extern "C" {
* Extra configuration for SDMMC peripheral slot * Extra configuration for SDMMC peripheral slot
*/ */
typedef struct { typedef struct {
#ifdef SOC_SDMMC_USE_GPIO_MATRIX
gpio_num_t clk; ///< GPIO number of CLK signal. gpio_num_t clk; ///< GPIO number of CLK signal.
gpio_num_t cmd; ///< GPIO number of CMD signal. gpio_num_t cmd; ///< GPIO number of CMD signal.
gpio_num_t d0; ///< GPIO number of D0 signal. gpio_num_t d0; ///< GPIO number of D0 signal.
@ -35,7 +34,6 @@ typedef struct {
gpio_num_t d5; ///< GPIO number of D5 signal. Ignored in 1- or 4- line mode. gpio_num_t d5; ///< GPIO number of D5 signal. Ignored in 1- or 4- line mode.
gpio_num_t d6; ///< GPIO number of D6 signal. Ignored in 1- or 4- line mode. gpio_num_t d6; ///< GPIO number of D6 signal. Ignored in 1- or 4- line mode.
gpio_num_t d7; ///< GPIO number of D7 signal. Ignored in 1- or 4- line mode. gpio_num_t d7; ///< GPIO number of D7 signal. Ignored in 1- or 4- line mode.
#endif // SOC_SDMMC_USE_GPIO_MATRIX
union { union {
gpio_num_t gpio_cd; ///< GPIO number of card detect signal gpio_num_t gpio_cd; ///< GPIO number of card detect signal
gpio_num_t cd; ///< GPIO number of card detect signal; shorter name. gpio_num_t cd; ///< GPIO number of card detect signal; shorter name.
@ -56,6 +54,8 @@ typedef struct {
* 0 means "active low", i.e. card is protected when the GPIO is low; * 0 means "active low", i.e. card is protected when the GPIO is low;
* 1 means "active high", i.e. card is protected when GPIO is high. * 1 means "active high", i.e. card is protected when GPIO is high.
*/ */
#define SDMMC_SLOT_FLAG_UHS1 BIT(2)
/**< Enable UHS-I mode for this slot */
} sdmmc_slot_config_t; } sdmmc_slot_config_t;
/** /**
@ -284,6 +284,18 @@ esp_err_t sdmmc_host_set_input_delay(int slot, sdmmc_delay_phase_t delay_phase);
*/ */
esp_err_t sdmmc_host_get_dma_info(int slot, esp_dma_mem_info_t *dma_mem_info); esp_err_t sdmmc_host_get_dma_info(int slot, esp_dma_mem_info_t *dma_mem_info);
/**
* @brief Check if the slot is set to uhs1 or not
*
* @param[in] slot Slot id
* @param[out] is_uhs1 Is uhs1 or not
*
* @return
* - ESP_OK: on success
* - ESP_ERR_INVALID_STATE: driver not in correct state
*/
esp_err_t sdmmc_host_is_slot_set_to_uhs1(int slot, bool *is_uhs1);
/** /**
* @brief Get the state of SDMMC host * @brief Get the state of SDMMC host
* *

View File

@ -20,7 +20,7 @@
#include "driver/sdmmc_host.h" #include "driver/sdmmc_host.h"
#include "esp_private/esp_clk_tree_common.h" #include "esp_private/esp_clk_tree_common.h"
#include "esp_private/periph_ctrl.h" #include "esp_private/periph_ctrl.h"
#include "sdmmc_private.h" #include "sdmmc_internal.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "esp_clk_tree.h" #include "esp_clk_tree.h"
@ -33,6 +33,8 @@
#define SDMMC_EVENT_QUEUE_LENGTH 32 #define SDMMC_EVENT_QUEUE_LENGTH 32
#define SDMMC_FREQ_SDR104 208000 /*!< MMC 208MHz speed */
#if !SOC_RCC_IS_INDEPENDENT #if !SOC_RCC_IS_INDEPENDENT
// Reset and Clock Control registers are mixing with other peripherals, so we need to use a critical section // Reset and Clock Control registers are mixing with other peripherals, so we need to use a critical section
#define SDMMC_RCC_ATOMIC() PERIPH_RCC_ATOMIC() #define SDMMC_RCC_ATOMIC() PERIPH_RCC_ATOMIC()
@ -65,9 +67,11 @@ if (!GPIO_IS_VALID_GPIO(_gpio_num)) { \
* Slot contexts * Slot contexts
*/ */
typedef struct slot_ctx_t { typedef struct slot_ctx_t {
int slot_id;
size_t slot_width; size_t slot_width;
sdmmc_slot_io_info_t slot_gpio_num; sdmmc_slot_io_info_t slot_gpio_num;
bool use_gpio_matrix; bool use_gpio_matrix;
bool is_uhs1;
#if SOC_SDMMC_NUM_SLOTS >= 2 #if SOC_SDMMC_NUM_SLOTS >= 2
int slot_host_div; int slot_host_div;
uint32_t slot_freq_khz; uint32_t slot_freq_khz;
@ -79,14 +83,15 @@ typedef struct slot_ctx_t {
* Host contexts * Host contexts
*/ */
typedef struct host_ctx_t { typedef struct host_ctx_t {
intr_handle_t intr_handle; intr_handle_t intr_handle;
QueueHandle_t event_queue; QueueHandle_t event_queue;
SemaphoreHandle_t io_intr_event; SemaphoreHandle_t io_intr_event;
sdmmc_hal_context_t hal; sdmmc_hal_context_t hal;
slot_ctx_t slot_ctx[SOC_SDMMC_NUM_SLOTS]; soc_periph_sdmmc_clk_src_t clk_src;
slot_ctx_t slot_ctx[SOC_SDMMC_NUM_SLOTS];
#if SOC_SDMMC_NUM_SLOTS >= 2 #if SOC_SDMMC_NUM_SLOTS >= 2
uint8_t num_of_init_slots; uint8_t num_of_init_slots;
int8_t active_slot_num; int8_t active_slot_num;
#endif #endif
} host_ctx_t; } host_ctx_t;
@ -163,13 +168,18 @@ esp_err_t sdmmc_host_reset(void)
* Of the second stage dividers, div0 is used for card 0, and div1 is used * Of the second stage dividers, div0 is used for card 0, and div1 is used
* for card 1. * for card 1.
*/ */
static void sdmmc_host_set_clk_div(int div) static void sdmmc_host_set_clk_div(soc_periph_sdmmc_clk_src_t src, int div)
{ {
esp_clk_tree_enable_src((soc_module_clk_t)SDMMC_CLK_SRC_DEFAULT, true); esp_clk_tree_enable_src((soc_module_clk_t)src, true);
SDMMC_CLK_SRC_ATOMIC() { SDMMC_CLK_SRC_ATOMIC() {
sdmmc_ll_set_clock_div(s_host_ctx.hal.dev, div); sdmmc_ll_set_clock_div(s_host_ctx.hal.dev, div);
sdmmc_ll_select_clk_source(s_host_ctx.hal.dev, SDMMC_CLK_SRC_DEFAULT); sdmmc_ll_select_clk_source(s_host_ctx.hal.dev, src);
sdmmc_ll_init_phase_delay(s_host_ctx.hal.dev); sdmmc_ll_init_phase_delay(s_host_ctx.hal.dev);
#if SOC_CLK_SDIO_PLL_SUPPORTED
if (src == SDMMC_CLK_SRC_SDIO_200M) {
sdmmc_ll_enable_sdio_pll(s_host_ctx.hal.dev, true);
}
#endif
} }
// Wait for the clock to propagate // Wait for the clock to propagate
@ -192,11 +202,23 @@ static esp_err_t sdmmc_host_clock_update_command(int slot, bool is_cmd11)
return ESP_OK; return ESP_OK;
} }
void sdmmc_host_get_clk_dividers(uint32_t freq_khz, int *host_div, int *card_div) void sdmmc_host_get_clk_dividers(uint32_t freq_khz, int *host_div, int *card_div, soc_periph_sdmmc_clk_src_t *src)
{ {
uint32_t clk_src_freq_hz = 0; uint32_t clk_src_freq_hz = 0;
esp_clk_tree_src_get_freq_hz(SDMMC_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq_hz); soc_periph_sdmmc_clk_src_t clk_src = 0;
assert(clk_src_freq_hz == (160 * 1000 * 1000)); #if SOC_SDMMC_UHS_I_SUPPORTED
if (freq_khz > SDMMC_FREQ_HIGHSPEED) {
clk_src = SDMMC_CLK_SRC_SDIO_200M;
} else
#endif
{
clk_src = SDMMC_CLK_SRC_DEFAULT;
}
s_host_ctx.clk_src = clk_src;
esp_err_t ret = esp_clk_tree_src_get_freq_hz(clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq_hz);
assert(ret == ESP_OK);
ESP_LOGD(TAG, "clk_src_freq_hz: %"PRId32" hz", clk_src_freq_hz);
#if SDMMC_LL_MAX_FREQ_KHZ_FPGA #if SDMMC_LL_MAX_FREQ_KHZ_FPGA
if (freq_khz >= SDMMC_LL_MAX_FREQ_KHZ_FPGA) { if (freq_khz >= SDMMC_LL_MAX_FREQ_KHZ_FPGA) {
@ -204,40 +226,53 @@ void sdmmc_host_get_clk_dividers(uint32_t freq_khz, int *host_div, int *card_div
freq_khz = SDMMC_LL_MAX_FREQ_KHZ_FPGA; freq_khz = SDMMC_LL_MAX_FREQ_KHZ_FPGA;
} }
#endif #endif
// Calculate new dividers // Calculate new dividers
if (freq_khz >= SDMMC_FREQ_HIGHSPEED) { #if SOC_SDMMC_UHS_I_SUPPORTED
*host_div = 4; // 160 MHz / 4 = 40 MHz if (freq_khz == SDMMC_FREQ_SDR104) {
*host_div = 1; // 200 MHz / 1 = 200 MHz
*card_div = 0; *card_div = 0;
} else if (freq_khz == SDMMC_FREQ_DEFAULT) { } else if (freq_khz == SDMMC_FREQ_SDR50) {
*host_div = 8; // 160 MHz / 8 = 20 MHz *host_div = 2; // 200 MHz / 2 = 100 MHz
*card_div = 0; *card_div = 0;
} else if (freq_khz == SDMMC_FREQ_PROBING) { } else
*host_div = 10; // 160 MHz / 10 / (20 * 2) = 400 kHz #endif
*card_div = 20; if (freq_khz >= SDMMC_FREQ_HIGHSPEED) {
} else { *host_div = 4; // 160 MHz / 4 = 40 MHz
/* *card_div = 0;
* for custom frequencies use maximum range of host divider (1-16), find the closest <= div. combination } else if (freq_khz == SDMMC_FREQ_DEFAULT) {
* if exceeded, combine with the card divider to keep reasonable precision (applies mainly to low frequencies) *host_div = 8; // 160 MHz / 8 = 20 MHz
* effective frequency range: 400 kHz - 32 MHz (32.1 - 39.9 MHz cannot be covered with given divider scheme) *card_div = 0;
*/ } else if (freq_khz == SDMMC_FREQ_PROBING) {
*host_div = (clk_src_freq_hz) / (freq_khz * 1000); *host_div = 10; // 160 MHz / 10 / (20 * 2) = 400 kHz
if (*host_div > 15) { *card_div = 20;
*host_div = 2; } else {
*card_div = (clk_src_freq_hz / 2) / (2 * freq_khz * 1000); /*
if (((clk_src_freq_hz / 2) % (2 * freq_khz * 1000)) > 0) { * for custom frequencies use maximum range of host divider (1-16), find the closest <= div. combination
(*card_div)++; * if exceeded, combine with the card divider to keep reasonable precision (applies mainly to low frequencies)
* effective frequency range: 400 kHz - 32 MHz (32.1 - 39.9 MHz cannot be covered with given divider scheme)
*/
*host_div = (clk_src_freq_hz) / (freq_khz * 1000);
if (*host_div > 15) {
*host_div = 2;
*card_div = (clk_src_freq_hz / 2) / (2 * freq_khz * 1000);
if (((clk_src_freq_hz / 2) % (2 * freq_khz * 1000)) > 0) {
(*card_div)++;
}
} else if ((clk_src_freq_hz % (freq_khz * 1000)) > 0) {
(*host_div)++;
} }
} else if ((clk_src_freq_hz % (freq_khz * 1000)) > 0) {
(*host_div)++;
} }
}
*src = clk_src;
} }
static int sdmmc_host_calc_freq(const int host_div, const int card_div) static int sdmmc_host_calc_freq(soc_periph_sdmmc_clk_src_t src, const int host_div, const int card_div)
{ {
uint32_t clk_src_freq_hz = 0; uint32_t clk_src_freq_hz = 0;
esp_clk_tree_src_get_freq_hz(SDMMC_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq_hz); esp_err_t ret = esp_clk_tree_src_get_freq_hz(src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq_hz);
assert(clk_src_freq_hz == (160 * 1000 * 1000)); assert(ret == ESP_OK);
return clk_src_freq_hz / host_div / ((card_div == 0) ? 1 : card_div * 2) / 1000; return clk_src_freq_hz / host_div / ((card_div == 0) ? 1 : card_div * 2) / 1000;
} }
@ -261,16 +296,17 @@ esp_err_t sdmmc_host_set_card_clk(int slot, uint32_t freq_khz)
return err; return err;
} }
soc_periph_sdmmc_clk_src_t clk_src = 0;
int host_div = 0; /* clock divider of the host (SDMMC.clock) */ int host_div = 0; /* clock divider of the host (SDMMC.clock) */
int card_div = 0; /* 1/2 of card clock divider (SDMMC.clkdiv) */ int card_div = 0; /* 1/2 of card clock divider (SDMMC.clkdiv) */
sdmmc_host_get_clk_dividers(freq_khz, &host_div, &card_div); sdmmc_host_get_clk_dividers(freq_khz, &host_div, &card_div, &clk_src);
int real_freq = sdmmc_host_calc_freq(host_div, card_div); int real_freq = sdmmc_host_calc_freq(clk_src, host_div, card_div);
ESP_LOGD(TAG, "slot=%d host_div=%d card_div=%d freq=%dkHz (max %" PRIu32 "kHz)", slot, host_div, card_div, real_freq, freq_khz); ESP_LOGD(TAG, "slot=%d clk_src=%d host_div=%d card_div=%d freq=%dkHz (max %" PRIu32 "kHz)", slot, clk_src, host_div, card_div, real_freq, freq_khz);
// Program card clock settings, send them to the CIU // Program card clock settings, send them to the CIU
sdmmc_ll_set_card_clock_div(s_host_ctx.hal.dev, slot, card_div); sdmmc_ll_set_card_clock_div(s_host_ctx.hal.dev, slot, card_div);
sdmmc_host_set_clk_div(host_div); sdmmc_host_set_clk_div(clk_src, host_div);
err = sdmmc_host_clock_update_command(slot, false); err = sdmmc_host_clock_update_command(slot, false);
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "setting clk div failed"); ESP_LOGE(TAG, "setting clk div failed");
@ -310,7 +346,7 @@ esp_err_t sdmmc_host_get_real_freq(int slot, int *real_freq_khz)
int host_div = sdmmc_ll_get_clock_div(s_host_ctx.hal.dev); int host_div = sdmmc_ll_get_clock_div(s_host_ctx.hal.dev);
int card_div = sdmmc_ll_get_card_clock_div(s_host_ctx.hal.dev, slot); int card_div = sdmmc_ll_get_card_clock_div(s_host_ctx.hal.dev, slot);
*real_freq_khz = sdmmc_host_calc_freq(host_div, card_div); *real_freq_khz = sdmmc_host_calc_freq(s_host_ctx.clk_src, host_div, card_div);
return ESP_OK; return ESP_OK;
} }
@ -326,7 +362,7 @@ esp_err_t sdmmc_host_set_input_delay(int slot, sdmmc_delay_phase_t delay_phase)
ESP_RETURN_ON_FALSE(delay_phase < SOC_SDMMC_DELAY_PHASE_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid delay phase"); ESP_RETURN_ON_FALSE(delay_phase < SOC_SDMMC_DELAY_PHASE_NUM, ESP_ERR_INVALID_ARG, TAG, "invalid delay phase");
uint32_t clk_src_freq_hz = 0; uint32_t clk_src_freq_hz = 0;
ESP_RETURN_ON_ERROR(esp_clk_tree_src_get_freq_hz(SDMMC_CLK_SRC_DEFAULT, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq_hz), ESP_RETURN_ON_ERROR(esp_clk_tree_src_get_freq_hz(s_host_ctx.clk_src, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &clk_src_freq_hz),
TAG, "get source clock frequency failed"); TAG, "get source clock frequency failed");
//Now we're in high speed. Note ESP SDMMC Host HW only supports integer divider. //Now we're in high speed. Note ESP SDMMC Host HW only supports integer divider.
@ -459,7 +495,7 @@ esp_err_t sdmmc_host_init(void)
sdmmc_hal_init(&s_host_ctx.hal); sdmmc_hal_init(&s_host_ctx.hal);
// Enable clock to peripheral. Use smallest divider first. // Enable clock to peripheral. Use smallest divider first.
sdmmc_host_set_clk_div(2); sdmmc_host_set_clk_div(SDMMC_CLK_SRC_DEFAULT, 2);
// Reset // Reset
esp_err_t err = sdmmc_host_reset(); esp_err_t err = sdmmc_host_reset();
@ -567,6 +603,18 @@ static bool s_check_pin_not_set(const sdmmc_slot_config_t *slot_config)
#endif #endif
} }
esp_err_t sdmmc_host_is_slot_set_to_uhs1(int slot, bool *is_uhs1)
{
if (s_host_ctx.slot_ctx[slot].slot_id != slot) {
ESP_LOGE(TAG, "%s: slot %d isn't initialized", __func__, slot);
return ESP_ERR_INVALID_STATE;
}
*is_uhs1 = s_host_ctx.slot_ctx[slot].is_uhs1;
return ESP_OK;
}
esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config) esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config)
{ {
if (!s_host_ctx.intr_handle) { if (!s_host_ctx.intr_handle) {
@ -578,6 +626,11 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config)
if (slot_config == NULL) { if (slot_config == NULL) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
if (slot_config->flags & SDMMC_SLOT_FLAG_UHS1) {
s_host_ctx.slot_ctx[slot].is_uhs1 = true;
}
int gpio_cd = slot_config->cd; int gpio_cd = slot_config->cd;
int gpio_wp = slot_config->wp; int gpio_wp = slot_config->wp;
bool gpio_wp_polarity = slot_config->flags & SDMMC_SLOT_FLAG_WP_ACTIVE_HIGH; bool gpio_wp_polarity = slot_config->flags & SDMMC_SLOT_FLAG_WP_ACTIVE_HIGH;
@ -603,12 +656,12 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config)
if (slot == 0) { if (slot == 0) {
#if !SDMMC_LL_SLOT_SUPPORT_GPIO_MATRIX(0) #if !SDMMC_LL_SLOT_SUPPORT_GPIO_MATRIX(0)
if (use_gpio_matrix && if (use_gpio_matrix &&
SDMMC_SLOT0_IOMUX_PIN_NUM_CLK == slot_config->clk && SDMMC_SLOT0_IOMUX_PIN_NUM_CLK == slot_config->clk &&
SDMMC_SLOT0_IOMUX_PIN_NUM_CMD == slot_config->cmd && SDMMC_SLOT0_IOMUX_PIN_NUM_CMD == slot_config->cmd &&
SDMMC_SLOT0_IOMUX_PIN_NUM_D0 == slot_config->d0 && SDMMC_SLOT0_IOMUX_PIN_NUM_D0 == slot_config->d0 &&
SDMMC_SLOT0_IOMUX_PIN_NUM_D1 == slot_config->d1 && SDMMC_SLOT0_IOMUX_PIN_NUM_D1 == slot_config->d1 &&
SDMMC_SLOT0_IOMUX_PIN_NUM_D2 == slot_config->d2 && SDMMC_SLOT0_IOMUX_PIN_NUM_D2 == slot_config->d2 &&
SDMMC_SLOT0_IOMUX_PIN_NUM_D3 == slot_config->d3) { SDMMC_SLOT0_IOMUX_PIN_NUM_D3 == slot_config->d3) {
use_gpio_matrix = false; use_gpio_matrix = false;
} else { } else {
ESP_RETURN_ON_FALSE(!use_gpio_matrix, ESP_ERR_INVALID_ARG, TAG, "doesn't support routing from GPIO matrix, driver uses dedicated IOs"); ESP_RETURN_ON_FALSE(!use_gpio_matrix, ESP_ERR_INVALID_ARG, TAG, "doesn't support routing from GPIO matrix, driver uses dedicated IOs");
@ -685,20 +738,23 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config)
if (slot_width >= 4) { if (slot_width >= 4) {
configure_pin(slot_gpio->d1, sdmmc_slot_gpio_sig[slot].d1, GPIO_MODE_INPUT_OUTPUT, "d1", use_gpio_matrix); configure_pin(slot_gpio->d1, sdmmc_slot_gpio_sig[slot].d1, GPIO_MODE_INPUT_OUTPUT, "d1", use_gpio_matrix);
configure_pin(slot_gpio->d2, sdmmc_slot_gpio_sig[slot].d2, GPIO_MODE_INPUT_OUTPUT, "d2", use_gpio_matrix); configure_pin(slot_gpio->d2, sdmmc_slot_gpio_sig[slot].d2, GPIO_MODE_INPUT_OUTPUT, "d2", use_gpio_matrix);
configure_pin(slot_gpio->d3, sdmmc_slot_gpio_sig[slot].d3, GPIO_MODE_INPUT_OUTPUT, "d3", use_gpio_matrix); if (s_host_ctx.slot_ctx[slot].is_uhs1) {
// // Force D3 high to make slave enter SD mode. configure_pin(slot_gpio->d3, sdmmc_slot_gpio_sig[slot].d3, GPIO_MODE_INPUT_OUTPUT, "d3", use_gpio_matrix);
// // Connect to peripheral after width configuration. } else {
// if (slot_gpio->d3 > GPIO_NUM_NC) { // Force D3 high to make slave enter SD mode.
// gpio_config_t gpio_conf = { // Connect to peripheral after width configuration.
// .pin_bit_mask = BIT64(slot_gpio->d3), if (slot_gpio->d3 > GPIO_NUM_NC) {
// .mode = GPIO_MODE_OUTPUT, gpio_config_t gpio_conf = {
// .pull_up_en = 0, .pin_bit_mask = BIT64(slot_gpio->d3),
// .pull_down_en = 0, .mode = GPIO_MODE_OUTPUT,
// .intr_type = GPIO_INTR_DISABLE, .pull_up_en = 0,
// }; .pull_down_en = 0,
// gpio_config(&gpio_conf); .intr_type = GPIO_INTR_DISABLE,
// gpio_set_level(slot_gpio->d3, 1); };
// } gpio_config(&gpio_conf);
gpio_set_level(slot_gpio->d3, 1);
}
}
} }
if (slot_width == 8) { if (slot_width == 8) {
configure_pin(slot_gpio->d4, sdmmc_slot_gpio_sig[slot].d4, GPIO_MODE_INPUT_OUTPUT, "d4", use_gpio_matrix); configure_pin(slot_gpio->d4, sdmmc_slot_gpio_sig[slot].d4, GPIO_MODE_INPUT_OUTPUT, "d4", use_gpio_matrix);
@ -752,6 +808,8 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config)
return ret; return ret;
} }
s_host_ctx.slot_ctx[slot].slot_id = slot;
#if SOC_SDMMC_NUM_SLOTS >= 2 #if SOC_SDMMC_NUM_SLOTS >= 2
if (s_host_ctx.num_of_init_slots < SOC_SDMMC_NUM_SLOTS && s_host_ctx.active_slot_num != slot) { if (s_host_ctx.num_of_init_slots < SOC_SDMMC_NUM_SLOTS && s_host_ctx.active_slot_num != slot) {
s_host_ctx.num_of_init_slots += 1; s_host_ctx.num_of_init_slots += 1;
@ -893,12 +951,12 @@ esp_err_t sdmmc_host_set_bus_width(int slot, size_t width)
sdmmc_ll_set_card_width(s_host_ctx.hal.dev, slot, SD_BUS_WIDTH_1_BIT); sdmmc_ll_set_card_width(s_host_ctx.hal.dev, slot, SD_BUS_WIDTH_1_BIT);
} else if (width == 4) { } else if (width == 4) {
sdmmc_ll_set_card_width(s_host_ctx.hal.dev, slot, SD_BUS_WIDTH_4_BIT); sdmmc_ll_set_card_width(s_host_ctx.hal.dev, slot, SD_BUS_WIDTH_4_BIT);
// // D3 was set to GPIO high to force slave into SD mode, until 4-bit mode is set // D3 was set to GPIO high to force slave into SD mode, until 4-bit mode is set
// configure_pin(s_host_ctx.slot_ctx[slot].slot_gpio_num.d3, sdmmc_slot_gpio_sig[slot].d3, GPIO_MODE_INPUT_OUTPUT, "d3", s_host_ctx.slot_ctx[slot].use_gpio_matrix); configure_pin(s_host_ctx.slot_ctx[slot].slot_gpio_num.d3, sdmmc_slot_gpio_sig[slot].d3, GPIO_MODE_INPUT_OUTPUT, "d3", s_host_ctx.slot_ctx[slot].use_gpio_matrix);
} else if (width == 8) { } else if (width == 8) {
sdmmc_ll_set_card_width(s_host_ctx.hal.dev, slot, SD_BUS_WIDTH_8_BIT); sdmmc_ll_set_card_width(s_host_ctx.hal.dev, slot, SD_BUS_WIDTH_8_BIT);
// // D3 was set to GPIO high to force slave into SD mode, until 4-bit mode is set // D3 was set to GPIO high to force slave into SD mode, until 4-bit mode is set
// configure_pin(s_host_ctx.slot_ctx[slot].slot_gpio_num.d3, sdmmc_slot_gpio_sig[slot].d3, GPIO_MODE_INPUT_OUTPUT, "d3", s_host_ctx.slot_ctx[slot].use_gpio_matrix); configure_pin(s_host_ctx.slot_ctx[slot].slot_gpio_num.d3, sdmmc_slot_gpio_sig[slot].d3, GPIO_MODE_INPUT_OUTPUT, "d3", s_host_ctx.slot_ctx[slot].use_gpio_matrix);
} else { } else {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
@ -946,7 +1004,9 @@ void sdmmc_host_enable_clk_cmd11(int slot, bool enable)
sdmmc_ll_enable_card_clock(s_host_ctx.hal.dev, slot, enable); sdmmc_ll_enable_card_clock(s_host_ctx.hal.dev, slot, enable);
sdmmc_host_clock_update_command(slot, true); sdmmc_host_clock_update_command(slot, true);
if (enable) { if (enable) {
sdmmc_ll_enable_18v_mode(s_host_ctx.hal.dev, slot, true); sdmmc_ll_enable_1v8_mode(s_host_ctx.hal.dev, slot, true);
} else {
sdmmc_ll_enable_1v8_mode(s_host_ctx.hal.dev, slot, false);
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */

View File

@ -20,8 +20,9 @@
#include "driver/sdmmc_host.h" #include "driver/sdmmc_host.h"
#include "esp_cache.h" #include "esp_cache.h"
#include "esp_private/esp_cache_private.h" #include "esp_private/esp_cache_private.h"
#include "sdmmc_private.h" #include "sdmmc_internal.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "hal/sdmmc_ll.h"
/* Number of DMA descriptors used for transfer. /* Number of DMA descriptors used for transfer.
* Increasing this value above 4 doesn't improve performance for the usual case * Increasing this value above 4 doesn't improve performance for the usual case
@ -350,7 +351,7 @@ static sdmmc_hw_cmd_t make_hw_cmd(sdmmc_command_t* cmd)
if (cmd->opcode == MMC_GO_IDLE_STATE) { if (cmd->opcode == MMC_GO_IDLE_STATE) {
res.send_init = 1; res.send_init = 1;
} }
if (cmd->flags & SCF_RSP_PRESENT) { if (cmd->flags & SCF_RSP_PRESENT) {
res.response_expect = 1; res.response_expect = 1;
if (cmd->flags & SCF_RSP_136) { if (cmd->flags & SCF_RSP_136) {
@ -450,7 +451,7 @@ static esp_err_t process_events(int slot, sdmmc_event_t evt, sdmmc_command_t* cm
}; };
sdmmc_event_t orig_evt = evt; sdmmc_event_t orig_evt = evt;
ESP_LOGV(TAG, "%s: slot=%d state=%s evt=%"PRIx32" dma=%"PRIx32, __func__, slot, ESP_LOGV(TAG, "%s: slot=%d state=%s evt=%"PRIx32" dma=%"PRIx32, __func__, slot,
s_state_names[*pstate], evt.sdmmc_status, evt.dma_status); s_state_names[*pstate], evt.sdmmc_status, evt.dma_status);
sdmmc_req_state_t next_state = *pstate; sdmmc_req_state_t next_state = *pstate;
sdmmc_req_state_t state = (sdmmc_req_state_t) -1; sdmmc_req_state_t state = (sdmmc_req_state_t) -1;
while (next_state != state) { while (next_state != state) {

View File

@ -35,7 +35,7 @@ void sdmmc_test_board_get_config_sdmmc(int slot_index, sdmmc_host_t *out_host_co
out_host_config->max_freq_khz = slot->max_freq_khz; out_host_config->max_freq_khz = slot->max_freq_khz;
} }
if (slot->uhs1_supported) { if (slot->uhs1_supported) {
out_host_config->flags |= SDMMC_HOST_FLAG_UHS1; out_slot_config->flags |= SDMMC_SLOT_FLAG_UHS1;
} }
#if SOC_SDMMC_USE_GPIO_MATRIX #if SOC_SDMMC_USE_GPIO_MATRIX

View File

@ -58,7 +58,7 @@ void sdmmc_test_sd_begin(int slot, int width, int freq_khz, int ddr, sdmmc_card_
} }
config.max_freq_khz = freq_khz; config.max_freq_khz = freq_khz;
bool slot_is_uhs1 = config.flags & SDMMC_HOST_FLAG_UHS1; bool slot_is_uhs1 = slot_config.flags & SDMMC_SLOT_FLAG_UHS1;
if (width == 1) { if (width == 1) {
config.flags = SDMMC_HOST_FLAG_1BIT; config.flags = SDMMC_HOST_FLAG_1BIT;
@ -80,7 +80,7 @@ void sdmmc_test_sd_begin(int slot, int width, int freq_khz, int ddr, sdmmc_card_
} }
if (slot_is_uhs1) { if (slot_is_uhs1) {
config.flags |= SDMMC_HOST_FLAG_UHS1; slot_config.flags |= SDMMC_SLOT_FLAG_UHS1;
} }
#if SOC_SDMMC_IO_POWER_EXTERNAL #if SOC_SDMMC_IO_POWER_EXTERNAL

View File

@ -40,6 +40,8 @@ typedef int sdspi_dev_handle_t;
.slot = SDSPI_DEFAULT_HOST, \ .slot = SDSPI_DEFAULT_HOST, \
.max_freq_khz = SDMMC_FREQ_DEFAULT, \ .max_freq_khz = SDMMC_FREQ_DEFAULT, \
.io_voltage = 3.3f, \ .io_voltage = 3.3f, \
.driver_strength = SDMMC_DRIVER_STRENGTH_B, \
.current_limit = SDMMC_CURRENT_LIMIT_200MA, \
.init = &sdspi_host_init, \ .init = &sdspi_host_init, \
.set_bus_width = NULL, \ .set_bus_width = NULL, \
.get_bus_width = NULL, \ .get_bus_width = NULL, \
@ -57,6 +59,7 @@ typedef int sdspi_dev_handle_t;
.dma_aligned_buffer = NULL, \ .dma_aligned_buffer = NULL, \
.pwr_ctrl_handle = NULL, \ .pwr_ctrl_handle = NULL, \
.get_dma_info = &sdspi_host_get_dma_info, \ .get_dma_info = &sdspi_host_get_dma_info, \
.is_slot_set_to_uhs1 = NULL, \
} }
/** /**

View File

@ -56,8 +56,9 @@ esp_err_t esp_clk_tree_src_get_freq_hz(soc_module_clk_t clk_src, esp_clk_tree_sr
case SOC_MOD_CLK_APLL: case SOC_MOD_CLK_APLL:
clk_src_freq = clk_hal_apll_get_freq_hz(); clk_src_freq = clk_hal_apll_get_freq_hz();
break; break;
// case SOC_MOD_CLK_SDIO_PLL: TODO: IDF-8886 case SOC_MOD_CLK_SDIO_PLL:
// break; clk_src_freq = CLK_LL_PLL_SDIO_FREQ_MHZ * MHZ;
break;
case SOC_MOD_CLK_RTC_SLOW: case SOC_MOD_CLK_RTC_SLOW:
clk_src_freq = esp_clk_tree_lp_slow_get_freq_hz(precision); clk_src_freq = esp_clk_tree_lp_slow_get_freq_hz(precision);
break; break;

View File

@ -408,6 +408,18 @@ static inline bool sdmmc_ll_is_card_write_protected(sdmmc_dev_t *hw, uint32_t sl
return is_protected; return is_protected;
} }
/**
* @brief Switch between 3.3V and 1.8V mode
*
* @param hw hardware instance address
* @param slot slot
* @param en enable / disable 1.8V (3.3V on disable)
*/
static inline void sdmmc_ll_enable_1v8_mode(sdmmc_dev_t *hw, uint32_t slot, bool en)
{
//for compatibility
}
/** /**
* @brief Enable DDR mode * @brief Enable DDR mode
* *

View File

@ -40,6 +40,7 @@ extern "C" {
#define CLK_LL_PLL_80M_FREQ_MHZ (80) #define CLK_LL_PLL_80M_FREQ_MHZ (80)
#define CLK_LL_PLL_160M_FREQ_MHZ (160) #define CLK_LL_PLL_160M_FREQ_MHZ (160)
#define CLK_LL_PLL_240M_FREQ_MHZ (240) #define CLK_LL_PLL_240M_FREQ_MHZ (240)
#define CLK_LL_PLL_SDIO_FREQ_MHZ (200)
#define CLK_LL_PLL_360M_FREQ_MHZ (360) #define CLK_LL_PLL_360M_FREQ_MHZ (360)
#define CLK_LL_PLL_400M_FREQ_MHZ (400) #define CLK_LL_PLL_400M_FREQ_MHZ (400)

View File

@ -24,6 +24,7 @@
#include "soc/sdmmc_reg.h" #include "soc/sdmmc_reg.h"
#include "soc/hp_sys_clkrst_struct.h" #include "soc/hp_sys_clkrst_struct.h"
#include "soc/lp_clkrst_struct.h" #include "soc/lp_clkrst_struct.h"
#include "soc/pmu_reg.h"
#ifdef __cplusplus #ifdef __cplusplus
@ -124,6 +125,37 @@ static inline void sdmmc_ll_reset_register(sdmmc_dev_t *hw)
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance /// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define sdmmc_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; sdmmc_ll_reset_register(__VA_ARGS__) #define sdmmc_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; sdmmc_ll_reset_register(__VA_ARGS__)
/**
* @brief Enable the bus clock for SDIO PLL
*
* @param hw hardware instance address
* @param en enable / disable
*/
static inline void sdmmc_ll_enable_sdio_pll(sdmmc_dev_t *hw, bool en)
{
if (en) {
REG_SET_BIT(PMU_RF_PWC_REG, PMU_SDIO_PLL_XPD);
REG_SET_BIT(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_XPD_SDIOPLL_I2C);
REG_SET_BIT(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_XPD_SDIOPLL);
REG_SET_BIT(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_GLOBAL_SDIOPLL_ICG);
LP_AON_CLKRST.hp_clk_ctrl.hp_sdio_pll0_clk_en = 1;
LP_AON_CLKRST.hp_clk_ctrl.hp_sdio_pll1_clk_en = 1;
LP_AON_CLKRST.hp_clk_ctrl.hp_sdio_pll2_clk_en = 1;
} else {
REG_CLR_BIT(PMU_RF_PWC_REG, PMU_SDIO_PLL_XPD);
REG_CLR_BIT(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_XPD_SDIOPLL_I2C);
REG_CLR_BIT(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_XPD_SDIOPLL);
REG_CLR_BIT(PMU_IMM_HP_CK_POWER_REG, PMU_TIE_HIGH_GLOBAL_SDIOPLL_ICG);
LP_AON_CLKRST.hp_clk_ctrl.hp_sdio_pll0_clk_en = 0;
LP_AON_CLKRST.hp_clk_ctrl.hp_sdio_pll0_clk_en = 0;
LP_AON_CLKRST.hp_clk_ctrl.hp_sdio_pll2_clk_en = 0;
}
}
/// use a macro to wrap the function, force the caller to use it in a critical section
/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance
#define sdmmc_ll_enable_sdio_pll(...) (void)__DECLARE_RCC_ATOMIC_ENV; sdmmc_ll_enable_sdio_pll(__VA_ARGS__)
/** /**
* @brief Select SDMMC clock source * @brief Select SDMMC clock source
* *
@ -137,9 +169,9 @@ static inline void sdmmc_ll_select_clk_source(sdmmc_dev_t *hw, soc_periph_sdmmc_
case SDMMC_CLK_SRC_PLL160M: case SDMMC_CLK_SRC_PLL160M:
clk_val = 0; clk_val = 0;
break; break;
// case SDMMC_CLK_SRC_PLL200M: // TODO: IDF-8886 case SDMMC_CLK_SRC_SDIO_200M:
// clk_val = 1; clk_val = 1;
// break; break;
default: default:
HAL_ASSERT(false); HAL_ASSERT(false);
break; break;
@ -161,12 +193,18 @@ static inline void sdmmc_ll_select_clk_source(sdmmc_dev_t *hw, soc_periph_sdmmc_
*/ */
static inline void sdmmc_ll_set_clock_div(sdmmc_dev_t *hw, uint32_t div) static inline void sdmmc_ll_set_clock_div(sdmmc_dev_t *hw, uint32_t div)
{ {
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_h = div / 2 - 1; if (div > 1) {
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_n = div - 1; HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_h = div / 2 - 1;
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_l = div - 1; HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_n = div - 1;
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_l = div - 1;
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_cfg_update = 1; HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_cfg_update = 1;
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_cfg_update = 0; HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_cfg_update = 0;
} else {
HP_SYS_CLKRST.peri_clk_ctrl01.reg_sdio_hs_mode = 1;
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_h = 0;
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_n = 0;
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_l = 0;
}
} }
/// use a macro to wrap the function, force the caller to use it in a critical section /// use a macro to wrap the function, force the caller to use it in a critical section
@ -192,7 +230,16 @@ static inline void sdmmc_ll_deinit_clk(sdmmc_dev_t *hw)
*/ */
static inline uint32_t sdmmc_ll_get_clock_div(sdmmc_dev_t *hw) static inline uint32_t sdmmc_ll_get_clock_div(sdmmc_dev_t *hw)
{ {
return HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_l + 1; uint32_t div = 0;
if (HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_h == 0 &&
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_n == 0 &&
HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_l == 0) {
div = 1;
} else {
div = HP_SYS_CLKRST.peri_clk_ctrl02.reg_sdio_ls_clk_edge_l + 1;
}
return div;
} }
/** /**
@ -458,7 +505,7 @@ static inline bool sdmmc_ll_is_card_write_protected(sdmmc_dev_t *hw, uint32_t sl
* @param slot slot * @param slot slot
* @param en enable / disable 1.8V (3.3V on disable) * @param en enable / disable 1.8V (3.3V on disable)
*/ */
static inline void sdmmc_ll_enable_18v_mode(sdmmc_dev_t *hw, uint32_t slot, bool en) static inline void sdmmc_ll_enable_1v8_mode(sdmmc_dev_t *hw, uint32_t slot, bool en)
{ {
if (en) { if (en) {
hw->uhs.volt |= BIT(slot); hw->uhs.volt |= BIT(slot);

View File

@ -444,6 +444,18 @@ static inline bool sdmmc_ll_is_card_write_protected(sdmmc_dev_t *hw, uint32_t sl
return is_protected; return is_protected;
} }
/**
* @brief Switch between 3.3V and 1.8V mode
*
* @param hw hardware instance address
* @param slot slot
* @param en enable / disable 1.8V (3.3V on disable)
*/
static inline void sdmmc_ll_enable_1v8_mode(sdmmc_dev_t *hw, uint32_t slot, bool en)
{
//for compatibility
}
/** /**
* @brief Enable DDR mode * @brief Enable DDR mode
* *

View File

@ -46,6 +46,7 @@ extern "C" {
#define MMC_SET_BLOCKLEN 16 /* R1 */ #define MMC_SET_BLOCKLEN 16 /* R1 */
#define MMC_READ_BLOCK_SINGLE 17 /* R1 */ #define MMC_READ_BLOCK_SINGLE 17 /* R1 */
#define MMC_READ_BLOCK_MULTIPLE 18 /* R1 */ #define MMC_READ_BLOCK_MULTIPLE 18 /* R1 */
#define MMC_SEND_TUNING_BLOCK 19 /* R1 */
#define MMC_WRITE_DAT_UNTIL_STOP 20 /* R1 */ #define MMC_WRITE_DAT_UNTIL_STOP 20 /* R1 */
#define MMC_SET_BLOCK_COUNT 23 /* R1 */ #define MMC_SET_BLOCK_COUNT 23 /* R1 */
#define MMC_WRITE_BLOCK_SINGLE 24 /* R1 */ #define MMC_WRITE_BLOCK_SINGLE 24 /* R1 */
@ -303,6 +304,8 @@ extern "C" {
#define SD_CSD_SPEED(resp) MMC_RSP_BITS((resp), 96, 8) #define SD_CSD_SPEED(resp) MMC_RSP_BITS((resp), 96, 8)
#define SD_CSD_SPEED_25_MHZ 0x32 #define SD_CSD_SPEED_25_MHZ 0x32
#define SD_CSD_SPEED_50_MHZ 0x5a #define SD_CSD_SPEED_50_MHZ 0x5a
#define SD_CSD_SPEED_100_MHZ 0xb
#define SD_CSD_SPEED_200_MHZ 0x2b
#define SD_CSD_CCC(resp) MMC_RSP_BITS((resp), 84, 12) #define SD_CSD_CCC(resp) MMC_RSP_BITS((resp), 84, 12)
#define SD_CSD_CCC_BASIC (1 << 0) /* basic */ #define SD_CSD_CCC_BASIC (1 << 0) /* basic */
#define SD_CSD_CCC_BR (1 << 2) /* block read */ #define SD_CSD_CCC_BR (1 << 2) /* block read */
@ -416,6 +419,14 @@ extern "C" {
#define SD_SFUNC_FUNC_MAX 15 #define SD_SFUNC_FUNC_MAX 15
#define SD_ACCESS_MODE 1 /* Function group 1, Access Mode */ #define SD_ACCESS_MODE 1 /* Function group 1, Access Mode */
#define SD_COMMAND_SYSTEM 2 /* Function group 1, Command System */
#define SD_DRIVER_STRENGTH 3 /* Function group 1, Driver Strength */
#define SD_CURRENT_LIMIT 4 /* Function group 1, Current Limit */
#define SD_DRIVER_STRENGTH_B 0 /* Type B */
#define SD_DRIVER_STRENGTH_A 1 /* Type A */
#define SD_DRIVER_STRENGTH_C 2 /* Type C */
#define SD_DRIVER_STRENGTH_D 3 /* Type D */
#define SD_ACCESS_MODE_SDR12 0 /* 25 MHz clock */ #define SD_ACCESS_MODE_SDR12 0 /* 25 MHz clock */
#define SD_ACCESS_MODE_SDR25 1 /* 50 MHz clock */ #define SD_ACCESS_MODE_SDR25 1 /* 50 MHz clock */

View File

@ -156,7 +156,11 @@ typedef struct {
/** /**
* SD/MMC Host clock timing delay phases * SD/MMC Host clock timing delay phases
* *
* This will only take effect when the host works in SDMMC_FREQ_HIGHSPEED or SDMMC_FREQ_52M. * This will only take effect when the host works in
* - SDMMC_FREQ_HIGHSPEED
* - SDMMC_FREQ_52M
* - SDR50
* - DDR50
* Driver will print out how long the delay is, in picosecond (ps). * Driver will print out how long the delay is, in picosecond (ps).
*/ */
typedef enum { typedef enum {
@ -164,8 +168,29 @@ typedef enum {
SDMMC_DELAY_PHASE_1, /*!< Delay phase 1 */ SDMMC_DELAY_PHASE_1, /*!< Delay phase 1 */
SDMMC_DELAY_PHASE_2, /*!< Delay phase 2 */ SDMMC_DELAY_PHASE_2, /*!< Delay phase 2 */
SDMMC_DELAY_PHASE_3, /*!< Delay phase 3 */ SDMMC_DELAY_PHASE_3, /*!< Delay phase 3 */
SDMMC_DELAY_PHASE_AUTO, /*!< Auto detect phase, only valid for UHS-I mode */
} sdmmc_delay_phase_t; } sdmmc_delay_phase_t;
/**
* @brief SD/MMC Driver Strength
*/
typedef enum {
SDMMC_DRIVER_STRENGTH_B, /*!< Type B */
SDMMC_DRIVER_STRENGTH_A, /*!< Type A */
SDMMC_DRIVER_STRENGTH_C, /*!< Type C */
SDMMC_DRIVER_STRENGTH_D, /*!< Type D */
} sdmmc_driver_strength_t;
/**
* @brief SD/MMC Current Limit
*/
typedef enum {
SDMMC_CURRENT_LIMIT_200MA, /*!< 200 mA */
SDMMC_CURRENT_LIMIT_400MA, /*!< 400 mA */
SDMMC_CURRENT_LIMIT_600MA, /*!< 600 mA */
SDMMC_CURRENT_LIMIT_800MA, /*!< 800 mA */
} sdmmc_current_limit_t;
/** /**
* SD/MMC Host description * SD/MMC Host description
* *
@ -185,7 +210,6 @@ typedef struct {
Currently this is only used by the SDIO driver. Set this flag when 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 using SDIO CMD53 byte mode, with user buffer that is behind the cache
or not aligned to 4 byte boundary. */ 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 slot; /*!< slot number, to be passed to host functions */
int max_freq_khz; /*!< max frequency supported by the host */ int max_freq_khz; /*!< max frequency supported by the host */
#define SDMMC_FREQ_DEFAULT 20000 /*!< SD/MMC Default speed (limited by clock divider) */ #define SDMMC_FREQ_DEFAULT 20000 /*!< SD/MMC Default speed (limited by clock divider) */
@ -193,7 +217,11 @@ typedef struct {
#define SDMMC_FREQ_PROBING 400 /*!< SD/MMC probing speed */ #define SDMMC_FREQ_PROBING 400 /*!< SD/MMC probing speed */
#define SDMMC_FREQ_52M 52000 /*!< MMC 52MHz speed */ #define SDMMC_FREQ_52M 52000 /*!< MMC 52MHz speed */
#define SDMMC_FREQ_26M 26000 /*!< MMC 26MHz speed */ #define SDMMC_FREQ_26M 26000 /*!< MMC 26MHz speed */
#define SDMMC_FREQ_DDR50 50000 /*!< MMC 50MHz speed */
#define SDMMC_FREQ_SDR50 100000 /*!< MMC 100MHz speed */
float io_voltage; /*!< I/O voltage used by the controller (voltage switching is not supported) */ float io_voltage; /*!< I/O voltage used by the controller (voltage switching is not supported) */
sdmmc_driver_strength_t driver_strength; /*!< Driver Strength */
sdmmc_current_limit_t current_limit; /*!< Current Limit */
esp_err_t (*init)(void); /*!< Host function to initialize the driver */ esp_err_t (*init)(void); /*!< Host function to initialize the driver */
esp_err_t (*set_bus_width)(int slot, size_t width); /*!< host function to set bus width */ esp_err_t (*set_bus_width)(int slot, size_t width); /*!< host function to set bus width */
size_t (*get_bus_width)(int slot); /*!< host function to get bus width */ size_t (*get_bus_width)(int slot); /*!< host function to get bus width */
@ -214,6 +242,7 @@ typedef struct {
void* dma_aligned_buffer; /*!< Leave it NULL. Reserved for cache aligned buffers for SDIO mode */ void* dma_aligned_buffer; /*!< Leave it NULL. Reserved for cache aligned buffers for SDIO mode */
sd_pwr_ctrl_handle_t pwr_ctrl_handle; /*!< Power control handle */ sd_pwr_ctrl_handle_t pwr_ctrl_handle; /*!< Power control handle */
esp_err_t (*get_dma_info)(int slot, esp_dma_mem_info_t *dma_mem_info); /*!< host function to dma memory information*/ esp_err_t (*get_dma_info)(int slot, esp_dma_mem_info_t *dma_mem_info); /*!< host function to dma memory information*/
esp_err_t (*is_slot_set_to_uhs1)(int slot, bool *is_uhs1); /*!< host slot is set to uhs1 or not*/
} sdmmc_host_t; } sdmmc_host_t;
/** /**
@ -232,7 +261,7 @@ typedef struct {
sdmmc_ssr_t ssr; /*!< decoded SSR (SD Status Register) value */ sdmmc_ssr_t ssr; /*!< decoded SSR (SD Status Register) value */
sdmmc_ext_csd_t ext_csd; /*!< decoded EXT_CSD (Extended Card Specific Data) register value */ sdmmc_ext_csd_t ext_csd; /*!< decoded EXT_CSD (Extended Card Specific Data) register value */
uint16_t rca; /*!< RCA (Relative Card Address) */ uint16_t rca; /*!< RCA (Relative Card Address) */
uint16_t max_freq_khz; /*!< Maximum frequency, in kHz, supported by the card */ uint32_t max_freq_khz; /*!< Maximum frequency, in kHz, supported by the card */
int real_freq_khz; /*!< Real working frequency, in kHz, configured on the host controller */ int real_freq_khz; /*!< Real working frequency, in kHz, configured on the host controller */
uint32_t is_mem : 1; /*!< Bit indicates if the card is a memory card */ uint32_t is_mem : 1; /*!< Bit indicates if the card is a memory card */
uint32_t is_sdio : 1; /*!< Bit indicates if the card is an IO card */ uint32_t is_sdio : 1; /*!< Bit indicates if the card is an IO card */
@ -240,7 +269,8 @@ typedef struct {
uint32_t num_io_functions : 3; /*!< If is_sdio is 1, contains the number of IO functions on the card */ uint32_t num_io_functions : 3; /*!< If is_sdio is 1, contains the number of IO functions on the card */
uint32_t log_bus_width : 2; /*!< log2(bus width supported by card) */ uint32_t log_bus_width : 2; /*!< log2(bus width supported by card) */
uint32_t is_ddr : 1; /*!< Card supports DDR mode */ uint32_t is_ddr : 1; /*!< Card supports DDR mode */
uint32_t reserved : 23; /*!< Reserved for future expansion */ uint32_t is_uhs1 : 1; /*!< Card supports UHS-1 mode */
uint32_t reserved : 22; /*!< Reserved for future expansion */
} sdmmc_card_t; } sdmmc_card_t;
/** /**

View File

@ -42,7 +42,11 @@ esp_err_t sdmmc_init_ocr(sdmmc_card_t* card)
acmd41_arg |= SD_OCR_SDHC_CAP; acmd41_arg |= SD_OCR_SDHC_CAP;
} }
if ((card->host.flags & SDMMC_HOST_FLAG_UHS1) != 0) { bool to_set_to_uhs1 = false;
if (card->host.is_slot_set_to_uhs1) {
ESP_RETURN_ON_ERROR(card->host.is_slot_set_to_uhs1(card->host.slot, &to_set_to_uhs1), TAG, "failed to get slot info");
}
if (to_set_to_uhs1) {
acmd41_arg |= SD_OCR_S18_RA; acmd41_arg |= SD_OCR_S18_RA;
acmd41_arg |= SD_OCR_XPC; acmd41_arg |= SD_OCR_XPC;
} }
@ -188,6 +192,21 @@ esp_err_t sdmmc_init_card_hs_mode(sdmmc_card_t* card)
return ESP_OK; return ESP_OK;
} }
esp_err_t sdmmc_init_sd_driver_strength(sdmmc_card_t *card)
{
return sdmmc_select_driver_strength(card, card->host.driver_strength);
}
esp_err_t sdmmc_init_sd_current_limit(sdmmc_card_t *card)
{
return sdmmc_select_current_limit(card, card->host.current_limit);
}
esp_err_t sdmmc_init_sd_timing_tuning(sdmmc_card_t *card)
{
return sdmmc_do_timing_tuning(card);
}
esp_err_t sdmmc_init_host_bus_width(sdmmc_card_t* card) esp_err_t sdmmc_init_host_bus_width(sdmmc_card_t* card)
{ {
int bus_width = 1; int bus_width = 1;
@ -215,6 +234,14 @@ esp_err_t sdmmc_init_host_frequency(sdmmc_card_t* card)
esp_err_t err; esp_err_t err;
assert(card->max_freq_khz <= card->host.max_freq_khz); assert(card->max_freq_khz <= card->host.max_freq_khz);
#if !SOC_SDMMC_UHS_I_SUPPORTED
ESP_RETURN_ON_FALSE(card->host.input_delay_phase != SDMMC_DELAY_PHASE_AUTO, ESP_ERR_INVALID_ARG, TAG, "auto tuning not supported");
#endif
if (card->host.input_delay_phase == SDMMC_DELAY_PHASE_AUTO) {
ESP_RETURN_ON_FALSE((card->host.max_freq_khz == SDMMC_FREQ_SDR50 || card->host.max_freq_khz == SDMMC_FREQ_SDR104), ESP_ERR_INVALID_ARG, TAG, "auto tuning only supported for SDR50 / SDR104");
}
if (card->max_freq_khz > SDMMC_FREQ_PROBING) { if (card->max_freq_khz > SDMMC_FREQ_PROBING) {
err = (*card->host.set_card_clk)(card->host.slot, card->max_freq_khz); err = (*card->host.set_card_clk)(card->host.slot, card->max_freq_khz);
if (err != ESP_OK) { if (err != ESP_OK) {
@ -346,6 +373,19 @@ esp_err_t sdmmc_fix_host_flags(sdmmc_card_t* card)
card->host.flags |= width_4bit; card->host.flags |= width_4bit;
} }
} }
#if !SOC_SDMMC_UHS_I_SUPPORTED
if ((card->host.max_freq_khz == SDMMC_FREQ_SDR50) ||
(card->host.max_freq_khz == SDMMC_FREQ_DDR50) ||
(card->host.max_freq_khz == SDMMC_FREQ_SDR104)) {
ESP_RETURN_ON_FALSE(false, ESP_ERR_NOT_SUPPORTED, TAG, "UHS-I is not supported");
}
#else
if (card->host.max_freq_khz == SDMMC_FREQ_DDR50) {
ESP_RETURN_ON_FALSE(((card->host.flags & SDMMC_HOST_FLAG_DDR) != 0), ESP_ERR_INVALID_ARG, TAG, "DDR is not selected");
}
#endif
return ESP_OK; return ESP_OK;
} }

View File

@ -18,6 +18,7 @@
#include <string.h> #include <string.h>
#include "esp_log.h" #include "esp_log.h"
#include "esp_check.h"
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
@ -26,6 +27,7 @@
#include "sdmmc_cmd.h" #include "sdmmc_cmd.h"
#include "sys/param.h" #include "sys/param.h"
#include "soc/soc_memory_layout.h" #include "soc/soc_memory_layout.h"
#include "soc/soc_caps.h"
#include "esp_dma_utils.h" #include "esp_dma_utils.h"
#define SDMMC_GO_IDLE_DELAY_MS 20 #define SDMMC_GO_IDLE_DELAY_MS 20
@ -57,6 +59,8 @@
#define SDMMC_MMC_TRIM_ARG 1 #define SDMMC_MMC_TRIM_ARG 1
#define SDMMC_MMC_DISCARD_ARG 3 #define SDMMC_MMC_DISCARD_ARG 3
#define SDMMC_FREQ_SDR104 208000 /*!< MMC 208MHz speed */
/* Functions to send individual commands */ /* Functions to send individual commands */
esp_err_t sdmmc_send_cmd(sdmmc_card_t* card, sdmmc_command_t* cmd); esp_err_t sdmmc_send_cmd(sdmmc_card_t* card, sdmmc_command_t* cmd);
esp_err_t sdmmc_send_app_cmd(sdmmc_card_t* card, sdmmc_command_t* cmd); esp_err_t sdmmc_send_app_cmd(sdmmc_card_t* card, sdmmc_command_t* cmd);
@ -80,13 +84,16 @@ 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); esp_err_t sdmmc_send_cmd_voltage_switch(sdmmc_card_t* card);
/* Higher level functions */ /* Higher level functions */
esp_err_t sdmmc_enable_hs_mode(sdmmc_card_t* card); esp_err_t sdmmc_enter_higher_speed_mode(sdmmc_card_t* card);
esp_err_t sdmmc_enable_hs_mode_and_check(sdmmc_card_t* card); esp_err_t sdmmc_enable_hs_mode_and_check(sdmmc_card_t* card);
esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src, esp_err_t sdmmc_write_sectors_dma(sdmmc_card_t* card, const void* src,
size_t start_block, size_t block_count, size_t buffer_len); size_t start_block, size_t block_count, size_t buffer_len);
esp_err_t sdmmc_read_sectors_dma(sdmmc_card_t* card, void* dst, esp_err_t sdmmc_read_sectors_dma(sdmmc_card_t* card, void* dst,
size_t start_block, size_t block_count, size_t buffer_len); size_t start_block, size_t block_count, size_t buffer_len);
uint32_t sdmmc_get_erase_timeout_ms(const sdmmc_card_t* card, int arg, size_t erase_size_kb); uint32_t sdmmc_get_erase_timeout_ms(const sdmmc_card_t* card, int arg, size_t erase_size_kb);
esp_err_t sdmmc_select_driver_strength(sdmmc_card_t *card, sdmmc_driver_strength_t driver_strength);
esp_err_t sdmmc_select_current_limit(sdmmc_card_t *card, sdmmc_current_limit_t current_limit);
esp_err_t sdmmc_do_timing_tuning(sdmmc_card_t *card);
/* SD specific */ /* SD specific */
esp_err_t sdmmc_check_scr(sdmmc_card_t* card); esp_err_t sdmmc_check_scr(sdmmc_card_t* card);
@ -141,6 +148,9 @@ 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_host_frequency(sdmmc_card_t* card);
esp_err_t sdmmc_init_mmc_check_ext_csd(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); esp_err_t sdmmc_init_sd_uhs1(sdmmc_card_t* card);
esp_err_t sdmmc_init_sd_driver_strength(sdmmc_card_t *card);
esp_err_t sdmmc_init_sd_current_limit(sdmmc_card_t *card);
esp_err_t sdmmc_init_sd_timing_tuning(sdmmc_card_t *card);
/* Various helper functions */ /* Various helper functions */
static inline bool host_is_spi(const sdmmc_card_t* card) static inline bool host_is_spi(const sdmmc_card_t* card)

View File

@ -97,6 +97,7 @@ esp_err_t sdmmc_card_init(const sdmmc_host_t* config, sdmmc_card_t* card)
/* switch to 1.8V if supported (UHS-I) */ /* 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); bool is_uhs1 = is_sdmem && (card->ocr & SD_OCR_S18_RA) && (card->ocr & SD_OCR_SDHC_CAP);
ESP_LOGV(TAG, "is_uhs1: %d", is_uhs1);
SDMMC_INIT_STEP(is_uhs1, sdmmc_init_sd_uhs1); SDMMC_INIT_STEP(is_uhs1, sdmmc_init_sd_uhs1);
/* Read the contents of CID register*/ /* Read the contents of CID register*/
@ -146,12 +147,21 @@ esp_err_t sdmmc_card_init(const sdmmc_host_t* config, sdmmc_card_t* card)
SDMMC_INIT_STEP(always, sdmmc_init_host_bus_width); SDMMC_INIT_STEP(always, sdmmc_init_host_bus_width);
} }
/* Driver Strength */
SDMMC_INIT_STEP(is_uhs1, sdmmc_init_sd_driver_strength);
/* Current Limit */
SDMMC_INIT_STEP(is_uhs1, sdmmc_init_sd_current_limit);
/* SD card: read SD Status register */ /* SD card: read SD Status register */
SDMMC_INIT_STEP(is_sdmem, sdmmc_init_sd_ssr); SDMMC_INIT_STEP(is_sdmem, sdmmc_init_sd_ssr);
/* Switch to the host to use card->max_freq_khz frequency. */ /* Switch to the host to use card->max_freq_khz frequency. */
SDMMC_INIT_STEP(always, sdmmc_init_host_frequency); SDMMC_INIT_STEP(always, sdmmc_init_host_frequency);
/* Timing tuning */
SDMMC_INIT_STEP(is_uhs1, sdmmc_init_sd_timing_tuning);
/* Sanity check after switching the bus mode and frequency */ /* Sanity check after switching the bus mode and frequency */
SDMMC_INIT_STEP(is_sdmem, sdmmc_check_scr); SDMMC_INIT_STEP(is_sdmem, sdmmc_check_scr);
/* Sanity check after eMMC switch to HS mode */ /* Sanity check after eMMC switch to HS mode */

View File

@ -69,7 +69,7 @@ esp_err_t sdmmc_init_mmc_read_ext_csd(sdmmc_card_t* card)
} }
/* For MMC cards, use speed value from EXT_CSD */ /* For MMC cards, use speed value from EXT_CSD */
card->csd.tr_speed = card->max_freq_khz * 1000; card->csd.tr_speed = card->max_freq_khz * 1000;
ESP_LOGD(TAG, "MMC card type %d, max_freq_khz=%d, is_ddr=%d", card_type, card->max_freq_khz, card->is_ddr); ESP_LOGD(TAG, "MMC card type %d, max_freq_khz=%"PRId32", is_ddr=%d", card_type, card->max_freq_khz, card->is_ddr);
card->max_freq_khz = MIN(card->max_freq_khz, card->host.max_freq_khz); card->max_freq_khz = MIN(card->max_freq_khz, card->host.max_freq_khz);
if (card->host.flags & SDMMC_HOST_FLAG_8BIT) { if (card->host.flags & SDMMC_HOST_FLAG_8BIT) {

View File

@ -16,6 +16,7 @@
*/ */
#include <inttypes.h> #include <inttypes.h>
#include "esp_check.h"
#include "esp_timer.h" #include "esp_timer.h"
#include "esp_cache.h" #include "esp_cache.h"
#include "sdmmc_common.h" #include "sdmmc_common.h"
@ -228,7 +229,7 @@ esp_err_t sdmmc_send_cmd_switch_func(sdmmc_card_t* card,
return ESP_OK; return ESP_OK;
} }
esp_err_t sdmmc_enable_hs_mode(sdmmc_card_t* card) esp_err_t sdmmc_enter_higher_speed_mode(sdmmc_card_t* card)
{ {
/* This will determine if the card supports SWITCH_FUNC command, /* This will determine if the card supports SWITCH_FUNC command,
* and high speed mode. If the cards supports both, this will enable * and high speed mode. If the cards supports both, this will enable
@ -255,14 +256,62 @@ esp_err_t sdmmc_enable_hs_mode(sdmmc_card_t* card)
goto out; goto out;
} }
uint32_t supported_mask = SD_SFUNC_SUPPORTED(response->data, 1); uint32_t supported_mask = SD_SFUNC_SUPPORTED(response->data, 1);
if ((supported_mask & BIT(SD_ACCESS_MODE_SDR25)) == 0) { ESP_LOGV(TAG, "%s: access mode supported_mask: 0x%"PRIx32, __func__, supported_mask);
err = ESP_ERR_NOT_SUPPORTED;
goto out; if (((card->host.flags & SDMMC_HOST_FLAG_DDR) != 0) && (card->is_uhs1 == 1)) {
} //UHS-I DDR50
err = sdmmc_send_cmd_switch_func(card, 1, SD_ACCESS_MODE, SD_ACCESS_MODE_SDR25, response); ESP_LOGV(TAG, "%s: to switch to DDR50", __func__);
if (err != ESP_OK) { if ((supported_mask & BIT(SD_ACCESS_MODE_DDR50)) == 0) {
ESP_LOGD(TAG, "%s: sdmmc_send_cmd_switch_func (2) returned 0x%x", __func__, err); err = ESP_ERR_NOT_SUPPORTED;
goto out; goto out;
}
err = sdmmc_send_cmd_switch_func(card, 1, SD_ACCESS_MODE, SD_ACCESS_MODE_DDR50, response);
if (err != ESP_OK) {
ESP_LOGD(TAG, "%s: sdmmc_send_cmd_switch_func (2) returned 0x%x", __func__, err);
goto out;
}
card->is_ddr = 1;
err = (*card->host.set_bus_ddr_mode)(card->host.slot, true);
if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: failed to switch bus to DDR mode (0x%x)", __func__, err);
return err;
}
} else if (card->host.max_freq_khz == SDMMC_FREQ_SDR104) {
//UHS-I SDR104
ESP_LOGV(TAG, "%s: to switch to SDR104", __func__);
if ((supported_mask & BIT(SD_ACCESS_MODE_SDR104)) == 0) {
err = ESP_ERR_NOT_SUPPORTED;
goto out;
}
err = sdmmc_send_cmd_switch_func(card, 1, SD_ACCESS_MODE, SD_ACCESS_MODE_SDR104, response);
if (err != ESP_OK) {
ESP_LOGD(TAG, "%s: sdmmc_send_cmd_switch_func (2) returned 0x%x", __func__, err);
goto out;
}
} else if (card->host.max_freq_khz == SDMMC_FREQ_SDR50) {
//UHS-I SDR50
ESP_LOGV(TAG, "%s: to switch to SDR50", __func__);
if ((supported_mask & BIT(SD_ACCESS_MODE_SDR50)) == 0) {
err = ESP_ERR_NOT_SUPPORTED;
goto out;
}
err = sdmmc_send_cmd_switch_func(card, 1, SD_ACCESS_MODE, SD_ACCESS_MODE_SDR50, response);
if (err != ESP_OK) {
ESP_LOGD(TAG, "%s: sdmmc_send_cmd_switch_func (2) returned 0x%x", __func__, err);
goto out;
}
} else {
ESP_LOGV(TAG, "%s: to switch to SDR25", __func__);
if ((supported_mask & BIT(SD_ACCESS_MODE_SDR25)) == 0) {
err = ESP_ERR_NOT_SUPPORTED;
goto out;
}
err = sdmmc_send_cmd_switch_func(card, 1, SD_ACCESS_MODE, SD_ACCESS_MODE_SDR25, response);
if (err != ESP_OK) {
ESP_LOGD(TAG, "%s: sdmmc_send_cmd_switch_func (2) returned 0x%x", __func__, err);
goto out;
}
} }
out: out:
@ -270,6 +319,172 @@ out:
return err; return err;
} }
static const uint8_t s_tuning_block_pattern[] = {
0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
};
/**
* Find consecutive successful sampling points.
* e.g. array: {1, 1, 0, 0, 1, 1, 1, 0}
* out_length: 3
* outout_end_index: 6
*/
static void find_max_consecutive_success_points(int *array, size_t size, size_t *out_length, uint32_t *out_end_index)
{
uint32_t max = 0;
uint32_t match_num = 0;
uint32_t i = 0;
uint32_t end = 0;
while (i < size) {
if (array[i] == 1) {
match_num++;
} else {
if (match_num > max) {
max = match_num;
end = i - 1;
}
match_num = 0;
}
i++;
}
*out_length = match_num > max ? match_num : max;
*out_end_index = match_num == size ? size : end;
}
static esp_err_t read_tuning_block(sdmmc_card_t *card)
{
esp_err_t ret = ESP_FAIL;
size_t tuning_block_size = sizeof(s_tuning_block_pattern);
ESP_LOGV(TAG, "tuning_block_size: %zu", tuning_block_size);
uint8_t *databuf = NULL;
databuf = heap_caps_calloc(1, tuning_block_size, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL);
ESP_RETURN_ON_FALSE(databuf, ESP_ERR_NO_MEM, TAG, "no mem for tuning block databuf");
sdmmc_command_t cmd = {
.opcode = MMC_SEND_TUNING_BLOCK,
.flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1,
.blklen = tuning_block_size,
.data = (void *) databuf,
.datalen = 1 * tuning_block_size,
.buflen = tuning_block_size,
};
ret = sdmmc_send_cmd(card, &cmd);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "%s: sdmmc_send_cmd returned 0x%x", __func__, ret);
return ret;
}
uint32_t status = 0;
size_t count = 0;
int64_t yield_delay_us = 100 * 1000; // initially 100ms
int64_t t0 = esp_timer_get_time();
int64_t t1 = 0;
while (!host_is_spi(card) && !(status & MMC_R1_READY_FOR_DATA)) {
t1 = esp_timer_get_time();
if (t1 - t0 > SDMMC_READY_FOR_DATA_TIMEOUT_US) {
ESP_LOGW(TAG, "read sectors dma - timeout");
return ESP_ERR_TIMEOUT;
}
if (t1 - t0 > yield_delay_us) {
yield_delay_us *= 2;
vTaskDelay(1);
}
ret = sdmmc_send_cmd_send_status(card, &status);
if (ret != ESP_OK) {
ESP_LOGW(TAG, "%s: sdmmc_send_cmd_send_status returned 0x%x", __func__, ret);
return ret;
}
if (++count % 16 == 0) {
ESP_LOGV(TAG, "waiting for card to become ready (%d)", count);
}
}
bool success = false;
if (memcmp(s_tuning_block_pattern, databuf, tuning_block_size) == 0) {
success = true;
}
return success ? ESP_OK : ESP_FAIL;
}
esp_err_t sdmmc_do_timing_tuning(sdmmc_card_t *card)
{
esp_err_t ret = ESP_FAIL;
ESP_RETURN_ON_FALSE(!host_is_spi(card), ESP_ERR_NOT_SUPPORTED, TAG, "sdspi not supported timing tuning");
ESP_RETURN_ON_FALSE(card->host.set_input_delay, ESP_ERR_NOT_SUPPORTED, TAG, "input phase delay feature isn't supported");
int results[SDMMC_DELAY_PHASE_AUTO] = {};
int slot = card->host.slot;
for (int i = SDMMC_DELAY_PHASE_0; i < SDMMC_DELAY_PHASE_AUTO; i++) {
ESP_RETURN_ON_ERROR((*card->host.set_input_delay)(slot, i), TAG, "failed to set input delay");
ret = read_tuning_block(card);
if (ret == ESP_OK) {
results[i] += 1;
}
}
for (int i = 0; i < 4; i++) {
ESP_LOGV(TAG, "results[%d]: %d", i, results[i]);
}
size_t consecutive_len = 0;
uint32_t end = 0;
find_max_consecutive_success_points(results, SDMMC_DELAY_PHASE_AUTO, &consecutive_len, &end);
sdmmc_delay_phase_t proper_delay_phase = SDMMC_DELAY_PHASE_AUTO;
if (consecutive_len == 1) {
proper_delay_phase = end;
} else if (consecutive_len <= SDMMC_DELAY_PHASE_AUTO) {
proper_delay_phase = end / 2;
} else {
assert(false && "exceeds max tuning point");
}
ESP_LOGV(TAG, "%s: proper_delay_phase: %d\n", __func__, proper_delay_phase);
if (proper_delay_phase != SDMMC_DELAY_PHASE_AUTO) {
ESP_RETURN_ON_ERROR((*card->host.set_input_delay)(slot, proper_delay_phase), TAG, "failed to set input delay");
}
return ESP_OK;
}
esp_err_t sdmmc_select_driver_strength(sdmmc_card_t *card, sdmmc_driver_strength_t driver_strength)
{
if (card->scr.sd_spec < SCR_SD_SPEC_VER_1_10 ||
((card->csd.card_command_class & SD_CSD_CCC_SWITCH) == 0)) {
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t ret = ESP_FAIL;
sdmmc_switch_func_rsp_t *response = NULL;
response = heap_caps_calloc(1, sizeof(*response), MALLOC_CAP_DMA);
ESP_RETURN_ON_FALSE(response, ESP_ERR_NO_MEM, TAG, "no mem for response buf");
ret = sdmmc_send_cmd_switch_func(card, 1, SD_DRIVER_STRENGTH, driver_strength, response);
ESP_GOTO_ON_ERROR(ret, out, TAG, "%s: sdmmc_send_cmd_switch_func (1) returned 0x%x", __func__, ret);
uint32_t supported_mask = SD_SFUNC_SELECTED(response->data, SD_DRIVER_STRENGTH);
ESP_GOTO_ON_FALSE(supported_mask != 0xf, ESP_ERR_NOT_SUPPORTED, out, TAG, "switch group1 result fail");
ESP_LOGV(TAG, "driver strength: supported_mask: 0x%"PRIx32, supported_mask);
ESP_GOTO_ON_FALSE(supported_mask == driver_strength, ESP_ERR_INVALID_ARG, out, TAG, "fail to switch to type 0x%x", driver_strength);
out:
free(response);
return ret;
}
esp_err_t sdmmc_enable_hs_mode_and_check(sdmmc_card_t* card) esp_err_t sdmmc_enable_hs_mode_and_check(sdmmc_card_t* card)
{ {
/* All cards should support at least default speed */ /* All cards should support at least default speed */
@ -281,10 +496,11 @@ esp_err_t sdmmc_enable_hs_mode_and_check(sdmmc_card_t* card)
} }
/* Try to enabled HS mode */ /* Try to enabled HS mode */
esp_err_t err = sdmmc_enable_hs_mode(card); esp_err_t err = sdmmc_enter_higher_speed_mode(card);
if (err != ESP_OK) { if (err != ESP_OK) {
return err; return err;
} }
/* HS mode has been enabled on the card. /* HS mode has been enabled on the card.
* Read CSD again, it should now indicate that the card supports * Read CSD again, it should now indicate that the card supports
* 50MHz clock. * 50MHz clock.
@ -313,12 +529,9 @@ esp_err_t sdmmc_enable_hs_mode_and_check(sdmmc_card_t* card)
} }
} }
if (card->csd.tr_speed != 50000000) { ESP_LOGD(TAG, "%s: after enabling HS mode, tr_speed=%d", __func__, card->csd.tr_speed);
ESP_LOGW(TAG, "unexpected: after enabling HS mode, tr_speed=%d", card->csd.tr_speed); card->max_freq_khz = MIN(card->host.max_freq_khz, SDMMC_FREQ_SDR104);
return ESP_ERR_NOT_SUPPORTED;
}
card->max_freq_khz = MIN(card->host.max_freq_khz, SDMMC_FREQ_HIGHSPEED);
return ESP_OK; return ESP_OK;
} }
@ -341,10 +554,36 @@ esp_err_t sdmmc_init_sd_uhs1(sdmmc_card_t* card)
esp_err_t err = sdmmc_send_cmd(card, &cmd); esp_err_t err = sdmmc_send_cmd(card, &cmd);
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "%s: send_cmd returned 0x%x", __func__, err); ESP_LOGE(TAG, "%s: send_cmd returned 0x%x", __func__, err);
return err;
} }
return ESP_OK; card->is_uhs1 = 1;
return err;
}
esp_err_t sdmmc_select_current_limit(sdmmc_card_t *card, sdmmc_current_limit_t current_limit)
{
if (card->scr.sd_spec < SCR_SD_SPEC_VER_1_10 ||
((card->csd.card_command_class & SD_CSD_CCC_SWITCH) == 0)) {
return ESP_ERR_NOT_SUPPORTED;
}
esp_err_t ret = ESP_FAIL;
sdmmc_switch_func_rsp_t *response = NULL;
response = heap_caps_calloc(1, sizeof(*response), MALLOC_CAP_DMA);
ESP_RETURN_ON_FALSE(response, ESP_ERR_NO_MEM, TAG, "no mem for response buf");
ret = sdmmc_send_cmd_switch_func(card, 1, SD_CURRENT_LIMIT, current_limit, response);
ESP_GOTO_ON_ERROR(ret, out, TAG, "%s: sdmmc_send_cmd_switch_func (1) returned 0x%x", __func__, ret);
uint32_t supported_mask = SD_SFUNC_SELECTED(response->data, SD_CURRENT_LIMIT);
ESP_GOTO_ON_FALSE(supported_mask != 0xf, ESP_ERR_NOT_SUPPORTED, out, TAG, "switch group4 result fail");
ESP_LOGV(TAG, "current limit: supported_mask: 0x%"PRIx32, supported_mask);
ESP_GOTO_ON_FALSE(supported_mask == current_limit, ESP_ERR_INVALID_ARG, out, TAG, "fail to switch to type 0x%x", current_limit);
out:
free(response);
return ret;
} }
esp_err_t sdmmc_check_scr(sdmmc_card_t* card) esp_err_t sdmmc_check_scr(sdmmc_card_t* card)
@ -415,11 +654,22 @@ esp_err_t sdmmc_decode_csd(sdmmc_response_t response, sdmmc_csd_t* out_csd)
out_csd->capacity *= read_bl_size / out_csd->sector_size; out_csd->capacity *= read_bl_size / out_csd->sector_size;
} }
int speed = SD_CSD_SPEED(response); int speed = SD_CSD_SPEED(response);
if (speed == SD_CSD_SPEED_50_MHZ) { ESP_LOGV(TAG, "%s: speed: 0x%x", __func__, speed);
switch (speed) {
case SD_CSD_SPEED_50_MHZ:
out_csd->tr_speed = 50000000; out_csd->tr_speed = 50000000;
} else { break;
case SD_CSD_SPEED_100_MHZ:
out_csd->tr_speed = 100000000;
break;
case SD_CSD_SPEED_200_MHZ:
out_csd->tr_speed = 200000000;
break;
default:
out_csd->tr_speed = 25000000; out_csd->tr_speed = 25000000;
break;
} }
return ESP_OK; return ESP_OK;
} }

View File

@ -67,6 +67,7 @@
#define SDMMC_INTMASK_HLE BIT(12) #define SDMMC_INTMASK_HLE BIT(12)
#define SDMMC_INTMASK_FRUN BIT(11) #define SDMMC_INTMASK_FRUN BIT(11)
#define SDMMC_INTMASK_HTO BIT(10) #define SDMMC_INTMASK_HTO BIT(10)
#define SDMMC_INTMASK_VOLT_SW SDMMC_INTMASK_HTO
#define SDMMC_INTMASK_DTO BIT(9) #define SDMMC_INTMASK_DTO BIT(9)
#define SDMMC_INTMASK_RTO BIT(8) #define SDMMC_INTMASK_RTO BIT(8)
#define SDMMC_INTMASK_DCRC BIT(7) #define SDMMC_INTMASK_DCRC BIT(7)

View File

@ -1359,6 +1359,10 @@ config SOC_SDMMC_PSRAM_DMA_CAPABLE
bool bool
default y default y
config SOC_SDMMC_UHS_I_SUPPORTED
bool
default y
config SOC_SHA_DMA_MAX_BUFFER_SIZE config SOC_SHA_DMA_MAX_BUFFER_SIZE
int int
default 3968 default 3968
@ -1947,6 +1951,10 @@ config SOC_CLK_MPLL_SUPPORTED
bool bool
default y default y
config SOC_CLK_SDIO_PLL_SUPPORTED
bool
default y
config SOC_CLK_XTAL32K_SUPPORTED config SOC_CLK_XTAL32K_SUPPORTED
bool bool
default y default y

View File

@ -151,6 +151,7 @@ typedef enum {
SOC_MOD_CLK_CPLL, /*!< CPLL is from 40MHz XTAL oscillator frequency multipliers */ SOC_MOD_CLK_CPLL, /*!< CPLL is from 40MHz XTAL oscillator frequency multipliers */
SOC_MOD_CLK_SPLL, /*!< SPLL is from 40MHz XTAL oscillator frequency multipliers, it has a "fixed" frequency of 480MHz */ SOC_MOD_CLK_SPLL, /*!< SPLL is from 40MHz XTAL oscillator frequency multipliers, it has a "fixed" frequency of 480MHz */
SOC_MOD_CLK_MPLL, /*!< MPLL is from 40MHz XTAL oscillator frequency multipliers */ SOC_MOD_CLK_MPLL, /*!< MPLL is from 40MHz XTAL oscillator frequency multipliers */
SOC_MOD_CLK_SDIO_PLL, /*!< SDIO PLL is from 40MHz XTAL oscillator frequency multipliers, it has a "fixed" frequency of 200MHz */
SOC_MOD_CLK_XTAL32K, /*!< XTAL32K_CLK comes from the external 32kHz crystal, passing a clock gating to the peripherals */ SOC_MOD_CLK_XTAL32K, /*!< XTAL32K_CLK comes from the external 32kHz crystal, passing a clock gating to the peripherals */
SOC_MOD_CLK_RC_FAST, /*!< RC_FAST_CLK comes from the internal 20MHz rc oscillator, passing a clock gating to the peripherals */ SOC_MOD_CLK_RC_FAST, /*!< RC_FAST_CLK comes from the internal 20MHz rc oscillator, passing a clock gating to the peripherals */
SOC_MOD_CLK_XTAL, /*!< XTAL_CLK comes from the external 40MHz crystal */ SOC_MOD_CLK_XTAL, /*!< XTAL_CLK comes from the external 40MHz crystal */
@ -706,7 +707,7 @@ typedef enum {
/** /**
* @brief Array initializer for all supported clock sources of SDMMC * @brief Array initializer for all supported clock sources of SDMMC
*/ */
#define SOC_SDMMC_CLKS {SOC_MOD_CLK_PLL_F160M} #define SOC_SDMMC_CLKS {SOC_MOD_CLK_PLL_F160M, SOC_MOD_CLK_SDIO_PLL}
/** /**
* @brief Type of SDMMC clock source * @brief Type of SDMMC clock source
@ -714,7 +715,7 @@ typedef enum {
typedef enum { typedef enum {
SDMMC_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_160M as the default choice */ SDMMC_CLK_SRC_DEFAULT = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_160M as the default choice */
SDMMC_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_160M as the source clock */ SDMMC_CLK_SRC_PLL160M = SOC_MOD_CLK_PLL_F160M, /*!< Select PLL_160M as the source clock */
// SOC_MOD_CLK_SDIO_PLL TODO:IDF-8886 SDMMC_CLK_SRC_SDIO_200M = SOC_MOD_CLK_SDIO_PLL,
} soc_periph_sdmmc_clk_src_t; } soc_periph_sdmmc_clk_src_t;
//////////////////////////////////////////////////Temp Sensor/////////////////////////////////////////////////////////// //////////////////////////////////////////////////Temp Sensor///////////////////////////////////////////////////////////

View File

@ -499,6 +499,7 @@
#define SOC_SDMMC_DELAY_PHASE_NUM 4 #define SOC_SDMMC_DELAY_PHASE_NUM 4
#define SOC_SDMMC_IO_POWER_EXTERNAL 1 ///< SDMMC IO power controlled by external power supply #define SOC_SDMMC_IO_POWER_EXTERNAL 1 ///< SDMMC IO power controlled by external power supply
#define SOC_SDMMC_PSRAM_DMA_CAPABLE 1 ///< SDMMC peripheral can do DMA transfer to/from PSRAM #define SOC_SDMMC_PSRAM_DMA_CAPABLE 1 ///< SDMMC peripheral can do DMA transfer to/from PSRAM
#define SOC_SDMMC_UHS_I_SUPPORTED 1
// TODO: IDF-5353 (Copy from esp32c3, need check) // TODO: IDF-5353 (Copy from esp32c3, need check)
/*--------------------------- SHA CAPS ---------------------------------------*/ /*--------------------------- SHA CAPS ---------------------------------------*/
@ -732,6 +733,7 @@
#define SOC_CLK_APLL_SUPPORTED (1) /*!< Support Audio PLL */ #define SOC_CLK_APLL_SUPPORTED (1) /*!< Support Audio PLL */
#define SOC_CLK_MPLL_SUPPORTED (1) /*!< Support MSPI PLL */ #define SOC_CLK_MPLL_SUPPORTED (1) /*!< Support MSPI PLL */
#define SOC_CLK_SDIO_PLL_SUPPORTED (1) /*!< Support SDIO PLL */
#define SOC_CLK_XTAL32K_SUPPORTED (1) /*!< Support to connect an external low frequency crystal */ #define SOC_CLK_XTAL32K_SUPPORTED (1) /*!< Support to connect an external low frequency crystal */
#define SOC_CLK_RC32K_SUPPORTED (1) /*!< Support an internal 32kHz RC oscillator */ #define SOC_CLK_RC32K_SUPPORTED (1) /*!< Support an internal 32kHz RC oscillator */

View File

@ -914,7 +914,7 @@ typedef union {
typedef union { typedef union {
struct { struct {
/** volt: R/W; bitpos: [1:0]; default: 0; /** volt: R/W; bitpos: [1:0]; default: 0;
* Voltage mode selection, 1 bit for each card. * Voltage mode selection, 1 bit for each card. On the ESP32-P4, this bit doesn't do anything, I/O voltage is controlled using LDO API instead.
* 0: 3.3V mode. * 0: 3.3V mode.
* 1: 1.8V mode. * 1: 1.8V mode.
*/ */

View File

@ -66,6 +66,7 @@
#define SDMMC_INTMASK_HLE BIT(12) #define SDMMC_INTMASK_HLE BIT(12)
#define SDMMC_INTMASK_FRUN BIT(11) #define SDMMC_INTMASK_FRUN BIT(11)
#define SDMMC_INTMASK_HTO BIT(10) #define SDMMC_INTMASK_HTO BIT(10)
#define SDMMC_INTMASK_VOLT_SW SDMMC_INTMASK_HTO
#define SDMMC_INTMASK_DTO BIT(9) #define SDMMC_INTMASK_DTO BIT(9)
#define SDMMC_INTMASK_RTO BIT(8) #define SDMMC_INTMASK_RTO BIT(8)
#define SDMMC_INTMASK_DCRC BIT(7) #define SDMMC_INTMASK_DCRC BIT(7)