diff --git a/components/esp_driver_sdmmc/src/sdmmc_host.c b/components/esp_driver_sdmmc/src/sdmmc_host.c index 9407f82953..e8459ea9f6 100644 --- a/components/esp_driver_sdmmc/src/sdmmc_host.c +++ b/components/esp_driver_sdmmc/src/sdmmc_host.c @@ -13,7 +13,6 @@ #include "esp_timer.h" #include "esp_check.h" #include "soc/soc_caps.h" -#include "soc/soc_pins.h" #include "soc/gpio_periph.h" #include "esp_rom_gpio.h" #include "esp_rom_sys.h" @@ -28,6 +27,7 @@ #include "soc/soc_caps.h" #include "hal/gpio_hal.h" #include "hal/sdmmc_hal.h" +#include "hal/sd_types.h" #include "hal/sdmmc_ll.h" #define SDMMC_EVENT_QUEUE_LENGTH 32 @@ -96,25 +96,35 @@ static host_ctx_t s_host_ctx = {0}; #endif 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 bool sdmmc_host_slot_initialized(int slot); #if SOC_SDMMC_NUM_SLOTS >= 2 static void sdmmc_host_change_to_slot(int slot); #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) { - // Set reset bits - SDMMC.ctrl.controller_reset = 1; - SDMMC.ctrl.dma_reset = 1; - SDMMC.ctrl.fifo_reset = 1; + s_module_reset(); // Wait for the reset bits to be cleared by hardware int64_t yield_delay_us = 100 * 1000; // initially 100ms int64_t t0 = esp_timer_get_time(); 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(); if (t1 - t0 > SDMMC_HOST_RESET_TIMEOUT_US) { 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. // According to the manual, this is okay and we must retry the command. - if (SDMMC.rintsts.hle) { - SDMMC.rintsts.hle = 1; + if (sdmmc_ll_get_interrupt_raw(s_host_ctx.hal.dev) & SDMMC_LL_EVENT_HLE) { + sdmmc_ll_clear_interrupt(s_host_ctx.hal.dev, SDMMC_LL_EVENT_HLE); repeat = true; break; } // When the command is accepted by CIU, start_command bit will be // cleared in SDMMC.cmd register. - if (SDMMC.cmd.start_command == 0) { + if (sdmmc_ll_is_command_taken(s_host_ctx.hal.dev)) { repeat = false; 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 t0 = esp_timer_get_time(); 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(); if (t1 - t0 > SDMMC_HOST_START_CMD_TIMEOUT_US) { 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); } } - SDMMC.cmdarg = arg; + sdmmc_ll_set_command_arg(s_host_ctx.hal.dev, arg); cmd.card_num = slot; cmd.start_command = 1; - SDMMC.cmd = cmd; + sdmmc_ll_set_command(s_host_ctx.hal.dev, cmd); return ESP_OK; } @@ -440,7 +450,7 @@ static void sdmmc_host_intmask_clear_disable(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, 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); } @@ -470,7 +480,7 @@ esp_err_t sdmmc_host_init(void) 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 sdmmc_host_intmask_clear_disable(); @@ -499,10 +509,10 @@ esp_err_t sdmmc_host_init(void) sdmmc_host_intmask_set_enable(); // 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 - sdmmc_host_dma_init(); + // Init DMA + sdmmc_ll_init_dma(s_host_ctx.hal.dev); // Initialize transaction handler 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) { return ESP_ERR_INVALID_ARG; } - const uint16_t mask = BIT(slot); if (width == 1) { - SDMMC.ctype.card_width_8 &= ~mask; - SDMMC.ctype.card_width &= ~mask; + sdmmc_ll_set_card_width(s_host_ctx.hal.dev, slot, SD_BUS_WIDTH_1_BIT); } else if (width == 4) { - SDMMC.ctype.card_width_8 &= ~mask; - SDMMC.ctype.card_width |= mask; + 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 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) { - 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 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 { @@ -935,22 +942,9 @@ esp_err_t sdmmc_host_set_cclk_always_on(int slot, bool cclk_always_on) 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) { - SDMMC.ctrl.use_internal_dma = 0; - SDMMC.ctrl.dma_reset = 1; - SDMMC.bmod.fb = 0; - SDMMC.bmod.enable = 0; + sdmmc_ll_stop_dma(s_host_ctx.hal.dev); } 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) { - 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) @@ -1044,12 +1038,12 @@ static void sdmmc_isr(void *arg) sdmmc_event_t event; int higher_priority_task_awoken = pdFALSE; - uint32_t pending = sdmmc_ll_get_intr_status(s_host_ctx.hal.dev) & 0xFFFF; - SDMMC.rintsts.val = pending; + uint32_t pending = sdmmc_ll_get_intr_status(s_host_ctx.hal.dev) & SDMMC_LL_SD_EVENT_MASK; + sdmmc_ll_clear_interrupt(s_host_ctx.hal.dev, pending); event.sdmmc_status = pending; - uint32_t dma_pending = SDMMC.idsts.val; - SDMMC.idsts.val = dma_pending; + uint32_t dma_pending = sdmmc_ll_get_idsts_interrupt_raw(s_host_ctx.hal.dev); + sdmmc_ll_clear_idsts_interrupt(s_host_ctx.hal.dev, dma_pending); event.dma_status = dma_pending & 0x1f; if (pending != 0 || dma_pending != 0) { diff --git a/components/esp_driver_sdmmc/test_apps/sdmmc/CMakeLists.txt b/components/esp_driver_sdmmc/test_apps/sdmmc/CMakeLists.txt index 937ae28ab7..614cf9cd42 100644 --- a/components/esp_driver_sdmmc/test_apps/sdmmc/CMakeLists.txt +++ b/components/esp_driver_sdmmc/test_apps/sdmmc/CMakeLists.txt @@ -6,3 +6,8 @@ set(COMPONENTS main) include($ENV{IDF_PATH}/tools/cmake/project.cmake) 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") diff --git a/components/hal/esp32/include/hal/sdmmc_ll.h b/components/hal/esp32/include/hal/sdmmc_ll.h index 841a6b226f..c9ccf8ffe4 100644 --- a/components/hal/esp32/include/hal/sdmmc_ll.h +++ b/components/hal/esp32/include/hal/sdmmc_ll.h @@ -14,8 +14,11 @@ #include #include +#include #include "esp_bit_defs.h" #include "hal/assert.h" +#include "hal/misc.h" +#include "hal/sd_types.h" #include "soc/clk_tree_defs.h" #include "soc/sdmmc_struct.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_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): - * SDMMC_INTMASK_RXDR, - * SDMMC_INTMASK_TXDR, - * SDMMC_INTMASK_BCI, - * SDMMC_INTMASK_ACD, - * SDMMC_INTMASK_IO_SLOT1, - * SDMMC_INTMASK_IO_SLOT0 + * SDMMC_LL_EVENT_RXDR, + * SDMMC_LL_EVENT_TXDR, + * SDMMC_LL_EVENT_BCI, + * SDMMC_LL_EVENT_ACD, + * SDMMC_LL_EVENT_IO_SLOT1, + * SDMMC_LL_EVENT_IO_SLOT0 */ // Default enabled interrupts (sdio is enabled only when use): -#define SDMMC_LL_INTMASK_DEFAULT \ - (SDMMC_INTMASK_CD | SDMMC_INTMASK_RESP_ERR | SDMMC_INTMASK_CMD_DONE | SDMMC_INTMASK_DATA_OVER | \ - SDMMC_INTMASK_RCRC | SDMMC_INTMASK_DCRC | SDMMC_INTMASK_RTO | SDMMC_INTMASK_DTO | SDMMC_INTMASK_HTO | \ - SDMMC_INTMASK_HLE | \ - SDMMC_INTMASK_SBE | \ - SDMMC_INTMASK_EBE) +#define SDMMC_LL_EVENT_DEFAULT \ + (SDMMC_LL_EVENT_CD | SDMMC_LL_EVENT_RESP_ERR | SDMMC_LL_EVENT_CMD_DONE | SDMMC_LL_EVENT_DATA_OVER | \ + SDMMC_LL_EVENT_RCRC | SDMMC_LL_EVENT_DCRC | SDMMC_LL_EVENT_RTO | SDMMC_LL_EVENT_DTO | SDMMC_LL_EVENT_HTO | \ + SDMMC_LL_EVENT_HLE | \ + SDMMC_LL_EVENT_SBE | \ + 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 @@ -59,6 +90,9 @@ typedef enum { } sdmmc_ll_delay_phase_t; +/*--------------------------------------------------------------- + Clock & Reset +---------------------------------------------------------------*/ /** * @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) { + uint32_t reg_val = HAL_FORCE_READ_U32_REG_FIELD(hw->clkena, cclk_enable); if (en) { - hw->clkena.cclk_enable |= BIT(slot); + reg_val |= BIT(slot); } 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) { hw->clksrc.card0 = 0; - hw->clkdiv.div0 = card_div; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkdiv, div0, card_div); } else if (slot == 1) { hw->clksrc.card1 = 1; - hw->clkdiv.div1 = card_div; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkdiv, div1, card_div); } else { 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) { 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) { HAL_ASSERT(hw->clksrc.card1 == 1); - card_div = hw->clkdiv.div1; + card_div = HAL_FORCE_READ_U32_REG_FIELD(hw->clkdiv, div1); } else { 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) { + uint32_t reg_val = HAL_FORCE_READ_U32_REG_FIELD(hw->clkena, cclk_low_power); if (en) { - hw->clkena.cclk_low_power |= BIT(slot); + reg_val |= BIT(slot); } 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 * @@ -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) { - 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) { + uint32_t ddr_reg_val = HAL_FORCE_READ_U32_REG_FIELD(hw->uhs, ddr); 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); } 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); } } @@ -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) { - 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; } +/** + * @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 * * @param hw hardware instance address - * @param slot slot * @param en enable / disable */ 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 */ -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 */ @@ -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 * @@ -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; } +/** + * @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 } #endif diff --git a/components/hal/esp32p4/include/hal/sdmmc_ll.h b/components/hal/esp32p4/include/hal/sdmmc_ll.h index 210df60123..1141854f5c 100644 --- a/components/hal/esp32p4/include/hal/sdmmc_ll.h +++ b/components/hal/esp32p4/include/hal/sdmmc_ll.h @@ -14,8 +14,11 @@ #include #include +#include #include "esp_bit_defs.h" #include "hal/assert.h" +#include "hal/misc.h" +#include "hal/sd_types.h" #include "soc/clk_tree_defs.h" #include "soc/sdmmc_struct.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_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): - * SDMMC_INTMASK_RXDR, - * SDMMC_INTMASK_TXDR, - * SDMMC_INTMASK_BCI, - * SDMMC_INTMASK_ACD, - * SDMMC_INTMASK_IO_SLOT1, - * SDMMC_INTMASK_IO_SLOT0 + * SDMMC_LL_EVENT_RXDR, + * SDMMC_LL_EVENT_TXDR, + * SDMMC_LL_EVENT_BCI, + * SDMMC_LL_EVENT_ACD, + * SDMMC_LL_EVENT_IO_SLOT1, + * SDMMC_LL_EVENT_IO_SLOT0 */ // Default enabled interrupts (sdio is enabled only when use): -#define SDMMC_LL_INTMASK_DEFAULT \ - (SDMMC_INTMASK_CD | SDMMC_INTMASK_RESP_ERR | SDMMC_INTMASK_CMD_DONE | SDMMC_INTMASK_DATA_OVER | \ - SDMMC_INTMASK_RCRC | SDMMC_INTMASK_DCRC | SDMMC_INTMASK_RTO | SDMMC_INTMASK_DTO | SDMMC_INTMASK_HTO | \ - SDMMC_INTMASK_HLE | \ - SDMMC_INTMASK_SBE | \ - SDMMC_INTMASK_EBE) +#define SDMMC_LL_EVENT_DEFAULT \ + (SDMMC_LL_EVENT_CD | SDMMC_LL_EVENT_RESP_ERR | SDMMC_LL_EVENT_CMD_DONE | SDMMC_LL_EVENT_DATA_OVER | \ + SDMMC_LL_EVENT_RCRC | SDMMC_LL_EVENT_DCRC | SDMMC_LL_EVENT_RTO | SDMMC_LL_EVENT_DTO | SDMMC_LL_EVENT_HTO | \ + SDMMC_LL_EVENT_HLE | \ + SDMMC_LL_EVENT_SBE | \ + 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 @@ -60,6 +91,9 @@ typedef enum { } sdmmc_ll_delay_phase_t; +/*--------------------------------------------------------------- + Clock & Reset +---------------------------------------------------------------*/ /** * @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) { 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) { hw->clksrc.card1 = 1; - hw->clkdiv.clk_divider1 = card_div; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkdiv, clk_divider1, card_div); } else { 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) { 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) { 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 { 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 * @@ -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) { - 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) { - 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; } +/** + * @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 * * @param hw hardware instance address - * @param slot slot * @param en enable / disable */ 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 */ -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 */ @@ -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 * @@ -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; } +/** + * @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 } #endif diff --git a/components/hal/esp32s3/include/hal/sdmmc_ll.h b/components/hal/esp32s3/include/hal/sdmmc_ll.h index fe4cb0a106..89aa2a8529 100644 --- a/components/hal/esp32s3/include/hal/sdmmc_ll.h +++ b/components/hal/esp32s3/include/hal/sdmmc_ll.h @@ -14,8 +14,11 @@ #include #include +#include #include "esp_bit_defs.h" #include "hal/assert.h" +#include "hal/misc.h" +#include "hal/sd_types.h" #include "soc/clk_tree_defs.h" #include "soc/sdmmc_struct.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_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): - * SDMMC_INTMASK_RXDR, - * SDMMC_INTMASK_TXDR, - * SDMMC_INTMASK_BCI, - * SDMMC_INTMASK_ACD, - * SDMMC_INTMASK_IO_SLOT1, - * SDMMC_INTMASK_IO_SLOT0 + * SDMMC_LL_EVENT_RXDR, + * SDMMC_LL_EVENT_TXDR, + * SDMMC_LL_EVENT_BCI, + * SDMMC_LL_EVENT_ACD, + * SDMMC_LL_EVENT_IO_SLOT1, + * SDMMC_LL_EVENT_IO_SLOT0 */ // Default enabled interrupts (sdio is enabled only when use): -#define SDMMC_LL_INTMASK_DEFAULT \ - (SDMMC_INTMASK_CD | SDMMC_INTMASK_RESP_ERR | SDMMC_INTMASK_CMD_DONE | SDMMC_INTMASK_DATA_OVER | \ - SDMMC_INTMASK_RCRC | SDMMC_INTMASK_DCRC | SDMMC_INTMASK_RTO | SDMMC_INTMASK_DTO | SDMMC_INTMASK_HTO | \ - SDMMC_INTMASK_HLE | \ - SDMMC_INTMASK_SBE | \ - SDMMC_INTMASK_EBE) +#define SDMMC_LL_EVENT_DEFAULT \ + (SDMMC_LL_EVENT_CD | SDMMC_LL_EVENT_RESP_ERR | SDMMC_LL_EVENT_CMD_DONE | SDMMC_LL_EVENT_DATA_OVER | \ + SDMMC_LL_EVENT_RCRC | SDMMC_LL_EVENT_DCRC | SDMMC_LL_EVENT_RTO | SDMMC_LL_EVENT_DTO | SDMMC_LL_EVENT_HTO | \ + SDMMC_LL_EVENT_HLE | \ + SDMMC_LL_EVENT_SBE | \ + 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 @@ -58,6 +89,9 @@ typedef enum { } sdmmc_ll_delay_phase_t; +/*--------------------------------------------------------------- + Clock & Reset +---------------------------------------------------------------*/ /** * @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) { + uint32_t reg_val = HAL_FORCE_READ_U32_REG_FIELD(hw->clkena, cclk_enable); if (en) { - hw->clkena.cclk_enable |= BIT(slot); + reg_val |= BIT(slot); } 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) { hw->clksrc.card0 = 0; - hw->clkdiv.div0 = card_div; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkdiv, div0, card_div); } else if (slot == 1) { hw->clksrc.card1 = 1; - hw->clkdiv.div1 = card_div; + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->clkdiv, div1, card_div); } else { 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) { 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) { HAL_ASSERT(hw->clksrc.card1 == 1); - card_div = hw->clkdiv.div1; + card_div = HAL_FORCE_READ_U32_REG_FIELD(hw->clkdiv, div1); } else { 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) { + uint32_t reg_val = HAL_FORCE_READ_U32_REG_FIELD(hw->clkena, cclk_low_power); if (en) { - hw->clkena.cclk_low_power |= BIT(slot); + reg_val |= BIT(slot); } 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 * @@ -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) { - 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) { + uint32_t ddr_reg_val = HAL_FORCE_READ_U32_REG_FIELD(hw->uhs, ddr); 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); } 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); } } @@ -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) { - 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; } +/** + * @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 * * @param hw hardware instance address - * @param slot slot * @param en enable / disable */ 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 */ -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 */ @@ -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 * @@ -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; } + +/** + * @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 } #endif diff --git a/components/hal/include/hal/sd_types.h b/components/hal/include/hal/sd_types.h new file mode 100644 index 0000000000..bdc2a6fa85 --- /dev/null +++ b/components/hal/include/hal/sd_types.h @@ -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 diff --git a/components/soc/esp32/include/soc/sdmmc_struct.h b/components/soc/esp32/include/soc/sdmmc_struct.h index 0af860aea8..82c075b0fa 100644 --- a/components/soc/esp32/include/soc/sdmmc_struct.h +++ b/components/soc/esp32/include/soc/sdmmc_struct.h @@ -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 */ @@ -146,10 +146,13 @@ typedef struct sdmmc_dev_t { uint32_t val; } ctype; - volatile struct { - uint32_t blksiz: 16; ///< block size, default 0x200 - uint32_t reserved: 16; - }; + volatile union { + struct { + uint32_t block_size: 16; ///< block size, default 0x200 + uint32_t reserved: 16; + }; + uint32_t val; + } blksiz; 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; /** 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; /** 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 reserved_16:2; /** 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; /** ram_indise_reg : RO; bitpos: [21]; default: 0; @@ -319,7 +322,7 @@ typedef struct sdmmc_dev_t { */ uint32_t ram_indise_reg: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 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 ddr: 16; ///< bit N enables DDR mode for card N }; + uint32_t val; } uhs; ///< UHS related settings volatile union { diff --git a/components/soc/esp32s3/include/soc/sdmmc_struct.h b/components/soc/esp32s3/include/soc/sdmmc_struct.h index c6078a7cca..44c98a9be6 100644 --- a/components/soc/esp32s3/include/soc/sdmmc_struct.h +++ b/components/soc/esp32s3/include/soc/sdmmc_struct.h @@ -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 */ @@ -144,10 +144,13 @@ typedef struct sdmmc_dev_t { uint32_t val; } ctype; - volatile struct { - uint32_t blksiz: 16; ///< block size, default 0x200 - uint32_t reserved: 16; - }; + volatile union { + struct { + uint32_t block_size: 16; ///< block size, default 0x200 + uint32_t reserved: 16; + }; + uint32_t val; + } blksiz; 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; /** 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; /** 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 reserved_16:2; /** 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; /** ram_indise_reg : RO; bitpos: [21]; default: 0; @@ -317,7 +320,7 @@ typedef struct sdmmc_dev_t { */ uint32_t ram_indise_reg: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 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 ddr: 16; ///< bit N enables DDR mode for card N }; + uint32_t val; } uhs; ///< UHS related settings volatile union {