Skip to content

Commit ed7b870

Browse files
committed
soc: ti: cc23x0: Add power management
Add power management capabilities for cc23x0: - runtime-idle - standby - soft-off Signed-off-by: Stoyan Bogdanov <sbogdanov@baylibre.com>
1 parent 00a7ca3 commit ed7b870

File tree

4 files changed

+207
-0
lines changed

4 files changed

+207
-0
lines changed

soc/ti/simplelink/cc23x0/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ zephyr_sources(soc.c)
77
zephyr_sources(ccfg.c)
88
zephyr_include_directories(.)
99

10+
zephyr_sources_ifdef(CONFIG_PM power.c)
11+
1012
zephyr_linker_sources_ifdef(CONFIG_HAS_TI_CCFG SECTIONS ccfg.ld)
1113

1214
set(SOC_LINKER_SCRIPT ${ZEPHYR_BASE}/include/zephyr/arch/arm/cortex_m/scripts/linker.ld CACHE INTERNAL "")

soc/ti/simplelink/cc23x0/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ config SOC_SERIES_CC23X0
1919
select THREAD_STACK_INFO
2020
select BUILD_OUTPUT_HEX
2121
select BUILD_NO_GAP_FILL
22+
select HAS_PM
23+
select PM_DEVICE if PM
2224

2325
menu "Bootloader Configuration"
2426
depends on SOC_SERIES_CC23X0

