From 014dddad1fbb81bc474a42167a05cc23cf9fac9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20M=C3=BAdry?= Date: Tue, 6 Aug 2024 10:34:13 +0200 Subject: [PATCH] feat(sdmmc): Concurrent use of SDMMC peripheral Host and device (card, etc.) initialization is not thread-safe. After initialization transactions are serialized and guarded by mutex. Changed `SDMMC_HOST_DEFAULT()` default deinit function to `sdmmc_host_deinit_slot` which has a slot number as argument. --- .../include/driver/sdmmc_default_configs.h | 7 +- .../include/driver/sdmmc_host.h | 41 +++- components/esp_driver_sdmmc/src/sdmmc_host.c | 198 +++++++++++++++--- components/hal/esp32/include/hal/sdmmc_ll.h | 30 ++- components/hal/esp32p4/include/hal/sdmmc_ll.h | 30 ++- components/hal/esp32s3/include/hal/sdmmc_ll.h | 30 ++- components/soc/include/soc/sdmmc_periph.h | 32 +-- 7 files changed, 318 insertions(+), 50 deletions(-) diff --git a/components/esp_driver_sdmmc/include/driver/sdmmc_default_configs.h b/components/esp_driver_sdmmc/include/driver/sdmmc_default_configs.h index add6c4c859..7b72fdb201 100644 --- a/components/esp_driver_sdmmc/include/driver/sdmmc_default_configs.h +++ b/components/esp_driver_sdmmc/include/driver/sdmmc_default_configs.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -26,7 +26,8 @@ extern "C" { .flags = SDMMC_HOST_FLAG_8BIT | \ SDMMC_HOST_FLAG_4BIT | \ SDMMC_HOST_FLAG_1BIT | \ - SDMMC_HOST_FLAG_DDR, \ + SDMMC_HOST_FLAG_DDR | \ + SDMMC_HOST_FLAG_DEINIT_ARG, \ .slot = SDMMC_HOST_SLOT_1, \ .max_freq_khz = SDMMC_FREQ_DEFAULT, \ .io_voltage = 3.3f, \ @@ -37,7 +38,7 @@ extern "C" { .set_card_clk = &sdmmc_host_set_card_clk, \ .set_cclk_always_on = &sdmmc_host_set_cclk_always_on, \ .do_transaction = &sdmmc_host_do_transaction, \ - .deinit = &sdmmc_host_deinit, \ + .deinit_p = &sdmmc_host_deinit_slot, \ .io_int_enable = sdmmc_host_io_int_enable, \ .io_int_wait = sdmmc_host_io_int_wait, \ .command_timeout_ms = 0, \ diff --git a/components/esp_driver_sdmmc/include/driver/sdmmc_host.h b/components/esp_driver_sdmmc/include/driver/sdmmc_host.h index fe2fb52cb6..51fbb33474 100644 --- a/components/esp_driver_sdmmc/include/driver/sdmmc_host.h +++ b/components/esp_driver_sdmmc/include/driver/sdmmc_host.h @@ -58,6 +58,14 @@ typedef struct { */ } sdmmc_slot_config_t; +/** + * SD/MMC host state structure + */ +typedef struct { + bool host_initialized; ///< Whether the host is initialized + int num_of_init_slots; ///< Number of initialized slots +} sdmmc_host_state_t; + /** * @brief Initialize SDMMC host peripheral * @@ -200,13 +208,31 @@ esp_err_t sdmmc_host_io_int_enable(int slot); esp_err_t sdmmc_host_io_int_wait(int slot, TickType_t timeout_ticks); /** - * @brief Disable SDMMC host and release allocated resources + * @brief Disable SDMMC host and release allocated resources gracefully + * + * @note If there are more than 1 active slots, this function will just decrease the reference count + * and won't actually disable the host until the last slot is disabled + * + * @note This function is not thread safe + * + * @param slot slot number (SDMMC_HOST_SLOT_0 or SDMMC_HOST_SLOT_1) + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_STATE if SDMMC host has not been initialized + * - ESP_ERR_INVALID_ARG if invalid slot number is used + */ +esp_err_t sdmmc_host_deinit_slot(int slot); + +/** + * @brief Disable SDMMC host and release allocated resources forcefully + * + * @note This function will deinitialize the host immediately, regardless of the number of active slots * * @note This function is not thread safe * * @return * - ESP_OK on success - * - ESP_ERR_INVALID_STATE if sdmmc_host_init function has not been called + * - ESP_ERR_INVALID_STATE if SDMMC host has not been initialized */ esp_err_t sdmmc_host_deinit(void); @@ -257,6 +283,17 @@ esp_err_t sdmmc_host_set_input_delay(int slot, sdmmc_delay_phase_t delay_phase); */ esp_err_t sdmmc_host_get_dma_info(int slot, esp_dma_mem_info_t *dma_mem_info); +/** + * @brief Get the state of SDMMC host + * + * @param[out] state output parameter for SDMMC host state structure + * + * @return + * - ESP_OK on success + * - ESP_ERR_INVALID_ARG on invalid argument + */ +esp_err_t sdmmc_host_get_state(sdmmc_host_state_t* state); + #ifdef __cplusplus } #endif diff --git a/components/esp_driver_sdmmc/src/sdmmc_host.c b/components/esp_driver_sdmmc/src/sdmmc_host.c index e13f13dfa5..b505ef747b 100644 --- a/components/esp_driver_sdmmc/src/sdmmc_host.c +++ b/components/esp_driver_sdmmc/src/sdmmc_host.c @@ -6,6 +6,7 @@ #include #include +#include #include #include "esp_log.h" #include "esp_intr_alloc.h" @@ -45,22 +46,6 @@ #define SDMMC_CLK_SRC_ATOMIC() #endif -/* 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 - */ -// Default enabled interrupts (sdio is enabled only when use): -#define SDMMC_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 SLOT_CHECK(slot_num) \ if (slot_num < 0 || slot_num >= SOC_SDMMC_NUM_SLOTS) { \ return ESP_ERR_INVALID_ARG; \ @@ -75,6 +60,11 @@ typedef struct slot_ctx_t { size_t slot_width; sdmmc_slot_io_info_t slot_gpio_num; bool use_gpio_matrix; +#if SOC_SDMMC_NUM_SLOTS >= 2 + int slot_host_div; + uint32_t slot_freq_khz; + sdmmc_ll_delay_phase_t slot_ll_delay_phase; +#endif } slot_ctx_t; /** @@ -86,13 +76,24 @@ typedef struct host_ctx_t { SemaphoreHandle_t io_intr_event; sdmmc_hal_context_t hal; slot_ctx_t slot_ctx[SOC_SDMMC_NUM_SLOTS]; +#if SOC_SDMMC_NUM_SLOTS >= 2 + uint8_t num_of_init_slots; + int8_t active_slot_num; +#endif } host_ctx_t; +#if SOC_SDMMC_NUM_SLOTS >= 2 +static host_ctx_t s_host_ctx = {.active_slot_num = -1}; +#else 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); +#if SOC_SDMMC_NUM_SLOTS >= 2 +static void sdmmc_host_change_to_slot(int slot); +#endif esp_err_t sdmmc_host_reset(void) { @@ -298,7 +299,12 @@ esp_err_t sdmmc_host_set_card_clk(int slot, uint32_t freq_khz) sdmmc_host_set_data_timeout(freq_khz); // always set response timeout to highest value, it's small enough anyway sdmmc_ll_set_response_timeout(s_host_ctx.hal.dev, 255); - +#if SOC_SDMMC_NUM_SLOTS >= 2 + // save the current frequency + s_host_ctx.slot_ctx[slot].slot_freq_khz = freq_khz; + // save host_div value + s_host_ctx.slot_ctx[slot].slot_host_div = host_div; +#endif return ESP_OK; } @@ -360,6 +366,10 @@ esp_err_t sdmmc_host_set_input_delay(int slot, sdmmc_delay_phase_t delay_phase) int phase_diff_ps = src_clk_period_ps * sdmmc_ll_get_clock_div(s_host_ctx.hal.dev) / SOC_SDMMC_DELAY_PHASE_NUM; ESP_LOGD(TAG, "difference between input delay phases is %d ps", phase_diff_ps); ESP_LOGI(TAG, "host sampling edge is delayed by %d ps", phase_diff_ps * delay_phase_num); +#if SOC_SDMMC_NUM_SLOTS >= 2 + // save the current phase delay setting + s_host_ctx.slot_ctx[slot].slot_ll_delay_phase = phase; +#endif #endif return ESP_OK; @@ -369,6 +379,11 @@ esp_err_t sdmmc_host_start_command(int slot, sdmmc_hw_cmd_t cmd, uint32_t arg) { SLOT_CHECK(slot); +#if SOC_SDMMC_NUM_SLOTS >= 2 + // change the host settings to the appropriate slot before starting the transaction + sdmmc_host_change_to_slot(slot); +#endif + // if this isn't a clock update command, check the card detect status if (!sdmmc_ll_is_card_detected(s_host_ctx.hal.dev, slot) && !cmd.update_clk_reg) { return ESP_ERR_NOT_FOUND; @@ -401,15 +416,16 @@ esp_err_t sdmmc_host_start_command(int slot, sdmmc_hw_cmd_t cmd, uint32_t arg) static void sdmmc_host_intmask_clear_disable(void) { - SDMMC.rintsts.val = 0xffffffff; - SDMMC.intmask.val = 0; - SDMMC.ctrl.int_enable = 0; + sdmmc_ll_clear_interrupt(s_host_ctx.hal.dev, 0xffffffff); + sdmmc_ll_enable_interrupt(s_host_ctx.hal.dev, 0xffffffff, false); + sdmmc_ll_enable_global_interrupt(s_host_ctx.hal.dev, false); } -static void sdmmc_host_intmask_set_enable(uint32_t mask) +static void sdmmc_host_intmask_set_enable(void) { - SDMMC.intmask.val = mask; - SDMMC.ctrl.int_enable = 1; + 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_global_interrupt(s_host_ctx.hal.dev, true); } esp_err_t sdmmc_host_init(void) @@ -464,7 +480,7 @@ esp_err_t sdmmc_host_init(void) return ret; } // Enable interrupts - sdmmc_host_intmask_set_enable(SDMMC_INTMASK_DEFAULT); + sdmmc_host_intmask_set_enable(); // Disable generation of Busy Clear Interrupt SDMMC.cardthrctl.busy_clr_int_en = 0; @@ -562,6 +578,8 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config) return ESP_ERR_INVALID_ARG; } s_host_ctx.slot_ctx[slot].slot_width = slot_width; + s_host_ctx.slot_ctx[slot].slot_gpio_num.cd = gpio_cd; + s_host_ctx.slot_ctx[slot].slot_gpio_num.wp = gpio_wp; bool pin_not_set = s_check_pin_not_set(slot_config); //SD driver behaviour is: all pins not defined == using iomux @@ -615,7 +633,7 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config) bool pullup = slot_config->flags & SDMMC_SLOT_FLAG_INTERNAL_PULLUP; if (pullup) { - sdmmc_host_pullup_en_internal(slot, slot_config->width); + sdmmc_host_pullup_en_internal(slot, s_host_ctx.slot_ctx[slot].slot_width); } configure_pin(s_host_ctx.slot_ctx[slot].slot_gpio_num.clk, sdmmc_slot_gpio_sig[slot].clk, GPIO_MODE_OUTPUT, "clk", use_gpio_matrix); @@ -689,14 +707,17 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config) return ret; } +#if SOC_SDMMC_NUM_SLOTS >= 2 + if (s_host_ctx.num_of_init_slots < SOC_SDMMC_NUM_SLOTS && s_host_ctx.active_slot_num != slot) { + s_host_ctx.num_of_init_slots += 1; + } + s_host_ctx.active_slot_num = slot; +#endif return ESP_OK; } -esp_err_t sdmmc_host_deinit(void) +static void sdmmc_host_deinit_internal(void) { - if (!s_host_ctx.intr_handle) { - return ESP_ERR_INVALID_STATE; - } esp_intr_free(s_host_ctx.intr_handle); s_host_ctx.intr_handle = NULL; vQueueDelete(s_host_ctx.event_queue); @@ -709,10 +730,110 @@ esp_err_t sdmmc_host_deinit(void) SDMMC_RCC_ATOMIC() { sdmmc_ll_enable_bus_clock(s_host_ctx.hal.dev, false); } + ESP_LOGD(TAG, "SDMMC host deinitialized"); +} + +static int sdmmc_host_decrease_init_slot_num(void) +{ +#if SOC_SDMMC_NUM_SLOTS >= 2 + s_host_ctx.active_slot_num = -1; // Reset the active slot number, will be set again before the next transaction + if (s_host_ctx.num_of_init_slots > 0) { + s_host_ctx.num_of_init_slots -= 1; + } + return s_host_ctx.num_of_init_slots; +#else + return 0; +#endif +} + +static void sdmmc_host_deinit_slot_internal(int slot) +{ + int8_t gpio_pin_num; + sdmmc_slot_io_info_t* gpio = &s_host_ctx.slot_ctx[slot].slot_gpio_num; + // Disconnect signals and reset used GPIO pins + for (size_t i = 0; i < (sizeof(gpio->val) / (sizeof(gpio->val[0]))); i++) { + gpio_pin_num = gpio->val[i]; + if (gpio_pin_num != GPIO_NUM_NC && GPIO_IS_VALID_GPIO(gpio_pin_num)) { + gpio_reset_pin(gpio_pin_num); + } + } + // Reset the slot context + memset(&(s_host_ctx.slot_ctx[slot]), 0, sizeof(slot_ctx_t)); +} + +esp_err_t sdmmc_host_deinit_slot(int slot) +{ + if (!(slot == 0 || slot == 1)) { + return ESP_ERR_INVALID_ARG; + } + if (!s_host_ctx.intr_handle) { + return ESP_ERR_INVALID_STATE; + } + sdmmc_host_deinit_slot_internal(slot); + int num_of_init_slots = sdmmc_host_decrease_init_slot_num(); + if (num_of_init_slots != 0) { + ESP_LOGD(TAG, "SDMMC host not deinitialized yet, number of initialized slots: %d", + num_of_init_slots); + return ESP_OK; + } + sdmmc_host_deinit_internal(); return ESP_OK; } +esp_err_t sdmmc_host_deinit(void) +{ + if (!s_host_ctx.intr_handle) { + return ESP_ERR_INVALID_STATE; + } + for (int slot = 0; slot < SOC_SDMMC_NUM_SLOTS; slot++) { + sdmmc_host_deinit_slot_internal(slot); + } + sdmmc_host_deinit_internal(); + + return ESP_OK; +} + +static bool sdmmc_host_slot_initialized(int slot) +{ + // slot_host_div is initialized to 0 and is set in sdmmc_host_set_card_clk during card initialization + // during card deinitialization it is set back to 0 + // should not be 0 if the slot is initialized + if (s_host_ctx.slot_ctx[slot].slot_host_div == 0) { + return false; + } + return true; +} + +#if SOC_SDMMC_NUM_SLOTS >= 2 +static void sdmmc_host_change_to_slot(int slot) +{ + // If the slot is not initialized (slot_host_div not set) or already active, do nothing + if (s_host_ctx.active_slot_num == slot || sdmmc_host_slot_initialized(slot) == false) { + return; + } + s_host_ctx.active_slot_num = slot; + + // Clear interrupt status and set interrupt mask to known state + sdmmc_host_intmask_clear_disable(); + + // Apply the appropriate saved host settings for the new slot before starting the transaction + SDMMC_CLK_SRC_ATOMIC() { + sdmmc_ll_set_clock_div(s_host_ctx.hal.dev, s_host_ctx.slot_ctx[slot].slot_host_div); +#if !CONFIG_IDF_TARGET_ESP32 + sdmmc_ll_set_din_delay(s_host_ctx.hal.dev, s_host_ctx.slot_ctx[slot].slot_ll_delay_phase); +#endif + } + sdmmc_host_set_data_timeout(s_host_ctx.slot_ctx[slot].slot_freq_khz); + + // Wait for the clock to propagate + esp_rom_delay_us(10); + + // Enable interrupts again + sdmmc_host_intmask_set_enable(); +} +#endif // SOC_SDMMC_NUM_SLOTS >= 2 + esp_err_t sdmmc_host_wait_for_event(int tick_count, sdmmc_event_t *out_event) { if (!out_event) { @@ -957,3 +1078,22 @@ esp_err_t sdmmc_host_get_dma_info(int slot, esp_dma_mem_info_t *dma_mem_info) dma_mem_info->dma_alignment_bytes = 4; return ESP_OK; } + +esp_err_t sdmmc_host_get_state(sdmmc_host_state_t* state) +{ + if (state == NULL) { + return ESP_ERR_INVALID_ARG; + } + + if (s_host_ctx.intr_handle) { + state->host_initialized = true; + state->num_of_init_slots = 1; + } else { + state->host_initialized = false; + state->num_of_init_slots = 0; + } +#if SOC_SDMMC_NUM_SLOTS >= 2 + state->num_of_init_slots = s_host_ctx.num_of_init_slots; +#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 424528b3a6..841a6b226f 100644 --- a/components/hal/esp32/include/hal/sdmmc_ll.h +++ b/components/hal/esp32/include/hal/sdmmc_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +18,7 @@ #include "hal/assert.h" #include "soc/clk_tree_defs.h" #include "soc/sdmmc_struct.h" +#include "soc/sdmmc_reg.h" #include "soc/dport_reg.h" #ifdef __cplusplus @@ -26,6 +27,22 @@ extern "C" { #define SDMMC_LL_GET_HW(id) (((id) == 0) ? (&SDMMC) : NULL) +/* 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 + */ +// 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) + /** * SDMMC capabilities */ @@ -391,6 +408,17 @@ static inline void sdmmc_ll_clear_interrupt(sdmmc_dev_t *hw, uint32_t mask) hw->rintsts.val = mask; } +/** + * @brief Enable / disable interrupts globally + * + * @param hw hardware instance address + * @param en enable / disable + */ +static inline void sdmmc_ll_enable_global_interrupt(sdmmc_dev_t *hw, bool en) +{ + hw->ctrl.int_enable = (uint32_t)en; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32p4/include/hal/sdmmc_ll.h b/components/hal/esp32p4/include/hal/sdmmc_ll.h index 07125faf5a..210df60123 100644 --- a/components/hal/esp32p4/include/hal/sdmmc_ll.h +++ b/components/hal/esp32p4/include/hal/sdmmc_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +18,7 @@ #include "hal/assert.h" #include "soc/clk_tree_defs.h" #include "soc/sdmmc_struct.h" +#include "soc/sdmmc_reg.h" #include "soc/hp_sys_clkrst_struct.h" #include "soc/lp_clkrst_struct.h" @@ -28,6 +29,22 @@ extern "C" { #define SDMMC_LL_GET_HW(id) (((id) == 0) ? (&SDMMC) : NULL) +/* 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 + */ +// 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) + /** * SDMMC capabilities */ @@ -438,6 +455,17 @@ static inline void sdmmc_ll_clear_interrupt(sdmmc_dev_t *hw, uint32_t mask) hw->rintsts.val = mask; } +/** + * @brief Enable / disable interrupts globally + * + * @param hw hardware instance address + * @param en enable / disable + */ +static inline void sdmmc_ll_enable_global_interrupt(sdmmc_dev_t *hw, bool en) +{ + hw->ctrl.int_enable = (uint32_t)en; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s3/include/hal/sdmmc_ll.h b/components/hal/esp32s3/include/hal/sdmmc_ll.h index 101bb970fc..fe4cb0a106 100644 --- a/components/hal/esp32s3/include/hal/sdmmc_ll.h +++ b/components/hal/esp32s3/include/hal/sdmmc_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +18,7 @@ #include "hal/assert.h" #include "soc/clk_tree_defs.h" #include "soc/sdmmc_struct.h" +#include "soc/sdmmc_reg.h" #include "soc/system_struct.h" #ifdef __cplusplus @@ -26,6 +27,22 @@ extern "C" { #define SDMMC_LL_GET_HW(id) (((id) == 0) ? (&SDMMC) : NULL) +/* 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 + */ +// 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) + /** * SDMMC capabilities */ @@ -427,6 +444,17 @@ static inline void sdmmc_ll_clear_interrupt(sdmmc_dev_t *hw, uint32_t mask) hw->rintsts.val = mask; } +/** + * @brief Enable / disable interrupts globally + * + * @param hw hardware instance address + * @param en enable / disable + */ +static inline void sdmmc_ll_enable_global_interrupt(sdmmc_dev_t *hw, bool en) +{ + hw->ctrl.int_enable = (uint32_t)en; +} + #ifdef __cplusplus } #endif diff --git a/components/soc/include/soc/sdmmc_periph.h b/components/soc/include/soc/sdmmc_periph.h index 603e578480..fe646f5325 100644 --- a/components/soc/include/soc/sdmmc_periph.h +++ b/components/soc/include/soc/sdmmc_periph.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 */ @@ -9,6 +9,7 @@ //include soc related (generated) definitions #include "soc/soc_caps.h" #include "soc/soc_pins.h" +#include "soc/gpio_num.h" #if SOC_SDMMC_HOST_SUPPORTED #include "soc/sdmmc_reg.h" #include "soc/sdmmc_struct.h" @@ -31,7 +32,7 @@ typedef struct { uint8_t card_int; /*!< Card interrupt signal in GPIO Matrix */ } sdmmc_slot_info_t; -/** Width and GPIO matrix signal numbers for auxillary SD host signals, one structure per slot */ +/** Width and GPIO matrix signal numbers for auxiliary SD host signals, one structure per slot */ extern const sdmmc_slot_info_t sdmmc_slot_info[SOC_SDMMC_NUM_SLOTS]; /** @@ -39,17 +40,22 @@ extern const sdmmc_slot_info_t sdmmc_slot_info[SOC_SDMMC_NUM_SLOTS]; * or GPIO Matrix signal numbers (if SOC_SDMMC_USE_GPIO_MATRIX is set) * for the SD bus signals. Field names match SD bus signal names. */ -typedef struct { - uint8_t clk; - uint8_t cmd; - uint8_t d0; - uint8_t d1; - uint8_t d2; - uint8_t d3; - uint8_t d4; - uint8_t d5; - uint8_t d6; - uint8_t d7; +typedef union { + struct { + gpio_num_t cd; + gpio_num_t wp; + gpio_num_t clk; + gpio_num_t cmd; + gpio_num_t d0; + gpio_num_t d1; + gpio_num_t d2; + gpio_num_t d3; + gpio_num_t d4; + gpio_num_t d5; + gpio_num_t d6; + gpio_num_t d7; + }; + gpio_num_t val[12]; // for iteration, num of entries in struct } sdmmc_slot_io_info_t; /** GPIO pin numbers of SD bus signals, one structure per slot */