From fbc7a9e209397e0d8c487d91e5106fbe9f633cd6 Mon Sep 17 00:00:00 2001 From: Andrzej Kaczmarek Date: Wed, 22 Mar 2023 14:30:11 +0100 Subject: [PATCH] soc: arm: smartbond: Add support for extended sleep This enabled extended sleep for Renesas SmartBond(tm). Extended sleep is low power mode where ARM core is powered off and can be woken up by PDC. This is default sleep mode when CONFIG_PM is enabled. Signed-off-by: Andrzej Kaczmarek Signed-off-by: Jerzy Kasenberg --- drivers/timer/smartbond_timer.c | 23 ++++++++ dts/arm/renesas/smartbond/da1469x.dtsi | 10 ++++ soc/renesas/smartbond/da1469x/CMakeLists.txt | 1 + soc/renesas/smartbond/da1469x/Kconfig | 1 + soc/renesas/smartbond/da1469x/power.c | 55 ++++++++++++++++++++ soc/renesas/smartbond/da1469x/soc.c | 21 +++++++- 6 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 soc/renesas/smartbond/da1469x/power.c 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 |