diff --git a/components/esp_hal_pmu/esp32s31/include/hal/ldo_ll.h b/components/esp_hal_pmu/esp32s31/include/hal/ldo_ll.h index d710b7df711..1eefc467139 100644 --- a/components/esp_hal_pmu/esp32s31/include/hal/ldo_ll.h +++ b/components/esp_hal_pmu/esp32s31/include/hal/ldo_ll.h @@ -9,13 +9,45 @@ #include #include #include "hal/misc.h" +#include "hal/pmu_types.h" #include "soc/pmu_struct.h" #ifdef __cplusplus extern "C" { #endif -#define LDO_LL_RAIL_VOLTAGE_MV 3300 +#define LDO_LL_NUM_UNITS 1 // Number of LDO units +#define LDO_LL_ADJUSTABLE_CHAN_MASK 0x01 // all the channels are adjustable by setting "mul" and "dref" registers + +#define LDO_LL_RECOMMEND_MAX_VOLTAGE_MV 2700 +#define LDO_LL_RECOMMEND_MIN_VOLTAGE_MV 500 +#define LDO_LL_RAIL_VOLTAGE_MV 3300 + +/** + * @brief In the analog design, the LDO output "channel" is index from 1, i.e., VO1, VO2, VO3, VO4. + * But in software, we mapped them to "LDO unit", which is index from 0, i.e., 0, 1, 2, 3. + */ +#define LDO_ID2UNIT(ldo_id) ((ldo_id) - 1) + +/** + * @brief LDO unit owner + */ +typedef enum { + LDO_LL_UNIT_OWNER_HW, // LDO unit is controlled by hardware + LDO_LL_UNIT_OWNER_SW, // LDO unit is controlled by software +} ldo_ll_unit_owner_t; + +/** + * @brief Check if a LDO channel is valid + * + * @param ldo_chan LDO channel ID, note, this is indexed from 1 + * @return True for valid, false for invalid + */ +__attribute__((always_inline)) +static inline bool ldo_ll_is_valid_ldo_channel(int ldo_chan) +{ + return (ldo_chan > 0) && (ldo_chan <= LDO_LL_NUM_UNITS); +} /** * @brief Convert voltage to dref and mul value @@ -62,6 +94,20 @@ static inline void ldo_ll_voltage_to_dref_mul(int ldo_unit, int voltage_mv, uint *use_rail_voltage = (voltage_mv == LDO_LL_RAIL_VOLTAGE_MV); } +/** + * @brief Set owner of a LDO unit + * + * @note Even if the LDO unit is controlled by hardware, its voltage can still be changed by software by `ldo_ll_adjust_voltage` + * + * @param ldo_unit LDO unit + * @param owner Owner of the LDO unit + */ +__attribute__((always_inline)) +static inline void ldo_ll_set_owner(int ldo_unit, ldo_ll_unit_owner_t owner) +{ + //for compatibility +} + /** * @brief Adjust voltage of a LDO unit * @@ -81,17 +127,6 @@ static inline void ldo_ll_adjust_voltage(int ldo_unit, uint8_t dref, uint8_t mul PMU.ext_ldo_ctrl.ext_ldo_tie_high = use_rail_voltage; } -/** - * @brief Enable power on the PSRAM domain - * - * @param enable True: enable; False: disable - */ -__attribute__((always_inline)) -static inline void ldo_ll_psram_power_enable(bool enable) -{ - PMU.psram_cfg.psram_xpd = enable; -} - /** * @brief Enable ripple suppression of a LDO unit * @@ -105,6 +140,20 @@ static inline void ldo_ll_enable_ripple_suppression(int ldo_unit, bool enable) PMU.ext_ldo_ctrl.ext_ldo_en_vdet = enable; } +/** + * @brief Enable a LDO unit + * + * @param ldo_unit LDO unit + * @param enable True: enable; False: disable + */ +__attribute__((always_inline)) +static inline void ldo_ll_enable(int ldo_unit, bool enable) +{ + //for compatibility + //PMU.hp_sys[PMU_MODE_HP_ACTIVE].regulator0.xpd is for chip internal LDO for chip power + //this will not be controlled by this general purpose LDO file +} + /** * @brief Enable current limit of a LDO unit to avoid inrush current * diff --git a/components/esp_hw_support/ldo/esp_ldo_regulator.c b/components/esp_hw_support/ldo/esp_ldo_regulator.c index f1e5bd6caad..f8be42b2bfe 100644 --- a/components/esp_hw_support/ldo/esp_ldo_regulator.c +++ b/components/esp_hw_support/ldo/esp_ldo_regulator.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -87,6 +87,7 @@ esp_err_t esp_ldo_acquire_channel(const esp_ldo_channel_config_t *config, esp_ld uint8_t dref = 0; uint8_t mul = 0; bool use_rail_voltage = false; + ldo_ll_enable_current_limit(unit_id, true); // calculate the dref and mul ldo_ll_voltage_to_dref_mul(unit_id, config->voltage_mv, &dref, &mul, &use_rail_voltage); ldo_ll_adjust_voltage(unit_id, dref, mul, use_rail_voltage); @@ -95,6 +96,7 @@ esp_err_t esp_ldo_acquire_channel(const esp_ldo_channel_config_t *config, esp_ld // suppress voltage ripple ldo_ll_enable_ripple_suppression(unit_id, true); ldo_ll_enable(unit_id, true); + ldo_ll_enable_current_limit(unit_id, false); } // update the channel attributes channel->ref_cnt++; @@ -146,7 +148,9 @@ esp_err_t esp_ldo_release_channel(esp_ldo_channel_handle_t chan) esp_err_t esp_ldo_channel_adjust_voltage(esp_ldo_channel_handle_t chan, int voltage_mv) { ESP_RETURN_ON_FALSE(chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); - ESP_RETURN_ON_FALSE(chan->flags.adjustable, ESP_ERR_NOT_SUPPORTED, TAG, "LDO is not adjustable"); + if (chan->voltage_mv != voltage_mv) { + ESP_RETURN_ON_FALSE(chan->flags.adjustable, ESP_ERR_NOT_SUPPORTED, TAG, "LDO is not adjustable"); + } // check if the target voltage is within the recommended range if (!((voltage_mv == LDO_LL_RAIL_VOLTAGE_MV) || (voltage_mv >= LDO_LL_RECOMMEND_MIN_VOLTAGE_MV && voltage_mv <= LDO_LL_RECOMMEND_MAX_VOLTAGE_MV))) { diff --git a/components/esp_hw_support/port/esp32s31/Kconfig.ldo b/components/esp_hw_support/port/esp32s31/Kconfig.ldo new file mode 100644 index 00000000000..9b5dd7d4924 --- /dev/null +++ b/components/esp_hw_support/port/esp32s31/Kconfig.ldo @@ -0,0 +1,34 @@ +menu "LDO Regulator Configurations" + depends on SOC_GP_LDO_SUPPORTED + + config ESP_LDO_RESERVE_PSRAM + bool "Reserve one LDO regulator channel for PSRAM (READ HELP)" + default y + help + The LDO channel can be used to power the PSRAM chip. + If the PSRAM chip is not powered by ESP internal LDO, you can disable this option. + Then you will free up one LDO channel for other general purpose. + + config ESP_LDO_CHAN_PSRAM_DOMAIN + int "LDO regulator channel that used to power PSRAM and MPLL (READ HELP)" + depends on ESP_LDO_RESERVE_PSRAM + default 1 + range 1 1 + help + Select which LDO channel to connect to the PSRAM chip. + + choice ESP_LDO_VOLTAGE_PSRAM_DOMAIN + prompt "PSRAM power domain voltage" + depends on ESP_LDO_RESERVE_PSRAM + default ESP_LDO_VOLTAGE_PSRAM_1800_MV + help + Select the voltage used by the PSRAM power domain. + + config ESP_LDO_VOLTAGE_PSRAM_1800_MV + bool "1.8V" + endchoice + + config ESP_LDO_VOLTAGE_PSRAM_DOMAIN + int + default 1800 if ESP_LDO_VOLTAGE_PSRAM_1800_MV +endmenu diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt index 1c06469e06f..b2394236f34 100644 --- a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/CMakeLists.txt @@ -10,7 +10,9 @@ if(CONFIG_SOC_RNG_SUPPORTED) list(APPEND srcs "test_random.c") endif() -if(CONFIG_SOC_GP_LDO_SUPPORTED) +if(CONFIG_SOC_GP_LDO_SUPPORTED AND NOT CONFIG_IDF_TARGET_ESP32S31) + # on s31 ldo is general purpose (and also for psram), but runners all have psram + # so we don't run ldo test on s31 to avoid breaking psram list(APPEND srcs "test_ldo.c") endif() diff --git a/components/esp_psram/CMakeLists.txt b/components/esp_psram/CMakeLists.txt index 9a12c8fa79e..d723602b8e0 100644 --- a/components/esp_psram/CMakeLists.txt +++ b/components/esp_psram/CMakeLists.txt @@ -24,7 +24,6 @@ set(srcs "system_layer/esp_psram_mspi.c") if(CONFIG_SPIRAM) list(APPEND srcs "system_layer/esp_psram.c") - list(APPEND srcs "system_layer/esp_psram_ldo_supply.c") if(${target} STREQUAL "esp32") list(APPEND srcs "esp32/esp_psram_extram_cache.c" diff --git a/components/esp_psram/device/esp_psram_impl_ap_hex.c b/components/esp_psram/device/esp_psram_impl_ap_hex.c index daed4151e26..e8216c73330 100644 --- a/components/esp_psram/device/esp_psram_impl_ap_hex.c +++ b/components/esp_psram/device/esp_psram_impl_ap_hex.c @@ -11,7 +11,6 @@ #include "esp_private/periph_ctrl.h" #include "esp_private/mspi_timing_tuning.h" #include "esp_private/esp_psram_impl.h" -#include "esp_private/esp_psram_ldo.h" #include "hal/psram_ctrlr_ll.h" #include "hal/mspi_ll.h" #include "soc/rtc.h" diff --git a/components/esp_psram/device/esp_psram_impl_ap_oct.c b/components/esp_psram/device/esp_psram_impl_ap_oct.c index 8d70ece8676..3c5f51244ea 100644 --- a/components/esp_psram/device/esp_psram_impl_ap_oct.c +++ b/components/esp_psram/device/esp_psram_impl_ap_oct.c @@ -13,7 +13,6 @@ #include "esp_private/periph_ctrl.h" #include "esp_private/mspi_timing_tuning.h" #include "esp_private/esp_psram_impl.h" -#include "esp_private/esp_psram_ldo.h" #include "hal/psram_ctrlr_ll.h" #include "hal/mspi_ll.h" #include "soc/rtc.h" @@ -415,12 +414,6 @@ esp_err_t esp_psram_impl_enable(void) { psram_ctrlr_ll_enable_power(true); -#if PSRAM_CTRLR_LL_DEDICATED_LDO - esp_psram_power_cfg_t config = { - .voltage_mv = CONFIG_SPIRAM_LDO_VOLTAGE_DOMAIN, - }; - esp_psram_power_init(&config); -#endif #if SOC_CLK_MPLL_SUPPORTED // We need to use the acquire and freq_set functions directly instead of general clk_tree API for IRAM safe function esp_clk_tree_mpll_acquire(); diff --git a/components/esp_psram/esp32s31/Kconfig.spiram b/components/esp_psram/esp32s31/Kconfig.spiram index 5dc5310b6f6..3fdcc32b7a7 100644 --- a/components/esp_psram/esp32s31/Kconfig.spiram +++ b/components/esp_psram/esp32s31/Kconfig.spiram @@ -93,20 +93,3 @@ menu "PSRAM config" source "$IDF_PATH/components/esp_psram/Kconfig.spiram.common" # insert non-chip-specific items here endmenu - -menu "PSRAM LDO Configurations" - - choice SPIRAM_LDO_VOLTAGE_DOMAIN - prompt "PSRAM power domain voltage" - default SPIRAM_LDO_VOLTAGE_1800_MV - help - Select the voltage used by the PSRAM power domain. - - config SPIRAM_LDO_VOLTAGE_1800_MV - bool "1.8V" - endchoice - - config SPIRAM_LDO_VOLTAGE_DOMAIN - int - default 1800 if SPIRAM_LDO_VOLTAGE_1800_MV -endmenu diff --git a/components/esp_psram/include/esp_private/esp_psram_ldo.h b/components/esp_psram/include/esp_private/esp_psram_ldo.h deleted file mode 100644 index bc3488f0d3c..00000000000 --- a/components/esp_psram/include/esp_private/esp_psram_ldo.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#pragma once - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Configuration for PSRAM domain LDO supply initialization - */ -typedef struct { - uint32_t voltage_mv; /*!< PSRAM supply voltage in mV */ -} esp_psram_power_cfg_t; - -/** - * @brief Initialize the PSRAM supply (LDO voltage and power switch) - * - * @param config Configuration for the PSRAM supply - */ -void esp_psram_power_init(const esp_psram_power_cfg_t *config); - -#ifdef __cplusplus -} -#endif diff --git a/components/esp_psram/linker.lf b/components/esp_psram/linker.lf index 01f9d6df59d..c5473cff39e 100644 --- a/components/esp_psram/linker.lf +++ b/components/esp_psram/linker.lf @@ -26,5 +26,3 @@ entries: esp_psram: esp_psram_init (noflash) esp_psram: s_psram_chip_init (noflash) esp_psram: s_xip_psram_placement (noflash) - if IDF_TARGET_ESP32S31 = y: - esp_psram_ldo_supply: esp_psram_power_init (noflash) diff --git a/components/esp_psram/system_layer/esp_psram_ldo_supply.c b/components/esp_psram/system_layer/esp_psram_ldo_supply.c deleted file mode 100644 index 27c8ff66033..00000000000 --- a/components/esp_psram/system_layer/esp_psram_ldo_supply.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "sdkconfig.h" -#if !CONFIG_IDF_TARGET_ESP32 && !CONFIG_IDF_TARGET_ESP32S2 -#include "hal/psram_ctrlr_ll.h" -#endif -#if PSRAM_CTRLR_LL_DEDICATED_LDO -#include "hal/ldo_ll.h" -#include "esp_private/esp_psram_ldo.h" - -void esp_psram_power_init(const esp_psram_power_cfg_t *config) -{ - uint8_t dref = 0; - uint8_t mul = 0; - bool use_rail_voltage = false; - ldo_ll_enable_current_limit(0, true); - ldo_ll_voltage_to_dref_mul(0, config->voltage_mv, &dref, &mul, &use_rail_voltage); - ldo_ll_adjust_voltage(0, dref, mul, use_rail_voltage); - ldo_ll_psram_power_enable(true); - ldo_ll_enable_current_limit(0, false); -} - -#endif diff --git a/components/sdmmc/sd_pwr_ctrl/sd_pwr_ctrl_by_on_chip_ldo.c b/components/sdmmc/sd_pwr_ctrl/sd_pwr_ctrl_by_on_chip_ldo.c index aebbaae36b2..902f47595ce 100644 --- a/components/sdmmc/sd_pwr_ctrl/sd_pwr_ctrl_by_on_chip_ldo.c +++ b/components/sdmmc/sd_pwr_ctrl/sd_pwr_ctrl_by_on_chip_ldo.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -18,6 +18,14 @@ #include "sd_pwr_ctrl_by_on_chip_ldo.h" #include "sd_pwr_ctrl_interface.h" +#if SOC_SDMMC_IO_UHS_POWER_EXTERNAL +#define SD_VOLT_MV 1800 +#define SD_VOLT_ADJUST_MODE false +#else +#define SD_VOLT_MV 3300 +#define SD_VOLT_ADJUST_MODE true +#endif + typedef struct { esp_ldo_channel_handle_t ldo_chan; int voltage_mv; @@ -38,9 +46,9 @@ esp_err_t sd_pwr_ctrl_new_on_chip_ldo(const sd_pwr_ctrl_ldo_config_t *configs, s ESP_GOTO_ON_FALSE(ctx, ESP_ERR_NO_MEM, err, TAG, "no mem for on-chip ldo control driver context"); esp_ldo_channel_config_t chan_cfg = { - .voltage_mv = 3300, + .voltage_mv = SD_VOLT_MV, .chan_id = configs->ldo_chan_id, - .flags.adjustable = true, // the SDMMC power control driver will adjust the voltage later according to different speed mode + .flags.adjustable = SD_VOLT_ADJUST_MODE, // the SDMMC power control driver will adjust the voltage later according to different speed mode }; esp_ldo_channel_handle_t ldo_chan = NULL; ESP_GOTO_ON_ERROR(esp_ldo_acquire_channel(&chan_cfg, &ldo_chan), err, TAG, "failed to enable the on-chip LDO unit"); @@ -51,6 +59,8 @@ esp_err_t sd_pwr_ctrl_new_on_chip_ldo(const sd_pwr_ctrl_ldo_config_t *configs, s ctx->voltage_mv = 0; *ret_drv = driver; + ESP_LOGD(TAG, "on-chip LDO unit %d enabled", configs->ldo_chan_id); + return ESP_OK; err: @@ -77,6 +87,7 @@ static esp_err_t s_ldo_set_voltage(void *arg, int voltage_mv) { //API checks done by caller sd_pwr_ctrl_ldo_ctx_t *ctx = arg; + ESP_LOGD(TAG, "setting LDO unit output voltage to %dmV", voltage_mv); ESP_RETURN_ON_ERROR(esp_ldo_channel_adjust_voltage(ctx->ldo_chan, voltage_mv), TAG, "failed to set LDO unit output voltage"); ctx->voltage_mv = voltage_mv; return ESP_OK;