diff --git a/dts/arm/ambiq/ambiq_apollo3_blue.dtsi b/dts/arm/ambiq/ambiq_apollo3_blue.dtsi index beebfa7a03bd..3b62b23ba0e9 100644 --- a/dts/arm/ambiq/ambiq_apollo3_blue.dtsi +++ b/dts/arm/ambiq/ambiq_apollo3_blue.dtsi @@ -23,6 +23,32 @@ cpu0: cpu@0 { compatible = "arm,cortex-m4f"; reg = <0>; + cpu-power-states = <&idle &suspend_to_ram>; + }; + + power-states { + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + /* As Apollo3blue datasheet, run_to_sleep and sleep_to_run + * transition time are both lower than 1us, but considering + * the software overhead we set a bigger value. + */ + min-residency-us = <100>; + exit-latency-us = <5>; + }; + + suspend_to_ram: suspend_to_ram { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-ram"; + /* As Apollo3blue datasheet, run_to_deepsleep transition time is + * the software overhead 1us and deepsleep_to_run transition time + * is about 25us,but considering the software overhead, we set + * a bigger value. + */ + min-residency-us = <2000>; + exit-latency-us = <125>; + }; }; }; diff --git a/dts/arm/ambiq/ambiq_apollo3p_blue.dtsi b/dts/arm/ambiq/ambiq_apollo3p_blue.dtsi index b97d9a2fc66e..783b7678f129 100644 --- a/dts/arm/ambiq/ambiq_apollo3p_blue.dtsi +++ b/dts/arm/ambiq/ambiq_apollo3p_blue.dtsi @@ -23,6 +23,32 @@ cpu0: cpu@0 { compatible = "arm,cortex-m4f"; reg = <0>; + cpu-power-states = <&idle &suspend_to_ram>; + }; + + power-states { + idle: idle { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-idle"; + /* As Apollo3blueplus datasheet, run_to_sleep and sleep_to_run + * transition time are both lower than 1us, but considering + * the software overhead we set a bigger value. + */ + min-residency-us = <100>; + exit-latency-us = <5>; + }; + + suspend_to_ram: suspend_to_ram { + compatible = "zephyr,power-state"; + power-state-name = "suspend-to-ram"; + /* As Apollo3blueplus datasheet, run_to_deepsleep transition time + * is the software overhead 1us and deepsleep_to_run transition + * time is about 25us,but considering the software overhead, + * we set a bigger value. + */ + min-residency-us = <2000>; + exit-latency-us = <125>; + }; }; }; diff --git a/soc/ambiq/apollo3x/CMakeLists.txt b/soc/ambiq/apollo3x/CMakeLists.txt index 4d73e4ed2fe6..e83284c85536 100644 --- a/soc/ambiq/apollo3x/CMakeLists.txt +++ b/soc/ambiq/apollo3x/CMakeLists.txt @@ -5,6 +5,7 @@ zephyr_sources(soc.c) zephyr_include_directories(.) +zephyr_sources_ifdef(CONFIG_PM power.c) zephyr_linker_sources(SECTIONS shared_ram.ld) diff --git a/soc/ambiq/apollo3x/Kconfig b/soc/ambiq/apollo3x/Kconfig index de93bd91e90b..ad9fb253fcbd 100644 --- a/soc/ambiq/apollo3x/Kconfig +++ b/soc/ambiq/apollo3x/Kconfig @@ -10,3 +10,4 @@ config SOC_SERIES_APOLLO3X select CPU_HAS_ARM_MPU select HAS_SWO select AMBIQ_HAL + select HAS_PM diff --git a/soc/ambiq/apollo3x/Kconfig.defconfig b/soc/ambiq/apollo3x/Kconfig.defconfig index abac3c9c75d3..95e84ae45533 100644 --- a/soc/ambiq/apollo3x/Kconfig.defconfig +++ b/soc/ambiq/apollo3x/Kconfig.defconfig @@ -6,4 +6,9 @@ if SOC_SERIES_APOLLO3X rsource "Kconfig.defconfig.apollo3*" +# Need to enlarge the IDLE stack size because the power +# management operations are executed in the idle task +config IDLE_STACK_SIZE + default 2048 if PM + endif # SOC_SERIES_APOLLO3X diff --git a/soc/ambiq/apollo3x/power.c b/soc/ambiq/apollo3x/power.c new file mode 100644 index 000000000000..630a34638abe --- /dev/null +++ b/soc/ambiq/apollo3x/power.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2024 Ambiq Micro Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include +#include +#include + +/* ambiq-sdk includes */ +#include + +LOG_MODULE_DECLARE(soc, CONFIG_SOC_LOG_LEVEL); + +void pm_state_set(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + + __disable_irq(); + __set_BASEPRI(0); + + switch (state) { + case PM_STATE_SUSPEND_TO_IDLE: + /* Put ARM core to normal sleep. */ + am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_NORMAL); + break; + case PM_STATE_SUSPEND_TO_RAM: + /* Put ARM core to deep sleep. */ + /* Cotex-m: power down, register value preserve.*/ + /* Cache: power down*/ + /* Flash: power down*/ + /* Sram: retention*/ + am_hal_sysctrl_sleep(AM_HAL_SYSCTRL_SLEEP_DEEP); + break; + default: + LOG_DBG("Unsupported power state %u", state); + break; + } +} + +/** + * @brief PM State Exit Post Operations + * + * For PM_STATE_SUSPEND_TO_IDLE: + * Nothing is needed after soc woken up. + * + * For PM_STATE_SUSPEND_TO_RAM: + * Flash, cache, sram automatically switch + * to active state on wake up + * + * @param state PM State + * @param substate_id Unused + * + */ +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + + __enable_irq(); + irq_unlock(0); +} + +static int ambiq_power_init(void) +{ + /* Enable flash. + * Currently all flash area is powered on, but we should only enable the used flash area and + * put unused flash in power down mode. + */ + if (am_hal_pwrctrl_memory_enable(AM_HAL_PWRCTRL_MEM_FLASH_MAX)) { + __ASSERT(0, "Failed to enable FLASH!"); + } + + /* Enable SRAM. + * Currently all SRAM area is powered on, but we should only enable the used ram area and + * put unused ram in power down mode. + */ + if (am_hal_pwrctrl_memory_enable(AM_HAL_PWRCTRL_MEM_SRAM_MAX)) { + __ASSERT(0, "Failed to enable SRAM!"); + } + + /* For optimal Deep Sleep current, configure cache to be powered-down in deepsleep. */ + am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_CACHE); + + /* Power off all flash area, when go to deep sleep.*/ + am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_FLASH_MAX); + + /* Keep the used SRAM area in retention mode. */ + am_hal_pwrctrl_memory_deepsleep_powerdown(AM_HAL_PWRCTRL_MEM_SRAM_MAX); + am_hal_pwrctrl_memory_deepsleep_retain(AM_HAL_PWRCTRL_MEM_SRAM_MAX); + +#if defined(CONFIG_SOC_APOLLO3P_BLUE) + /* + * If user has enabled AM_HAL_SYSCTRL_DEEPSLEEP_WA in am_hal_sysctrl.h + * this will allow user to acheive lower current draw in deepsleep + */ + am_hal_sysctrl_control(AM_HAL_SYSCTRL_CONTROL_DEEPSLEEP_MINPWR_EN, 0); +#endif + + return 0; +} + +SYS_INIT(ambiq_power_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/ambiq/apollo3x/soc.c b/soc/ambiq/apollo3x/soc.c index d10b4a5dcfb7..c76dda6d8500 100644 --- a/soc/ambiq/apollo3x/soc.c +++ b/soc/ambiq/apollo3x/soc.c @@ -10,6 +10,12 @@ static int arm_apollo3_init(void) { + /* Set the clock frequency. */ + am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_SYSCLK_MAX, 0); + + /* Enable Flash cache.*/ + am_hal_cachectrl_config(&am_hal_cachectrl_defaults); + am_hal_cachectrl_enable(); /* Initialize for low power in the power control block */ am_hal_pwrctrl_low_power_init(); diff --git a/soc/ambiq/apollo4x/power.c b/soc/ambiq/apollo4x/power.c index 8fe8557ba7ed..30950436517a 100644 --- a/soc/ambiq/apollo4x/power.c +++ b/soc/ambiq/apollo4x/power.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 Ambiq LLC + * Copyright (c) 2024 Ambiq Micro Inc. * * SPDX-License-Identifier: Apache-2.0 */