1 /*
2 * Copyright (c) 2019 Linaro Limited.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <zephyr.h>
7 #include <init.h>
8 #include <pm/pm.h>
9
10 #include <driverlib/pwr_ctrl.h>
11 #include <driverlib/sys_ctrl.h>
12
13 #include <ti/drivers/Power.h>
14 #include <ti/drivers/power/PowerCC26X2.h>
15
16 #include <ti/drivers/dpl/ClockP.h>
17
18 #include <ti/devices/cc13x2_cc26x2/driverlib/cpu.h>
19 #include <ti/devices/cc13x2_cc26x2/driverlib/vims.h>
20 #include <ti/devices/cc13x2_cc26x2/driverlib/sys_ctrl.h>
21
22 #include <logging/log.h>
23 #define LOG_LEVEL CONFIG_SOC_LOG_LEVEL
24 LOG_MODULE_REGISTER(soc);
25
26 const PowerCC26X2_Config PowerCC26X2_config = {
27 #if defined(CONFIG_IEEE802154_CC13XX_CC26XX) \
28 || defined(CONFIG_BLE_CC13XX_CC26XX) \
29 || defined(CONFIG_IEEE802154_CC13XX_CC26XX_SUB_GHZ)
30 .policyInitFxn = NULL,
31 .policyFxn = NULL,
32 .calibrateFxn = &PowerCC26XX_calibrate,
33 .enablePolicy = false,
34 .calibrateRCOSC_LF = true,
35 .calibrateRCOSC_HF = true
36 #else
37 /* Configuring TI Power module to not use its policy function (we use Zephyr's
38 * instead), and disable oscillator calibration functionality for now.
39 */
40 .policyInitFxn = NULL,
41 .policyFxn = NULL,
42 .calibrateFxn = NULL,
43 .enablePolicy = false,
44 .calibrateRCOSC_LF = false,
45 .calibrateRCOSC_HF = false
46 #endif
47 };
48
49 extern PowerCC26X2_ModuleState PowerCC26X2_module;
50
51 #ifdef CONFIG_PM
52 /*
53 * Power state mapping:
54 * PM_STATE_SUSPEND_TO_IDLE: Idle
55 * PM_STATE_STANDBY: Standby
56 * PM_STATE_SUSPEND_TO_RAM | PM_STATE_SUSPEND_TO_DISK: Shutdown
57 */
58
59 /* Invoke Low Power/System Off specific Tasks */
pm_power_state_set(struct pm_state_info info)60 __weak void pm_power_state_set(struct pm_state_info info)
61 {
62 uint32_t modeVIMS;
63 uint32_t constraints;
64
65 LOG_DBG("SoC entering power state %d", info.state);
66
67 /* Switch to using PRIMASK instead of BASEPRI register, since
68 * we are only able to wake up from standby while using PRIMASK.
69 */
70 /* Set PRIMASK */
71 CPUcpsid();
72 /* Set BASEPRI to 0 */
73 irq_unlock(0);
74
75 switch (info.state) {
76 case PM_STATE_SUSPEND_TO_IDLE:
77 /* query the declared constraints */
78 constraints = Power_getConstraintMask();
79 /* 1. Get the current VIMS mode */
80 do {
81 modeVIMS = VIMSModeGet(VIMS_BASE);
82 } while (modeVIMS == VIMS_MODE_CHANGING);
83
84 /* 2. Configure flash to remain on in IDLE or not and keep
85 * VIMS powered on if it is configured as GPRAM
86 * 3. Always keep cache retention ON in IDLE
87 * 4. Turn off the CPU power domain
88 * 5. Ensure any possible outstanding AON writes complete
89 * 6. Enter IDLE
90 */
91 if ((constraints & (1 << PowerCC26XX_NEED_FLASH_IN_IDLE)) ||
92 (modeVIMS == VIMS_MODE_DISABLED)) {
93 SysCtrlIdle(VIMS_ON_BUS_ON_MODE);
94 } else {
95 SysCtrlIdle(VIMS_ON_CPU_ON_MODE);
96 }
97
98 /* 7. Make sure MCU and AON are in sync after wakeup */
99 SysCtrlAonUpdate();
100 break;
101
102 case PM_STATE_STANDBY:
103 /* go to standby mode */
104 Power_sleep(PowerCC26XX_STANDBY);
105 break;
106 case PM_STATE_SUSPEND_TO_RAM:
107 __fallthrough;
108 case PM_STATE_SUSPEND_TO_DISK:
109 __fallthrough;
110 case PM_STATE_SOFT_OFF:
111 Power_shutdown(0, 0);
112 break;
113 default:
114 LOG_DBG("Unsupported power state %u", info.state);
115 break;
116 }
117
118 LOG_DBG("SoC leaving power state %d", info.state);
119 }
120
121 /* Handle SOC specific activity after Low Power Mode Exit */
pm_power_state_exit_post_ops(struct pm_state_info info)122 __weak void pm_power_state_exit_post_ops(struct pm_state_info info)
123 {
124 /*
125 * System is now in active mode. Reenable interrupts which were disabled
126 * when OS started idling code.
127 */
128 CPUcpsie();
129 }
130 #endif /* CONFIG_PM */
131
132 /* Initialize TI Power module */
power_initialize(const struct device * dev)133 static int power_initialize(const struct device *dev)
134 {
135 unsigned int ret;
136
137 ARG_UNUSED(dev);
138
139 ret = irq_lock();
140 Power_init();
141 irq_unlock(ret);
142
143 return 0;
144 }
145
146 /*
147 * Unlatch IO pins after waking up from shutdown
148 * This needs to be called during POST_KERNEL in order for "Booting Zephyr"
149 * message to show up
150 */
unlatch_pins(const struct device * dev)151 static int unlatch_pins(const struct device *dev)
152 {
153 /* Get the reason for reset. */
154 uint32_t rSrc = SysCtrlResetSourceGet();
155
156 if (rSrc == RSTSRC_WAKEUP_FROM_SHUTDOWN) {
157 PowerCtrlPadSleepDisable();
158 }
159
160 return 0;
161 }
162
163 /*
164 * ======== PowerCC26XX_schedulerDisable ========
165 */
PowerCC26XX_schedulerDisable(void)166 void PowerCC26XX_schedulerDisable(void)
167 {
168 /*
169 * We are leaving this empty because Zephyr's
170 * scheduler would not get to run with interrupts being disabled
171 * in the context of Power_sleep() in any case.
172 */
173 }
174
175 /*
176 * ======== PowerCC26XX_schedulerRestore ========
177 */
PowerCC26XX_schedulerRestore(void)178 void PowerCC26XX_schedulerRestore(void)
179 {
180 /*
181 * We are leaving this empty because Zephyr's
182 * scheduler would not get to run with interrupts being disabled
183 * in the context of Power_sleep() in any case.
184 */
185 }
186
187 #ifdef CONFIG_PM
188 /* Constraint API hooks */
189
pm_constraint_set(enum pm_state state)190 void pm_constraint_set(enum pm_state state)
191 {
192 switch (state) {
193 case PM_STATE_RUNTIME_IDLE:
194 Power_setConstraint(PowerCC26XX_DISALLOW_IDLE);
195 break;
196 case PM_STATE_STANDBY:
197 Power_setConstraint(PowerCC26XX_DISALLOW_STANDBY);
198 break;
199 default:
200 break;
201 }
202 }
203
pm_constraint_release(enum pm_state state)204 void pm_constraint_release(enum pm_state state)
205 {
206 switch (state) {
207 case PM_STATE_RUNTIME_IDLE:
208 Power_releaseConstraint(PowerCC26XX_DISALLOW_IDLE);
209 break;
210 case PM_STATE_STANDBY:
211 Power_releaseConstraint(PowerCC26XX_DISALLOW_STANDBY);
212 break;
213 default:
214 break;
215 }
216 }
217
pm_constraint_get(enum pm_state state)218 bool pm_constraint_get(enum pm_state state)
219 {
220 bool ret = true;
221 uint32_t constraints;
222
223 constraints = Power_getConstraintMask();
224 switch (state) {
225 case PM_STATE_RUNTIME_IDLE:
226 ret = (constraints & (1 << PowerCC26XX_DISALLOW_IDLE)) == 0;
227 break;
228 case PM_STATE_STANDBY:
229 ret = (constraints & (1 << PowerCC26XX_DISALLOW_STANDBY)) == 0;
230 break;
231 default:
232 break;
233 }
234
235 return ret;
236 }
237 #endif /* CONFIG_PM */
238
239 SYS_INIT(power_initialize, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
240 SYS_INIT(unlatch_pins, POST_KERNEL, CONFIG_APPLICATION_INIT_PRIORITY);
241