diff --git a/drivers/timer/smartbond_timer.c b/drivers/timer/smartbond_timer.c index 34c9a7d721..4ab03f5d95 100644 --- a/drivers/timer/smartbond_timer.c +++ b/drivers/timer/smartbond_timer.c @@ -75,6 +75,29 @@ void sys_clock_set_timeout(int32_t ticks, bool idle) /* FIXME we could disable timer here */ } + /* + * When Watchdog is NOT enabled but power management is, system + * starts watchdog before PD_SYS is powered off. + * Watchdog default reload value is 0x1FFF (~82s for RC32K and 172s for RCX). + * After this time watchdog will reset system if not woken up before. + * When Watchdog is not configured power management freezes watchdog + * as soon as system is awaken. Following code makes sure that + * system never goes to sleep for longer time that watchdog reload value. + */ + if (!IS_ENABLED(CONFIG_WDT_SMARTBOND) && IS_ENABLED(CONFIG_PM)) { + uint32_t watchdog_expire_ticks; + + if (CRG_TOP->CLK_RCX_REG & CRG_TOP_CLK_RCX_REG_RCX_ENABLE_Msk) { + watchdog_expire_ticks = SYS_WDOG->WATCHDOG_REG * 21 * + CONFIG_SYS_CLOCK_TICKS_PER_SEC / 1000; + } else { + watchdog_expire_ticks = SYS_WDOG->WATCHDOG_REG * + CONFIG_SYS_CLOCK_TICKS_PER_SEC / 100; + } + if (watchdog_expire_ticks - 2 < ticks) { + ticks = watchdog_expire_ticks - 2; + } + } ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : ticks; ticks = CLAMP(ticks - 1, 0, (int32_t)MAX_TICKS); diff --git a/dts/arm/renesas/smartbond/da1469x.dtsi b/dts/arm/renesas/smartbond/da1469x.dtsi index ae523ae671..eed1abc33e 100644 --- a/dts/arm/renesas/smartbond/da1469x.dtsi +++ b/dts/arm/renesas/smartbond/da1469x.dtsi @@ -28,6 +28,16 @@ compatible = "arm,cortex-m33f"; reg = <0>; clock-frequency = <32000000>; + cpu-power-states = <&standby>; + }; + + power-states { + standby: standby { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <500>; + exit-latency-us = <100>; + }; }; }; diff --git a/soc/renesas/smartbond/da1469x/CMakeLists.txt b/soc/renesas/smartbond/da1469x/CMakeLists.txt index 0c45be52d2..164e641cc0 100644 --- a/soc/renesas/smartbond/da1469x/CMakeLists.txt +++ b/soc/renesas/smartbond/da1469x/CMakeLists.txt @@ -8,5 +8,6 @@ zephyr_linker_sources( zephyr_library() zephyr_library_sources(soc.c) zephyr_include_directories(.) +zephyr_library_sources_ifdef(CONFIG_PM power.c) set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/renesas/smartbond/da1469x/Kconfig b/soc/renesas/smartbond/da1469x/Kconfig index 1462ea6457..0dcaed68f0 100644 --- a/soc/renesas/smartbond/da1469x/Kconfig +++ b/soc/renesas/smartbond/da1469x/Kconfig @@ -9,6 +9,7 @@ config SOC_SERIES_DA1469X select CPU_CORTEX_M_HAS_SYSTICK select ARMV8_M_DSP select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE + select HAS_PM select CLOCK_CONTROL select CLOCK_CONTROL_SMARTBOND select PLATFORM_SPECIFIC_INIT diff --git a/soc/renesas/smartbond/da1469x/power.c b/soc/renesas/smartbond/da1469x/power.c new file mode 100644 index 0000000000..1b325c47eb --- /dev/null +++ b/soc/renesas/smartbond/da1469x/power.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2023 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#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); + + switch (state) { + case PM_STATE_STANDBY: + /* We enter here with interrupts disabled by BASEPRI which prevents wfi from + * waking up on interrupts. Need to disable interrupts by PRIMASK instead and + * reset BASEPRI to 0. + */ + __disable_irq(); + arch_irq_unlock(0); + + da1469x_sleep(); + + break; + default: + LOG_DBG("Unsupported power state %u", state); + break; + } +} + +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(state); + ARG_UNUSED(substate_id); +} + +static int renesas_da1469x_pm_init(void) +{ + static const struct da1469x_sleep_config sleep_cfg = { + .enable_xtal_on_wakeup = DT_NODE_HAS_STATUS(DT_NODELABEL(xtal32m), okay), + }; + + da1469x_sleep_config(&sleep_cfg); + + return 0; +} + +SYS_INIT(renesas_da1469x_pm_init, PRE_KERNEL_2, 2); diff --git a/soc/renesas/smartbond/da1469x/soc.c b/soc/renesas/smartbond/da1469x/soc.c index 5fc566748c..2d458ca050 100644 --- a/soc/renesas/smartbond/da1469x/soc.c +++ b/soc/renesas/smartbond/da1469x/soc.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -13,7 +14,9 @@ #include #include #include -#include +#include + +LOG_MODULE_REGISTER(soc, CONFIG_SOC_LOG_LEVEL); #define REMAP_ADR0_QSPI 0x2 @@ -108,15 +111,31 @@ static void z_renesas_configure_cache(void) void z_arm_platform_init(void) { +#if defined(CONFIG_PM) + uint32_t *ivt; +#endif + #if defined(CONFIG_BOOTLOADER_MCUBOOT) z_renesas_configure_cache(); #endif + +#if defined(CONFIG_PM) + /* IVT is always placed in reserved space at the start of RAM which + * is then remapped to 0x0 and retained. Generic reset handler is + * changed to custom routine since next time ARM core is reset we + * need to determine whether it was a regular reset or a wakeup from + * extended sleep and ARM core state needs to be restored. + */ + ivt = (uint32_t *)_image_ram_start; + ivt[1] = (uint32_t)da1469x_wakeup_handler; +#endif } static int renesas_da1469x_init(void) { /* Freeze watchdog until configured */ GPREG->SET_FREEZE_REG = GPREG_SET_FREEZE_REG_FRZ_SYS_WDOG_Msk; + SYS_WDOG->WATCHDOG_REG = SYS_WDOG_WATCHDOG_REG_WDOG_VAL_Msk; /* Reset clock dividers to 0 */ CRG_TOP->CLK_AMBA_REG &= ~(CRG_TOP_CLK_AMBA_REG_HCLK_DIV_Msk |