Merge branch 'change/sdmmc_ll_layer' into 'master'

sdmmc: full ll layer

Closes IDF-10544 and IDF-10251

See merge request espressif/esp-idf!33156
This commit is contained in:
Armando (Dou Yiwen) 2024-09-04 10:54:37 +08:00
commit 85bc5acfc7
8 changed files with 1038 additions and 140 deletions

View File

@ -13,7 +13,6 @@
#include "esp_timer.h" #include "esp_timer.h"
#include "esp_check.h" #include "esp_check.h"
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "soc/soc_pins.h"
#include "soc/gpio_periph.h" #include "soc/gpio_periph.h"
#include "esp_rom_gpio.h" #include "esp_rom_gpio.h"
#include "esp_rom_sys.h" #include "esp_rom_sys.h"
@ -28,6 +27,7 @@
#include "soc/soc_caps.h" #include "soc/soc_caps.h"
#include "hal/gpio_hal.h" #include "hal/gpio_hal.h"
#include "hal/sdmmc_hal.h" #include "hal/sdmmc_hal.h"
#include "hal/sd_types.h"
#include "hal/sdmmc_ll.h" #include "hal/sdmmc_ll.h"
#define SDMMC_EVENT_QUEUE_LENGTH 32 #define SDMMC_EVENT_QUEUE_LENGTH 32
@ -96,25 +96,35 @@ static host_ctx_t s_host_ctx = {0};
#endif #endif
static void sdmmc_isr(void *arg); static void sdmmc_isr(void *arg);
static void sdmmc_host_dma_init(void);
static esp_err_t sdmmc_host_pullup_en_internal(int slot, int width); static esp_err_t sdmmc_host_pullup_en_internal(int slot, int width);
static bool sdmmc_host_slot_initialized(int slot); static bool sdmmc_host_slot_initialized(int slot);
#if SOC_SDMMC_NUM_SLOTS >= 2 #if SOC_SDMMC_NUM_SLOTS >= 2
static void sdmmc_host_change_to_slot(int slot); static void sdmmc_host_change_to_slot(int slot);
#endif #endif
static void s_module_reset(void)
{
// reset module
sdmmc_ll_reset_controller(s_host_ctx.hal.dev);
sdmmc_ll_reset_dma(s_host_ctx.hal.dev);
sdmmc_ll_reset_fifo(s_host_ctx.hal.dev);
}
static bool s_is_module_reset_done(void)
{
bool is_done = sdmmc_ll_is_controller_reset_done(s_host_ctx.hal.dev) && sdmmc_ll_is_dma_reset_done(s_host_ctx.hal.dev) && sdmmc_ll_is_fifo_reset_done(s_host_ctx.hal.dev);
return is_done;
}
esp_err_t sdmmc_host_reset(void) esp_err_t sdmmc_host_reset(void)
{ {
// Set reset bits s_module_reset();
SDMMC.ctrl.controller_reset = 1;
SDMMC.ctrl.dma_reset = 1;
SDMMC.ctrl.fifo_reset = 1;
// Wait for the reset bits to be cleared by hardware // Wait for the reset bits to be cleared by hardware
int64_t yield_delay_us = 100 * 1000; // initially 100ms int64_t yield_delay_us = 100 * 1000; // initially 100ms
int64_t t0 = esp_timer_get_time(); int64_t t0 = esp_timer_get_time();
int64_t t1 = 0; int64_t t1 = 0;
while (SDMMC.ctrl.controller_reset || SDMMC.ctrl.fifo_reset || SDMMC.ctrl.dma_reset) { while (!s_is_module_reset_done()) {
t1 = esp_timer_get_time(); t1 = esp_timer_get_time();
if (t1 - t0 > SDMMC_HOST_RESET_TIMEOUT_US) { if (t1 - t0 > SDMMC_HOST_RESET_TIMEOUT_US) {
return ESP_ERR_TIMEOUT; return ESP_ERR_TIMEOUT;
@ -187,14 +197,14 @@ static esp_err_t sdmmc_host_clock_update_command(int slot)
} }
// Sending clock update command to the CIU can generate HLE error. // Sending clock update command to the CIU can generate HLE error.
// According to the manual, this is okay and we must retry the command. // According to the manual, this is okay and we must retry the command.
if (SDMMC.rintsts.hle) { if (sdmmc_ll_get_interrupt_raw(s_host_ctx.hal.dev) & SDMMC_LL_EVENT_HLE) {
SDMMC.rintsts.hle = 1; sdmmc_ll_clear_interrupt(s_host_ctx.hal.dev, SDMMC_LL_EVENT_HLE);
repeat = true; repeat = true;
break; break;
} }
// When the command is accepted by CIU, start_command bit will be // When the command is accepted by CIU, start_command bit will be
// cleared in SDMMC.cmd register. // cleared in SDMMC.cmd register.
if (SDMMC.cmd.start_command == 0) { if (sdmmc_ll_is_command_taken(s_host_ctx.hal.dev)) {
repeat = false; repeat = false;
break; break;
} }
@ -413,7 +423,7 @@ esp_err_t sdmmc_host_start_command(int slot, sdmmc_hw_cmd_t cmd, uint32_t arg)
int64_t yield_delay_us = 100 * 1000; // initially 100ms int64_t yield_delay_us = 100 * 1000; // initially 100ms
int64_t t0 = esp_timer_get_time(); int64_t t0 = esp_timer_get_time();
int64_t t1 = 0; int64_t t1 = 0;
while (SDMMC.cmd.start_command == 1) { while (!sdmmc_ll_is_command_taken(s_host_ctx.hal.dev)) {
t1 = esp_timer_get_time(); t1 = esp_timer_get_time();
if (t1 - t0 > SDMMC_HOST_START_CMD_TIMEOUT_US) { if (t1 - t0 > SDMMC_HOST_START_CMD_TIMEOUT_US) {
return ESP_ERR_TIMEOUT; return ESP_ERR_TIMEOUT;
@ -423,10 +433,10 @@ esp_err_t sdmmc_host_start_command(int slot, sdmmc_hw_cmd_t cmd, uint32_t arg)
vTaskDelay(1); vTaskDelay(1);
} }
} }
SDMMC.cmdarg = arg; sdmmc_ll_set_command_arg(s_host_ctx.hal.dev, arg);
cmd.card_num = slot; cmd.card_num = slot;
cmd.start_command = 1; cmd.start_command = 1;
SDMMC.cmd = cmd; sdmmc_ll_set_command(s_host_ctx.hal.dev, cmd);
return ESP_OK; return ESP_OK;
} }
@ -440,7 +450,7 @@ static void sdmmc_host_intmask_clear_disable(void)
static void sdmmc_host_intmask_set_enable(void) static void sdmmc_host_intmask_set_enable(void)
{ {
sdmmc_ll_enable_interrupt(s_host_ctx.hal.dev, 0xffffffff, false); sdmmc_ll_enable_interrupt(s_host_ctx.hal.dev, 0xffffffff, false);
sdmmc_ll_enable_interrupt(s_host_ctx.hal.dev, SDMMC_LL_INTMASK_DEFAULT, true); sdmmc_ll_enable_interrupt(s_host_ctx.hal.dev, SDMMC_LL_EVENT_DEFAULT, true);
sdmmc_ll_enable_global_interrupt(s_host_ctx.hal.dev, true); sdmmc_ll_enable_global_interrupt(s_host_ctx.hal.dev, true);
} }
@ -470,7 +480,7 @@ esp_err_t sdmmc_host_init(void)
return err; return err;
} }
ESP_LOGD(TAG, "peripheral version %"PRIx32", hardware config %08"PRIx32, SDMMC.verid, SDMMC.hcon.val); ESP_LOGD(TAG, "peripheral version %"PRIx32", hardware config %08"PRIx32, sdmmc_ll_get_version_id(s_host_ctx.hal.dev), sdmmc_ll_get_hw_config_info(s_host_ctx.hal.dev));
// Clear interrupt status and set interrupt mask to known state // Clear interrupt status and set interrupt mask to known state
sdmmc_host_intmask_clear_disable(); sdmmc_host_intmask_clear_disable();
@ -499,10 +509,10 @@ esp_err_t sdmmc_host_init(void)
sdmmc_host_intmask_set_enable(); sdmmc_host_intmask_set_enable();
// Disable generation of Busy Clear Interrupt // Disable generation of Busy Clear Interrupt
SDMMC.cardthrctl.busy_clr_int_en = 0; sdmmc_ll_enable_busy_clear_interrupt(s_host_ctx.hal.dev, false);
// Enable DMA // Init DMA
sdmmc_host_dma_init(); sdmmc_ll_init_dma(s_host_ctx.hal.dev);
// Initialize transaction handler // Initialize transaction handler
ret = sdmmc_host_transaction_handler_init(); ret = sdmmc_host_transaction_handler_init();
@ -880,17 +890,14 @@ esp_err_t sdmmc_host_set_bus_width(int slot, size_t width)
if (sdmmc_slot_info[slot].width < width) { if (sdmmc_slot_info[slot].width < width) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
const uint16_t mask = BIT(slot);
if (width == 1) { if (width == 1) {
SDMMC.ctype.card_width_8 &= ~mask; sdmmc_ll_set_card_width(s_host_ctx.hal.dev, slot, SD_BUS_WIDTH_1_BIT);
SDMMC.ctype.card_width &= ~mask;
} else if (width == 4) { } else if (width == 4) {
SDMMC.ctype.card_width_8 &= ~mask; sdmmc_ll_set_card_width(s_host_ctx.hal.dev, slot, SD_BUS_WIDTH_4_BIT);
SDMMC.ctype.card_width |= mask;
// 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.ctype.card_width_8 |= mask; 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 {
@ -935,22 +942,9 @@ esp_err_t sdmmc_host_set_cclk_always_on(int slot, bool cclk_always_on)
return ESP_OK; return ESP_OK;
} }
static void sdmmc_host_dma_init(void)
{
SDMMC.ctrl.dma_enable = 1;
SDMMC.bmod.val = 0;
SDMMC.bmod.sw_reset = 1;
SDMMC.idinten.ni = 1;
SDMMC.idinten.ri = 1;
SDMMC.idinten.ti = 1;
}
void sdmmc_host_dma_stop(void) void sdmmc_host_dma_stop(void)
{ {
SDMMC.ctrl.use_internal_dma = 0; sdmmc_ll_stop_dma(s_host_ctx.hal.dev);
SDMMC.ctrl.dma_reset = 1;
SDMMC.bmod.fb = 0;
SDMMC.bmod.enable = 0;
} }
void sdmmc_host_dma_prepare(sdmmc_desc_t *desc, size_t block_size, size_t data_size) void sdmmc_host_dma_prepare(sdmmc_desc_t *desc, size_t block_size, size_t data_size)
@ -972,7 +966,7 @@ void sdmmc_host_dma_resume(void)
bool sdmmc_host_card_busy(void) bool sdmmc_host_card_busy(void)
{ {
return SDMMC.status.data_busy == 1; return sdmmc_ll_is_card_data_busy(s_host_ctx.hal.dev);
} }
esp_err_t sdmmc_host_io_int_enable(int slot) esp_err_t sdmmc_host_io_int_enable(int slot)
@ -1044,12 +1038,12 @@ static void sdmmc_isr(void *arg)
sdmmc_event_t event; sdmmc_event_t event;
int higher_priority_task_awoken = pdFALSE; int higher_priority_task_awoken = pdFALSE;
uint32_t pending = sdmmc_ll_get_intr_status(s_host_ctx.hal.dev) & 0xFFFF; uint32_t pending = sdmmc_ll_get_intr_status(s_host_ctx.hal.dev) & SDMMC_LL_SD_EVENT_MASK;
SDMMC.rintsts.val = pending; sdmmc_ll_clear_interrupt(s_host_ctx.hal.dev, pending);
event.sdmmc_status = pending; event.sdmmc_status = pending;
uint32_t dma_pending = SDMMC.idsts.val; uint32_t dma_pending = sdmmc_ll_get_idsts_interrupt_raw(s_host_ctx.hal.dev);
SDMMC.idsts.val = dma_pending; sdmmc_ll_clear_idsts_interrupt(s_host_ctx.hal.dev, dma_pending);
event.dma_status = dma_pending & 0x1f; event.dma_status = dma_pending & 0x1f;
if (pending != 0 || dma_pending != 0) { if (pending != 0 || dma_pending != 0) {

View File

@ -6,3 +6,8 @@ set(COMPONENTS main)
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(sdmmc_test_console) project(sdmmc_test_console)
message(STATUS "Checking sdmmc registers are not read-write by half-word")
include($ENV{IDF_PATH}/tools/ci/check_register_rw_half_word.cmake)
check_register_rw_half_word(SOC_MODULES "sdmmc" "pcr" "hp_sys_clkrst"
HAL_MODULES "sdmmc")

View File

@ -14,8 +14,11 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h>
#include "esp_bit_defs.h" #include "esp_bit_defs.h"
#include "hal/assert.h" #include "hal/assert.h"
#include "hal/misc.h"
#include "hal/sd_types.h"
#include "soc/clk_tree_defs.h" #include "soc/clk_tree_defs.h"
#include "soc/sdmmc_struct.h" #include "soc/sdmmc_struct.h"
#include "soc/sdmmc_reg.h" #include "soc/sdmmc_reg.h"
@ -27,21 +30,49 @@ extern "C" {
#define SDMMC_LL_GET_HW(id) (((id) == 0) ? (&SDMMC) : NULL) #define SDMMC_LL_GET_HW(id) (((id) == 0) ? (&SDMMC) : NULL)
#define SDMMC_LL_EVENT_IO_SLOT1 (1<<17)
#define SDMMC_LL_EVENT_IO_SLOT0 (1<<16)
#define SDMMC_LL_EVENT_EBE (1<<15)
#define SDMMC_LL_EVENT_ACD (1<<14)
#define SDMMC_LL_EVENT_SBE (1<<13)
#define SDMMC_LL_EVENT_BCI (1<<13)
#define SDMMC_LL_EVENT_HLE (1<<12)
#define SDMMC_LL_EVENT_FRUN (1<<11)
#define SDMMC_LL_EVENT_HTO (1<<10)
#define SDMMC_LL_EVENT_DTO (1<<9)
#define SDMMC_LL_EVENT_RTO (1<<8)
#define SDMMC_LL_EVENT_DCRC (1<<7)
#define SDMMC_LL_EVENT_RCRC (1<<6)
#define SDMMC_LL_EVENT_RXDR (1<<5)
#define SDMMC_LL_EVENT_TXDR (1<<4)
#define SDMMC_LL_EVENT_DATA_OVER (1<<3)
#define SDMMC_LL_EVENT_CMD_DONE (1<<2)
#define SDMMC_LL_EVENT_RESP_ERR (1<<1)
#define SDMMC_LL_EVENT_CD (1<<0)
/* Default disabled interrupts (on init): /* Default disabled interrupts (on init):
* SDMMC_INTMASK_RXDR, * SDMMC_LL_EVENT_RXDR,
* SDMMC_INTMASK_TXDR, * SDMMC_LL_EVENT_TXDR,
* SDMMC_INTMASK_BCI, * SDMMC_LL_EVENT_BCI,
* SDMMC_INTMASK_ACD, * SDMMC_LL_EVENT_ACD,
* SDMMC_INTMASK_IO_SLOT1, * SDMMC_LL_EVENT_IO_SLOT1,
* SDMMC_INTMASK_IO_SLOT0 * SDMMC_LL_EVENT_IO_SLOT0
*/ */
// Default enabled interrupts (sdio is enabled only when use): // Default enabled interrupts (sdio is enabled only when use):
#define SDMMC_LL_INTMASK_DEFAULT \ #define SDMMC_LL_EVENT_DEFAULT \
(SDMMC_INTMASK_CD | SDMMC_INTMASK_RESP_ERR | SDMMC_INTMASK_CMD_DONE | SDMMC_INTMASK_DATA_OVER | \ (SDMMC_LL_EVENT_CD | SDMMC_LL_EVENT_RESP_ERR | SDMMC_LL_EVENT_CMD_DONE | SDMMC_LL_EVENT_DATA_OVER | \
SDMMC_INTMASK_RCRC | SDMMC_INTMASK_DCRC | SDMMC_INTMASK_RTO | SDMMC_INTMASK_DTO | SDMMC_INTMASK_HTO | \ SDMMC_LL_EVENT_RCRC | SDMMC_LL_EVENT_DCRC | SDMMC_LL_EVENT_RTO | SDMMC_LL_EVENT_DTO | SDMMC_LL_EVENT_HTO | \
SDMMC_INTMASK_HLE | \ SDMMC_LL_EVENT_HLE | \
SDMMC_INTMASK_SBE | \ SDMMC_LL_EVENT_SBE | \
SDMMC_INTMASK_EBE) SDMMC_LL_EVENT_EBE)
#define SDMMC_LL_SD_EVENT_MASK \
(SDMMC_LL_EVENT_CD | SDMMC_LL_EVENT_RESP_ERR | SDMMC_LL_EVENT_CMD_DONE | SDMMC_LL_EVENT_DATA_OVER | \
SDMMC_LL_EVENT_TXDR | SDMMC_LL_EVENT_RXDR |\
SDMMC_LL_EVENT_RCRC | SDMMC_LL_EVENT_DCRC | SDMMC_LL_EVENT_RTO | SDMMC_LL_EVENT_DTO | SDMMC_LL_EVENT_HTO | \
SDMMC_LL_EVENT_FRUN | SDMMC_LL_EVENT_HLE |\
SDMMC_LL_EVENT_SBE | SDMMC_LL_EVENT_ACD |\
SDMMC_LL_EVENT_EBE)
/** /**
* SDMMC capabilities * SDMMC capabilities
@ -59,6 +90,9 @@ typedef enum {
} sdmmc_ll_delay_phase_t; } sdmmc_ll_delay_phase_t;
/*---------------------------------------------------------------
Clock & Reset
---------------------------------------------------------------*/
/** /**
* @brief Enable the bus clock for SDMMC module * @brief Enable the bus clock for SDMMC module
* *
@ -174,11 +208,13 @@ static inline void sdmmc_ll_init_phase_delay(sdmmc_dev_t *hw)
*/ */
static inline void sdmmc_ll_enable_card_clock(sdmmc_dev_t *hw, uint32_t slot, bool en) static inline void sdmmc_ll_enable_card_clock(sdmmc_dev_t *hw, uint32_t slot, bool en)
{ {
uint32_t reg_val = HAL_FORCE_READ_U32_REG_FIELD(hw->clkena, cclk_enable);
if (en) { if (en) {
hw->clkena.cclk_enable |= BIT(slot); reg_val |= BIT(slot);
} else { } else {
hw->clkena.cclk_enable &= ~BIT(slot); reg_val &= ~BIT(slot);
} }
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkena, cclk_enable, reg_val);
} }
/** /**
@ -192,10 +228,10 @@ static inline void sdmmc_ll_set_card_clock_div(sdmmc_dev_t *hw, uint32_t slot, u
{ {
if (slot == 0) { if (slot == 0) {
hw->clksrc.card0 = 0; hw->clksrc.card0 = 0;
hw->clkdiv.div0 = card_div; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkdiv, div0, card_div);
} else if (slot == 1) { } else if (slot == 1) {
hw->clksrc.card1 = 1; hw->clksrc.card1 = 1;
hw->clkdiv.div1 = card_div; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkdiv, div1, card_div);
} else { } else {
HAL_ASSERT(false); HAL_ASSERT(false);
} }
@ -215,10 +251,10 @@ static inline uint32_t sdmmc_ll_get_card_clock_div(sdmmc_dev_t *hw, uint32_t slo
if (slot == 0) { if (slot == 0) {
HAL_ASSERT(hw->clksrc.card0 == 0); HAL_ASSERT(hw->clksrc.card0 == 0);
card_div = hw->clkdiv.div0; card_div = HAL_FORCE_READ_U32_REG_FIELD(hw->clkdiv, div0);
} else if (slot == 1) { } else if (slot == 1) {
HAL_ASSERT(hw->clksrc.card1 == 1); HAL_ASSERT(hw->clksrc.card1 == 1);
card_div = hw->clkdiv.div1; card_div = HAL_FORCE_READ_U32_REG_FIELD(hw->clkdiv, div1);
} else { } else {
HAL_ASSERT(false); HAL_ASSERT(false);
} }
@ -235,13 +271,90 @@ static inline uint32_t sdmmc_ll_get_card_clock_div(sdmmc_dev_t *hw, uint32_t slo
*/ */
static inline void sdmmc_ll_enable_card_clock_low_power(sdmmc_dev_t *hw, uint32_t slot, bool en) static inline void sdmmc_ll_enable_card_clock_low_power(sdmmc_dev_t *hw, uint32_t slot, bool en)
{ {
uint32_t reg_val = HAL_FORCE_READ_U32_REG_FIELD(hw->clkena, cclk_low_power);
if (en) { if (en) {
hw->clkena.cclk_low_power |= BIT(slot); reg_val |= BIT(slot);
} else { } else {
hw->clkena.cclk_low_power &= ~BIT(slot); reg_val &= ~BIT(slot);
} }
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkena, cclk_low_power, reg_val);
} }
/**
* @brief Reset controller
*
* @note Self clear after two AHB clock cycles, needs wait done
*
* @param hw hardware instance address
*/
static inline void sdmmc_ll_reset_controller(sdmmc_dev_t *hw)
{
hw->ctrl.controller_reset = 1;
}
/**
* @brief Get if controller reset is done
*
* @param hw hardware instance address
*
* @return true: done; false: not done
*/
static inline bool sdmmc_ll_is_controller_reset_done(sdmmc_dev_t *hw)
{
return hw->ctrl.controller_reset == 0;
}
/**
* @brief Reset DMA
*
* @note Self clear after two AHB clock cycles, needs wait done
*
* @param hw hardware instance address
*/
static inline void sdmmc_ll_reset_dma(sdmmc_dev_t *hw)
{
hw->ctrl.dma_reset = 1;
}
/**
* @brief Get if dma reset is done
*
* @param hw hardware instance address
*
* @return true: done; false: not done
*/
static inline bool sdmmc_ll_is_dma_reset_done(sdmmc_dev_t *hw)
{
return hw->ctrl.dma_reset == 0;
}
/**
* @brief Reset fifo
*
* @note Self clear after reset done, needs wait done
*
* @param hw hardware instance address
*/
static inline void sdmmc_ll_reset_fifo(sdmmc_dev_t *hw)
{
hw->ctrl.fifo_reset = 1;
}
/**
* @brief Get if fifo reset is done
*
* @param hw hardware instance address
*
* @return true: done; false: not done
*/
static inline bool sdmmc_ll_is_fifo_reset_done(sdmmc_dev_t *hw)
{
return hw->ctrl.fifo_reset == 0;
}
/*---------------------------------------------------------------
MISC
---------------------------------------------------------------*/
/** /**
* @brief Set card data read timeout cycles * @brief Set card data read timeout cycles
* *
@ -265,7 +378,7 @@ static inline void sdmmc_ll_set_data_timeout(sdmmc_dev_t *hw, uint32_t timeout_c
*/ */
static inline void sdmmc_ll_set_response_timeout(sdmmc_dev_t *hw, uint32_t timeout_cycles) static inline void sdmmc_ll_set_response_timeout(sdmmc_dev_t *hw, uint32_t timeout_cycles)
{ {
hw->tmout.response = timeout_cycles; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tmout, response, timeout_cycles);
} }
/** /**
@ -304,11 +417,14 @@ static inline bool sdmmc_ll_is_card_write_protected(sdmmc_dev_t *hw, uint32_t sl
*/ */
static inline void sdmmc_ll_enable_ddr_mode(sdmmc_dev_t *hw, uint32_t slot, bool en) static inline void sdmmc_ll_enable_ddr_mode(sdmmc_dev_t *hw, uint32_t slot, bool en)
{ {
uint32_t ddr_reg_val = HAL_FORCE_READ_U32_REG_FIELD(hw->uhs, ddr);
if (en) { if (en) {
hw->uhs.ddr |= BIT(slot); ddr_reg_val|= BIT(slot);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->uhs, ddr, ddr_reg_val);
hw->emmc_ddr_reg |= BIT(slot); hw->emmc_ddr_reg |= BIT(slot);
} else { } else {
hw->uhs.ddr &= ~BIT(slot); ddr_reg_val&= ~BIT(slot);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->uhs, ddr, ddr_reg_val);
hw->emmc_ddr_reg &= ~BIT(slot); hw->emmc_ddr_reg &= ~BIT(slot);
} }
} }
@ -332,7 +448,7 @@ static inline void sdmmc_ll_set_data_transfer_len(sdmmc_dev_t *hw, uint32_t len)
*/ */
static inline void sdmmc_ll_set_block_size(sdmmc_dev_t *hw, uint32_t block_size) static inline void sdmmc_ll_set_block_size(sdmmc_dev_t *hw, uint32_t block_size)
{ {
hw->blksiz = block_size; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->blksiz, block_size, block_size);
} }
/** /**
@ -346,11 +462,143 @@ static inline void sdmmc_ll_set_desc_addr(sdmmc_dev_t *hw, uint32_t desc_addr)
hw->dbaddr = (sdmmc_desc_t *)desc_addr; hw->dbaddr = (sdmmc_desc_t *)desc_addr;
} }
/**
* @brief Poll demand
*
* @param hw hardware instance address
*/
static inline void sdmmc_ll_poll_demand(sdmmc_dev_t *hw)
{
hw->pldmnd = 1;
}
/**
* @brief Set command
*
* @param hw hardware instance address
*/
static inline void sdmmc_ll_set_command(sdmmc_dev_t *hw, sdmmc_hw_cmd_t cmd)
{
memcpy((void *)&hw->cmd, &cmd, sizeof(sdmmc_hw_cmd_t));
}
/**
* @brief Get if command is taken by CIU
*
* @param hw hardware instance address
*
* @return 1: is taken; 0: not taken, should not write to any command regs
*/
static inline bool sdmmc_ll_is_command_taken(sdmmc_dev_t *hw)
{
return hw->cmd.start_command == 0;
}
/**
* @brief Set command argument
*
* @param hw hardware instance address
* @param arg value indicates command argument to be passed to card
*/
static inline void sdmmc_ll_set_command_arg(sdmmc_dev_t *hw, uint32_t arg)
{
hw->cmdarg = arg;
}
/**
* @brief Get version ID
*
* @param hw hardware instance address
*
* @return version ID
*/
static inline uint32_t sdmmc_ll_get_version_id(sdmmc_dev_t *hw)
{
return hw->verid;
}
/**
* @brief Get hardware configuration info
*
* @param hw hardware instance address
*
* @return hardware configurations
*/
static inline uint32_t sdmmc_ll_get_hw_config_info(sdmmc_dev_t *hw)
{
return hw->hcon.val;
}
/**
* @brief Set card width
*
* @param hw hardware instance address
* @param slot slot ID
* @param width card width
*/
static inline void sdmmc_ll_set_card_width(sdmmc_dev_t *hw, uint32_t slot, sd_bus_width_t width)
{
uint16_t mask = 1 << slot;
uint32_t reg_val = HAL_FORCE_READ_U32_REG_FIELD(hw->ctype, card_width);
uint32_t reg_val_8 = HAL_FORCE_READ_U32_REG_FIELD(hw->ctype, card_width_8);
switch (width) {
case SD_BUS_WIDTH_1_BIT:
reg_val_8 &= ~mask;
reg_val &= ~mask;
break;
case SD_BUS_WIDTH_4_BIT:
reg_val_8 &= ~mask;
reg_val |= mask;
break;
case SD_BUS_WIDTH_8_BIT:
reg_val_8 |= mask;
break;
default:
HAL_ASSERT(false);
}
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->ctype, card_width, reg_val);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->ctype, card_width_8, reg_val_8);
}
/**
* @brief Is card data busy
*
* @param hw hardware instance address
*
* @return 1: busy; 0: idle
*/
static inline bool sdmmc_ll_is_card_data_busy(sdmmc_dev_t *hw)
{
return hw->status.data_busy == 1;
}
/*---------------------------------------------------------------
DMA
---------------------------------------------------------------*/
/**
* @brief Init DMA
* - enable dma
* - clear bus mode reg and reset all dmac internal regs
* - enable internal dmac interrupt
*
* @param hw hardware instance address
*/
static inline void sdmmc_ll_init_dma(sdmmc_dev_t *hw)
{
hw->ctrl.dma_enable = 1;
hw->bmod.val = 0;
hw->bmod.sw_reset = 1;
hw->idinten.ni = 1;
hw->idinten.ri = 1;
hw->idinten.ti = 1;
}
/** /**
* @brief Enable DMA * @brief Enable DMA
* *
* @param hw hardware instance address * @param hw hardware instance address
* @param slot slot
* @param en enable / disable * @param en enable / disable
*/ */
static inline void sdmmc_ll_enable_dma(sdmmc_dev_t *hw, bool en) static inline void sdmmc_ll_enable_dma(sdmmc_dev_t *hw, bool en)
@ -362,17 +610,23 @@ static inline void sdmmc_ll_enable_dma(sdmmc_dev_t *hw, bool en)
} }
/** /**
* @brief Poll demand * @brief Stop DMA
* *
* @param hw hardware instance address * @param hw hardware instance address
*/ */
static inline void sdmmc_ll_poll_demand(sdmmc_dev_t *hw) static inline void sdmmc_ll_stop_dma(sdmmc_dev_t *hw)
{ {
hw->pldmnd = 1; hw->ctrl.use_internal_dma = 0;
hw->ctrl.dma_reset = 1; //here might be an issue as we don't wait the `dma_reset` to be self-cleared, check in next steps
hw->bmod.fb = 0;
hw->bmod.enable = 0;
} }
/*---------------------------------------------------------------
INTR
---------------------------------------------------------------*/
/** /**
* @brief Get interrupt status * @brief Get masked interrupt-status register value
* *
* @param hw hardware instance address * @param hw hardware instance address
*/ */
@ -397,6 +651,14 @@ static inline void sdmmc_ll_enable_interrupt(sdmmc_dev_t *hw, uint32_t mask, boo
} }
} }
/**
* @brief Get RAW interrupt-status register value
*/
static inline uint32_t sdmmc_ll_get_interrupt_raw(sdmmc_dev_t *hw)
{
return hw->rintsts.val;
}
/** /**
* @brief Clear interrupt * @brief Clear interrupt
* *
@ -419,6 +681,36 @@ static inline void sdmmc_ll_enable_global_interrupt(sdmmc_dev_t *hw, bool en)
hw->ctrl.int_enable = (uint32_t)en; hw->ctrl.int_enable = (uint32_t)en;
} }
/**
* @brief Enable / disable busy clear interrupt
*
* @param hw hardware instance address
* @param en enable / disable
*/
static inline void sdmmc_ll_enable_busy_clear_interrupt(sdmmc_dev_t *hw, bool en)
{
hw->cardthrctl.busy_clr_int_en = en;
}
/**
* @brief Get internal dmac status register val
*/
static inline uint32_t sdmmc_ll_get_idsts_interrupt_raw(sdmmc_dev_t *hw)
{
return hw->idsts.val;
}
/**
* @brief Clear internal dmac status register events
*
* @param hw hardware instance address
* @param mask interrupt mask
*/
static inline void sdmmc_ll_clear_idsts_interrupt(sdmmc_dev_t *hw, uint32_t mask)
{
hw->idsts.val = mask;
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -14,8 +14,11 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h>
#include "esp_bit_defs.h" #include "esp_bit_defs.h"
#include "hal/assert.h" #include "hal/assert.h"
#include "hal/misc.h"
#include "hal/sd_types.h"
#include "soc/clk_tree_defs.h" #include "soc/clk_tree_defs.h"
#include "soc/sdmmc_struct.h" #include "soc/sdmmc_struct.h"
#include "soc/sdmmc_reg.h" #include "soc/sdmmc_reg.h"
@ -29,21 +32,49 @@ extern "C" {
#define SDMMC_LL_GET_HW(id) (((id) == 0) ? (&SDMMC) : NULL) #define SDMMC_LL_GET_HW(id) (((id) == 0) ? (&SDMMC) : NULL)
#define SDMMC_LL_EVENT_IO_SLOT1 (1<<17)
#define SDMMC_LL_EVENT_IO_SLOT0 (1<<16)
#define SDMMC_LL_EVENT_EBE (1<<15)
#define SDMMC_LL_EVENT_ACD (1<<14)
#define SDMMC_LL_EVENT_SBE (1<<13)
#define SDMMC_LL_EVENT_BCI (1<<13)
#define SDMMC_LL_EVENT_HLE (1<<12)
#define SDMMC_LL_EVENT_FRUN (1<<11)
#define SDMMC_LL_EVENT_HTO (1<<10)
#define SDMMC_LL_EVENT_DTO (1<<9)
#define SDMMC_LL_EVENT_RTO (1<<8)
#define SDMMC_LL_EVENT_DCRC (1<<7)
#define SDMMC_LL_EVENT_RCRC (1<<6)
#define SDMMC_LL_EVENT_RXDR (1<<5)
#define SDMMC_LL_EVENT_TXDR (1<<4)
#define SDMMC_LL_EVENT_DATA_OVER (1<<3)
#define SDMMC_LL_EVENT_CMD_DONE (1<<2)
#define SDMMC_LL_EVENT_RESP_ERR (1<<1)
#define SDMMC_LL_EVENT_CD (1<<0)
/* Default disabled interrupts (on init): /* Default disabled interrupts (on init):
* SDMMC_INTMASK_RXDR, * SDMMC_LL_EVENT_RXDR,
* SDMMC_INTMASK_TXDR, * SDMMC_LL_EVENT_TXDR,
* SDMMC_INTMASK_BCI, * SDMMC_LL_EVENT_BCI,
* SDMMC_INTMASK_ACD, * SDMMC_LL_EVENT_ACD,
* SDMMC_INTMASK_IO_SLOT1, * SDMMC_LL_EVENT_IO_SLOT1,
* SDMMC_INTMASK_IO_SLOT0 * SDMMC_LL_EVENT_IO_SLOT0
*/ */
// Default enabled interrupts (sdio is enabled only when use): // Default enabled interrupts (sdio is enabled only when use):
#define SDMMC_LL_INTMASK_DEFAULT \ #define SDMMC_LL_EVENT_DEFAULT \
(SDMMC_INTMASK_CD | SDMMC_INTMASK_RESP_ERR | SDMMC_INTMASK_CMD_DONE | SDMMC_INTMASK_DATA_OVER | \ (SDMMC_LL_EVENT_CD | SDMMC_LL_EVENT_RESP_ERR | SDMMC_LL_EVENT_CMD_DONE | SDMMC_LL_EVENT_DATA_OVER | \
SDMMC_INTMASK_RCRC | SDMMC_INTMASK_DCRC | SDMMC_INTMASK_RTO | SDMMC_INTMASK_DTO | SDMMC_INTMASK_HTO | \ SDMMC_LL_EVENT_RCRC | SDMMC_LL_EVENT_DCRC | SDMMC_LL_EVENT_RTO | SDMMC_LL_EVENT_DTO | SDMMC_LL_EVENT_HTO | \
SDMMC_INTMASK_HLE | \ SDMMC_LL_EVENT_HLE | \
SDMMC_INTMASK_SBE | \ SDMMC_LL_EVENT_SBE | \
SDMMC_INTMASK_EBE) SDMMC_LL_EVENT_EBE)
#define SDMMC_LL_SD_EVENT_MASK \
(SDMMC_LL_EVENT_CD | SDMMC_LL_EVENT_RESP_ERR | SDMMC_LL_EVENT_CMD_DONE | SDMMC_LL_EVENT_DATA_OVER | \
SDMMC_LL_EVENT_TXDR | SDMMC_LL_EVENT_RXDR |\
SDMMC_LL_EVENT_RCRC | SDMMC_LL_EVENT_DCRC | SDMMC_LL_EVENT_RTO | SDMMC_LL_EVENT_DTO | SDMMC_LL_EVENT_HTO | \
SDMMC_LL_EVENT_FRUN | SDMMC_LL_EVENT_HLE |\
SDMMC_LL_EVENT_SBE | SDMMC_LL_EVENT_ACD |\
SDMMC_LL_EVENT_EBE)
/** /**
* SDMMC capabilities * SDMMC capabilities
@ -60,6 +91,9 @@ typedef enum {
} sdmmc_ll_delay_phase_t; } sdmmc_ll_delay_phase_t;
/*---------------------------------------------------------------
Clock & Reset
---------------------------------------------------------------*/
/** /**
* @brief Enable the bus clock for SDMMC module * @brief Enable the bus clock for SDMMC module
* *
@ -239,10 +273,10 @@ static inline void sdmmc_ll_set_card_clock_div(sdmmc_dev_t *hw, uint32_t slot, u
{ {
if (slot == 0) { if (slot == 0) {
hw->clksrc.card0 = 0; hw->clksrc.card0 = 0;
hw->clkdiv.clk_divider0 = card_div; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkdiv, clk_divider0, card_div);
} else if (slot == 1) { } else if (slot == 1) {
hw->clksrc.card1 = 1; hw->clksrc.card1 = 1;
hw->clkdiv.clk_divider1 = card_div; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkdiv, clk_divider1, card_div);
} else { } else {
HAL_ASSERT(false); HAL_ASSERT(false);
} }
@ -262,10 +296,10 @@ static inline uint32_t sdmmc_ll_get_card_clock_div(sdmmc_dev_t *hw, uint32_t slo
if (slot == 0) { if (slot == 0) {
HAL_ASSERT(hw->clksrc.card0 == 0); HAL_ASSERT(hw->clksrc.card0 == 0);
card_div = hw->clkdiv.clk_divider0; card_div = HAL_FORCE_READ_U32_REG_FIELD(hw->clkdiv, clk_divider0);
} else if (slot == 1) { } else if (slot == 1) {
HAL_ASSERT(hw->clksrc.card1 == 1); HAL_ASSERT(hw->clksrc.card1 == 1);
card_div = hw->clkdiv.clk_divider1; card_div = HAL_FORCE_READ_U32_REG_FIELD(hw->clkdiv, clk_divider1);
} else { } else {
HAL_ASSERT(false); HAL_ASSERT(false);
} }
@ -289,6 +323,81 @@ static inline void sdmmc_ll_enable_card_clock_low_power(sdmmc_dev_t *hw, uint32_
} }
} }
/**
* @brief Reset controller
*
* @note Self clear after two AHB clock cycles, needs wait done
*
* @param hw hardware instance address
*/
static inline void sdmmc_ll_reset_controller(sdmmc_dev_t *hw)
{
hw->ctrl.controller_reset = 1;
}
/**
* @brief Get if controller reset is done
*
* @param hw hardware instance address
*
* @return true: done; false: not done
*/
static inline bool sdmmc_ll_is_controller_reset_done(sdmmc_dev_t *hw)
{
return hw->ctrl.controller_reset == 0;
}
/**
* @brief Reset DMA
*
* @note Self clear after two AHB clock cycles, needs wait done
*
* @param hw hardware instance address
*/
static inline void sdmmc_ll_reset_dma(sdmmc_dev_t *hw)
{
hw->ctrl.dma_reset = 1;
}
/**
* @brief Get if dma reset is done
*
* @param hw hardware instance address
*
* @return true: done; false: not done
*/
static inline bool sdmmc_ll_is_dma_reset_done(sdmmc_dev_t *hw)
{
return hw->ctrl.dma_reset == 0;
}
/**
* @brief Reset fifo
*
* @note Self clear after reset done, needs wait done
*
* @param hw hardware instance address
*/
static inline void sdmmc_ll_reset_fifo(sdmmc_dev_t *hw)
{
hw->ctrl.fifo_reset = 1;
}
/**
* @brief Get if fifo reset is done
*
* @param hw hardware instance address
*
* @return true: done; false: not done
*/
static inline bool sdmmc_ll_is_fifo_reset_done(sdmmc_dev_t *hw)
{
return hw->ctrl.fifo_reset == 0;
}
/*---------------------------------------------------------------
MISC
---------------------------------------------------------------*/
/** /**
* @brief Set card data read timeout cycles * @brief Set card data read timeout cycles
* *
@ -312,7 +421,7 @@ static inline void sdmmc_ll_set_data_timeout(sdmmc_dev_t *hw, uint32_t timeout_c
*/ */
static inline void sdmmc_ll_set_response_timeout(sdmmc_dev_t *hw, uint32_t timeout_cycles) static inline void sdmmc_ll_set_response_timeout(sdmmc_dev_t *hw, uint32_t timeout_cycles)
{ {
hw->tmout.response_timeout = timeout_cycles; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tmout, response_timeout, timeout_cycles);
} }
/** /**
@ -379,7 +488,7 @@ static inline void sdmmc_ll_set_data_transfer_len(sdmmc_dev_t *hw, uint32_t len)
*/ */
static inline void sdmmc_ll_set_block_size(sdmmc_dev_t *hw, uint32_t block_size) static inline void sdmmc_ll_set_block_size(sdmmc_dev_t *hw, uint32_t block_size)
{ {
hw->blksiz.block_size = block_size; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->blksiz, block_size, block_size);
} }
/** /**
@ -393,11 +502,138 @@ static inline void sdmmc_ll_set_desc_addr(sdmmc_dev_t *hw, uint32_t desc_addr)
hw->dbaddr.dbaddr_reg = desc_addr; hw->dbaddr.dbaddr_reg = desc_addr;
} }
/**
* @brief Poll demand
*
* @param hw hardware instance address
*/
static inline void sdmmc_ll_poll_demand(sdmmc_dev_t *hw)
{
hw->pldmnd.pldmnd_pd = 1;
}
/**
* @brief Set command
*
* @param hw hardware instance address
*/
static inline void sdmmc_ll_set_command(sdmmc_dev_t *hw, sdmmc_hw_cmd_t cmd)
{
memcpy((void *)&hw->cmd, &cmd, sizeof(sdmmc_hw_cmd_t));
}
/**
* @brief Get if command is taken by CIU
*
* @param hw hardware instance address
*
* @return 1: is taken; 0: not taken, should not write to any command regs
*/
static inline bool sdmmc_ll_is_command_taken(sdmmc_dev_t *hw)
{
return hw->cmd.start_command == 0;
}
/**
* @brief Set command argument
*
* @param hw hardware instance address
* @param arg value indicates command argument to be passed to card
*/
static inline void sdmmc_ll_set_command_arg(sdmmc_dev_t *hw, uint32_t arg)
{
hw->cmdarg = arg;
}
/**
* @brief Get version ID
*
* @param hw hardware instance address
*
* @return version ID
*/
static inline uint32_t sdmmc_ll_get_version_id(sdmmc_dev_t *hw)
{
return hw->verid;
}
/**
* @brief Get hardware configuration info
*
* @param hw hardware instance address
*
* @return hardware configurations
*/
static inline uint32_t sdmmc_ll_get_hw_config_info(sdmmc_dev_t *hw)
{
return hw->hcon.val;
}
/**
* @brief Set card width
*
* @param hw hardware instance address
* @param slot slot ID
* @param width card width
*/
static inline void sdmmc_ll_set_card_width(sdmmc_dev_t *hw, uint32_t slot, sd_bus_width_t width)
{
uint16_t mask = 1 << slot;
switch (width) {
case SD_BUS_WIDTH_1_BIT:
hw->ctype.card_width_8 &= ~mask;
hw->ctype.card_width &= ~mask;
break;
case SD_BUS_WIDTH_4_BIT:
hw->ctype.card_width_8 &= ~mask;
hw->ctype.card_width |= mask;
break;
case SD_BUS_WIDTH_8_BIT:
hw->ctype.card_width_8 |= mask;
break;
default:
HAL_ASSERT(false);
}
}
/**
* @brief Is card data busy
*
* @param hw hardware instance address
*
* @return 1: busy; 0: idle
*/
static inline bool sdmmc_ll_is_card_data_busy(sdmmc_dev_t *hw)
{
return hw->status.data_busy == 1;
}
/*---------------------------------------------------------------
DMA
---------------------------------------------------------------*/
/**
* @brief Init DMA
* - enable dma
* - clear bus mode reg and reset all dmac internal regs
* - enable internal dmac interrupt
*
* @param hw hardware instance address
*/
static inline void sdmmc_ll_init_dma(sdmmc_dev_t *hw)
{
hw->ctrl.dma_enable = 1;
hw->bmod.val = 0;
hw->bmod.sw_reset = 1;
hw->idinten.ni = 1;
hw->idinten.ri = 1;
hw->idinten.ti = 1;
}
/** /**
* @brief Enable DMA * @brief Enable DMA
* *
* @param hw hardware instance address * @param hw hardware instance address
* @param slot slot
* @param en enable / disable * @param en enable / disable
*/ */
static inline void sdmmc_ll_enable_dma(sdmmc_dev_t *hw, bool en) static inline void sdmmc_ll_enable_dma(sdmmc_dev_t *hw, bool en)
@ -409,17 +645,23 @@ static inline void sdmmc_ll_enable_dma(sdmmc_dev_t *hw, bool en)
} }
/** /**
* @brief Poll demand * @brief Stop DMA
* *
* @param hw hardware instance address * @param hw hardware instance address
*/ */
static inline void sdmmc_ll_poll_demand(sdmmc_dev_t *hw) static inline void sdmmc_ll_stop_dma(sdmmc_dev_t *hw)
{ {
hw->pldmnd.pldmnd_pd = 1; hw->ctrl.use_internal_dma = 0;
hw->ctrl.dma_reset = 1; //here might be an issue as we don't wait the `dma_reset` to be self-cleared, check in next steps
hw->bmod.fb = 0;
hw->bmod.enable = 0;
} }
/*---------------------------------------------------------------
INTR
---------------------------------------------------------------*/
/** /**
* @brief Get interrupt status * @brief Get masked interrupt-status register value
* *
* @param hw hardware instance address * @param hw hardware instance address
*/ */
@ -444,6 +686,14 @@ static inline void sdmmc_ll_enable_interrupt(sdmmc_dev_t *hw, uint32_t mask, boo
} }
} }
/**
* @brief Get RAW interrupt-status register value
*/
static inline uint32_t sdmmc_ll_get_interrupt_raw(sdmmc_dev_t *hw)
{
return hw->rintsts.val;
}
/** /**
* @brief Clear interrupt * @brief Clear interrupt
* *
@ -466,6 +716,36 @@ static inline void sdmmc_ll_enable_global_interrupt(sdmmc_dev_t *hw, bool en)
hw->ctrl.int_enable = (uint32_t)en; hw->ctrl.int_enable = (uint32_t)en;
} }
/**
* @brief Enable / disable busy clear interrupt
*
* @param hw hardware instance address
* @param en enable / disable
*/
static inline void sdmmc_ll_enable_busy_clear_interrupt(sdmmc_dev_t *hw, bool en)
{
hw->cardthrctl.busy_clr_int_en = en;
}
/**
* @brief Get internal dmac status register val
*/
static inline uint32_t sdmmc_ll_get_idsts_interrupt_raw(sdmmc_dev_t *hw)
{
return hw->idsts.val;
}
/**
* @brief Clear internal dmac status register events
*
* @param hw hardware instance address
* @param mask interrupt mask
*/
static inline void sdmmc_ll_clear_idsts_interrupt(sdmmc_dev_t *hw, uint32_t mask)
{
hw->idsts.val = mask;
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -14,8 +14,11 @@
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h>
#include "esp_bit_defs.h" #include "esp_bit_defs.h"
#include "hal/assert.h" #include "hal/assert.h"
#include "hal/misc.h"
#include "hal/sd_types.h"
#include "soc/clk_tree_defs.h" #include "soc/clk_tree_defs.h"
#include "soc/sdmmc_struct.h" #include "soc/sdmmc_struct.h"
#include "soc/sdmmc_reg.h" #include "soc/sdmmc_reg.h"
@ -27,21 +30,49 @@ extern "C" {
#define SDMMC_LL_GET_HW(id) (((id) == 0) ? (&SDMMC) : NULL) #define SDMMC_LL_GET_HW(id) (((id) == 0) ? (&SDMMC) : NULL)
#define SDMMC_LL_EVENT_IO_SLOT1 (1<<17)
#define SDMMC_LL_EVENT_IO_SLOT0 (1<<16)
#define SDMMC_LL_EVENT_EBE (1<<15)
#define SDMMC_LL_EVENT_ACD (1<<14)
#define SDMMC_LL_EVENT_SBE (1<<13)
#define SDMMC_LL_EVENT_BCI (1<<13)
#define SDMMC_LL_EVENT_HLE (1<<12)
#define SDMMC_LL_EVENT_FRUN (1<<11)
#define SDMMC_LL_EVENT_HTO (1<<10)
#define SDMMC_LL_EVENT_DTO (1<<9)
#define SDMMC_LL_EVENT_RTO (1<<8)
#define SDMMC_LL_EVENT_DCRC (1<<7)
#define SDMMC_LL_EVENT_RCRC (1<<6)
#define SDMMC_LL_EVENT_RXDR (1<<5)
#define SDMMC_LL_EVENT_TXDR (1<<4)
#define SDMMC_LL_EVENT_DATA_OVER (1<<3)
#define SDMMC_LL_EVENT_CMD_DONE (1<<2)
#define SDMMC_LL_EVENT_RESP_ERR (1<<1)
#define SDMMC_LL_EVENT_CD (1<<0)
/* Default disabled interrupts (on init): /* Default disabled interrupts (on init):
* SDMMC_INTMASK_RXDR, * SDMMC_LL_EVENT_RXDR,
* SDMMC_INTMASK_TXDR, * SDMMC_LL_EVENT_TXDR,
* SDMMC_INTMASK_BCI, * SDMMC_LL_EVENT_BCI,
* SDMMC_INTMASK_ACD, * SDMMC_LL_EVENT_ACD,
* SDMMC_INTMASK_IO_SLOT1, * SDMMC_LL_EVENT_IO_SLOT1,
* SDMMC_INTMASK_IO_SLOT0 * SDMMC_LL_EVENT_IO_SLOT0
*/ */
// Default enabled interrupts (sdio is enabled only when use): // Default enabled interrupts (sdio is enabled only when use):
#define SDMMC_LL_INTMASK_DEFAULT \ #define SDMMC_LL_EVENT_DEFAULT \
(SDMMC_INTMASK_CD | SDMMC_INTMASK_RESP_ERR | SDMMC_INTMASK_CMD_DONE | SDMMC_INTMASK_DATA_OVER | \ (SDMMC_LL_EVENT_CD | SDMMC_LL_EVENT_RESP_ERR | SDMMC_LL_EVENT_CMD_DONE | SDMMC_LL_EVENT_DATA_OVER | \
SDMMC_INTMASK_RCRC | SDMMC_INTMASK_DCRC | SDMMC_INTMASK_RTO | SDMMC_INTMASK_DTO | SDMMC_INTMASK_HTO | \ SDMMC_LL_EVENT_RCRC | SDMMC_LL_EVENT_DCRC | SDMMC_LL_EVENT_RTO | SDMMC_LL_EVENT_DTO | SDMMC_LL_EVENT_HTO | \
SDMMC_INTMASK_HLE | \ SDMMC_LL_EVENT_HLE | \
SDMMC_INTMASK_SBE | \ SDMMC_LL_EVENT_SBE | \
SDMMC_INTMASK_EBE) SDMMC_LL_EVENT_EBE)
#define SDMMC_LL_SD_EVENT_MASK \
(SDMMC_LL_EVENT_CD | SDMMC_LL_EVENT_RESP_ERR | SDMMC_LL_EVENT_CMD_DONE | SDMMC_LL_EVENT_DATA_OVER | \
SDMMC_LL_EVENT_TXDR | SDMMC_LL_EVENT_RXDR |\
SDMMC_LL_EVENT_RCRC | SDMMC_LL_EVENT_DCRC | SDMMC_LL_EVENT_RTO | SDMMC_LL_EVENT_DTO | SDMMC_LL_EVENT_HTO | \
SDMMC_LL_EVENT_FRUN | SDMMC_LL_EVENT_HLE |\
SDMMC_LL_EVENT_SBE | SDMMC_LL_EVENT_ACD |\
SDMMC_LL_EVENT_EBE)
/** /**
* SDMMC capabilities * SDMMC capabilities
@ -58,6 +89,9 @@ typedef enum {
} sdmmc_ll_delay_phase_t; } sdmmc_ll_delay_phase_t;
/*---------------------------------------------------------------
Clock & Reset
---------------------------------------------------------------*/
/** /**
* @brief Enable the bus clock for SDMMC module * @brief Enable the bus clock for SDMMC module
* *
@ -210,11 +244,13 @@ static inline void sdmmc_ll_set_din_delay(sdmmc_dev_t *hw, sdmmc_ll_delay_phase_
*/ */
static inline void sdmmc_ll_enable_card_clock(sdmmc_dev_t *hw, uint32_t slot, bool en) static inline void sdmmc_ll_enable_card_clock(sdmmc_dev_t *hw, uint32_t slot, bool en)
{ {
uint32_t reg_val = HAL_FORCE_READ_U32_REG_FIELD(hw->clkena, cclk_enable);
if (en) { if (en) {
hw->clkena.cclk_enable |= BIT(slot); reg_val |= BIT(slot);
} else { } else {
hw->clkena.cclk_enable &= ~BIT(slot); reg_val &= ~BIT(slot);
} }
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkena, cclk_enable, reg_val);
} }
/** /**
@ -228,10 +264,10 @@ static inline void sdmmc_ll_set_card_clock_div(sdmmc_dev_t *hw, uint32_t slot, u
{ {
if (slot == 0) { if (slot == 0) {
hw->clksrc.card0 = 0; hw->clksrc.card0 = 0;
hw->clkdiv.div0 = card_div; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkdiv, div0, card_div);
} else if (slot == 1) { } else if (slot == 1) {
hw->clksrc.card1 = 1; hw->clksrc.card1 = 1;
hw->clkdiv.div1 = card_div; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkdiv, div1, card_div);
} else { } else {
HAL_ASSERT(false); HAL_ASSERT(false);
} }
@ -251,10 +287,10 @@ static inline uint32_t sdmmc_ll_get_card_clock_div(sdmmc_dev_t *hw, uint32_t slo
if (slot == 0) { if (slot == 0) {
HAL_ASSERT(hw->clksrc.card0 == 0); HAL_ASSERT(hw->clksrc.card0 == 0);
card_div = hw->clkdiv.div0; card_div = HAL_FORCE_READ_U32_REG_FIELD(hw->clkdiv, div0);
} else if (slot == 1) { } else if (slot == 1) {
HAL_ASSERT(hw->clksrc.card1 == 1); HAL_ASSERT(hw->clksrc.card1 == 1);
card_div = hw->clkdiv.div1; card_div = HAL_FORCE_READ_U32_REG_FIELD(hw->clkdiv, div1);
} else { } else {
HAL_ASSERT(false); HAL_ASSERT(false);
} }
@ -271,13 +307,90 @@ static inline uint32_t sdmmc_ll_get_card_clock_div(sdmmc_dev_t *hw, uint32_t slo
*/ */
static inline void sdmmc_ll_enable_card_clock_low_power(sdmmc_dev_t *hw, uint32_t slot, bool en) static inline void sdmmc_ll_enable_card_clock_low_power(sdmmc_dev_t *hw, uint32_t slot, bool en)
{ {
uint32_t reg_val = HAL_FORCE_READ_U32_REG_FIELD(hw->clkena, cclk_low_power);
if (en) { if (en) {
hw->clkena.cclk_low_power |= BIT(slot); reg_val |= BIT(slot);
} else { } else {
hw->clkena.cclk_low_power &= ~BIT(slot); reg_val &= ~BIT(slot);
} }
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkena, cclk_low_power, reg_val);
} }
/**
* @brief Reset controller
*
* @note Self clear after two AHB clock cycles, needs wait done
*
* @param hw hardware instance address
*/
static inline void sdmmc_ll_reset_controller(sdmmc_dev_t *hw)
{
hw->ctrl.controller_reset = 1;
}
/**
* @brief Get if controller reset is done
*
* @param hw hardware instance address
*
* @return true: done; false: not done
*/
static inline bool sdmmc_ll_is_controller_reset_done(sdmmc_dev_t *hw)
{
return hw->ctrl.controller_reset == 0;
}
/**
* @brief Reset DMA
*
* @note Self clear after two AHB clock cycles, needs wait done
*
* @param hw hardware instance address
*/
static inline void sdmmc_ll_reset_dma(sdmmc_dev_t *hw)
{
hw->ctrl.dma_reset = 1;
}
/**
* @brief Get if dma reset is done
*
* @param hw hardware instance address
*
* @return true: done; false: not done
*/
static inline bool sdmmc_ll_is_dma_reset_done(sdmmc_dev_t *hw)
{
return hw->ctrl.dma_reset == 0;
}
/**
* @brief Reset fifo
*
* @note Self clear after reset done, needs wait done
*
* @param hw hardware instance address
*/
static inline void sdmmc_ll_reset_fifo(sdmmc_dev_t *hw)
{
hw->ctrl.fifo_reset = 1;
}
/**
* @brief Get if fifo reset is done
*
* @param hw hardware instance address
*
* @return true: done; false: not done
*/
static inline bool sdmmc_ll_is_fifo_reset_done(sdmmc_dev_t *hw)
{
return hw->ctrl.fifo_reset == 0;
}
/*---------------------------------------------------------------
MISC
---------------------------------------------------------------*/
/** /**
* @brief Set card data read timeout cycles * @brief Set card data read timeout cycles
* *
@ -301,7 +414,7 @@ static inline void sdmmc_ll_set_data_timeout(sdmmc_dev_t *hw, uint32_t timeout_c
*/ */
static inline void sdmmc_ll_set_response_timeout(sdmmc_dev_t *hw, uint32_t timeout_cycles) static inline void sdmmc_ll_set_response_timeout(sdmmc_dev_t *hw, uint32_t timeout_cycles)
{ {
hw->tmout.response = timeout_cycles; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->tmout, response, timeout_cycles);
} }
/** /**
@ -340,11 +453,14 @@ static inline bool sdmmc_ll_is_card_write_protected(sdmmc_dev_t *hw, uint32_t sl
*/ */
static inline void sdmmc_ll_enable_ddr_mode(sdmmc_dev_t *hw, uint32_t slot, bool en) static inline void sdmmc_ll_enable_ddr_mode(sdmmc_dev_t *hw, uint32_t slot, bool en)
{ {
uint32_t ddr_reg_val = HAL_FORCE_READ_U32_REG_FIELD(hw->uhs, ddr);
if (en) { if (en) {
hw->uhs.ddr |= BIT(slot); ddr_reg_val|= BIT(slot);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->uhs, ddr, ddr_reg_val);
hw->emmc_ddr_reg |= BIT(slot); hw->emmc_ddr_reg |= BIT(slot);
} else { } else {
hw->uhs.ddr &= ~BIT(slot); ddr_reg_val&= ~BIT(slot);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->uhs, ddr, ddr_reg_val);
hw->emmc_ddr_reg &= ~BIT(slot); hw->emmc_ddr_reg &= ~BIT(slot);
} }
} }
@ -368,7 +484,7 @@ static inline void sdmmc_ll_set_data_transfer_len(sdmmc_dev_t *hw, uint32_t len)
*/ */
static inline void sdmmc_ll_set_block_size(sdmmc_dev_t *hw, uint32_t block_size) static inline void sdmmc_ll_set_block_size(sdmmc_dev_t *hw, uint32_t block_size)
{ {
hw->blksiz = block_size; HAL_FORCE_MODIFY_U32_REG_FIELD(hw->blksiz, block_size, block_size);
} }
/** /**
@ -382,11 +498,143 @@ static inline void sdmmc_ll_set_desc_addr(sdmmc_dev_t *hw, uint32_t desc_addr)
hw->dbaddr = (sdmmc_desc_t *)desc_addr; hw->dbaddr = (sdmmc_desc_t *)desc_addr;
} }
/**
* @brief Poll demand
*
* @param hw hardware instance address
*/
static inline void sdmmc_ll_poll_demand(sdmmc_dev_t *hw)
{
hw->pldmnd = 1;
}
/**
* @brief Set command
*
* @param hw hardware instance address
*/
static inline void sdmmc_ll_set_command(sdmmc_dev_t *hw, sdmmc_hw_cmd_t cmd)
{
memcpy((void *)&hw->cmd, &cmd, sizeof(sdmmc_hw_cmd_t));
}
/**
* @brief Get if command is taken by CIU
*
* @param hw hardware instance address
*
* @return 1: is taken; 0: not taken, should not write to any command regs
*/
static inline bool sdmmc_ll_is_command_taken(sdmmc_dev_t *hw)
{
return hw->cmd.start_command == 0;
}
/**
* @brief Set command argument
*
* @param hw hardware instance address
* @param arg value indicates command argument to be passed to card
*/
static inline void sdmmc_ll_set_command_arg(sdmmc_dev_t *hw, uint32_t arg)
{
hw->cmdarg = arg;
}
/**
* @brief Get version ID
*
* @param hw hardware instance address
*
* @return version ID
*/
static inline uint32_t sdmmc_ll_get_version_id(sdmmc_dev_t *hw)
{
return hw->verid;
}
/**
* @brief Get hardware configuration info
*
* @param hw hardware instance address
*
* @return hardware configurations
*/
static inline uint32_t sdmmc_ll_get_hw_config_info(sdmmc_dev_t *hw)
{
return hw->hcon.val;
}
/**
* @brief Set card width
*
* @param hw hardware instance address
* @param slot slot ID
* @param width card width
*/
static inline void sdmmc_ll_set_card_width(sdmmc_dev_t *hw, uint32_t slot, sd_bus_width_t width)
{
uint16_t mask = 1 << slot;
uint32_t reg_val = HAL_FORCE_READ_U32_REG_FIELD(hw->ctype, card_width);
uint32_t reg_val_8 = HAL_FORCE_READ_U32_REG_FIELD(hw->ctype, card_width_8);
switch (width) {
case SD_BUS_WIDTH_1_BIT:
reg_val_8 &= ~mask;
reg_val &= ~mask;
break;
case SD_BUS_WIDTH_4_BIT:
reg_val_8 &= ~mask;
reg_val |= mask;
break;
case SD_BUS_WIDTH_8_BIT:
reg_val_8 |= mask;
break;
default:
HAL_ASSERT(false);
}
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->ctype, card_width, reg_val);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->ctype, card_width_8, reg_val_8);
}
/**
* @brief Is card data busy
*
* @param hw hardware instance address
*
* @return 1: busy; 0: idle
*/
static inline bool sdmmc_ll_is_card_data_busy(sdmmc_dev_t *hw)
{
return hw->status.data_busy == 1;
}
/*---------------------------------------------------------------
DMA
---------------------------------------------------------------*/
/**
* @brief Init DMA
* - enable dma
* - clear bus mode reg and reset all dmac internal regs
* - enable internal dmac interrupt
*
* @param hw hardware instance address
*/
static inline void sdmmc_ll_init_dma(sdmmc_dev_t *hw)
{
hw->ctrl.dma_enable = 1;
hw->bmod.val = 0;
hw->bmod.sw_reset = 1;
hw->idinten.ni = 1;
hw->idinten.ri = 1;
hw->idinten.ti = 1;
}
/** /**
* @brief Enable DMA * @brief Enable DMA
* *
* @param hw hardware instance address * @param hw hardware instance address
* @param slot slot
* @param en enable / disable * @param en enable / disable
*/ */
static inline void sdmmc_ll_enable_dma(sdmmc_dev_t *hw, bool en) static inline void sdmmc_ll_enable_dma(sdmmc_dev_t *hw, bool en)
@ -398,17 +646,23 @@ static inline void sdmmc_ll_enable_dma(sdmmc_dev_t *hw, bool en)
} }
/** /**
* @brief Poll demand * @brief Stop DMA
* *
* @param hw hardware instance address * @param hw hardware instance address
*/ */
static inline void sdmmc_ll_poll_demand(sdmmc_dev_t *hw) static inline void sdmmc_ll_stop_dma(sdmmc_dev_t *hw)
{ {
hw->pldmnd = 1; hw->ctrl.use_internal_dma = 0;
hw->ctrl.dma_reset = 1; //here might be an issue as we don't wait the `dma_reset` to be self-cleared, check in next steps
hw->bmod.fb = 0;
hw->bmod.enable = 0;
} }
/*---------------------------------------------------------------
INTR
---------------------------------------------------------------*/
/** /**
* @brief Get interrupt status * @brief Get masked interrupt-status register value
* *
* @param hw hardware instance address * @param hw hardware instance address
*/ */
@ -433,6 +687,14 @@ static inline void sdmmc_ll_enable_interrupt(sdmmc_dev_t *hw, uint32_t mask, boo
} }
} }
/**
* @brief Get RAW interrupt-status register value
*/
static inline uint32_t sdmmc_ll_get_interrupt_raw(sdmmc_dev_t *hw)
{
return hw->rintsts.val;
}
/** /**
* @brief Clear interrupt * @brief Clear interrupt
* *
@ -455,6 +717,37 @@ static inline void sdmmc_ll_enable_global_interrupt(sdmmc_dev_t *hw, bool en)
hw->ctrl.int_enable = (uint32_t)en; hw->ctrl.int_enable = (uint32_t)en;
} }
/**
* @brief Enable / disable busy clear interrupt
*
* @param hw hardware instance address
* @param en enable / disable
*/
static inline void sdmmc_ll_enable_busy_clear_interrupt(sdmmc_dev_t *hw, bool en)
{
hw->cardthrctl.busy_clr_int_en = en;
}
/**
* @brief Get internal dmac status register val
*/
static inline uint32_t sdmmc_ll_get_idsts_interrupt_raw(sdmmc_dev_t *hw)
{
return hw->idsts.val;
}
/**
* @brief Clear internal dmac status register events
*
* @param hw hardware instance address
* @param mask interrupt mask
*/
static inline void sdmmc_ll_clear_idsts_interrupt(sdmmc_dev_t *hw, uint32_t mask)
{
hw->idsts.val = mask;
}
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "soc/soc_caps.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief SD bus width
*/
typedef enum {
SD_BUS_WIDTH_1_BIT, ///< 1 bit
SD_BUS_WIDTH_4_BIT, ///< 4 bit
SD_BUS_WIDTH_8_BIT, ///< 8 bit
} sd_bus_width_t;
#ifdef __cplusplus
}
#endif

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2023 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
*/ */
@ -146,10 +146,13 @@ typedef struct sdmmc_dev_t {
uint32_t val; uint32_t val;
} ctype; } ctype;
volatile struct { volatile union {
uint32_t blksiz: 16; ///< block size, default 0x200 struct {
uint32_t block_size: 16; ///< block size, default 0x200
uint32_t reserved: 16; uint32_t reserved: 16;
}; };
uint32_t val;
} blksiz;
volatile uint32_t bytcnt; ///< number of bytes to be transferred volatile uint32_t bytcnt; ///< number of bytes to be transferred
@ -302,7 +305,7 @@ typedef struct sdmmc_dev_t {
*/ */
uint32_t bus_type_reg:1; uint32_t bus_type_reg:1;
/** data_width_reg : RO; bitpos: [9:7]; default: 1; /** data_width_reg : RO; bitpos: [9:7]; default: 1;
* Regisger data widht is 32. * Regisger data width is 32.
*/ */
uint32_t data_width_reg:3; uint32_t data_width_reg:3;
/** addr_width_reg : RO; bitpos: [15:10]; default: 19; /** addr_width_reg : RO; bitpos: [15:10]; default: 19;
@ -311,7 +314,7 @@ typedef struct sdmmc_dev_t {
uint32_t addr_width_reg:6; uint32_t addr_width_reg:6;
uint32_t reserved_16:2; uint32_t reserved_16:2;
/** dma_width_reg : RO; bitpos: [20:18]; default: 1; /** dma_width_reg : RO; bitpos: [20:18]; default: 1;
* DMA data witdth is 32. * DMA data width is 32.
*/ */
uint32_t dma_width_reg:3; uint32_t dma_width_reg:3;
/** ram_indise_reg : RO; bitpos: [21]; default: 0; /** ram_indise_reg : RO; bitpos: [21]; default: 0;
@ -319,7 +322,7 @@ typedef struct sdmmc_dev_t {
*/ */
uint32_t ram_indise_reg:1; uint32_t ram_indise_reg:1;
/** hold_reg : RO; bitpos: [22]; default: 1; /** hold_reg : RO; bitpos: [22]; default: 1;
* Have a hold regiser in data path . * Have a hold register in data path .
*/ */
uint32_t hold_reg:1; uint32_t hold_reg:1;
uint32_t reserved_23:1; uint32_t reserved_23:1;
@ -337,6 +340,7 @@ typedef struct sdmmc_dev_t {
uint32_t voltage: 16; ///< voltage control for slots; no-op on ESP32. uint32_t voltage: 16; ///< voltage control for slots; no-op on ESP32.
uint32_t ddr: 16; ///< bit N enables DDR mode for card N uint32_t ddr: 16; ///< bit N enables DDR mode for card N
}; };
uint32_t val;
} uhs; ///< UHS related settings } uhs; ///< UHS related settings
volatile union { volatile union {

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2015-2023 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
*/ */
@ -144,10 +144,13 @@ typedef struct sdmmc_dev_t {
uint32_t val; uint32_t val;
} ctype; } ctype;
volatile struct { volatile union {
uint32_t blksiz: 16; ///< block size, default 0x200 struct {
uint32_t block_size: 16; ///< block size, default 0x200
uint32_t reserved: 16; uint32_t reserved: 16;
}; };
uint32_t val;
} blksiz;
volatile uint32_t bytcnt; ///< number of bytes to be transferred volatile uint32_t bytcnt; ///< number of bytes to be transferred
@ -300,7 +303,7 @@ typedef struct sdmmc_dev_t {
*/ */
uint32_t bus_type_reg:1; uint32_t bus_type_reg:1;
/** data_width_reg : RO; bitpos: [9:7]; default: 1; /** data_width_reg : RO; bitpos: [9:7]; default: 1;
* Regisger data widht is 32. * Regisger data width is 32.
*/ */
uint32_t data_width_reg:3; uint32_t data_width_reg:3;
/** addr_width_reg : RO; bitpos: [15:10]; default: 19; /** addr_width_reg : RO; bitpos: [15:10]; default: 19;
@ -309,7 +312,7 @@ typedef struct sdmmc_dev_t {
uint32_t addr_width_reg:6; uint32_t addr_width_reg:6;
uint32_t reserved_16:2; uint32_t reserved_16:2;
/** dma_width_reg : RO; bitpos: [20:18]; default: 1; /** dma_width_reg : RO; bitpos: [20:18]; default: 1;
* DMA data witdth is 32. * DMA data width is 32.
*/ */
uint32_t dma_width_reg:3; uint32_t dma_width_reg:3;
/** ram_indise_reg : RO; bitpos: [21]; default: 0; /** ram_indise_reg : RO; bitpos: [21]; default: 0;
@ -317,7 +320,7 @@ typedef struct sdmmc_dev_t {
*/ */
uint32_t ram_indise_reg:1; uint32_t ram_indise_reg:1;
/** hold_reg : RO; bitpos: [22]; default: 1; /** hold_reg : RO; bitpos: [22]; default: 1;
* Have a hold regiser in data path . * Have a hold register in data path .
*/ */
uint32_t hold_reg:1; uint32_t hold_reg:1;
uint32_t reserved_23:1; uint32_t reserved_23:1;
@ -335,6 +338,7 @@ typedef struct sdmmc_dev_t {
uint32_t voltage: 16; ///< voltage control for slots; no-op on ESP32. uint32_t voltage: 16; ///< voltage control for slots; no-op on ESP32.
uint32_t ddr: 16; ///< bit N enables DDR mode for card N uint32_t ddr: 16; ///< bit N enables DDR mode for card N
}; };
uint32_t val;
} uhs; ///< UHS related settings } uhs; ///< UHS related settings
volatile union { volatile union {