diff --git a/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts index 1a2f8be10d84..34f0fe9316e7 100644 --- a/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts +++ b/boards/ti/lp_em_cc2340r5/lp_em_cc2340r5.dts @@ -62,6 +62,10 @@ zephyr,code = ; }; }; + + lfxosc: lf_xosc { + compatible = "ti,cc23x0-lf-xosc"; + }; }; &gpio0 { diff --git a/drivers/counter/Kconfig.cc23x0_rtc b/drivers/counter/Kconfig.cc23x0_rtc index 5afcbda2d3e8..ce4e9ad6b2c1 100644 --- a/drivers/counter/Kconfig.cc23x0_rtc +++ b/drivers/counter/Kconfig.cc23x0_rtc @@ -5,5 +5,6 @@ config COUNTER_CC23X0_RTC bool "CC23x0 Counter driver based on the RTC Timer" default y depends on DT_HAS_TI_CC23X0_RTC_ENABLED + depends on CC23X0_SYSTIM_TIMER help Enable counter driver based on RTC timer for cc23x0 diff --git a/drivers/timer/CMakeLists.txt b/drivers/timer/CMakeLists.txt index 3c488da9a3e7..408873f77742 100644 --- a/drivers/timer/CMakeLists.txt +++ b/drivers/timer/CMakeLists.txt @@ -12,6 +12,7 @@ zephyr_library_sources_ifdef(CONFIG_ARM_ARCH_TIMER arm_arch_timer.c) zephyr_library_sources_ifdef(CONFIG_INTEL_ADSP_TIMER intel_adsp_timer.c) zephyr_library_sources_ifdef(CONFIG_CC13XX_CC26XX_RTC_TIMER cc13xx_cc26xx_rtc_timer.c) zephyr_library_sources_ifdef(CONFIG_CC23X0_SYSTIM_TIMER cc23x0_systim_timer.c) +zephyr_library_sources_ifdef(CONFIG_CC23X0_RTC_TIMER cc23x0_rtc_timer.c) zephyr_library_sources_ifdef(CONFIG_CH32V00X_SYSTICK wch_systick_ch32v00x.c) zephyr_library_sources_ifdef(CONFIG_CORTEX_M_SYSTICK cortex_m_systick.c) zephyr_library_sources_ifdef(CONFIG_ESP32_SYS_TIMER esp32_sys_timer.c) diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index c154370c4563..5038252e851f 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -69,7 +69,7 @@ source "drivers/timer/Kconfig.arcv2" source "drivers/timer/Kconfig.arm_arch" source "drivers/timer/Kconfig.cavs" source "drivers/timer/Kconfig.cc13xx_cc26xx_rtc" -source "drivers/timer/Kconfig.cc23x0_systim" +source "drivers/timer/Kconfig.cc23x0" source "drivers/timer/Kconfig.wch_ch32v00x" source "drivers/timer/Kconfig.cortex_m_systick" source "drivers/timer/Kconfig.esp32" diff --git a/drivers/timer/Kconfig.cc23x0 b/drivers/timer/Kconfig.cc23x0 new file mode 100644 index 000000000000..95a0453fa315 --- /dev/null +++ b/drivers/timer/Kconfig.cc23x0 @@ -0,0 +1,26 @@ +# Copyright (c) 2024 Texas Instruments Incorporated +# Copyright (c) 2024 BayLibre, SAS +# +# SPDX-License-Identifier: Apache-2.0 + +choice + prompt "TI SimpleLink CC23X default System Timer" + depends on HAS_CC23X0_SDK + default CC23X0_RTC_TIMER + help + Select Default System Timer. + +config CC23X0_SYSTIM_TIMER + bool "SYSTIM timer" + select TICKLESS_CAPABLE + help + This module provides SYSTIM as "system clock driver" interfaces + for the TI Simplelink CC23X0 devices. + +config CC23X0_RTC_TIMER + bool "RTC timer" + select TICKLESS_CAPABLE + help + This module provides RTC as "system clock driver" interfaces + for the TI Simplelink CC23X0 devices. +endchoice diff --git a/drivers/timer/Kconfig.cc23x0_rtc b/drivers/timer/Kconfig.cc23x0_rtc new file mode 100644 index 000000000000..74c4fc177204 --- /dev/null +++ b/drivers/timer/Kconfig.cc23x0_rtc @@ -0,0 +1,12 @@ +# Copyright (c) 2024 BayLibre, SAS +# +# SPDX-License-Identifier: Apache-2.0 + +config CC23X0_RTC_TIMER + bool "TI SimpleLink CC23X0 RTC system clock timer" + default y + depends on HAS_CC23X0_SDK + select TICKLESS_CAPABLE + help + This module provides the RTC as "system clock driver" interfaces + for the TI Simplelink CC23X0 devices. diff --git a/drivers/timer/Kconfig.cc23x0_systim b/drivers/timer/Kconfig.cc23x0_systim deleted file mode 100644 index 41db73e6d52c..000000000000 --- a/drivers/timer/Kconfig.cc23x0_systim +++ /dev/null @@ -1,13 +0,0 @@ -# Copyright (c) 2024 Texas Instruments Incorporated -# Copyright (c) 2024 BayLibre, SAS -# -# SPDX-License-Identifier: Apache-2.0 - -config CC23X0_SYSTIM_TIMER - bool "TI SimpleLink CC23X0 system clock timer" - default y - depends on HAS_CC23X0_SDK - select TICKLESS_CAPABLE - help - This module provides the "system clock driver" interfaces - for the TI Simplelink CC23X0 devices. diff --git a/drivers/timer/cc23x0_rtc_timer.c b/drivers/timer/cc23x0_rtc_timer.c new file mode 100644 index 000000000000..171ec1436c44 --- /dev/null +++ b/drivers/timer/cc23x0_rtc_timer.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2024 BayLibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_cc23x0_rtc_timer + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define RTC_TIMEOUT_MAX 0xFFBFFFFFU + +/* Set rtc interrupt to lowest priority */ +#define SYSTIM_ISR_PRIORITY 3U + +/* Keep track of rtc counter at previous announcement to the kernel */ +static uint32_t last_rtc_count; + +static void rtc_isr(const void *arg); +static int sys_clock_driver_init(void); + +#define TICK_PERIOD_MICRO_SEC (1000000 / CONFIG_SYS_CLOCK_TICKS_PER_SEC) + +void sys_clock_set_timeout(int32_t ticks, bool idle) +{ + ARG_UNUSED(idle); + + /* If timeout is necessary */ + if (ticks != K_TICKS_FOREVER) { + /* Get current value as early as possible */ + uint32_t ticks_now = HWREG(RTC_BASE + RTC_O_TIME8U); + + if ((ticks_now + ticks) >= RTC_TIMEOUT_MAX) { + /* Reset timer and start from 0 */ + HWREG(RTC_BASE + RTC_O_CTL) = 0x1; + HWREG(RTC_BASE + RTC_O_CH0CC8U) = ticks; + } + + HWREG(RTC_BASE + RTC_O_CH0CC8U) = ticks_now + ticks; + } +} + +uint32_t sys_clock_elapsed(void) +{ + uint32_t current_rtc_count = HWREG(RTC_BASE + RTC_O_TIME8U); + + uint32_t elapsed_rtc; + + if (current_rtc_count >= last_rtc_count) { + elapsed_rtc = current_rtc_count - last_rtc_count; + } else { + elapsed_rtc = (0xFFFFFFFF - last_rtc_count) + current_rtc_count; + } + + int32_t elapsed_ticks = elapsed_rtc / TICK_PERIOD_MICRO_SEC; + + return elapsed_ticks; +} + +uint32_t sys_clock_cycle_get_32(void) +{ + return HWREG(RTC_BASE + RTC_O_TIME8U); +} + +void rtc_isr(const void *arg) +{ + uint32_t current_rtc_count = HWREG(RTC_BASE + RTC_O_TIME8U); + + uint32_t elapsed_rtc; + + if (current_rtc_count >= last_rtc_count) { + elapsed_rtc = current_rtc_count - last_rtc_count; + } else { + elapsed_rtc = (0xFFFFFFFF - last_rtc_count) + current_rtc_count; + } + + int32_t elapsed_ticks = elapsed_rtc; + + HWREG(RTC_BASE + RTC_O_ICLR) = 0x1; + + sys_clock_announce(elapsed_ticks); + + last_rtc_count = current_rtc_count; +} + +static int sys_clock_driver_init(void) +{ + uint32_t now_ticks; + + now_ticks = HWREG(RTC_BASE + RTC_O_TIME8U); + last_rtc_count = now_ticks; + + HWREG(RTC_BASE + RTC_O_ICLR) = 0x3; + HWREG(RTC_BASE + RTC_O_IMCLR) = 0x3; + + HWREG(EVTSVT_BASE + EVTSVT_O_CPUIRQ16SEL) = EVTSVT_CPUIRQ16SEL_PUBID_AON_RTC_COMB; + HWREG(RTC_BASE + RTC_O_CH0CC8U) = now_ticks + RTC_TIMEOUT_MAX; + + HWREG(RTC_BASE + RTC_O_IMASK) = 0x1; + HWREG(RTC_BASE + RTC_O_ARMSET) = 0x1; + + /* Take configurable interrupt IRQ16 for rtc */ + IRQ_CONNECT(CPUIRQ16_IRQn, SYSTIM_ISR_PRIORITY, rtc_isr, 0, 0); + irq_enable(CPUIRQ16_IRQn); + + return 0; +} + +SYS_INIT(sys_clock_driver_init, PRE_KERNEL_2, CONFIG_SYSTEM_CLOCK_INIT_PRIORITY); diff --git a/dts/arm/ti/cc23x0.dtsi b/dts/arm/ti/cc23x0.dtsi index 96a1e189a8b8..d3ab5fda5383 100644 --- a/dts/arm/ti/cc23x0.dtsi +++ b/dts/arm/ti/cc23x0.dtsi @@ -22,6 +22,31 @@ compatible = "arm,cortex-m0+"; clock-frequency = ; reg = <0>; + cpu-power-states = <&state0 &state1 &state2>; + }; + + power-states { + state0: state0 { + compatible = "zephyr,power-state"; + power-state-name = "runtime-idle"; + min-residency-us = <315>; + }; + + state1: state1 { + compatible = "zephyr,power-state"; + power-state-name = "standby"; + min-residency-us = <315>; + exit-latency-us = <185>; + }; + + /* PM_STATE_SOFT_OFF can be entered only by calling pm_state_force */ + state2: state2 { + compatible = "zephyr,power-state"; + power-state-name = "soft-off"; + min-residency-us = <0>; + exit-latency-us = <0>; + status = "disabled"; + }; }; }; diff --git a/dts/bindings/clock/ti,cc23x0-lf-xosc.yaml b/dts/bindings/clock/ti,cc23x0-lf-xosc.yaml new file mode 100644 index 000000000000..4ba43598b299 --- /dev/null +++ b/dts/bindings/clock/ti,cc23x0-lf-xosc.yaml @@ -0,0 +1,8 @@ +# Copyright (c) 2024 Baylibre, SAS +# SPDX-License-Identifier: Apache-2.0 + +description: TI CC23X0 external low-frequency oscillator + +compatible: "ti,cc23x0-lf-xosc" + +include: base.yaml diff --git a/soc/ti/simplelink/cc23x0/CMakeLists.txt b/soc/ti/simplelink/cc23x0/CMakeLists.txt index b8e02adbd58e..27581e425aea 100644 --- a/soc/ti/simplelink/cc23x0/CMakeLists.txt +++ b/soc/ti/simplelink/cc23x0/CMakeLists.txt @@ -7,6 +7,8 @@ zephyr_sources(soc.c) zephyr_sources(ccfg.c) zephyr_include_directories(.) +zephyr_sources_ifdef(CONFIG_PM power.c) + zephyr_linker_sources_ifdef(CONFIG_HAS_TI_CCFG SECTIONS ccfg.ld) set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "") diff --git a/soc/ti/simplelink/cc23x0/Kconfig b/soc/ti/simplelink/cc23x0/Kconfig index fa1c2c45af3e..7580070e3df7 100644 --- a/soc/ti/simplelink/cc23x0/Kconfig +++ b/soc/ti/simplelink/cc23x0/Kconfig @@ -19,6 +19,8 @@ config SOC_SERIES_CC23X0 select THREAD_STACK_INFO select BUILD_OUTPUT_HEX select BUILD_NO_GAP_FILL + select HAS_PM + select PM_DEVICE if PM menu "Bootloader Configuration" depends on SOC_SERIES_CC23X0 diff --git a/soc/ti/simplelink/cc23x0/Kconfig.defconfig b/soc/ti/simplelink/cc23x0/Kconfig.defconfig index 442c9b09c9e0..8341ef56e96b 100644 --- a/soc/ti/simplelink/cc23x0/Kconfig.defconfig +++ b/soc/ti/simplelink/cc23x0/Kconfig.defconfig @@ -10,8 +10,20 @@ if SOC_SERIES_CC23X0 config SYS_CLOCK_HW_CYCLES_PER_SEC default $(dt_node_int_prop_int,/cpus/cpu@0,clock-frequency) -config SYS_CLOCK_TICKS_PER_SEC - default 1000 +if CC23X0_RTC_TIMER + config SYS_CLOCK_HW_CYCLES_PER_SEC + default 32768 + + config SYS_CLOCK_TICKS_PER_SEC + default 125375 +endif +if CC23X0_SYSTIM_TIMER + config SYS_CLOCK_HW_CYCLES_PER_SEC + default 48000000 + + config SYS_CLOCK_TICKS_PER_SEC + default 1000 +endif config NUM_IRQS default 19 diff --git a/soc/ti/simplelink/cc23x0/power.c b/soc/ti/simplelink/cc23x0/power.c new file mode 100644 index 000000000000..f685b14823ca --- /dev/null +++ b/soc/ti/simplelink/cc23x0/power.c @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2024 Texas Instruments Incorporated + * Copyright (c) 2024 Baylibre, SAS + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* Configuring TI Power module to not use its policy function (we use Zephyr's + * instead), and disable oscillator calibration functionality for now. + */ +const PowerCC23X0_Config PowerCC23X0_config = { + .policyInitFxn = NULL, + .policyFxn = NULL, +}; + +#ifdef CONFIG_PM + +#ifndef CONFIG_CC23X0_RTC_TIMER + +#define MAX_SYSTIMER_DELTA 0xFFBFFFFFU +#define RTC_TO_SYSTIM_TICKS 8U +#define SYSTIM_CH_STEP 4U +#define SYSTIM_CH(idx) (SYSTIM_O_CH0CC + idx * SYSTIM_CH_STEP) +#define SYSTIM_TO_RTC_SHIFT 3U +#define SYSTIM_CH_CNT 5U +#define RTC_CH_CNT 2U +#define RTC_NEXT(val, now) (((val - PowerCC23X0_WAKEDELAYSTANDBY) >> SYSTIM_TO_RTC_SHIFT) + now) + +#endif + +static void pm_cc23x0_enter_standby(void); +static int power_initialize(void); +extern int_fast16_t PowerCC23X0_notify(uint_fast16_t eventType); + +#ifndef CONFIG_CC23X0_RTC_TIMER +static void pm_cc23x0_systim_standby_restore(void); + +/* Global to stash the SysTimer timeouts while we enter standby */ +static uint32_t systim[SYSTIM_CH_CNT]; +static uint32_t rtc[RTC_CH_CNT]; +static uintptr_t key; +static uint32_t systim_mask; +static uint32_t rtc_mask; + +/* Shift values to convert between the different resolutions of the SysTimer + * channels. Channel 0 can technically support either 1us or 250ns. Until the + * channel is actively used, we will hard-code it to 1us resolution to improve + * runtime. + */ +const uint8_t systim_offset[SYSTIM_CH_CNT] = { + 0, /* 1us */ + 0, /* 1us */ + 2, /* 250ns -> 1us */ + 2, /* 250ns -> 1us */ + 2 /* 250ns -> 1us */ +}; +#endif + +#ifndef CONFIG_CC23X0_RTC_TIMER +static void pm_cc23x0_systim_standby_restore(void) +{ + HWREG(RTC_BASE + RTC_O_ARMCLR) = RTC_ARMCLR_CH0_CLR; + HWREG(RTC_BASE + RTC_O_ICLR) = RTC_ICLR_EV0_CLR; + + ULLSync(); + + HwiP_clearInterrupt(INT_CPUIRQ16); + HwiP_clearInterrupt(INT_CPUIRQ3); + + HWREG(EVTSVT_BASE + EVTSVT_O_CPUIRQ16SEL) = EVTSVT_CPUIRQ16SEL_PUBID_SYSTIM0; + HWREG(EVTSVT_BASE + EVTSVT_O_CPUIRQ3SEL) = EVTSVT_CPUIRQ16SEL_PUBID_AON_RTC_COMB; + + while (HWREG(SYSTIM_BASE + SYSTIM_O_STATUS) != SYSTIM_STATUS_VAL_RUN) { + ; + } + + for (uint8_t idx = 0; idx < SYSTIM_CH_CNT; idx++) { + if (systim_mask & (1 << idx)) { + HWREG(SYSTIM_BASE + SYSTIM_CH(idx)) = systim[idx]; + } + } + + HWREG(SYSTIM_BASE + SYSTIM_O_IMASK) = systim_mask; + HWREG(RTC_BASE + RTC_O_IMASK) = rtc_mask; + + if (rtc_mask != 0) { + if (rtc_mask & 0x1) { + HWREG(RTC_BASE + RTC_O_CH0CC8U) = rtc[0]; + } + if (rtc_mask & 0x2) { + HWREG(RTC_BASE + RTC_O_CH1CC8U) = rtc[1]; + } + } + + LRFDApplyClockDependencies(); + PowerCC23X0_notify(PowerLPF3_AWAKE_STANDBY); + HwiP_restore(key); +} +#endif + +static void pm_cc23x0_enter_standby(void) +{ +#ifndef CONFIG_CC23X0_RTC_TIMER + uint32_t rtc_now = 0; + uint32_t systim_now = 0; + uint32_t systim_next = MAX_SYSTIMER_DELTA; + uint32_t systim_delta = 0; + uint32_t rtc_delta = 0; + + key = HwiP_disable(); + + uint32_t constraints = Power_getConstraintMask(); + bool standby = (constraints & (1 << PowerLPF3_DISALLOW_STANDBY)) == 0; + bool idle = (constraints & (1 << PowerLPF3_DISALLOW_IDLE)) == 0; + + if (standby && (HWREG(CKMD_BASE + CKMD_O_LFCLKSEL) & CKMD_LFCLKSEL_MAIN_LFOSC) && + !(HWREG(CKMD_BASE + CKMD_O_LFCLKSTAT) & CKMD_LFCLKSTAT_FLTSETTLED_M)) { + standby = false; + idle = false; + } + + if (standby) { + systim_mask = HWREG(SYSTIM_BASE + SYSTIM_O_IMASK); + if (systim_mask != 0) { + systim_next = 0xFFFFFFFF; + systim_now = HWREG(SYSTIM_BASE + SYSTIM_O_TIME1U); + for (uint8_t idx = 0; idx < SYSTIM_CH_CNT; idx++) { + if (systim_mask & (1 << idx)) { + systim[idx] = HWREG(SYSTIM_BASE + SYSTIM_CH(idx)); + systim_delta = systim[idx]; + systim_delta -= systim_now << systim_offset[idx]; + + if (systim_delta > MAX_SYSTIMER_DELTA) { + systim_delta = 0; + } + + systim_delta = systim_delta >> systim_offset[idx]; + systim_next = MIN(systim_next, systim_delta); + } + } + } else { + systim_next = MAX_SYSTIMER_DELTA; + } + + rtc_mask = HWREG(RTC_BASE + RTC_O_IMASK); + if (rtc_mask != 0) { + rtc_now = HWREG(RTC_BASE + RTC_O_TIME8U); + if (rtc_mask & 0x1) { + rtc[0] = HWREG(RTC_BASE + RTC_O_CH0CC8U); + rtc_delta = (rtc[0] - rtc_now) << 3; + systim_next = MIN(systim_next, rtc_delta); + } + if (rtc_mask & 0x2) { + rtc[1] = HWREG(RTC_BASE + RTC_O_CH1CC8U); + rtc_delta = (rtc[1] - rtc_now) << 3; + systim_next = MIN(systim_next, rtc_delta); + } + } + + if (systim_next > PowerCC23X0_TOTALTIMESTANDBY) { + HWREG(EVTSVT_BASE + EVTSVT_O_CPUIRQ3SEL) = 0; + HWREG(EVTSVT_BASE + EVTSVT_O_CPUIRQ16SEL) = + EVTSVT_CPUIRQ16SEL_PUBID_AON_RTC_COMB; + HwiP_clearInterrupt(INT_CPUIRQ16); + rtc_now = HWREG(RTC_BASE + RTC_O_TIME8U); + HWREG(RTC_BASE + RTC_O_CH0CC8U) = RTC_NEXT(systim_next, rtc_now); +#endif + Power_sleep(PowerLPF3_STANDBY); +#ifndef CONFIG_CC23X0_RTC_TIMER + pm_cc23x0_systim_standby_restore(); + } else if (idle) { + __WFI(); + } + } else if (idle) { + __WFI(); + } + + HwiP_restore(key); +#endif +} + +void pm_state_set(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(substate_id); + + switch (state) { + case PM_STATE_RUNTIME_IDLE: + PowerCC23X0_doWFI(); + break; + case PM_STATE_STANDBY: + pm_cc23x0_enter_standby(); + break; + case PM_STATE_SOFT_OFF: + Power_shutdown(0, 0); + break; + default: + break; + } +} + +void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id) +{ + ARG_UNUSED(state); + ARG_UNUSED(substate_id); + + HwiP_restore(0); +} + +#endif /* CONFIG_PM */ + +static int power_initialize(void) +{ + Power_init(); + + if (DT_HAS_COMPAT_STATUS_OKAY(ti_cc23x0_lf_xosc)) { + PowerLPF3_selectLFXT(); + } + + PMCTLSetVoltageRegulator(PMCTL_VOLTAGE_REGULATOR_DCDC); + + return 0; +} + +SYS_INIT(power_initialize, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/soc/ti/simplelink/cc23x0/soc.c b/soc/ti/simplelink/cc23x0/soc.c index cddae58b4e05..c687e3704ccf 100644 --- a/soc/ti/simplelink/cc23x0/soc.c +++ b/soc/ti/simplelink/cc23x0/soc.c @@ -7,6 +7,9 @@ #include +const uint_least8_t GPIO_pinLowerBound; +const uint_least8_t GPIO_pinUpperBound = 25; + void soc_reset_hook(void) { /* Perform necessary trim of the device. */