diff --git a/components/driver/CMakeLists.txt b/components/driver/CMakeLists.txt index a39965b633..fcac19fe12 100644 --- a/components/driver/CMakeLists.txt +++ b/components/driver/CMakeLists.txt @@ -57,6 +57,8 @@ if(${target} STREQUAL "esp32s3") list(APPEND srcs "adc_common.c" "dedic_gpio.c" "gdma.c" + "sdmmc_host.c" + "sdmmc_transaction.c" "spi_slave_hd.c" "touch_sensor_common.c" ) diff --git a/components/driver/include/driver/sdmmc_host.h b/components/driver/include/driver/sdmmc_host.h index e9da4ae190..e381d4337c 100644 --- a/components/driver/include/driver/sdmmc_host.h +++ b/components/driver/include/driver/sdmmc_host.h @@ -59,8 +59,26 @@ extern "C" { * Extra configuration for SDMMC peripheral slot */ typedef struct { - gpio_num_t gpio_cd; ///< GPIO number of card detect signal - gpio_num_t gpio_wp; ///< GPIO number of write protect signal +#ifdef SOC_SDMMC_USE_GPIO_MATRIX + gpio_num_t clk; ///< GPIO number of CLK signal. + gpio_num_t cmd; ///< GPIO number of CMD signal. + gpio_num_t d0; ///< GPIO number of D0 signal. + gpio_num_t d1; ///< GPIO number of D1 signal. + gpio_num_t d2; ///< GPIO number of D2 signal. + gpio_num_t d3; ///< GPIO number of D3 signal. + gpio_num_t d4; ///< GPIO number of D4 signal. Ignored in 1- or 4- line mode. + gpio_num_t d5; ///< GPIO number of D5 signal. Ignored in 1- or 4- line mode. + gpio_num_t d6; ///< GPIO number of D6 signal. Ignored in 1- or 4- line mode. + gpio_num_t d7; ///< GPIO number of D7 signal. Ignored in 1- or 4- line mode. +#endif // SOC_SDMMC_USE_GPIO_MATRIX + union { + gpio_num_t gpio_cd; ///< GPIO number of card detect signal + gpio_num_t cd; ///< GPIO number of card detect signal; shorter name. + }; + union { + gpio_num_t gpio_wp; ///< GPIO number of write protect signal + gpio_num_t wp; ///< GPIO number of write protect signal; shorter name. + }; uint8_t width; ///< Bus width used by the slot (might be less than the max width supported) uint32_t flags; ///< Features used by this slot #define SDMMC_SLOT_FLAG_INTERNAL_PULLUP BIT(0) @@ -72,18 +90,44 @@ typedef struct { #define SDMMC_SLOT_NO_CD GPIO_NUM_NC ///< indicates that card detect line is not used #define SDMMC_SLOT_NO_WP GPIO_NUM_NC ///< indicates that write protect line is not used -#define SDMMC_SLOT_WIDTH_DEFAULT 0 ///< use the default width for the slot (8 for slot 0, 4 for slot 1) +#define SDMMC_SLOT_WIDTH_DEFAULT 0 ///< use the maximum possible width for the slot + +#ifdef SOC_SDMMC_USE_GPIO_MATRIX /** * Macro defining default configuration of SDMMC host slot */ #define SDMMC_SLOT_CONFIG_DEFAULT() {\ - .gpio_cd = SDMMC_SLOT_NO_CD, \ - .gpio_wp = SDMMC_SLOT_NO_WP, \ + .clk = GPIO_NUM_14, \ + .cmd = GPIO_NUM_15, \ + .d0 = GPIO_NUM_2, \ + .d1 = GPIO_NUM_4, \ + .d2 = GPIO_NUM_12, \ + .d3 = GPIO_NUM_13, \ + .d4 = GPIO_NUM_33, \ + .d5 = GPIO_NUM_34, \ + .d6 = GPIO_NUM_35, \ + .d7 = GPIO_NUM_36, \ + .cd = SDMMC_SLOT_NO_CD, \ + .wp = SDMMC_SLOT_NO_WP, \ .width = SDMMC_SLOT_WIDTH_DEFAULT, \ .flags = 0, \ } +#else // SOC_SDMMC_USE_GPIO_MATRIX + +/** + * Macro defining default configuration of SDMMC host slot + */ +#define SDMMC_SLOT_CONFIG_DEFAULT() {\ + .cd = SDMMC_SLOT_NO_CD, \ + .wp = SDMMC_SLOT_NO_WP, \ + .width = SDMMC_SLOT_WIDTH_DEFAULT, \ + .flags = 0, \ +} + +#endif // SOC_SDMMC_USE_GPIO_MATRIX + /** * @brief Initialize SDMMC host peripheral * @@ -226,6 +270,9 @@ esp_err_t sdmmc_host_deinit(void); /** * @brief Enable the pull-ups of sd pins. * + * This function is deprecated. Please set SDMMC_SLOT_FLAG_INTERNAL_PULLUP flag in + * sdmmc_slot_config_t::flags instead. + * * @note You should always place actual pullups on the lines instead of using * this function. Internal pullup resistance are high and not sufficient, may * cause instability in products. This is for debug or examples only. @@ -238,7 +285,7 @@ esp_err_t sdmmc_host_deinit(void); * - ESP_ERR_INVALID_ARG: if configured width larger than maximum the slot can * support */ -esp_err_t sdmmc_host_pullup_en(int slot, int width); +esp_err_t sdmmc_host_pullup_en(int slot, int width) __attribute__((deprecated)); #ifdef __cplusplus } diff --git a/components/driver/sdmmc_host.c b/components/driver/sdmmc_host.c index 30b5bdd22e..d20a4ce156 100644 --- a/components/driver/sdmmc_host.c +++ b/components/driver/sdmmc_host.c @@ -37,13 +37,44 @@ static void sdmmc_isr(void* arg); static void sdmmc_host_dma_init(void); - static const char* TAG = "sdmmc_periph"; static intr_handle_t s_intr_handle; static QueueHandle_t s_event_queue; static SemaphoreHandle_t s_io_intr_event; -size_t s_slot_width[2] = {1,1}; +static size_t s_slot_width[2] = {1, 1}; + +/* The following definitions are used to simplify GPIO configuration in the driver, + * whether IOMUX or GPIO Matrix is used by the chip. + * Two simple "APIs" are provided to the driver code: + * - configure_pin(name, slot, mode): Configures signal "name" for the given slot and mode. + * - GPIO_NUM(slot, name): Returns the GPIO number of signal "name" for the given slot. + * + * To make this work, configure_pin is defined as a macro that picks the parameters required + * for configuring GPIO matrix or IOMUX from relevant arrays, and passes them to either of + * configure_pin_gpio_matrix, configure_pin_iomux functions. + * Likewise, GPIO_NUM is a macro that picks the pin number from one of the two structures. + * + * Macros are used rather than inline functions to look up members of different structures + * with same names. E.g. the number of pin d3 is obtained either from .d3 member of + * sdmmc_slot_gpio_num array (for IOMUX) or from .d3 member of s_sdmmc_slot_gpio_num array + * (for GPIO matrix). + */ +#ifdef SOC_SDMMC_USE_GPIO_MATRIX +static void configure_pin_gpio_matrix(uint8_t gpio_num, uint8_t gpio_matrix_sig, gpio_mode_t mode, const char* name); +#define configure_pin(name, slot, mode) \ + configure_pin_gpio_matrix(s_sdmmc_slot_gpio_num[slot].name, sdmmc_slot_gpio_sig[slot].name, mode, #name) +static sdmmc_slot_io_info_t s_sdmmc_slot_gpio_num[SOC_SDMMC_NUM_SLOTS]; +#define GPIO_NUM(slot, name) s_sdmmc_slot_gpio_num[slot].name + +#elif SOC_SDMMC_USE_IOMUX +static void configure_pin_iomux(uint8_t gpio_num); +#define configure_pin(name, slot, mode) configure_pin_iomux(sdmmc_slot_gpio_num[slot].name) +#define GPIO_NUM(slot, name) sdmmc_slot_gpio_num[slot].name + +#endif // SOC_SDMMC_USE_GPIO_MATRIX + +static esp_err_t sdmmc_host_pullup_en_internal(int slot, int width); void sdmmc_host_reset(void) { @@ -94,9 +125,21 @@ static void sdmmc_host_set_clk_div(int div) SDMMC.clock.div_factor_p = p; SDMMC.clock.div_factor_h = h; SDMMC.clock.div_factor_m = p; + + // Make sure 160 MHz source clock is used +#if SOC_SDMMC_SUPPORT_XTAL_CLOCK + SDMMC.clock.clk_sel = 1; +#endif +#if SOC_SDMMC_USE_GPIO_MATRIX + // 90 degree phase on input and output clocks + const int inout_clock_phase = 1; +#else + // 180 degree phase on input and output clocks + const int inout_clock_phase = 4; +#endif // Set phases for in/out clocks - SDMMC.clock.phase_dout = 4; // 180 degree phase on the output clock - SDMMC.clock.phase_din = 4; // 180 degree phase on the input clock + SDMMC.clock.phase_dout = inout_clock_phase; + SDMMC.clock.phase_din = inout_clock_phase; SDMMC.clock.phase_core = 0; // Wait for the clock to propagate esp_rom_delay_us(10); @@ -294,20 +337,41 @@ esp_err_t sdmmc_host_init(void) return ESP_OK; } -static void configure_pin(int pin) +#ifdef SOC_SDMMC_USE_IOMUX + +static void configure_pin_iomux(uint8_t gpio_num) { const int sdmmc_func = 3; const int drive_strength = 3; - assert(pin!=GPIO_NUM_NC); - gpio_pulldown_dis(pin); + assert(gpio_num != (uint8_t) GPIO_NUM_NC); + gpio_pulldown_dis(gpio_num); - uint32_t reg = GPIO_PIN_MUX_REG[pin]; + uint32_t reg = GPIO_PIN_MUX_REG[gpio_num]; assert(reg != UINT32_MAX); PIN_INPUT_ENABLE(reg); gpio_hal_iomux_func_sel(reg, sdmmc_func); PIN_SET_DRV(reg, drive_strength); } +#elif SOC_SDMMC_USE_GPIO_MATRIX + +static void configure_pin_gpio_matrix(uint8_t gpio_num, uint8_t gpio_matrix_sig, gpio_mode_t mode, const char* name) +{ + assert (gpio_num != (uint8_t) GPIO_NUM_NC); + ESP_LOGD(TAG, "using GPIO%d as %s pin", gpio_num, name); + gpio_reset_pin(gpio_num); + gpio_set_direction(gpio_num, mode); + gpio_pulldown_dis(gpio_num); + if (mode == GPIO_MODE_INPUT || mode == GPIO_MODE_INPUT_OUTPUT) { + esp_rom_gpio_connect_in_signal(gpio_num, gpio_matrix_sig, false); + } + if (mode == GPIO_MODE_OUTPUT || mode == GPIO_MODE_INPUT_OUTPUT) { + esp_rom_gpio_connect_out_signal(gpio_num, gpio_matrix_sig, false, false); + } +} + +#endif // SOC_SDMMC_USE_{IOMUX,GPIO_MATRIX} + esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t* slot_config) { if (!s_intr_handle) { @@ -319,54 +383,75 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t* slot_config) if (slot_config == NULL) { return ESP_ERR_INVALID_ARG; } - bool pullup = slot_config->flags & SDMMC_SLOT_FLAG_INTERNAL_PULLUP; - if (pullup) { - sdmmc_host_pullup_en(slot, slot_config->width); - } - int gpio_cd = slot_config->gpio_cd; - int gpio_wp = slot_config->gpio_wp; + int gpio_cd = slot_config->cd; + int gpio_wp = slot_config->wp; uint8_t slot_width = slot_config->width; // Configure pins - const sdmmc_slot_info_t* pslot = &sdmmc_slot_info[slot]; + const sdmmc_slot_info_t* slot_info = &sdmmc_slot_info[slot]; if (slot_width == SDMMC_SLOT_WIDTH_DEFAULT) { - slot_width = pslot->width; + slot_width = slot_info->width; } - else if (slot_width > pslot->width) { + else if (slot_width > slot_info->width) { return ESP_ERR_INVALID_ARG; } s_slot_width[slot] = slot_width; - configure_pin(pslot->clk_gpio); - configure_pin(pslot->cmd_gpio); - configure_pin(pslot->d0_gpio); +#if SOC_SDMMC_USE_GPIO_MATRIX + /* Save pin configuration for this slot */ + s_sdmmc_slot_gpio_num[slot].clk = slot_config->clk; + s_sdmmc_slot_gpio_num[slot].cmd = slot_config->cmd; + s_sdmmc_slot_gpio_num[slot].d0 = slot_config->d0; + /* Save d1 even in 1-line mode, it might be needed for SDIO INT line */ + s_sdmmc_slot_gpio_num[slot].d1 = slot_config->d1; + if (slot_width >= 4) { + s_sdmmc_slot_gpio_num[slot].d2 = slot_config->d2; + } + /* Save d3 even for 1-line mode, as it needs to be set high */ + s_sdmmc_slot_gpio_num[slot].d3 = slot_config->d3; + if (slot_width >= 8) { + s_sdmmc_slot_gpio_num[slot].d4 = slot_config->d4; + s_sdmmc_slot_gpio_num[slot].d5 = slot_config->d5; + s_sdmmc_slot_gpio_num[slot].d6 = slot_config->d6; + s_sdmmc_slot_gpio_num[slot].d7 = slot_config->d7; + } +#endif + + bool pullup = slot_config->flags & SDMMC_SLOT_FLAG_INTERNAL_PULLUP; + if (pullup) { + sdmmc_host_pullup_en_internal(slot, slot_config->width); + } + + configure_pin(clk, slot, GPIO_MODE_OUTPUT); + configure_pin(cmd, slot, GPIO_MODE_INPUT_OUTPUT); + configure_pin(d0, slot, GPIO_MODE_INPUT_OUTPUT); if (slot_width >= 4) { - configure_pin(pslot->d1_gpio); - configure_pin(pslot->d2_gpio); + configure_pin(d1, slot, GPIO_MODE_INPUT_OUTPUT); + configure_pin(d2, slot, GPIO_MODE_INPUT_OUTPUT); // Force D3 high to make slave enter SD mode. // Connect to peripheral after width configuration. gpio_config_t gpio_conf = { - .pin_bit_mask = BIT64(pslot->d3_gpio), - .mode = GPIO_MODE_OUTPUT , + .pin_bit_mask = BIT64(GPIO_NUM(slot, d3)), + .mode = GPIO_MODE_OUTPUT, .pull_up_en = 0, .pull_down_en = 0, .intr_type = GPIO_INTR_DISABLE, }; gpio_config(&gpio_conf); - gpio_set_level(pslot->d3_gpio, 1); - if (slot_width == 8) { - configure_pin(pslot->d4_gpio); - configure_pin(pslot->d5_gpio); - configure_pin(pslot->d6_gpio); - configure_pin(pslot->d7_gpio); - } + gpio_set_level(GPIO_NUM(slot, d3), 1); + } + if (slot_width == 8) { + configure_pin(d4, slot, GPIO_MODE_INPUT_OUTPUT); + configure_pin(d5, slot, GPIO_MODE_INPUT_OUTPUT); + configure_pin(d6, slot, GPIO_MODE_INPUT_OUTPUT); + configure_pin(d7, slot, GPIO_MODE_INPUT_OUTPUT); } // SDIO slave interrupt is edge sensitive to ~(int_n | card_int | card_detect) // set this and card_detect to high to enable sdio interrupt - esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, pslot->card_int, false); + esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, slot_info->card_int, false); // Set up Card Detect input int matrix_in_cd; @@ -379,7 +464,7 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t* slot_config) // if not set, default to CD low (card present) matrix_in_cd = GPIO_MATRIX_CONST_ZERO_INPUT; } - esp_rom_gpio_connect_in_signal(matrix_in_cd, pslot->card_detect, false); + esp_rom_gpio_connect_in_signal(matrix_in_cd, slot_info->card_detect, false); // Set up Write Protect input int matrix_in_wp; @@ -394,7 +479,7 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t* slot_config) } // WP signal is normally active low, but hardware expects // an active-high signal, so invert it in GPIO matrix - esp_rom_gpio_connect_in_signal(matrix_in_wp, pslot->write_protect, true); + esp_rom_gpio_connect_in_signal(matrix_in_wp, slot_info->write_protect, true); // By default, set probing frequency (400kHz) and 1-bit bus esp_err_t ret = sdmmc_host_set_card_clk(slot, 400); @@ -456,11 +541,11 @@ esp_err_t sdmmc_host_set_bus_width(int slot, size_t width) SDMMC.ctype.card_width_8 &= ~mask; SDMMC.ctype.card_width |= mask; // D3 was set to GPIO high to force slave into SD mode, until 4-bit mode is set - configure_pin(sdmmc_slot_info[slot].d3_gpio); + configure_pin(d3, slot, GPIO_MODE_INPUT_OUTPUT); } else if (width == 8) { SDMMC.ctype.card_width_8 |= mask; // D3 was set to GPIO high to force slave into SD mode, until 4-bit mode is set - configure_pin(sdmmc_slot_info[slot].d3_gpio); + configure_pin(d3, slot, GPIO_MODE_INPUT_OUTPUT); } else { return ESP_ERR_INVALID_ARG; } @@ -542,7 +627,7 @@ bool sdmmc_host_card_busy(void) esp_err_t sdmmc_host_io_int_enable(int slot) { - configure_pin(sdmmc_slot_info[slot].d1_gpio); + configure_pin(d1, slot, GPIO_MODE_INPUT_OUTPUT); return ESP_OK; } @@ -558,7 +643,7 @@ esp_err_t sdmmc_host_io_int_wait(int slot, TickType_t timeout_ticks) SDMMC.intmask.sdio &= ~BIT(slot); /* Disable SDIO interrupt */ SDMMC.rintsts.sdio = BIT(slot); - if (gpio_get_level(sdmmc_slot_info[slot].d1_gpio) == 0) { + if (gpio_get_level(GPIO_NUM(slot, d1)) == 0) { return ESP_OK; } /* Otherwise, need to wait for an interrupt. Since D1 was high, @@ -619,25 +704,28 @@ static void sdmmc_isr(void* arg) { } } -esp_err_t sdmmc_host_pullup_en(int slot, int width) +static esp_err_t sdmmc_host_pullup_en_internal(int slot, int width) { if (width > sdmmc_slot_info[slot].width) { //in esp32 we only support 8 bit in slot 0, note this is occupied by the flash by default return ESP_ERR_INVALID_ARG; } - //according to the spec, the host control the clk, we don't to pull it up here - gpio_pullup_en(sdmmc_slot_info[slot].cmd_gpio); - gpio_pullup_en(sdmmc_slot_info[slot].d0_gpio); + // according to the spec, the host controls the clk, we don't to pull it up here + gpio_pullup_en(GPIO_NUM(slot, cmd)); + gpio_pullup_en(GPIO_NUM(slot, d0)); if (width >= 4) { - gpio_pullup_en(sdmmc_slot_info[slot].d1_gpio); - gpio_pullup_en(sdmmc_slot_info[slot].d2_gpio); - gpio_pullup_en(sdmmc_slot_info[slot].d3_gpio); + gpio_pullup_en(GPIO_NUM(slot, d1)); + gpio_pullup_en(GPIO_NUM(slot, d2)); + gpio_pullup_en(GPIO_NUM(slot, d3)); } if (width == 8) { - gpio_pullup_en(sdmmc_slot_info[slot].d4_gpio); - gpio_pullup_en(sdmmc_slot_info[slot].d5_gpio); - gpio_pullup_en(sdmmc_slot_info[slot].d6_gpio); - gpio_pullup_en(sdmmc_slot_info[slot].d7_gpio); + gpio_pullup_en(GPIO_NUM(slot, d4)); + gpio_pullup_en(GPIO_NUM(slot, d5)); + gpio_pullup_en(GPIO_NUM(slot, d6)); + gpio_pullup_en(GPIO_NUM(slot, d7)); } return ESP_OK; } + +/* Deprecared public function */ +esp_err_t sdmmc_host_pullup_en(int slot, int width) __attribute__((alias("sdmmc_host_pullup_en_internal"))); diff --git a/components/esp32s3/ld/esp32s3.peripherals.ld b/components/esp32s3/ld/esp32s3.peripherals.ld index 5e0188ee9a..4df638a025 100644 --- a/components/esp32s3/ld/esp32s3.peripherals.ld +++ b/components/esp32s3/ld/esp32s3.peripherals.ld @@ -28,6 +28,7 @@ PROVIDE ( GPSPI2 = 0x60024000 ); PROVIDE ( GPSPI3 = 0x60025000 ); PROVIDE ( SYSCON = 0x60026000 ); PROVIDE ( I2C1 = 0x60027000 ); +PROVIDE ( SDMMC = 0x60028000 ); PROVIDE ( TWAI = 0x6002B000 ); PROVIDE ( GPSPI4 = 0x60037000 ); PROVIDE ( GDMA = 0x6003F000 ); diff --git a/components/soc/esp32/include/soc/soc_caps.h b/components/soc/esp32/include/soc/soc_caps.h index 4fd8632706..2031df36ee 100644 --- a/components/soc/esp32/include/soc/soc_caps.h +++ b/components/soc/esp32/include/soc/soc_caps.h @@ -282,3 +282,11 @@ # define CAN_BRP_DIV_SUPPORTED SOC_TWAI_BRP_DIV_SUPPORTED # define CAN_BRP_DIV_THRESH SOC_TWAI_BRP_DIV_THRESH #endif + +/*-------------------------- SDMMC CAPS -----------------------------------------*/ + +/* On ESP32, clock/cmd/data pins use IO MUX. + * Card detect, write protect, interrupt use GPIO Matrix on all chips. + */ +#define SOC_SDMMC_USE_IOMUX 1 +#define SOC_SDMMC_NUM_SLOTS 2 diff --git a/components/soc/esp32/sdmmc_periph.c b/components/soc/esp32/sdmmc_periph.c index db3af78203..9b98bffcbb 100644 --- a/components/soc/esp32/sdmmc_periph.c +++ b/components/soc/esp32/sdmmc_periph.c @@ -14,37 +14,44 @@ #include "soc/sdmmc_periph.h" -const sdmmc_slot_info_t sdmmc_slot_info[2] = { +const sdmmc_slot_info_t sdmmc_slot_info[SOC_SDMMC_NUM_SLOTS] = { { - .clk_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_CLK, - .cmd_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_CMD, - .d0_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_D0, - .d1_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_D1, - .d2_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_D2, - .d3_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_D3, - .d4_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_D4, - .d5_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_D5, - .d6_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_D6, - .d7_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_D7, + .width = 8, .card_detect = HOST_CARD_DETECT_N_1_IDX, .write_protect = HOST_CARD_WRITE_PRT_1_IDX, .card_int = HOST_CARD_INT_N_1_IDX, - .width = 8 }, { - .clk_gpio = SDMMC_SLOT1_IOMUX_PIN_NUM_CLK, - .cmd_gpio = SDMMC_SLOT1_IOMUX_PIN_NUM_CMD, - .d0_gpio = SDMMC_SLOT1_IOMUX_PIN_NUM_D0, - .d1_gpio = SDMMC_SLOT1_IOMUX_PIN_NUM_D1, - .d2_gpio = SDMMC_SLOT1_IOMUX_PIN_NUM_D2, - .d3_gpio = SDMMC_SLOT1_IOMUX_PIN_NUM_D3, - .d4_gpio = -1, //slot1 has no D4-7 - .d5_gpio = -1, - .d6_gpio = -1, - .d7_gpio = -1, + .width = 4, .card_detect = HOST_CARD_DETECT_N_2_IDX, .write_protect = HOST_CARD_WRITE_PRT_2_IDX, .card_int = HOST_CARD_INT_N_2_IDX, - .width = 4 + } +}; + +const sdmmc_slot_io_info_t sdmmc_slot_gpio_num[SOC_SDMMC_NUM_SLOTS] = { + { + .clk = SDMMC_SLOT0_IOMUX_PIN_NUM_CLK, + .cmd = SDMMC_SLOT0_IOMUX_PIN_NUM_CMD, + .d0 = SDMMC_SLOT0_IOMUX_PIN_NUM_D0, + .d1 = SDMMC_SLOT0_IOMUX_PIN_NUM_D1, + .d2 = SDMMC_SLOT0_IOMUX_PIN_NUM_D2, + .d3 = SDMMC_SLOT0_IOMUX_PIN_NUM_D3, + .d4 = SDMMC_SLOT0_IOMUX_PIN_NUM_D4, + .d5 = SDMMC_SLOT0_IOMUX_PIN_NUM_D5, + .d6 = SDMMC_SLOT0_IOMUX_PIN_NUM_D6, + .d7 = SDMMC_SLOT0_IOMUX_PIN_NUM_D7, + }, + { + .clk = SDMMC_SLOT1_IOMUX_PIN_NUM_CLK, + .cmd = SDMMC_SLOT1_IOMUX_PIN_NUM_CMD, + .d0 = SDMMC_SLOT1_IOMUX_PIN_NUM_D0, + .d1 = SDMMC_SLOT1_IOMUX_PIN_NUM_D1, + .d2 = SDMMC_SLOT1_IOMUX_PIN_NUM_D2, + .d3 = SDMMC_SLOT1_IOMUX_PIN_NUM_D3, + .d4 = -1, //slot1 has no D4-7 + .d5 = -1, + .d6 = -1, + .d7 = -1, } }; diff --git a/components/soc/esp32s2/include/soc/sdmmc_reg.h b/components/soc/esp32s2/include/soc/sdmmc_reg.h deleted file mode 100644 index 2f9c68f80b..0000000000 --- a/components/soc/esp32s2/include/soc/sdmmc_reg.h +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef _SOC_SDMMC_REG_H_ -#define _SOC_SDMMC_REG_H_ -#include "soc.h" - -#define SDMMC_CTRL_REG (DR_REG_SDMMC_BASE + 0x00) -#define SDMMC_PWREN_REG (DR_REG_SDMMC_BASE + 0x04) -#define SDMMC_CLKDIV_REG (DR_REG_SDMMC_BASE + 0x08) -#define SDMMC_CLKSRC_REG (DR_REG_SDMMC_BASE + 0x0c) -#define SDMMC_CLKENA_REG (DR_REG_SDMMC_BASE + 0x10) -#define SDMMC_TMOUT_REG (DR_REG_SDMMC_BASE + 0x14) -#define SDMMC_CTYPE_REG (DR_REG_SDMMC_BASE + 0x18) -#define SDMMC_BLKSIZ_REG (DR_REG_SDMMC_BASE + 0x1c) -#define SDMMC_BYTCNT_REG (DR_REG_SDMMC_BASE + 0x20) -#define SDMMC_INTMASK_REG (DR_REG_SDMMC_BASE + 0x24) -#define SDMMC_CMDARG_REG (DR_REG_SDMMC_BASE + 0x28) -#define SDMMC_CMD_REG (DR_REG_SDMMC_BASE + 0x2c) -#define SDMMC_RESP0_REG (DR_REG_SDMMC_BASE + 0x30) -#define SDMMC_RESP1_REG (DR_REG_SDMMC_BASE + 0x34) -#define SDMMC_RESP2_REG (DR_REG_SDMMC_BASE + 0x38) -#define SDMMC_RESP3_REG (DR_REG_SDMMC_BASE + 0x3c) - -#define SDMMC_MINTSTS_REG (DR_REG_SDMMC_BASE + 0x40) -#define SDMMC_RINTSTS_REG (DR_REG_SDMMC_BASE + 0x44) -#define SDMMC_STATUS_REG (DR_REG_SDMMC_BASE + 0x48) -#define SDMMC_FIFOTH_REG (DR_REG_SDMMC_BASE + 0x4c) -#define SDMMC_CDETECT_REG (DR_REG_SDMMC_BASE + 0x50) -#define SDMMC_WRTPRT_REG (DR_REG_SDMMC_BASE + 0x54) -#define SDMMC_GPIO_REG (DR_REG_SDMMC_BASE + 0x58) -#define SDMMC_TCBCNT_REG (DR_REG_SDMMC_BASE + 0x5c) -#define SDMMC_TBBCNT_REG (DR_REG_SDMMC_BASE + 0x60) -#define SDMMC_DEBNCE_REG (DR_REG_SDMMC_BASE + 0x64) -#define SDMMC_USRID_REG (DR_REG_SDMMC_BASE + 0x68) -#define SDMMC_VERID_REG (DR_REG_SDMMC_BASE + 0x6c) -#define SDMMC_HCON_REG (DR_REG_SDMMC_BASE + 0x70) -#define SDMMC_UHS_REG_REG (DR_REG_SDMMC_BASE + 0x74) -#define SDMMC_RST_N_REG (DR_REG_SDMMC_BASE + 0x78) -#define SDMMC_BMOD_REG (DR_REG_SDMMC_BASE + 0x80) -#define SDMMC_PLDMND_REG (DR_REG_SDMMC_BASE + 0x84) -#define SDMMC_DBADDR_REG (DR_REG_SDMMC_BASE + 0x88) -#define SDMMC_DBADDRU_REG (DR_REG_SDMMC_BASE + 0x8c) -#define SDMMC_IDSTS_REG (DR_REG_SDMMC_BASE + 0x8c) -#define SDMMC_IDINTEN_REG (DR_REG_SDMMC_BASE + 0x90) -#define SDMMC_DSCADDR_REG (DR_REG_SDMMC_BASE + 0x94) -#define SDMMC_DSCADDRL_REG (DR_REG_SDMMC_BASE + 0x98) -#define SDMMC_DSCADDRU_REG (DR_REG_SDMMC_BASE + 0x9c) -#define SDMMC_BUFADDRL_REG (DR_REG_SDMMC_BASE + 0xa0) -#define SDMMC_BUFADDRU_REG (DR_REG_SDMMC_BASE + 0xa4) -#define SDMMC_CARDTHRCTL_REG (DR_REG_SDMMC_BASE + 0x100) -#define SDMMC_BACK_END_POWER_REG (DR_REG_SDMMC_BASE + 0x104) -#define SDMMC_UHS_REG_EXT_REG (DR_REG_SDMMC_BASE + 0x108) -#define SDMMC_EMMC_DDR_REG_REG (DR_REG_SDMMC_BASE + 0x10c) -#define SDMMC_ENABLE_SHIFT_REG (DR_REG_SDMMC_BASE + 0x110) - -#define SDMMC_CLOCK_REG (DR_REG_SDMMC_BASE + 0x800) - -#define SDMMC_INTMASK_IO_SLOT1 BIT(17) -#define SDMMC_INTMASK_IO_SLOT0 BIT(16) -#define SDMMC_INTMASK_EBE BIT(15) -#define SDMMC_INTMASK_ACD BIT(14) -#define SDMMC_INTMASK_SBE BIT(13) -#define SDMMC_INTMASK_HLE BIT(12) -#define SDMMC_INTMASK_FRUN BIT(11) -#define SDMMC_INTMASK_HTO BIT(10) -#define SDMMC_INTMASK_DTO BIT(9) -#define SDMMC_INTMASK_RTO BIT(8) -#define SDMMC_INTMASK_DCRC BIT(7) -#define SDMMC_INTMASK_RCRC BIT(6) -#define SDMMC_INTMASK_RXDR BIT(5) -#define SDMMC_INTMASK_TXDR BIT(4) -#define SDMMC_INTMASK_DATA_OVER BIT(3) -#define SDMMC_INTMASK_CMD_DONE BIT(2) -#define SDMMC_INTMASK_RESP_ERR BIT(1) -#define SDMMC_INTMASK_CD BIT(0) - -#define SDMMC_IDMAC_INTMASK_AI BIT(9) -#define SDMMC_IDMAC_INTMASK_NI BIT(8) -#define SDMMC_IDMAC_INTMASK_CES BIT(5) -#define SDMMC_IDMAC_INTMASK_DU BIT(4) -#define SDMMC_IDMAC_INTMASK_FBE BIT(2) -#define SDMMC_IDMAC_INTMASK_RI BIT(1) -#define SDMMC_IDMAC_INTMASK_TI BIT(0) - -#endif /* _SOC_SDMMC_REG_H_ */ diff --git a/components/soc/esp32s2/include/soc/sdmmc_struct.h b/components/soc/esp32s2/include/soc/sdmmc_struct.h deleted file mode 100644 index 7e3c6912eb..0000000000 --- a/components/soc/esp32s2/include/soc/sdmmc_struct.h +++ /dev/null @@ -1,377 +0,0 @@ -// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -#ifndef _SOC_SDMMC_STRUCT_H_ -#define _SOC_SDMMC_STRUCT_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - uint32_t reserved1: 1; - uint32_t disable_int_on_completion: 1; - uint32_t last_descriptor: 1; - uint32_t first_descriptor: 1; - uint32_t second_address_chained: 1; - uint32_t end_of_ring: 1; - uint32_t reserved2: 24; - uint32_t card_error_summary: 1; - uint32_t owned_by_idmac: 1; - uint32_t buffer1_size: 13; - uint32_t buffer2_size: 13; - uint32_t reserved3: 6; - void* buffer1_ptr; - union { - void* buffer2_ptr; - void* next_desc_ptr; - }; -} sdmmc_desc_t; - -#define SDMMC_DMA_MAX_BUF_LEN 4096 - -_Static_assert(sizeof(sdmmc_desc_t) == 16, "invalid size of sdmmc_desc_t structure"); - - -typedef struct { - uint32_t cmd_index: 6; ///< Command index - uint32_t response_expect: 1; ///< set if response is expected - uint32_t response_long: 1; ///< 0: short response expected, 1: long response expected - uint32_t check_response_crc: 1; ///< set if controller should check response CRC - uint32_t data_expected: 1; ///< 0: no data expected, 1: data expected - uint32_t rw: 1; ///< 0: read from card, 1: write to card (don't care if no data expected) - uint32_t stream_mode: 1; ///< 0: block transfer, 1: stream transfer (don't care if no data expected) - uint32_t send_auto_stop: 1; ///< set to send stop at the end of the transfer - uint32_t wait_complete: 1; ///< 0: send command at once, 1: wait for previous command to complete - uint32_t stop_abort_cmd: 1; ///< set if this is a stop or abort command intended to stop current transfer - uint32_t send_init: 1; ///< set to send init sequence (80 clocks of 1) - uint32_t card_num: 5; ///< card number - uint32_t update_clk_reg: 1; ///< 0: normal command, 1: don't send command, just update clock registers - uint32_t read_ceata: 1; ///< set if performing read from CE-ATA device - uint32_t ccs_expected: 1; ///< set if CCS is expected from CE-ATA device - uint32_t enable_boot: 1; ///< set for mandatory boot mode - uint32_t expect_boot_ack: 1; ///< when set along with enable_boot, controller expects boot ack pattern - uint32_t disable_boot: 1; ///< set to terminate boot operation (don't set along with enable_boot) - uint32_t boot_mode: 1; ///< 0: mandatory boot operation, 1: alternate boot operation - uint32_t volt_switch: 1; ///< set to enable voltage switching (for CMD11 only) - uint32_t use_hold_reg: 1; ///< clear to bypass HOLD register - uint32_t reserved: 1; - uint32_t start_command: 1; ///< Start command; once command is sent to the card, bit is cleared. -} sdmmc_hw_cmd_t; ///< command format used in cmd register; this structure is defined to make it easier to build command values - -_Static_assert(sizeof(sdmmc_hw_cmd_t) == 4, "invalid size of sdmmc_cmd_t structure"); - - -typedef volatile struct { - union { - struct { - uint32_t controller_reset: 1; - uint32_t fifo_reset: 1; - uint32_t dma_reset: 1; - uint32_t reserved1: 1; - uint32_t int_enable: 1; - uint32_t dma_enable: 1; - uint32_t read_wait: 1; - uint32_t send_irq_response: 1; - uint32_t abort_read_data: 1; - uint32_t send_ccsd: 1; - uint32_t send_auto_stop_ccsd: 1; - uint32_t ceata_device_interrupt_status: 1; - uint32_t reserved2: 4; - uint32_t card_voltage_a: 4; - uint32_t card_voltage_b: 4; - uint32_t enable_od_pullup: 1; - uint32_t use_internal_dma: 1; - uint32_t reserved3: 6; - }; - uint32_t val; - } ctrl; - - uint32_t pwren; ///< 1: enable power to card, 0: disable power to card - - union { - struct { - uint32_t div0: 8; ///< 0: bypass, 1-255: divide clock by (2*div0). - uint32_t div1: 8; ///< 0: bypass, 1-255: divide clock by (2*div0). - uint32_t div2: 8; ///< 0: bypass, 1-255: divide clock by (2*div0). - uint32_t div3: 8; ///< 0: bypass, 1-255: divide clock by (2*div0). - }; - uint32_t val; - } clkdiv; - - union { - struct { - uint32_t card0: 2; ///< 0-3: select clock divider for card 0 among div0-div3 - uint32_t card1: 2; ///< 0-3: select clock divider for card 1 among div0-div3 - uint32_t reserved: 28; - }; - uint32_t val; - } clksrc; - - union { - struct { - uint32_t cclk_enable: 16; ///< 1: enable clock to card, 0: disable clock - uint32_t cclk_low_power: 16; ///< 1: enable clock gating when card is idle, 0: disable clock gating - }; - uint32_t val; - } clkena; - - union { - struct { - uint32_t response: 8; ///< response timeout, in card output clock cycles - uint32_t data: 24; ///< data read timeout, in card output clock cycles - }; - uint32_t val; - } tmout; - - union { - struct { - uint32_t card_width: 16; ///< one bit for each card: 0: 1-bit mode, 1: 4-bit mode - uint32_t card_width_8: 16; ///< one bit for each card: 0: not 8-bit mode (corresponding card_width bit is used), 1: 8-bit mode (card_width bit is ignored) - }; - uint32_t val; - } ctype; - - uint32_t blksiz: 16; ///< block size, default 0x200 - uint32_t : 16; - - uint32_t bytcnt; ///< number of bytes to be transferred - - union { - struct { - uint32_t cd: 1; ///< Card detect interrupt enable - uint32_t re: 1; ///< Response error interrupt enable - uint32_t cmd_done: 1; ///< Command done interrupt enable - uint32_t dto: 1; ///< Data transfer over interrupt enable - uint32_t txdr: 1; ///< Transmit FIFO data request interrupt enable - uint32_t rxdr: 1; ///< Receive FIFO data request interrupt enable - uint32_t rcrc: 1; ///< Response CRC error interrupt enable - uint32_t dcrc: 1; ///< Data CRC error interrupt enable - uint32_t rto: 1; ///< Response timeout interrupt enable - uint32_t drto: 1; ///< Data read timeout interrupt enable - uint32_t hto: 1; ///< Data starvation-by-host timeout interrupt enable - uint32_t frun: 1; ///< FIFO underrun/overrun error interrupt enable - uint32_t hle: 1; ///< Hardware locked write error interrupt enable - uint32_t sbi_bci: 1; ///< Start bit error / busy clear interrupt enable - uint32_t acd: 1; ///< Auto command done interrupt enable - uint32_t ebe: 1; ///< End bit error / write no CRC interrupt enable - uint32_t sdio: 16; ///< SDIO interrupt enable - }; - uint32_t val; - } intmask; - - uint32_t cmdarg; ///< Command argument to be passed to card - - sdmmc_hw_cmd_t cmd; - - uint32_t resp[4]; ///< Response from card - - union { - struct { - uint32_t cd: 1; ///< Card detect interrupt masked status - uint32_t re: 1; ///< Response error interrupt masked status - uint32_t cmd_done: 1; ///< Command done interrupt masked status - uint32_t dto: 1; ///< Data transfer over interrupt masked status - uint32_t txdr: 1; ///< Transmit FIFO data request interrupt masked status - uint32_t rxdr: 1; ///< Receive FIFO data request interrupt masked status - uint32_t rcrc: 1; ///< Response CRC error interrupt masked status - uint32_t dcrc: 1; ///< Data CRC error interrupt masked status - uint32_t rto: 1; ///< Response timeout interrupt masked status - uint32_t drto: 1; ///< Data read timeout interrupt masked status - uint32_t hto: 1; ///< Data starvation-by-host timeout interrupt masked status - uint32_t frun: 1; ///< FIFO underrun/overrun error interrupt masked status - uint32_t hle: 1; ///< Hardware locked write error interrupt masked status - uint32_t sbi_bci: 1; ///< Start bit error / busy clear interrupt masked status - uint32_t acd: 1; ///< Auto command done interrupt masked status - uint32_t ebe: 1; ///< End bit error / write no CRC interrupt masked status - uint32_t sdio: 16; ///< SDIO interrupt masked status - }; - uint32_t val; - } mintsts; - - union { - struct { - uint32_t cd: 1; ///< Card detect raw interrupt status - uint32_t re: 1; ///< Response error raw interrupt status - uint32_t cmd_done: 1; ///< Command done raw interrupt status - uint32_t dto: 1; ///< Data transfer over raw interrupt status - uint32_t txdr: 1; ///< Transmit FIFO data request raw interrupt status - uint32_t rxdr: 1; ///< Receive FIFO data request raw interrupt status - uint32_t rcrc: 1; ///< Response CRC error raw interrupt status - uint32_t dcrc: 1; ///< Data CRC error raw interrupt status - uint32_t rto: 1; ///< Response timeout raw interrupt status - uint32_t drto: 1; ///< Data read timeout raw interrupt status - uint32_t hto: 1; ///< Data starvation-by-host timeout raw interrupt status - uint32_t frun: 1; ///< FIFO underrun/overrun error raw interrupt status - uint32_t hle: 1; ///< Hardware locked write error raw interrupt status - uint32_t sbi_bci: 1; ///< Start bit error / busy clear raw interrupt status - uint32_t acd: 1; ///< Auto command done raw interrupt status - uint32_t ebe: 1; ///< End bit error / write no CRC raw interrupt status - uint32_t sdio: 16; ///< SDIO raw interrupt status - }; - uint32_t val; - } rintsts; ///< interrupts can be cleared by writing this register - - union { - struct { - uint32_t fifo_rx_watermark: 1; ///< FIFO reached receive watermark level - uint32_t fifo_tx_watermark: 1; ///< FIFO reached transmit watermark level - uint32_t fifo_empty: 1; ///< FIFO is empty - uint32_t fifo_full: 1; ///< FIFO is full - uint32_t cmd_fsm_state: 4; ///< command FSM state - uint32_t data3_status: 1; ///< this bit reads 1 if card is present - uint32_t data_busy: 1; ///< this bit reads 1 if card is busy - uint32_t data_fsm_busy: 1; ///< this bit reads 1 if transmit/receive FSM is busy - uint32_t response_index: 6; ///< index of the previous response - uint32_t fifo_count: 13; ///< number of filled locations in the FIFO - uint32_t dma_ack: 1; ///< DMA acknowledge signal - uint32_t dma_req: 1; ///< DMA request signal - }; - uint32_t val; - } status; - - union { - struct { - uint32_t tx_watermark: 12; ///< FIFO TX watermark level - uint32_t reserved1: 4; - uint32_t rx_watermark: 12; ///< FIFO RX watermark level - uint32_t dw_dma_mts: 3; - uint32_t reserved2: 1; - }; - uint32_t val; - } fifoth; - - union { - struct { - uint32_t cards: 2; ///< bit N reads 0 if card N is present - uint32_t reserved: 30; - }; - uint32_t val; - } cdetect; - - union { - struct { - uint32_t cards: 2; ///< bit N reads 1 if card N is write protected - uint32_t reserved: 30; - }; - uint32_t val; - } wrtprt; - - uint32_t gpio; ///< unused - uint32_t tcbcnt; ///< transferred (to card) byte count - uint32_t tbbcnt; ///< transferred from host to FIFO byte count - - union { - struct { - uint32_t debounce_count: 24; ///< number of host cycles used by debounce filter, typical time should be 5-25ms - uint32_t reserved: 8; - }; - } debnce; - - uint32_t usrid; ///< user ID - uint32_t verid; ///< IP block version - uint32_t hcon; ///< compile-time IP configuration - uint32_t uhs; ///< TBD - - union { - struct { - uint32_t cards: 2; ///< bit N resets card N, active low - uint32_t reserved: 30; - }; - } rst_n; - - uint32_t reserved_7c; - - union { - struct { - uint32_t sw_reset: 1; ///< set to reset DMA controller - uint32_t fb: 1; ///< set if AHB master performs fixed burst transfers - uint32_t dsl: 5; ///< descriptor skip length: number of words to skip between two unchained descriptors - uint32_t enable: 1; ///< set to enable IDMAC - uint32_t pbl: 3; ///< programmable burst length - uint32_t reserved: 21; - }; - uint32_t val; - } bmod; - - uint32_t pldmnd; ///< set any bit to resume IDMAC FSM from suspended state - sdmmc_desc_t* dbaddr; ///< descriptor list base - - union { - struct { - uint32_t ti: 1; ///< transmit interrupt status - uint32_t ri: 1; ///< receive interrupt status - uint32_t fbe: 1; ///< fatal bus error - uint32_t reserved1: 1; - uint32_t du: 1; ///< descriptor unavailable - uint32_t ces: 1; ///< card error summary - uint32_t reserved2: 2; - uint32_t nis: 1; ///< normal interrupt summary - uint32_t fbe_code: 3; ///< code of fatal bus error - uint32_t fsm: 4; ///< DMAC FSM state - uint32_t reserved3: 15; - }; - uint32_t val; - } idsts; - - union { - struct { - uint32_t ti: 1; ///< transmit interrupt enable - uint32_t ri: 1; ///< receive interrupt enable - uint32_t fbe: 1; ///< fatal bus error interrupt enable - uint32_t reserved1: 1; - uint32_t du: 1; ///< descriptor unavailable interrupt enable - uint32_t ces: 1; ///< card error interrupt enable - uint32_t reserved2: 2; - uint32_t ni: 1; ///< normal interrupt interrupt enable - uint32_t ai: 1; ///< abnormal interrupt enable - uint32_t reserved3: 22; - }; - uint32_t val; - } idinten; - - uint32_t dscaddr; ///< current host descriptor address - uint32_t dscaddrl; ///< unused - uint32_t dscaddru; ///< unused - uint32_t bufaddrl; ///< unused - uint32_t bufaddru; ///< unused - uint32_t reserved_a8[22]; - uint32_t cardthrctl; - uint32_t back_end_power; - uint32_t uhs_reg_ext; - uint32_t emmc_ddr_reg; - uint32_t enable_shift; - uint32_t reserved_114[443]; - union { - struct { - uint32_t phase_dout: 3; ///< phase of data output clock (0x0: 0, 0x1: 90, 0x4: 180, 0x6: 270) - uint32_t phase_din: 3; ///< phase of data input clock - uint32_t phase_core: 3; ///< phase of the clock to SDMMC peripheral - uint32_t div_factor_p: 4; ///< controls clock period; it will be (div_factor_p + 1) / 160MHz - uint32_t div_factor_h: 4; ///< controls length of high pulse; it will be (div_factor_h + 1) / 160MHz - uint32_t div_factor_m: 4; ///< should be equal to div_factor_p - }; - uint32_t val; - } clock; -} sdmmc_dev_t; -extern sdmmc_dev_t SDMMC; - -_Static_assert(sizeof(sdmmc_dev_t) == 0x804, "invalid size of sdmmc_dev_t structure"); - -#ifdef __cplusplus -} -#endif - -#endif //_SOC_SDMMC_STRUCT_H_ diff --git a/components/soc/esp32s3/include/soc/sdmmc_pins.h b/components/soc/esp32s3/include/soc/sdmmc_pins.h index b279793b6d..107bbf94ad 100644 --- a/components/soc/esp32s3/include/soc/sdmmc_pins.h +++ b/components/soc/esp32s3/include/soc/sdmmc_pins.h @@ -14,22 +14,6 @@ #pragma once -#define SDMMC_SLOT0_IOMUX_PIN_NUM_CLK 6 -#define SDMMC_SLOT0_IOMUX_PIN_NUM_CMD 11 -#define SDMMC_SLOT0_IOMUX_PIN_NUM_D0 7 -#define SDMMC_SLOT0_IOMUX_PIN_NUM_D1 8 -#define SDMMC_SLOT0_IOMUX_PIN_NUM_D2 9 -#define SDMMC_SLOT0_IOMUX_PIN_NUM_D3 10 -#define SDMMC_SLOT0_IOMUX_PIN_NUM_D4 16 -#define SDMMC_SLOT0_IOMUX_PIN_NUM_D5 17 -#define SDMMC_SLOT0_IOMUX_PIN_NUM_D6 5 -#define SDMMC_SLOT0_IOMUX_PIN_NUM_D7 18 -#define SDMMC_SLOT0_FUNC 0 - -#define SDMMC_SLOT1_IOMUX_PIN_NUM_CLK 14 -#define SDMMC_SLOT1_IOMUX_PIN_NUM_CMD 15 -#define SDMMC_SLOT1_IOMUX_PIN_NUM_D0 2 -#define SDMMC_SLOT1_IOMUX_PIN_NUM_D1 4 -#define SDMMC_SLOT1_IOMUX_PIN_NUM_D2 12 -#define SDMMC_SLOT1_IOMUX_PIN_NUM_D3 13 -#define SDMMC_SLOT1_FUNC 4 +/* SDMMC pins on ESP32-S3 are configurable through GPIO matrix. + * This file is kept for compatibility only. + */ diff --git a/components/soc/esp32s3/include/soc/sdmmc_struct.h b/components/soc/esp32s3/include/soc/sdmmc_struct.h index dc4e65df0c..6f5eef66ec 100644 --- a/components/soc/esp32s3/include/soc/sdmmc_struct.h +++ b/components/soc/esp32s3/include/soc/sdmmc_struct.h @@ -19,7 +19,7 @@ extern "C" { #endif -typedef struct { +typedef struct sdmmc_desc_s { uint32_t reserved1: 1; uint32_t disable_int_on_completion: 1; uint32_t last_descriptor: 1; @@ -32,10 +32,10 @@ typedef struct { uint32_t buffer1_size: 13; uint32_t buffer2_size: 13; uint32_t reserved3: 6; - void *buffer1_ptr; + void* buffer1_ptr; union { - void *buffer2_ptr; - void *next_desc_ptr; + void* buffer2_ptr; + void* next_desc_ptr; }; } sdmmc_desc_t; @@ -44,7 +44,7 @@ typedef struct { _Static_assert(sizeof(sdmmc_desc_t) == 16, "invalid size of sdmmc_desc_t structure"); -typedef struct { +typedef struct sdmmc_hw_cmd_s { uint32_t cmd_index: 6; ///< Command index uint32_t response_expect: 1; ///< set if response is expected uint32_t response_long: 1; ///< 0: short response expected, 1: long response expected @@ -73,7 +73,7 @@ typedef struct { _Static_assert(sizeof(sdmmc_hw_cmd_t) == 4, "invalid size of sdmmc_cmd_t structure"); -typedef volatile struct { +typedef volatile struct sdmmc_dev_s { union { struct { uint32_t controller_reset: 1; @@ -282,7 +282,12 @@ typedef volatile struct { uint32_t usrid; ///< user ID uint32_t verid; ///< IP block version uint32_t hcon; ///< compile-time IP configuration - uint32_t uhs; ///< TBD + union { + struct { + uint32_t voltage: 16; ///< voltage control for slots; no-op on ESP32. + uint32_t ddr: 16; ///< bit N enables DDR mode for card N + }; + } uhs; ///< UHS related settings union { struct { @@ -306,7 +311,7 @@ typedef volatile struct { } bmod; uint32_t pldmnd; ///< set any bit to resume IDMAC FSM from suspended state - sdmmc_desc_t *dbaddr; ///< descriptor list base + sdmmc_desc_t* dbaddr; ///< descriptor list base union { struct { @@ -347,7 +352,16 @@ typedef volatile struct { uint32_t bufaddrl; ///< unused uint32_t bufaddru; ///< unused uint32_t reserved_a8[22]; - uint32_t cardthrctl; + union { + struct { + uint32_t read_thr_en : 1; ///< initiate transfer only if FIFO has more space than the read threshold + uint32_t busy_clr_int_en : 1; ///< enable generation of busy clear interrupts + uint32_t write_thr_en : 1; ///< equivalent of read_thr_en for writes + uint32_t reserved1 : 13; + uint32_t card_threshold : 12; ///< threshold value for reads/writes, in bytes + }; + uint32_t val; + } cardthrctl; uint32_t back_end_power; uint32_t uhs_reg_ext; uint32_t emmc_ddr_reg; @@ -361,6 +375,8 @@ typedef volatile struct { uint32_t div_factor_p: 4; ///< controls clock period; it will be (div_factor_p + 1) / 160MHz uint32_t div_factor_h: 4; ///< controls length of high pulse; it will be (div_factor_h + 1) / 160MHz uint32_t div_factor_m: 4; ///< should be equal to div_factor_p + uint32_t reserved1 : 2; + uint32_t clk_sel : 1; ///< clock source select (0: XTAL, 1: 160 MHz from PLL) }; uint32_t val; } clock; diff --git a/components/soc/esp32s3/include/soc/soc_caps.h b/components/soc/esp32s3/include/soc/soc_caps.h index 52250af3c1..c3f8cd0fc8 100644 --- a/components/soc/esp32s3/include/soc/soc_caps.h +++ b/components/soc/esp32s3/include/soc/soc_caps.h @@ -21,6 +21,7 @@ #define SOC_HMAC_SUPPORTED 1 #define SOC_ASYNC_MEMCPY_SUPPORTED 1 #define SOC_EFUSE_SECURE_BOOT_KEY_DIGESTS 3 +#define SOC_SDMMC_HOST_SUPPORTED 1 /*-------------------------- ADC CAPS ----------------------------------------*/ @@ -218,3 +219,13 @@ #define SOC_SPI_MEM_SUPPORT_SW_SUSPEND (1) /*-------------------------- COEXISTENCE HARDWARE PTI CAPS -------------------------------*/ #define SOC_COEX_HW_PTI (1) + +/*-------------------------- SDMMC CAPS -----------------------------------------*/ + +/* Card detect, write protect, interrupt use GPIO Matrix on all chips. + * On ESP32-S3, clock/cmd/data pins use GPIO Matrix as well. + */ +#define SOC_SDMMC_USE_GPIO_MATRIX 1 +#define SOC_SDMMC_NUM_SLOTS 2 +/* Indicates that there is an option to use XTAL clock instead of PLL for SDMMC */ +#define SOC_SDMMC_SUPPORT_XTAL_CLOCK 1 diff --git a/components/soc/esp32s3/sdmmc_periph.c b/components/soc/esp32s3/sdmmc_periph.c index 4bf7c14db8..0d9d9621ff 100644 --- a/components/soc/esp32s3/sdmmc_periph.c +++ b/components/soc/esp32s3/sdmmc_periph.c @@ -14,37 +14,44 @@ #include "soc/sdmmc_periph.h" -const sdmmc_slot_info_t sdmmc_slot_info[2] = { +const sdmmc_slot_info_t sdmmc_slot_info[SOC_SDMMC_NUM_SLOTS] = { { - .clk_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_CLK, - .cmd_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_CMD, - .d0_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_D0, - .d1_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_D1, - .d2_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_D2, - .d3_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_D3, - .d4_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_D4, - .d5_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_D5, - .d6_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_D6, - .d7_gpio = SDMMC_SLOT0_IOMUX_PIN_NUM_D7, + .width = 8, .card_detect = SDHOST_CARD_DETECT_N_1_IDX, .write_protect = SDHOST_CARD_WRITE_PRT_1_IDX, .card_int = SDHOST_CARD_INT_N_1_IDX, - .width = 8 }, { - .clk_gpio = SDMMC_SLOT1_IOMUX_PIN_NUM_CLK, - .cmd_gpio = SDMMC_SLOT1_IOMUX_PIN_NUM_CMD, - .d0_gpio = SDMMC_SLOT1_IOMUX_PIN_NUM_D0, - .d1_gpio = SDMMC_SLOT1_IOMUX_PIN_NUM_D1, - .d2_gpio = SDMMC_SLOT1_IOMUX_PIN_NUM_D2, - .d3_gpio = SDMMC_SLOT1_IOMUX_PIN_NUM_D3, - .d4_gpio = -1, //slot1 has no D4-7 - .d5_gpio = -1, - .d6_gpio = -1, - .d7_gpio = -1, + .width = 8, .card_detect = SDHOST_CARD_DETECT_N_2_IDX, .write_protect = SDHOST_CARD_WRITE_PRT_2_IDX, .card_int = SDHOST_CARD_INT_N_2_IDX, - .width = 4 + } +}; + +const sdmmc_slot_io_info_t sdmmc_slot_gpio_sig[SOC_SDMMC_NUM_SLOTS] = { + { + .clk = SDHOST_CCLK_OUT_1_IDX, + .cmd = SDHOST_CCMD_OUT_1_IDX, + .d0 = SDHOST_CDATA_OUT_10_IDX, + .d1 = SDHOST_CDATA_OUT_11_IDX, + .d2 = SDHOST_CDATA_OUT_12_IDX, + .d3 = SDHOST_CDATA_OUT_13_IDX, + .d4 = SDHOST_CDATA_OUT_14_IDX, + .d5 = SDHOST_CDATA_OUT_15_IDX, + .d6 = SDHOST_CDATA_OUT_16_IDX, + .d7 = SDHOST_CDATA_OUT_17_IDX, + }, + { + .clk = SDHOST_CCLK_OUT_2_IDX, + .cmd = SDHOST_CCMD_OUT_2_IDX, + .d0 = SDHOST_CDATA_OUT_20_IDX, + .d1 = SDHOST_CDATA_OUT_21_IDX, + .d2 = SDHOST_CDATA_OUT_22_IDX, + .d3 = SDHOST_CDATA_OUT_23_IDX, + .d4 = SDHOST_CDATA_OUT_24_IDX, + .d5 = SDHOST_CDATA_OUT_25_IDX, + .d6 = SDHOST_CDATA_OUT_26_IDX, + .d7 = SDHOST_CDATA_OUT_27_IDX, } }; diff --git a/components/soc/include/soc/sdmmc_periph.h b/components/soc/include/soc/sdmmc_periph.h index 7a64f4c5fe..c1d38fa29b 100644 --- a/components/soc/include/soc/sdmmc_periph.h +++ b/components/soc/include/soc/sdmmc_periph.h @@ -15,6 +15,7 @@ #pragma once #include //include soc related (generated) definitions +#include "soc/soc_caps.h" #include "soc/soc_pins.h" #include "soc/sdmmc_reg.h" #include "soc/sdmmc_struct.h" @@ -24,25 +25,50 @@ extern "C" { #endif +/** + * Common SDMMC slot info, doesn't depend on SOC_SDMMC_USE_{IOMUX,GPIO_MATRIX} + */ typedef struct { - uint8_t clk_gpio; - uint8_t cmd_gpio; - uint8_t d0_gpio; - uint8_t d1_gpio; - uint8_t d2_gpio; - uint8_t d3_gpio; - uint8_t d4_gpio; - uint8_t d5_gpio; - uint8_t d6_gpio; - uint8_t d7_gpio; - uint8_t card_detect; - uint8_t write_protect; - uint8_t card_int; - uint8_t width; + uint8_t width; /*!< Maximum supported slot width (1, 4, 8) */ + uint8_t card_detect; /*!< Card detect signal in GPIO Matrix */ + uint8_t write_protect; /*!< Write protect signal in GPIO Matrix */ + uint8_t card_int; /*!< Card interrupt signal in GPIO Matrix */ } sdmmc_slot_info_t; -/** pin and signal information of each slot */ -extern const sdmmc_slot_info_t sdmmc_slot_info[]; +/** Width and GPIO matrix signal numbers for auxillary SD host signals, one structure per slot */ +extern const sdmmc_slot_info_t sdmmc_slot_info[SOC_SDMMC_NUM_SLOTS]; + +/** + * This structure lists pin numbers (if SOC_SDMMC_USE_IOMUX is set) + * 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; +} sdmmc_slot_io_info_t; + +/* Note: it is in theory possible to have both IOMUX and GPIO Matrix supported + * in the same SoC. However this is not used on any SoC at this point, and would + * complicate the driver. Hence only one of these options is supported at a time. + */ +#if SOC_SDMMC_USE_IOMUX +/** GPIO pin numbers of SD bus signals, one structure per slot */ +extern const sdmmc_slot_io_info_t sdmmc_slot_gpio_num[SOC_SDMMC_NUM_SLOTS]; + +#elif SOC_SDMMC_USE_GPIO_MATRIX +/** GPIO matrix signal numbers of SD bus signals, one structure per slot */ +extern const sdmmc_slot_io_info_t sdmmc_slot_gpio_sig[SOC_SDMMC_NUM_SLOTS]; + +#endif // SOC_SDMMC_USE_{IOMUX,GPIO_MATRIX} #ifdef __cplusplus } diff --git a/examples/storage/sd_card/sdmmc/main/sd_card_example_main.c b/examples/storage/sd_card/sdmmc/main/sd_card_example_main.c index 7386d154e4..6146b16538 100644 --- a/examples/storage/sd_card/sdmmc/main/sd_card_example_main.c +++ b/examples/storage/sd_card/sdmmc/main/sd_card_example_main.c @@ -52,17 +52,24 @@ void app_main(void) // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals. sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT(); - // To use 1-line SD mode, uncomment the following line: - // slot_config.width = 1; + // To use 1-line SD mode, change this to 1: + slot_config.width = 4; - // GPIOs 15, 2, 4, 12, 13 should have external 10k pull-ups. - // Internal pull-ups are not sufficient. However, enabling internal pull-ups - // does make a difference some boards, so we do that here. - gpio_set_pull_mode(15, GPIO_PULLUP_ONLY); // CMD, needed in 4- and 1- line modes - gpio_set_pull_mode(2, GPIO_PULLUP_ONLY); // D0, needed in 4- and 1-line modes - gpio_set_pull_mode(4, GPIO_PULLUP_ONLY); // D1, needed in 4-line mode only - gpio_set_pull_mode(12, GPIO_PULLUP_ONLY); // D2, needed in 4-line mode only - gpio_set_pull_mode(13, GPIO_PULLUP_ONLY); // D3, needed in 4- and 1-line modes + // On chips where the GPIOs used for SD card can be configured, set them in + // the slot_config structure: +#ifdef SOC_SDMMC_USE_GPIO_MATRIX + slot_config.clk = GPIO_NUM_14; + slot_config.cmd = GPIO_NUM_15; + slot_config.d0 = GPIO_NUM_2; + slot_config.d1 = GPIO_NUM_4; + slot_config.d2 = GPIO_NUM_12; + slot_config.d3 = GPIO_NUM_13; +#endif + + // Enable internal pullups on enabled pins. The internal pullups + // are insufficient however, please make sure 10k external pullups are + // connected on the bus. This is for debug / example purpose only. + slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP; ret = esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &card);