soc/ti/simplelink/cc23x0/power.c

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
/*
2+
* Copyright (c) 2024 Texas Instruments Incorporated
3+
* Copyright (c) 2024 Baylibre, SAS
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#include <zephyr/kernel.h>
9+
#include <zephyr/init.h>
10+
#include <zephyr/pm/pm.h>
11+
#include <zephyr/pm/policy.h>
12+
13+
#include <ti/drivers/utils/Math.h>
14+
#include <ti/drivers/Power.h>
15+
#include <ti/drivers/power/PowerCC23X0.h>
16+
17+
#include <inc/hw_types.h>
18+
#include <inc/hw_memmap.h>
19+
#include <inc/hw_ckmd.h>
20+
#include <inc/hw_systim.h>
21+
#include <inc/hw_rtc.h>
22+
#include <inc/hw_evtsvt.h>
23+
#include <inc/hw_ints.h>
24+
25+
#include <driverlib/lrfd.h>
26+
#include <driverlib/ull.h>
27+
#include <driverlib/pmctl.h>
28+
29+
/* Configuring TI Power module to not use its policy function (we use Zephyr's
30+
* instead), and disable oscillator calibration functionality for now.
31+
*/
32+
const PowerCC23X0_Config PowerCC23X0_config = {
33+
.policyInitFxn = NULL,
34+
.policyFxn = NULL,
35+
};
36+
37+
#ifdef CONFIG_PM
38+
39+
#define MAX_SYSTIMER_DELTA 0xFFBFFFFFU
40+
#define RTC_TO_SYSTIM_TICKS 8U
41+
#define SYSTIM_CH_STEP 4U
42+
#define SYSTIM_CH(idx) (SYSTIM_O_CH0CC + idx * SYSTIM_CH_STEP)
43+
#define SYSTIM_TO_RTC_SHIFT 3U
44+
#define SYSTIM_CH_CNT 5U
45+
#define RTC_NEXT(val, now) (((val - PowerCC23X0_WAKEDELAYSTANDBY) >> SYSTIM_TO_RTC_SHIFT) + now)
46+
47+
static void pm_cc23x0_enter_standby(void);
48+
static int power_initialize(void);
49+
extern int_fast16_t PowerCC23X0_notify(uint_fast16_t eventType);
50+
static void pm_cc23x0_systim_standby_restore(void);
51+
52+
/* Global to stash the SysTimer timeouts while we enter standby */
53+
static uint32_t systim[SYSTIM_CH_CNT];
54+
static uintptr_t key;
55+
static uint32_t systim_mask;
56+
57+
/* Shift values to convert between the different resolutions of the SysTimer
58+
* channels. Channel 0 can technically support either 1us or 250ns. Until the
59+
* channel is actively used, we will hard-code it to 1us resolution to improve
60+
* runtime.
61+
*/
62+
const uint8_t systim_offset[SYSTIM_CH_CNT] = {
63+
0, /* 1us */
64+
0, /* 1us */
65+
2, /* 250ns -> 1us */
66+
2, /* 250ns -> 1us */
67+
2 /* 250ns -> 1us */
68+
};
69+
70+
static void pm_cc23x0_systim_standby_restore(void)
71+
{
72+
HWREG(RTC_BASE + RTC_O_ARMCLR) = RTC_ARMCLR_CH0_CLR;
73+
HWREG(RTC_BASE + RTC_O_ICLR) = RTC_ICLR_EV0_CLR;
74+
75+
ULLSync();
76+
77+
HwiP_clearInterrupt(INT_CPUIRQ16);
78+
HWREG(EVTSVT_BASE + EVTSVT_O_CPUIRQ16SEL) = EVTSVT_CPUIRQ16SEL_PUBID_SYSTIM0;
79+
80+
while (HWREG(SYSTIM_BASE + SYSTIM_O_STATUS) != SYSTIM_STATUS_VAL_RUN) {
81+
;
82+
}
83+
84+
for (uint8_t idx = 0; idx < SYSTIM_CH_CNT; idx++) {
85+
if (systim_mask & (1 << idx)) {
86+
HWREG(SYSTIM_BASE + SYSTIM_CH(idx)) = systim[idx];
87+
}
88+
}
89+
90+
HWREG(SYSTIM_BASE + SYSTIM_O_IMASK) = systim_mask;
91+
LRFDApplyClockDependencies();
92+
PowerCC23X0_notify(PowerLPF3_AWAKE_STANDBY);
93+
94+
HwiP_restore(key);
95+
}
96+
97+
static void pm_cc23x0_enter_standby(void)
98+
{
99+
uint32_t rtc_now = 0;
100+
uint32_t systim_now = 0;
101+
uint32_t systim_next = MAX_SYSTIMER_DELTA;
102+
uint32_t systim_delta = 0;
103+
104+
key = HwiP_disable();
105+
106+
uint32_t constraints = Power_getConstraintMask();
107+
bool standby = (constraints & (1 << PowerLPF3_DISALLOW_STANDBY)) == 0;
108+
bool idle = (constraints & (1 << PowerLPF3_DISALLOW_IDLE)) == 0;
109+
110+
if (standby && (HWREG(CKMD_BASE + CKMD_O_LFCLKSEL) & CKMD_LFCLKSEL_MAIN_LFOSC) &&
111+
!(HWREG(CKMD_BASE + CKMD_O_LFCLKSTAT) & CKMD_LFCLKSTAT_FLTSETTLED_M)) {
112+
standby = false;
113+
idle = false;
114+
}
115+
116+
if (standby) {
117+
systim_mask = HWREG(SYSTIM_BASE + SYSTIM_O_IMASK);
118+
if (systim_mask != 0) {
119+
systim_next = 0xFFFFFFFF;
120+
systim_now = HWREG(SYSTIM_BASE + SYSTIM_O_TIME1U);
121+
for (uint8_t idx = 0; idx < SYSTIM_CH_CNT; idx++) {
122+
if (systim_mask & (1 << idx)) {
123+
systim[idx] = HWREG(SYSTIM_BASE + SYSTIM_CH(idx));
124+
systim_delta = systim[idx];
125+
systim_delta -= systim_now << systim_offset[idx];
126+
127+
if (systim_delta > MAX_SYSTIMER_DELTA) {
128+
systim_delta = 0;
129+
}
130+
131+
systim_delta = systim_delta >> systim_offset[idx];
132+
systim_next = MIN(systim_next, systim_delta);
133+
}
134+
}
135+
} else {
136+
systim_next = MAX_SYSTIMER_DELTA;
137+
}
138+
139+
if (systim_next > PowerCC23X0_TOTALTIMESTANDBY) {
140+
HWREG(EVTSVT_BASE + EVTSVT_O_CPUIRQ16SEL) =
141+
EVTSVT_CPUIRQ16SEL_PUBID_AON_RTC_COMB;
142+
HwiP_clearInterrupt(INT_CPUIRQ16);
143+
rtc_now = HWREG(RTC_BASE + RTC_O_TIME8U);
144+
HWREG(RTC_BASE + RTC_O_CH0CC8U) = RTC_NEXT(systim_next, rtc_now);
145+
146+
Power_sleep(PowerLPF3_STANDBY);
147+
pm_cc23x0_systim_standby_restore();
148+
} else if (idle) {
149+
__WFI();
150+
}
151+
} else if (idle) {
152+
__WFI();
153+
}
154+
155+
HwiP_restore(key);
156+
}
157+
158+
void pm_state_set(enum pm_state state, uint8_t substate_id)
159+
{
160+
ARG_UNUSED(substate_id);
161+
162+
switch (state) {
163+
case PM_STATE_RUNTIME_IDLE:
164+
PowerCC23X0_doWFI();
165+
break;
166+
case PM_STATE_STANDBY:
167+
pm_cc23x0_enter_standby();
168+
break;
169+
case PM_STATE_SOFT_OFF:
170+
Power_shutdown(0, 0);
171+
break;
172+
default:
173+
break;
174+
}
175+
}
176+
177+
void pm_state_exit_post_ops(enum pm_state state, uint8_t substate_id)
178+
{
179+
ARG_UNUSED(state);
180+
ARG_UNUSED(substate_id);
181+
182+
HwiP_restore(0);
183+
}
184+
185+
#endif /* CONFIG_PM */
186+
187+
static int power_initialize(void)
188+
{
189+
Power_init();
190+
191+
if (DT_HAS_COMPAT_STATUS_OKAY(ti_cc23x0_lf_xosc)) {
192+
PowerLPF3_selectLFXT();
193+
}
194+
195+
PMCTLSetVoltageRegulator(PMCTL_VOLTAGE_REGULATOR_DCDC);
196+
197+
return 0;
198+
}
199+
200+
SYS_INIT(power_initialize, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);

soc/ti/simplelink/cc23x0/soc.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
#include <driverlib/setup.h>
99

10+
const uint_least8_t GPIO_pinLowerBound;
11+
const uint_least8_t GPIO_pinUpperBound = 25;
12+
1013
void soc_reset_hook(void)
1114
{
1215
/* Perform necessary trim of the device. */

0 commit comments

Comments
 (0)