contrib: replace the BSD-3-Clause license tag
[openocd.git] / contrib / loaders / flash / msp432 / driverlib.c
1 /* SPDX-License-Identifier: BSD-3-Clause */
2
3 /******************************************************************************
4 *
5 * Copyright (C) 2017-2018 Texas Instruments Incorporated - http://www.ti.com/
6 *
7 ******************************************************************************/
8
9 #include <stdint.h>
10 #include <stdbool.h>
11 #include "driverlib.h"
12
13 /*
14 * Wrapper function for the CPSID instruction.
15 * Returns the state of PRIMASK on entry.
16 */
17 uint32_t __attribute__((naked)) cpu_cpsid(void)
18 {
19 uint32_t ret;
20
21 /* Read PRIMASK and disable interrupts. */
22 __asm(" mrs r0, PRIMASK\n"
23 " cpsid i\n"
24 " bx lr\n"
25 : "=r" (ret));
26
27 /*
28 * The return is handled in the inline assembly, but the compiler will
29 * still complain if there is not an explicit return here (despite the fact
30 * that this does not result in any code being produced because of the
31 * naked attribute).
32 */
33 return ret;
34 }
35
36 /* Wrapper function for the CPUWFI instruction. */
37 void __attribute__((naked)) cpu_wfi(void)
38 {
39 /* Wait for the next interrupt. */
40 __asm(" wfi\n"
41 " bx lr\n");
42 }
43
44 /* Power Control Module APIs */
45 #if defined(PCM)
46
47 static bool __pcm_set_core_voltage_level_advanced(uint_fast8_t voltage_level,
48 uint32_t time_out, bool blocking)
49 {
50 uint8_t power_mode;
51 uint8_t current_voltage_level;
52 uint32_t reg_value;
53 bool bool_timeout;
54
55 /* Getting current power mode and level */
56 power_mode = pcm_get_power_mode();
57 current_voltage_level = pcm_get_core_voltage_level();
58
59 bool_timeout = time_out > 0 ? true : false;
60
61 /* If we are already at the power mode they requested, return */
62 if (current_voltage_level == voltage_level)
63 return true;
64
65 while (current_voltage_level != voltage_level) {
66
67 reg_value = PCM->CTL0;
68
69 switch (pcm_get_power_state()) {
70 case PCM_AM_LF_VCORE1:
71 case PCM_AM_DCDC_VCORE1:
72 case PCM_AM_LDO_VCORE0:
73 PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE1)
74 | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
75 break;
76 case PCM_AM_LF_VCORE0:
77 case PCM_AM_DCDC_VCORE0:
78 case PCM_AM_LDO_VCORE1:
79 PCM->CTL0 = (PCM_KEY | (PCM_AM_LDO_VCORE0)
80 | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
81 break;
82 default:
83 break;
84 }
85
86 if (blocking) {
87 while (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS)) {
88 if (bool_timeout && !(--time_out))
89 return false;
90 }
91 } else
92 return true;
93
94 current_voltage_level = pcm_get_core_voltage_level();
95 }
96
97 /* Changing the power mode if we are stuck in LDO mode */
98 if (power_mode != pcm_get_power_mode()) {
99 if (power_mode == PCM_DCDC_MODE)
100 return pcm_set_power_mode(PCM_DCDC_MODE);
101 else
102 return pcm_set_power_mode(PCM_LF_MODE);
103 }
104
105 return true;
106 }
107
108 bool pcm_set_core_voltage_level(uint_fast8_t voltage_level)
109 {
110 return __pcm_set_core_voltage_level_advanced(voltage_level, 0, true);
111 }
112
113 uint8_t pcm_get_power_mode(void)
114 {
115 uint8_t current_power_state;
116
117 current_power_state = pcm_get_power_state();
118
119 switch (current_power_state) {
120 case PCM_AM_LDO_VCORE0:
121 case PCM_AM_LDO_VCORE1:
122 case PCM_LPM0_LDO_VCORE0:
123 case PCM_LPM0_LDO_VCORE1:
124 default:
125 return PCM_LDO_MODE;
126 case PCM_AM_DCDC_VCORE0:
127 case PCM_AM_DCDC_VCORE1:
128 case PCM_LPM0_DCDC_VCORE0:
129 case PCM_LPM0_DCDC_VCORE1:
130 return PCM_DCDC_MODE;
131 case PCM_LPM0_LF_VCORE0:
132 case PCM_LPM0_LF_VCORE1:
133 case PCM_AM_LF_VCORE1:
134 case PCM_AM_LF_VCORE0:
135 return PCM_LF_MODE;
136 }
137 }
138
139 uint8_t pcm_get_core_voltage_level(void)
140 {
141 uint8_t current_power_state = pcm_get_power_state();
142
143 switch (current_power_state) {
144 case PCM_AM_LDO_VCORE0:
145 case PCM_AM_DCDC_VCORE0:
146 case PCM_AM_LF_VCORE0:
147 case PCM_LPM0_LDO_VCORE0:
148 case PCM_LPM0_DCDC_VCORE0:
149 case PCM_LPM0_LF_VCORE0:
150 default:
151 return PCM_VCORE0;
152 case PCM_AM_LDO_VCORE1:
153 case PCM_AM_DCDC_VCORE1:
154 case PCM_AM_LF_VCORE1:
155 case PCM_LPM0_LDO_VCORE1:
156 case PCM_LPM0_DCDC_VCORE1:
157 case PCM_LPM0_LF_VCORE1:
158 return PCM_VCORE1;
159 case PCM_LPM3:
160 return PCM_VCORELPM3;
161 }
162 }
163
164 static bool __pcm_set_power_mode_advanced(uint_fast8_t power_mode,
165 uint32_t time_out, bool blocking)
166 {
167 uint8_t current_power_mode;
168 uint8_t current_power_state;
169 uint32_t reg_value;
170 bool bool_timeout;
171
172 /* Getting Current Power Mode */
173 current_power_mode = pcm_get_power_mode();
174
175 /* If the power mode being set it the same as the current mode, return */
176 if (power_mode == current_power_mode)
177 return true;
178
179 current_power_state = pcm_get_power_state();
180
181 bool_timeout = time_out > 0 ? true : false;
182
183 /* Go through the while loop while we haven't achieved the power mode */
184 while (current_power_mode != power_mode) {
185
186 reg_value = PCM->CTL0;
187
188 switch (current_power_state) {
189 case PCM_AM_DCDC_VCORE0:
190 case PCM_AM_LF_VCORE0:
191 PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE0
192 | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
193 break;
194 case PCM_AM_LF_VCORE1:
195 case PCM_AM_DCDC_VCORE1:
196 PCM->CTL0 = (PCM_KEY | PCM_AM_LDO_VCORE1
197 | (reg_value & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_AMR_MASK)));
198 break;
199 case PCM_AM_LDO_VCORE1: {
200 if (power_mode == PCM_DCDC_MODE) {
201 PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE1
202 | (reg_value & ~(PCM_CTL0_KEY_MASK
203 | PCM_CTL0_AMR_MASK)));
204 } else if (power_mode == PCM_LF_MODE) {
205 PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE1
206 | (reg_value & ~(PCM_CTL0_KEY_MASK
207 | PCM_CTL0_AMR_MASK)));
208 } else
209 return false;
210 break;
211 }
212 case PCM_AM_LDO_VCORE0: {
213 if (power_mode == PCM_DCDC_MODE) {
214 PCM->CTL0 = (PCM_KEY | PCM_AM_DCDC_VCORE0
215 | (reg_value & ~(PCM_CTL0_KEY_MASK
216 | PCM_CTL0_AMR_MASK)));
217 } else if (power_mode == PCM_LF_MODE) {
218 PCM->CTL0 = (PCM_KEY | PCM_AM_LF_VCORE0
219 | (reg_value & ~(PCM_CTL0_KEY_MASK
220 | PCM_CTL0_AMR_MASK)));
221 } else
222 return false;
223 break;
224 }
225 default:
226 break;
227 }
228
229 if (blocking) {
230 while (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS)) {
231 if (bool_timeout && !(--time_out))
232 return false;
233 }
234 } else
235 return true;
236
237 current_power_mode = pcm_get_power_mode();
238 current_power_state = pcm_get_power_state();
239 }
240
241 return true;
242 }
243
244 bool pcm_set_power_mode(uint_fast8_t power_mode)
245 {
246 return __pcm_set_power_mode_advanced(power_mode, 0, true);
247 }
248
249 static bool __pcm_set_power_state_advanced(uint_fast8_t power_state,
250 uint32_t timeout, bool blocking)
251 {
252 uint8_t current_power_state;
253 current_power_state = pcm_get_power_state();
254
255 if (current_power_state == power_state)
256 return true;
257
258 switch (power_state) {
259 case PCM_AM_LDO_VCORE0:
260 return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout,
261 blocking) && __pcm_set_power_mode_advanced(PCM_LDO_MODE,
262 timeout, blocking);
263 case PCM_AM_LDO_VCORE1:
264 return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout,
265 blocking) && __pcm_set_power_mode_advanced(PCM_LDO_MODE,
266 timeout, blocking);
267 case PCM_AM_DCDC_VCORE0:
268 return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout,
269 blocking) && __pcm_set_power_mode_advanced(PCM_DCDC_MODE,
270 timeout, blocking);
271 case PCM_AM_DCDC_VCORE1:
272 return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout,
273 blocking) && __pcm_set_power_mode_advanced(PCM_DCDC_MODE,
274 timeout, blocking);
275 case PCM_AM_LF_VCORE0:
276 return __pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout,
277 blocking) && __pcm_set_power_mode_advanced(PCM_LF_MODE,
278 timeout, blocking);
279 case PCM_AM_LF_VCORE1:
280 return __pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout,
281 blocking) && __pcm_set_power_mode_advanced(PCM_LF_MODE,
282 timeout, blocking);
283 case PCM_LPM0_LDO_VCORE0:
284 if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout,
285 blocking) || !__pcm_set_power_mode_advanced(PCM_LDO_MODE,
286 timeout, blocking))
287 break;
288 return pcm_goto_lpm0();
289 case PCM_LPM0_LDO_VCORE1:
290 if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout,
291 blocking) || !__pcm_set_power_mode_advanced(PCM_LDO_MODE,
292 timeout, blocking))
293 break;
294 return pcm_goto_lpm0();
295 case PCM_LPM0_DCDC_VCORE0:
296 if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout,
297 blocking) || !__pcm_set_power_mode_advanced(PCM_DCDC_MODE,
298 timeout, blocking))
299 break;
300 return pcm_goto_lpm0();
301 case PCM_LPM0_DCDC_VCORE1:
302 if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout,
303 blocking) || !__pcm_set_power_mode_advanced(PCM_DCDC_MODE,
304 timeout, blocking))
305 break;
306 return pcm_goto_lpm0();
307 case PCM_LPM0_LF_VCORE0:
308 if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE0, timeout,
309 blocking) || !__pcm_set_power_mode_advanced(PCM_LF_MODE,
310 timeout, blocking))
311 break;
312 return pcm_goto_lpm0();
313 case PCM_LPM0_LF_VCORE1:
314 if (!__pcm_set_core_voltage_level_advanced(PCM_VCORE1, timeout,
315 blocking) || !__pcm_set_power_mode_advanced(PCM_LF_MODE,
316 timeout, blocking))
317 break;
318 return pcm_goto_lpm0();
319 case PCM_LPM3:
320 return pcm_goto_lpm3();
321 case PCM_LPM4:
322 return pcm_goto_lpm4();
323 case PCM_LPM45:
324 return pcm_shutdown_device(PCM_LPM45);
325 case PCM_LPM35_VCORE0:
326 return pcm_shutdown_device(PCM_LPM35_VCORE0);
327 default:
328 return false;
329 }
330
331 return false;
332 }
333
334 bool pcm_set_power_state(uint_fast8_t power_state)
335 {
336 return __pcm_set_power_state_advanced(power_state, 0, true);
337 }
338
339 bool pcm_shutdown_device(uint32_t shutdown_mode)
340 {
341 uint32_t shutdown_mode_bits = (shutdown_mode == PCM_LPM45) ?
342 PCM_CTL0_LPMR_12 : PCM_CTL0_LPMR_10;
343
344 /* If a power transition is occurring, return false */
345 if (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS))
346 return false;
347
348 /* Initiating the shutdown */
349 SCB->SCR |= SCB_SCR_SLEEPDEEP_MSK;
350
351 PCM->CTL0 = (PCM_KEY | shutdown_mode_bits
352 | (PCM->CTL0 & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_LPMR_MASK)));
353
354 cpu_wfi();
355
356 return true;
357 }
358
359 bool pcm_goto_lpm4(void)
360 {
361 /* Disabling RTC_C and WDT_A */
362 wdt_a_hold_timer();
363 rtc_c_hold_clock();
364
365 /* LPM4 is just LPM3 with WDT_A/RTC_C disabled... */
366 return pcm_goto_lpm3();
367 }
368
369 bool pcm_goto_lpm0(void)
370 {
371 /* If we are in the middle of a state transition, return false */
372 if (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS))
373 return false;
374
375 SCB->SCR &= ~SCB_SCR_SLEEPDEEP_MSK;
376
377 cpu_wfi();
378
379 return true;
380 }
381
382 bool pcm_goto_lpm3(void)
383 {
384 uint_fast8_t current_power_state;
385 uint_fast8_t current_power_mode;
386
387 /* If we are in the middle of a state transition, return false */
388 if (BITBAND_PERI(PCM->CTL1, PCM_CTL1_PMR_BUSY_OFS))
389 return false;
390
391 /* If we are in the middle of a shutdown, return false */
392 if ((PCM->CTL0 & PCM_CTL0_LPMR_MASK) == PCM_CTL0_LPMR_10
393 || (PCM->CTL0 & PCM_CTL0_LPMR_MASK) == PCM_CTL0_LPMR_12)
394 return false;
395
396 current_power_mode = pcm_get_power_mode();
397 current_power_state = pcm_get_power_state();
398
399 if (current_power_mode == PCM_DCDC_MODE)
400 pcm_set_power_mode(PCM_LDO_MODE);
401
402 /* Clearing the SDR */
403 PCM->CTL0 =
404 (PCM->CTL0 & ~(PCM_CTL0_KEY_MASK | PCM_CTL0_LPMR_MASK)) | PCM_KEY;
405
406 /* Setting the sleep deep bit */
407 SCB->SCR |= SCB_SCR_SLEEPDEEP_MSK;
408
409 cpu_wfi();
410
411 SCB->SCR &= ~SCB_SCR_SLEEPDEEP_MSK;
412
413 return pcm_set_power_state(current_power_state);
414 }
415
416 uint8_t pcm_get_power_state(void)
417 {
418 return (PCM->CTL0 & PCM_CTL0_CPM_MASK) >> PCM_CTL0_CPM_OFS;
419 }
420
421 #endif
422
423 /* Real Time Clock APIs */
424 #if defined(RTC_C)
425
426 void rtc_c_hold_clock(void)
427 {
428 RTC_C->CTL0 = (RTC_C->CTL0 & ~RTC_C_CTL0_KEY_MASK) | RTC_C_KEY;
429 BITBAND_PERI(RTC_C->CTL13, RTC_C_CTL13_HOLD_OFS) = 1;
430 BITBAND_PERI(RTC_C->CTL0, RTC_C_CTL0_KEY_OFS) = 0;
431 }
432
433 #endif
434
435 /* Watch Dog Timer APIs */
436 #if defined(WDT_A)
437
438 void wdt_a_hold_timer(void)
439 {
440 /* Set Hold bit */
441 uint8_t new_wdt_status = (WDT_A->CTL | WDT_A_CTL_HOLD);
442
443 WDT_A->CTL = WDT_A_CTL_PW + new_wdt_status;
444 }
445
446 #endif

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)