From 847d525d78256cff9f372abc9a58eebd86770076 Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 29 Dec 2023 15:55:34 +0800 Subject: [PATCH 1/4] feat(sdmmc): use ldo as power supply on esp32p4 --- components/esp_driver_sdmmc/src/sdmmc_host.c | 29 ++++++++++++++++++- components/hal/esp32p4/include/hal/sdmmc_ll.h | 1 - components/sdmmc/CMakeLists.txt | 2 +- components/sdmmc/sdmmc_sd.c | 18 ++++++++---- 4 files changed, 41 insertions(+), 9 deletions(-) diff --git a/components/esp_driver_sdmmc/src/sdmmc_host.c b/components/esp_driver_sdmmc/src/sdmmc_host.c index cbfe397aa8..2f79ef30b9 100644 --- a/components/esp_driver_sdmmc/src/sdmmc_host.c +++ b/components/esp_driver_sdmmc/src/sdmmc_host.c @@ -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 */ @@ -19,6 +19,7 @@ #include "driver/gpio.h" #include "driver/sdmmc_host.h" #include "esp_private/periph_ctrl.h" +#include "esp_private/esp_ldo.h" #include "sdmmc_private.h" #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" @@ -54,6 +55,7 @@ typedef struct slot_ctx_t { size_t slot_width; sdmmc_slot_io_info_t slot_gpio_num; bool use_gpio_matrix; + esp_ldo_unit_handle_t ldo_unit; } slot_ctx_t; /** @@ -662,6 +664,21 @@ esp_err_t sdmmc_host_init_slot(int slot, const sdmmc_slot_config_t *slot_config) if (ret != ESP_OK) { return ret; } + +#if SOC_MULTI_USAGE_LDO_SUPPORTED + esp_ldo_unit_init_cfg_t init_ldo_cfg = { + .unit_id = LDO_UNIT_4, + .cfg = { + .voltage_mv = 3300, + }, + .flags.shared_ldo = true, + }; + esp_ldo_unit_handle_t ldo_unit = NULL; + ESP_RETURN_ON_ERROR(esp_ldo_init_unit(&init_ldo_cfg, &ldo_unit), TAG, "LDO init failed"); + ESP_RETURN_ON_ERROR(esp_ldo_enable_unit(ldo_unit), TAG, "LDO enable failed"); + s_host_ctx.slot_ctx[slot].ldo_unit = ldo_unit; +#endif + return ESP_OK; } @@ -683,6 +700,16 @@ esp_err_t sdmmc_host_deinit(void) sdmmc_ll_enable_bus_clock(s_host_ctx.hal.dev, false); } +#if SOC_MULTI_USAGE_LDO_SUPPORTED + for (int i = 0; i < SOC_SDMMC_NUM_SLOTS; i++) { + if (s_host_ctx.slot_ctx[i].ldo_unit) { + ESP_RETURN_ON_ERROR(esp_ldo_disable_unit(s_host_ctx.slot_ctx[i].ldo_unit), TAG, "LDO disable failed"); + ESP_RETURN_ON_ERROR(esp_ldo_deinit_unit(s_host_ctx.slot_ctx[i].ldo_unit), TAG, "LDO deinit failed"); + s_host_ctx.slot_ctx[i].ldo_unit = NULL; + } + } +#endif + return ESP_OK; } diff --git a/components/hal/esp32p4/include/hal/sdmmc_ll.h b/components/hal/esp32p4/include/hal/sdmmc_ll.h index 4397c10fbe..07125faf5a 100644 --- a/components/hal/esp32p4/include/hal/sdmmc_ll.h +++ b/components/hal/esp32p4/include/hal/sdmmc_ll.h @@ -31,7 +31,6 @@ extern "C" { /** * SDMMC capabilities */ -#define SDMMC_LL_MAX_FREQ_KHZ_FPGA (4*1000) #define SDMMC_LL_SLOT_SUPPORT_GPIO_MATRIX(SLOT_ID) ((SLOT_ID == 0) ? 0 : 1) #define SDMMC_LL_IOMUX_FUNC 0 diff --git a/components/sdmmc/CMakeLists.txt b/components/sdmmc/CMakeLists.txt index 243b26c4d6..d435540f3a 100644 --- a/components/sdmmc/CMakeLists.txt +++ b/components/sdmmc/CMakeLists.txt @@ -11,4 +11,4 @@ idf_component_register(SRCS "sdmmc_cmd.c" "sdmmc_mmc.c" "sdmmc_sd.c" INCLUDE_DIRS include - PRIV_REQUIRES soc esp_timer) + PRIV_REQUIRES soc esp_timer esp_mm) diff --git a/components/sdmmc/sdmmc_sd.c b/components/sdmmc/sdmmc_sd.c index 6275e7cf7f..464ab1362b 100644 --- a/components/sdmmc/sdmmc_sd.c +++ b/components/sdmmc/sdmmc_sd.c @@ -17,6 +17,7 @@ #include #include "esp_timer.h" +#include "esp_cache.h" #include "sdmmc_common.h" static const char* TAG = "sdmmc_sd"; @@ -191,12 +192,14 @@ esp_err_t sdmmc_send_cmd_switch_func(sdmmc_card_t* card, uint32_t other_func_mask = (0x00ffffff & ~(0xf << group_shift)); uint32_t func_val = (function << group_shift) | other_func_mask; + size_t datalen = sizeof(sdmmc_switch_func_rsp_t); sdmmc_command_t cmd = { .opcode = MMC_SWITCH, .flags = SCF_CMD_ADTC | SCF_CMD_READ | SCF_RSP_R1, .blklen = sizeof(sdmmc_switch_func_rsp_t), .data = resp->data, - .datalen = sizeof(sdmmc_switch_func_rsp_t), + .datalen = datalen, + .buflen = datalen, .arg = (!!mode << 31) | func_val }; @@ -233,13 +236,16 @@ esp_err_t sdmmc_enable_hs_mode(sdmmc_card_t* card) ((card->csd.card_command_class & SD_CSD_CCC_SWITCH) == 0)) { return ESP_ERR_NOT_SUPPORTED; } - sdmmc_switch_func_rsp_t* response = (sdmmc_switch_func_rsp_t*) - heap_caps_malloc(sizeof(*response), MALLOC_CAP_DMA); - if (response == NULL) { - return ESP_ERR_NO_MEM; + + size_t actual_size = 0; + sdmmc_switch_func_rsp_t *response = NULL; + esp_err_t err = esp_dma_malloc(sizeof(*response), 0, (void *)&response, &actual_size); + assert(actual_size == sizeof(*response)); + if (err != ESP_OK) { + return err; } - esp_err_t err = sdmmc_send_cmd_switch_func(card, 0, SD_ACCESS_MODE, 0, response); + err = sdmmc_send_cmd_switch_func(card, 0, SD_ACCESS_MODE, 0, response); if (err != ESP_OK) { ESP_LOGD(TAG, "%s: sdmmc_send_cmd_switch_func (1) returned 0x%x", __func__, err); goto out; From 5ae29bc4e5421a2872d55a945febdb5c23fc2bce Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 29 Dec 2023 15:55:52 +0800 Subject: [PATCH 2/4] doc(sdmmc): added doc about ldo usage on esp32p4 --- docs/en/api-reference/peripherals/sdmmc_host.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/api-reference/peripherals/sdmmc_host.rst b/docs/en/api-reference/peripherals/sdmmc_host.rst index 5b8f231447..b8517de4ba 100644 --- a/docs/en/api-reference/peripherals/sdmmc_host.rst +++ b/docs/en/api-reference/peripherals/sdmmc_host.rst @@ -76,6 +76,7 @@ Overview - :c:macro:`SDMMC_HOST_SLOT_1` is routed via GPIO Matrix. This means that any GPIO may be used for each of the SD card signals. It is for non UHS-I usage. - :c:macro:`SDMMC_HOST_SLOT_0` is dedicated to UHS-I mode, which is not yet supported in the driver. + Currently SDMMC host driver is using the on-chip LDO 4 as the default power supply. SDMMC power control driver is not supported yet. If you buy the ESP32P4 chip itself and plan to use SDMMC peripheral, make sure the VDDPST_5 pin is connected to the on-chip LDO 4 or correct external power supply. Supported Speed Modes --------------------- From 2a5343b2e088c6c49018628b1589e26f7e96c4b9 Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 29 Dec 2023 15:54:50 +0800 Subject: [PATCH 3/4] change(ldo): added ldo_types.h --- .../include/esp_private/esp_ldo.h | 6 +--- .../main/test_ldo.c | 10 +++---- components/hal/include/hal/ldo_types.h | 28 +++++++++++++++++++ 3 files changed, 34 insertions(+), 10 deletions(-) create mode 100644 components/hal/include/hal/ldo_types.h diff --git a/components/esp_hw_support/include/esp_private/esp_ldo.h b/components/esp_hw_support/include/esp_private/esp_ldo.h index 9cbe9cd4e9..efde4d84aa 100644 --- a/components/esp_hw_support/include/esp_private/esp_ldo.h +++ b/components/esp_hw_support/include/esp_private/esp_ldo.h @@ -9,16 +9,12 @@ #include #include #include "esp_err.h" +#include "hal/ldo_types.h" #ifdef __cplusplus extern "C" { #endif -#define ESP_LDO_ID_1 0 ///< See datasheet `VFB/VO1` -#define ESP_LDO_ID_2 1 ///< See datasheet `VFB/VO2` -#define ESP_LDO_ID_3 2 ///< See datasheet `VFB/VO3` -#define ESP_LDO_ID_4 3 ///< See datasheet `VFB/VO4` - /** * @brief Type of LDO unit handle */ diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_ldo.c b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_ldo.c index 47c806bcb3..fe0e693c7d 100644 --- a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_ldo.c +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_ldo.c @@ -15,7 +15,7 @@ TEST_CASE("LDO unit early / normal allocation", "[LDO]") { esp_ldo_unit_init_cfg_t init_early_unit_cfg = { - .unit_id = ESP_LDO_ID_3, + .unit_id = LDO_UNIT_3, .cfg = { .voltage_mv = 1800, }, @@ -27,7 +27,7 @@ TEST_CASE("LDO unit early / normal allocation", "[LDO]") esp_ldo_unit_handle_t unit = NULL; esp_ldo_unit_init_cfg_t init_unit_cfg = { - .unit_id = ESP_LDO_ID_4, + .unit_id = LDO_UNIT_4, .cfg = { .voltage_mv = 2500, }, @@ -48,7 +48,7 @@ TEST_CASE("LDO unit early / normal allocation", "[LDO]") TEST_CASE("LDO unit output", "[LDO][mannual][ignore]") { esp_ldo_unit_init_cfg_t early_unit_cfg = { - .unit_id = ESP_LDO_ID_2, + .unit_id = LDO_UNIT_2, .cfg = { .voltage_mv = 2500, }, @@ -57,12 +57,12 @@ TEST_CASE("LDO unit output", "[LDO][mannual][ignore]") esp_ldo_unit_handle_t early_unit2 = esp_ldo_init_unit_early(&early_unit_cfg); assert(early_unit2); - early_unit_cfg.unit_id = ESP_LDO_ID_3; + early_unit_cfg.unit_id = LDO_UNIT_3; early_unit_cfg.cfg.voltage_mv = 3300; esp_ldo_unit_handle_t early_unit3 = esp_ldo_init_unit_early(&early_unit_cfg); assert(early_unit3); - early_unit_cfg.unit_id = ESP_LDO_ID_4; + early_unit_cfg.unit_id = LDO_UNIT_4; early_unit_cfg.cfg.voltage_mv = 1100; esp_ldo_unit_handle_t early_unit4 = esp_ldo_init_unit_early(&early_unit_cfg); assert(early_unit4); diff --git a/components/hal/include/hal/ldo_types.h b/components/hal/include/hal/ldo_types.h new file mode 100644 index 0000000000..f4b8c47d69 --- /dev/null +++ b/components/hal/include/hal/ldo_types.h @@ -0,0 +1,28 @@ +/* + * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief LDO Unit + * + * @note See datasheet to know LDO, alias includes but not least to `VFB/VOn` + */ +typedef enum { + LDO_UNIT_1, ///< LDO 1 + LDO_UNIT_2, ///< LDO 2 + LDO_UNIT_3, ///< LDO 3 + LDO_UNIT_4, ///< LDO 4 +} ldo_unit_t; + +#ifdef __cplusplus +} +#endif From a9a36512a8201e15d7979ed0e110beba34ba4055 Mon Sep 17 00:00:00 2001 From: Armando Date: Tue, 2 Jan 2024 13:09:56 +0800 Subject: [PATCH 4/4] bugfix(dma): fixed wrong esp_dma_is_buffer_aligned result for psram on s3 --- components/esp_hw_support/dma/esp_dma_utils.c | 57 ++++++++++++------- .../esp_hw_support/include/esp_dma_utils.h | 1 + 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/components/esp_hw_support/dma/esp_dma_utils.c b/components/esp_hw_support/dma/esp_dma_utils.c index 5db42309c2..6dd01cf863 100644 --- a/components/esp_hw_support/dma/esp_dma_utils.c +++ b/components/esp_hw_support/dma/esp_dma_utils.c @@ -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 */ @@ -69,41 +69,54 @@ esp_err_t esp_dma_calloc(size_t n, size_t size, uint32_t flags, void **out_ptr, return ret; } +static bool s_buf_in_region(const void *ptr, size_t size, esp_dma_buf_location_t location, uint32_t *in_out_flags) +{ + bool found = false; + if (location == ESP_DMA_BUF_LOCATION_INTERNAL) { + if (esp_ptr_dma_capable(ptr) && esp_ptr_dma_capable(ptr + size - 1)) { + found = true; + } + } else if (location == ESP_DMA_BUF_LOCATION_PSRAM) { +#if SOC_PSRAM_DMA_CAPABLE + if (esp_ptr_external_ram(ptr) && esp_ptr_external_ram(ptr + size - 1)) { + *in_out_flags |= ESP_DMA_MALLOC_FLAG_PSRAM; + found = true; + } +#endif + } + return found; +} + bool esp_dma_is_buffer_aligned(const void *ptr, size_t size, esp_dma_buf_location_t location) { assert(ptr); uint32_t flags = ESP_CACHE_MALLOC_FLAG_DMA; - if (location == ESP_DMA_BUF_LOCATION_INTERNAL) { - if (!esp_ptr_dma_capable(ptr) || !esp_ptr_dma_capable(ptr + size - 1)) { - return false; + bool found = false; + if (location == ESP_DMA_BUF_LOCATION_AUTO) { + for (int i = ESP_DMA_BUF_LOCATION_INTERNAL; i < ESP_DMA_BUF_LOCATION_AUTO; i++) { + if (s_buf_in_region(ptr, size, i, &flags)) { + found = true; + break; + } } + } else if (location == ESP_DMA_BUF_LOCATION_INTERNAL) { + found = s_buf_in_region(ptr, size, ESP_DMA_BUF_LOCATION_INTERNAL, &flags); } else { -#if !SOC_PSRAM_DMA_CAPABLE + found = s_buf_in_region(ptr, size, ESP_DMA_BUF_LOCATION_PSRAM, &flags); + } + if (!found) { return false; -#endif - if (!esp_ptr_external_ram(ptr) || !esp_ptr_external_ram(ptr + size - 1)) { - return false; - } - - flags |= ESP_DMA_MALLOC_FLAG_PSRAM; } bool is_aligned = false; - -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + size_t dma_alignment = 0; size_t cache_alignment = 0; + size_t alignment = 0; esp_err_t ret = esp_cache_get_alignment(flags, &cache_alignment); assert(ret == ESP_OK); - if (((intptr_t)ptr % cache_alignment == 0) && (size % cache_alignment == 0)) { - is_aligned = true; - } -#else - (void)size; - if ((intptr_t)ptr % 4 == 0) { - is_aligned = true; - } -#endif + alignment = MAX(dma_alignment, cache_alignment); + is_aligned = ((intptr_t)ptr % alignment == 0) && (size % alignment == 0); return is_aligned; } diff --git a/components/esp_hw_support/include/esp_dma_utils.h b/components/esp_hw_support/include/esp_dma_utils.h index 3c59db9008..747cd1b31b 100644 --- a/components/esp_hw_support/include/esp_dma_utils.h +++ b/components/esp_hw_support/include/esp_dma_utils.h @@ -59,6 +59,7 @@ esp_err_t esp_dma_calloc(size_t n, size_t size, uint32_t flags, void **out_ptr, typedef enum { ESP_DMA_BUF_LOCATION_INTERNAL, ///< DMA buffer is in internal memory ESP_DMA_BUF_LOCATION_PSRAM, ///< DMA buffer is in PSRAM + ESP_DMA_BUF_LOCATION_AUTO, ///< Auto detect buffer location, under this condition API will loop to search the buffer location } esp_dma_buf_location_t; /**