diff --git a/components/driver/sdmmc/sdmmc_host.c b/components/driver/sdmmc/sdmmc_host.c index 926572f07f..f6f1e3e47c 100644 --- a/components/driver/sdmmc/sdmmc_host.c +++ b/components/driver/sdmmc/sdmmc_host.c @@ -29,16 +29,23 @@ #include "hal/sdmmc_hal.h" #include "hal/sdmmc_ll.h" -#define SDMMC_EVENT_QUEUE_LENGTH 32 -#define SDMMC_CLK_NEEDS_RCC CONFIG_IDF_TARGET_ESP32P4 +#define SDMMC_EVENT_QUEUE_LENGTH 32 -#if SDMMC_CLK_NEEDS_RCC +#if !SOC_RCC_IS_INDEPENDENT // Reset and Clock Control registers are mixing with other peripherals, so we need to use a critical section -#define SDMMC_RCC_ATOMIC() PERIPH_RCC_ATOMIC() +#define SDMMC_RCC_ATOMIC() PERIPH_RCC_ATOMIC() #else #define SDMMC_RCC_ATOMIC() #endif +#if SOC_PERIPH_CLK_CTRL_SHARED +// Clock source and related clock settings are mixing with other peripherals, so we need to use a critical section +#define SDMMC_CLK_SRC_ATOMIC() PERIPH_RCC_ATOMIC() +#else +#define SDMMC_CLK_SRC_ATOMIC() +#endif + + static const char *TAG = "sdmmc_periph"; /** @@ -119,7 +126,7 @@ esp_err_t sdmmc_host_reset(void) */ static void sdmmc_host_set_clk_div(int div) { - SDMMC_RCC_ATOMIC() { + SDMMC_CLK_SRC_ATOMIC() { sdmmc_ll_set_clock_div(s_host_ctx.hal.dev, div); sdmmc_ll_select_clk_source(s_host_ctx.hal.dev, SDMMC_CLK_SRC_DEFAULT); sdmmc_ll_init_phase_delay(s_host_ctx.hal.dev); @@ -325,7 +332,7 @@ esp_err_t sdmmc_host_set_input_delay(int slot, sdmmc_delay_phase_t delay_phase) delay_phase_num = 0; break; } - SDMMC_RCC_ATOMIC() { + SDMMC_CLK_SRC_ATOMIC() { sdmmc_ll_set_din_delay(s_host_ctx.hal.dev, phase); } @@ -379,15 +386,10 @@ esp_err_t sdmmc_host_init(void) } //enable bus clock for registers -#if SDMMC_CLK_NEEDS_RCC SDMMC_RCC_ATOMIC() { sdmmc_ll_enable_bus_clock(s_host_ctx.hal.dev, true); sdmmc_ll_reset_register(s_host_ctx.hal.dev); } -#else - periph_module_reset(PERIPH_SDMMC_MODULE); - periph_module_enable(PERIPH_SDMMC_MODULE); -#endif //hal context init sdmmc_hal_init(&s_host_ctx.hal); @@ -678,14 +680,10 @@ esp_err_t sdmmc_host_deinit(void) s_host_ctx.io_intr_event = NULL; sdmmc_ll_deinit_clk(s_host_ctx.hal.dev); sdmmc_host_transaction_handler_deinit(); -#if SDMMC_CLK_NEEDS_RCC //disable bus clock for registers SDMMC_RCC_ATOMIC() { sdmmc_ll_enable_bus_clock(s_host_ctx.hal.dev, false); } -#else - periph_module_disable(PERIPH_SDMMC_MODULE); -#endif return ESP_OK; } diff --git a/components/hal/esp32/include/hal/sdmmc_ll.h b/components/hal/esp32/include/hal/sdmmc_ll.h index d22a64010b..497b950d9a 100644 --- a/components/hal/esp32/include/hal/sdmmc_ll.h +++ b/components/hal/esp32/include/hal/sdmmc_ll.h @@ -18,6 +18,7 @@ #include "hal/assert.h" #include "soc/clk_tree_defs.h" #include "soc/sdmmc_struct.h" +#include "soc/dport_reg.h" #ifdef __cplusplus extern "C" { @@ -40,6 +41,41 @@ typedef enum { SDMMC_LL_DELAY_PHASE_3, } sdmmc_ll_delay_phase_t; + +/** + * @brief Enable the bus clock for SDMMC module + * + * @param hw hardware instance address + * @param en enable / disable + */ +static inline void sdmmc_ll_enable_bus_clock(sdmmc_dev_t *hw, bool en) +{ + if (en) { + DPORT_SET_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_SDIO_HOST_EN); + } else { + DPORT_CLEAR_PERI_REG_MASK(DPORT_WIFI_CLK_EN_REG, DPORT_WIFI_CLK_SDIO_HOST_EN); + } +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define sdmmc_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; sdmmc_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the SDMMC module + * + * @param hw hardware instance address + */ +static inline void sdmmc_ll_reset_register(sdmmc_dev_t *hw) +{ + DPORT_SET_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, DPORT_SDIO_HOST_RST); + DPORT_CLEAR_PERI_REG_MASK(DPORT_CORE_RST_EN_REG, DPORT_SDIO_HOST_RST); +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define sdmmc_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; sdmmc_ll_reset_register(__VA_ARGS__) + /** * @brief Select SDMMC clock source * diff --git a/components/hal/esp32s3/include/hal/sdmmc_ll.h b/components/hal/esp32s3/include/hal/sdmmc_ll.h index 5ceca775b3..4581aeb992 100644 --- a/components/hal/esp32s3/include/hal/sdmmc_ll.h +++ b/components/hal/esp32s3/include/hal/sdmmc_ll.h @@ -18,6 +18,7 @@ #include "hal/assert.h" #include "soc/clk_tree_defs.h" #include "soc/sdmmc_struct.h" +#include "soc/system_struct.h" #ifdef __cplusplus extern "C" { @@ -39,6 +40,37 @@ typedef enum { SDMMC_LL_DELAY_PHASE_3, } sdmmc_ll_delay_phase_t; + +/** + * @brief Enable the bus clock for SDMMC module + * + * @param hw hardware instance address + * @param en enable / disable + */ +static inline void sdmmc_ll_enable_bus_clock(sdmmc_dev_t *hw, bool en) +{ + SYSTEM.perip_clk_en1.sdio_host_clk_en = en; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define sdmmc_ll_enable_bus_clock(...) (void)__DECLARE_RCC_ATOMIC_ENV; sdmmc_ll_enable_bus_clock(__VA_ARGS__) + +/** + * @brief Reset the SDMMC module + * + * @param hw hardware instance address + */ +static inline void sdmmc_ll_reset_register(sdmmc_dev_t *hw) +{ + SYSTEM.perip_rst_en1.sdio_host_rst = 1; + SYSTEM.perip_rst_en1.sdio_host_rst = 0; +} + +/// use a macro to wrap the function, force the caller to use it in a critical section +/// the critical section needs to declare the __DECLARE_RCC_ATOMIC_ENV variable in advance +#define sdmmc_ll_reset_register(...) (void)__DECLARE_RCC_ATOMIC_ENV; sdmmc_ll_reset_register(__VA_ARGS__) + /** * @brief Select SDMMC clock source *