1 /*
2 * Copyright (c) 2021 Bestechnic (Shanghai) Co., Ltd. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "analog.h"
16 #include "cmsis.h"
17 #include "hal_cache.h"
18 #include "hal_cmu.h"
19 #include "hal_dma.h"
20 #include "hal_gpadc.h"
21 #include "hal_location.h"
22 #include "hal_norflash.h"
23 #include "hal_psram.h"
24 #include "hal_psramuhs.h"
25 #include "hal_sleep.h"
26 #include "hal_spi.h"
27 #include "hal_sysfreq.h"
28 #include "hal_trace.h"
29 #include "hal_timer.h"
30 #include "hal_uart.h"
31 #include "pmu.h"
32
33 #if !(defined(CHIP_SUBSYS_SENS) || \
34 (defined(CHIP_SUBSYS_BTH) && !defined(BTH_AS_MAIN_MCU)))
35 #define CHIP_SLEEP_CTRL_ENABLE
36 #endif
37
38 #ifdef CORE_SLEEP_POWER_DOWN
39 #define PM_NOTIF_HDLR_CNT 10
40 #else
41 #define PM_NOTIF_HDLR_CNT 3
42 #endif
43
44 //static uint8_t SRAM_STACK_LOC sleep_stack[128];
45
46 static HAL_SLEEP_HOOK_HANDLER sleep_hook_handler[HAL_SLEEP_HOOK_USER_QTY];
47 static HAL_DEEP_SLEEP_HOOK_HANDLER deep_sleep_hook_handler[HAL_DEEP_SLEEP_HOOK_USER_QTY];
48
49 static uint32_t cpu_wake_lock_map;
50 static uint32_t sys_wake_lock_map;
51 static uint32_t chip_wake_lock_map;
52 #ifdef CORE_SLEEP_POWER_DOWN
53 static bool skip_power_down;
54 #endif
55
56 static uint8_t pm_user_cnt;
57 STATIC_ASSERT((1 << (sizeof(pm_user_cnt) * 8)) > PM_NOTIF_HDLR_CNT, "pm_user_cnt to small to hold PM_NOTIF_HDLR_CNT");
58 static enum HAL_PM_USER_TYPE_T pm_user[PM_NOTIF_HDLR_CNT];
59 static HAL_PM_NOTIF_HANDLER pm_notif[PM_NOTIF_HDLR_CNT];
60
61 #ifdef SLEEP_STATS_TRACE
62 static uint32_t stats_trace_interval;
63 static uint32_t stats_trace_time;
64 #ifdef WAKEUP_SRC_STATS
65 static uint32_t wakeup_start_time;
66 static uint32_t wakeup_src_map[(USER_IRQn_QTY + 31) / 32];
67 static uint32_t wakeup_multi_src_map[(USER_IRQn_QTY + 31) / 32];
68 static uint32_t wakeup_total_interval[USER_IRQn_QTY];
69 #endif
70 #endif
71 static uint32_t stats_interval;
72 static uint32_t stats_start_time;
73 static uint32_t light_sleep_time;
74 static uint32_t sys_deep_sleep_time;
75 static uint32_t chip_deep_sleep_time;
76 static bool stats_started;
77 static bool stats_valid;
78 static uint8_t light_sleep_ratio;
79 static uint8_t sys_deep_sleep_ratio;
80 static uint8_t chip_deep_sleep_ratio;
81
hal_sleep_start_stats(uint32_t stats_interval_ms,uint32_t trace_interval_ms)82 void hal_sleep_start_stats(uint32_t stats_interval_ms, uint32_t trace_interval_ms)
83 {
84 uint32_t lock;
85
86 lock = int_lock();
87 if (stats_interval_ms) {
88 stats_interval = MS_TO_TICKS(stats_interval_ms);
89 stats_start_time = hal_sys_timer_get();
90 light_sleep_time = 0;
91 sys_deep_sleep_time = 0;
92 chip_deep_sleep_time = 0;
93 stats_valid = false;
94 stats_started = true;
95 } else {
96 stats_started = false;
97 }
98 int_unlock(lock);
99
100 #ifdef SLEEP_STATS_TRACE
101 if (stats_interval_ms && trace_interval_ms) {
102 stats_trace_interval = MS_TO_TICKS(trace_interval_ms);
103 stats_trace_time = stats_start_time;
104 } else {
105 stats_trace_interval = 0;
106 }
107 #ifdef WAKEUP_SRC_STATS
108 int i;
109
110 for (i = 0; i < ARRAY_SIZE(wakeup_src_map); i++) {
111 wakeup_src_map[i] = 0;
112 wakeup_multi_src_map[i] = 0;
113 }
114 for (i = 0; i < ARRAY_SIZE(wakeup_total_interval); i++) {
115 wakeup_total_interval[i] = 0;
116 }
117 #endif
118 #ifdef CACHE_STATS
119 hal_cache_monitor_enable(HAL_CACHE_ID_I_CACHE);
120 hal_cache_monitor_enable(HAL_CACHE_ID_D_CACHE);
121 #endif
122 #endif
123 }
124
hal_sleep_get_stats(struct CPU_USAGE_T * usage)125 int hal_sleep_get_stats(struct CPU_USAGE_T *usage)
126 {
127 int ret;
128 uint32_t lock;
129
130 if (!usage) {
131 return -1;
132 }
133
134 lock = int_lock();
135 if (stats_valid) {
136 usage->light_sleep = light_sleep_ratio;
137 usage->sys_deep_sleep = sys_deep_sleep_ratio;
138 usage->chip_deep_sleep = chip_deep_sleep_ratio;
139 usage->busy = 100 - (light_sleep_ratio + sys_deep_sleep_ratio + chip_deep_sleep_ratio);
140 ret = 0;
141 } else {
142 ret = 1;
143 }
144 int_unlock(lock);
145
146 return ret;
147 }
148
149 #if defined(SLEEP_STATS_TRACE) && defined(WAKEUP_SRC_STATS)
hal_sleep_calc_wakeup_interval(uint32_t cur_time)150 static void SRAM_TEXT_LOC hal_sleep_calc_wakeup_interval(uint32_t cur_time)
151 {
152 uint32_t interval;
153 int i;
154 int j;
155 int index;
156 uint32_t src_cnt = 0;
157
158 interval = cur_time - wakeup_start_time;
159
160 for (i = 0; i < ARRAY_SIZE(wakeup_src_map); i++) {
161 for (j = 0; j < 32; j++) {
162 if (wakeup_src_map[i] & (1 << j)) {
163 index = i * 32 + j;
164 if (index < ARRAY_SIZE(wakeup_total_interval)) {
165 wakeup_total_interval[index] += interval;
166 src_cnt++;
167 }
168 }
169 }
170 }
171
172 if (src_cnt >= 2) {
173 for (i = 0; i < ARRAY_SIZE(wakeup_src_map); i++) {
174 wakeup_multi_src_map[i] |= wakeup_src_map[i];
175 }
176 }
177 }
178
hal_sleep_save_wakeup_src(void)179 static void SRAM_TEXT_LOC hal_sleep_save_wakeup_src(void)
180 {
181 int i;
182
183 wakeup_start_time = hal_sys_timer_get();
184
185 for (i = 0; i < ARRAY_SIZE(wakeup_src_map); i++) {
186 wakeup_src_map[i] = (NVIC->ICPR[i] & NVIC->ISER[i]);
187 }
188 }
189
hal_sleep_print_wakeup_src(void)190 static void hal_sleep_print_wakeup_src(void)
191 {
192 int i;
193 uint32_t cur_time;
194
195 cur_time = hal_sys_timer_get();
196
197 hal_sleep_calc_wakeup_interval(cur_time);
198
199 // Set wakeup start time to current time
200 wakeup_start_time = cur_time;
201
202 TRACE(0, "DEEP SLEEP WAKEUP SRC STATS:");
203 for (i = 0; i < ARRAY_SIZE(wakeup_total_interval); i++) {
204 if (wakeup_total_interval[i]) {
205 TRACE(TR_ATTR_NO_TS, "\t[%2u]: %5u ms", i, TICKS_TO_MS(wakeup_total_interval[i]));
206 // Reset the total interval
207 wakeup_total_interval[i] = 0;
208 }
209 }
210 // Reset the multi src map but keep current wakeup src map
211 for (i = 0; i < ARRAY_SIZE(wakeup_src_map); i++) {
212 wakeup_multi_src_map[i] = 0;
213 }
214 }
215 #endif
216
hal_sleep_set_sleep_hook(enum HAL_SLEEP_HOOK_USER_T user,HAL_SLEEP_HOOK_HANDLER handler)217 int hal_sleep_set_sleep_hook(enum HAL_SLEEP_HOOK_USER_T user, HAL_SLEEP_HOOK_HANDLER handler)
218 {
219 if (user >= ARRAY_SIZE(sleep_hook_handler)) {
220 return 1;
221 }
222 sleep_hook_handler[user] = handler;
223 return 0;
224 }
225
hal_sleep_exec_sleep_hook(void)226 static int SRAM_TEXT_LOC hal_sleep_exec_sleep_hook(void)
227 {
228 int i;
229 int ret;
230
231 for (i = 0; i < ARRAY_SIZE(sleep_hook_handler); i++) {
232 if (sleep_hook_handler[i]) {
233 ret = sleep_hook_handler[i]();
234 if (ret) {
235 return ret;
236 }
237 }
238 }
239
240 return 0;
241 }
242
hal_sleep_set_deep_sleep_hook(enum HAL_DEEP_SLEEP_HOOK_USER_T user,HAL_DEEP_SLEEP_HOOK_HANDLER handler)243 int hal_sleep_set_deep_sleep_hook(enum HAL_DEEP_SLEEP_HOOK_USER_T user, HAL_DEEP_SLEEP_HOOK_HANDLER handler)
244 {
245 if (user >= ARRAY_SIZE(deep_sleep_hook_handler)) {
246 return 1;
247 }
248 deep_sleep_hook_handler[user] = handler;
249 return 0;
250 }
251
hal_sleep_exec_deep_sleep_hook(void)252 static int SRAM_TEXT_LOC hal_sleep_exec_deep_sleep_hook(void)
253 {
254 int i;
255 int ret;
256
257 for (i = 0; i < ARRAY_SIZE(deep_sleep_hook_handler); i++) {
258 if (deep_sleep_hook_handler[i]) {
259 ret = deep_sleep_hook_handler[i]();
260 if (ret) {
261 return ret;
262 }
263 }
264 }
265
266 return 0;
267 }
268
hal_sleep_irq_pending(void)269 int SRAM_TEXT_LOC hal_sleep_irq_pending(void)
270 {
271 #if defined(__GIC_PRESENT) && (__GIC_PRESENT)
272 int i;
273
274 for (i = 0; i < (USER_IRQn_QTY + 31) / 32; i++) {
275 if (GICDistributor->ICPENDR[i] & GICDistributor->ISENABLER[i]) {
276 return 1;
277 }
278 }
279 #else
280 #if 0
281 int i;
282
283 for (i = 0; i < (USER_IRQn_QTY + 31) / 32; i++) {
284 if (NVIC->ICPR[i] & NVIC->ISER[i]) {
285 return 1;
286 }
287 }
288 #else
289 // If there is any pending and enabled exception (including sysTick)
290 // SCB_ICSR_VECTPENDING is not banked between security states
291 if (SCB->ICSR & SCB_ICSR_VECTPENDING_Msk) {
292 return 1;
293 }
294 #endif
295 #endif
296
297 return 0;
298 }
299
hal_sleep_specific_irq_pending(const uint32_t * irq,uint32_t cnt)300 int SRAM_TEXT_LOC hal_sleep_specific_irq_pending(const uint32_t *irq, uint32_t cnt)
301 {
302 int i;
303 uint32_t check_cnt;
304
305 check_cnt = (USER_IRQn_QTY + 31) / 32;
306 if (check_cnt > cnt) {
307 check_cnt = cnt;
308 }
309
310 #if defined(__GIC_PRESENT) && (__GIC_PRESENT)
311 for (i = 0; i < check_cnt; i++) {
312 if (GICDistributor->ICPENDR[i] & GICDistributor->ISENABLER[i] & irq[i]) {
313 return 1;
314 }
315 }
316 #else
317 for (i = 0; i < check_cnt; i++) {
318 if (NVIC->ICPR[i] & NVIC->ISER[i] & irq[i]) {
319 return 1;
320 }
321 #if defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3U)
322 if (NVIC_NS->ICPR[i] & NVIC_NS->ISER[i] & irq[i]) {
323 return 1;
324 }
325 #endif
326 }
327 #endif
328
329 return 0;
330 }
331
pm_notif_sleep(enum HAL_CMU_LPU_SLEEP_MODE_T mode)332 static int pm_notif_sleep(enum HAL_CMU_LPU_SLEEP_MODE_T mode)
333 {
334 enum HAL_PM_STATE_T state;
335 int i;
336
337 if (pm_user_cnt == 0) {
338 return 0;
339 }
340
341 if (0) {
342 #ifdef CORE_SLEEP_POWER_DOWN
343 } else if (mode == HAL_CMU_LPU_SLEEP_MODE_POWER_DOWN) {
344 state = HAL_PM_STATE_POWER_DOWN_SLEEP;
345 #endif
346 } else {
347 state = HAL_PM_STATE_NORMAL_SLEEP;
348 }
349
350 for (i = pm_user_cnt - 1; i >= 0; i--) {
351 if (pm_notif[i]) {
352 pm_notif[i](state);
353 }
354 }
355
356 return 0;
357 }
358
pm_notif_wakeup(enum HAL_CMU_LPU_SLEEP_MODE_T mode)359 static int pm_notif_wakeup(enum HAL_CMU_LPU_SLEEP_MODE_T mode)
360 {
361 enum HAL_PM_STATE_T state;
362 int i;
363
364 if (pm_user_cnt == 0) {
365 return 0;
366 }
367
368 if (0) {
369 #ifdef CORE_SLEEP_POWER_DOWN
370 } else if (mode == HAL_CMU_LPU_SLEEP_MODE_POWER_DOWN) {
371 state = HAL_PM_STATE_POWER_DOWN_WAKEUP;
372 #endif
373 } else {
374 state = HAL_PM_STATE_NORMAL_WAKEUP;
375 }
376
377 for (i = 0; i < pm_user_cnt; i++) {
378 if (pm_notif[i]) {
379 pm_notif[i](state);
380 }
381 }
382
383 return 0;
384 }
385
hal_sleep_lowpower_mode(void)386 static enum HAL_SLEEP_STATUS_T SRAM_TEXT_LOC hal_sleep_lowpower_mode(void)
387 {
388 enum HAL_SLEEP_STATUS_T ret;
389 enum HAL_CMU_LPU_SLEEP_MODE_T mode;
390 uint32_t prev_time = 0;
391 uint32_t cur_time;
392 uint32_t interval;
393
394 ret = HAL_SLEEP_STATUS_LIGHT;
395
396 // Deep sleep hook
397 if (hal_sleep_exec_deep_sleep_hook() || hal_trace_busy()) {
398 return ret;
399 }
400
401 if (chip_wake_lock_map) {
402 mode = HAL_CMU_LPU_SLEEP_MODE_SYS;
403 #ifdef CORE_SLEEP_POWER_DOWN
404 } else if (!skip_power_down) {
405 mode = HAL_CMU_LPU_SLEEP_MODE_POWER_DOWN;
406 #endif
407 } else {
408 mode = HAL_CMU_LPU_SLEEP_MODE_CHIP;
409 }
410
411 // Stop modules (except for psram and flash, spi)
412 pm_notif_sleep(mode);
413
414 #ifdef FAST_TIMER_COMPENSATE
415 hal_fast_timer_sleep();
416 #endif
417
418 #ifdef CHIP_SLEEP_CTRL_ENABLE
419 hal_gpadc_sleep();
420 if (chip_wake_lock_map == 0) {
421 analog_sleep();
422 pmu_sleep();
423 }
424 #endif
425 // End of stopping modules
426
427 #ifdef CORE_SLEEP_POWER_DOWN
428 // Save uart trace related cfg
429 hal_dma_sleep();
430 hal_uart_sleep();
431 #endif
432
433 #ifdef CHIP_SLEEP_CTRL_ENABLE
434 // Stop psram and then flash
435 #ifdef CORE_SLEEP_POWER_DOWN
436 hal_cache_sleep();
437 #endif
438 #ifdef PSRAM_ENABLE
439 hal_psram_sleep();
440 #endif
441 #ifdef PSRAMUHS_ENABLE
442 hal_psramuhs_sleep();
443 #endif
444 #ifndef __MCU_FW_2002__
445 hal_norflash_sleep(HAL_FLASH_ID_0);
446 #endif
447 #endif
448
449 #ifdef CORE_SLEEP_POWER_DOWN
450 // Save ispi cfg
451 hal_spi_sleep();
452 #endif
453
454 if (!hal_sleep_irq_pending()) {
455 if (stats_started) {
456 prev_time = hal_sys_timer_get();
457 #ifdef SLEEP_STATS_TRACE
458 #ifdef WAKEUP_SRC_STATS
459 hal_sleep_calc_wakeup_interval(prev_time);
460 #endif
461 #ifdef SYSFREQ_STATS
462 hal_sysfreq_add_freq_time(false, prev_time);
463 #endif
464 #endif
465 }
466
467 hal_cmu_lpu_sleep(mode);
468
469 if (stats_started) {
470 cur_time = hal_sys_timer_get();
471 interval = cur_time - prev_time;
472 if (chip_wake_lock_map) {
473 sys_deep_sleep_time += interval;
474 } else {
475 chip_deep_sleep_time += interval;
476 }
477 #ifdef SLEEP_STATS_TRACE
478 #ifdef WAKEUP_SRC_STATS
479 hal_sleep_save_wakeup_src();
480 #endif
481 #ifdef SYSFREQ_STATS
482 hal_sysfreq_add_freq_time(true, cur_time);
483 #endif
484 #endif
485 }
486
487 ret = HAL_SLEEP_STATUS_DEEP;
488 }
489
490 #ifdef CORE_SLEEP_POWER_DOWN
491 // Restore ispi cfg
492 hal_spi_wakeup();
493 #endif
494
495 #ifdef CHIP_SLEEP_CTRL_ENABLE
496 #ifndef __MCU_FW_2002__
497 // Restore flash and then psram
498 hal_norflash_wakeup(HAL_FLASH_ID_0);
499 #endif
500 #ifdef PSRAMUHS_ENABLE
501 hal_psramuhs_wakeup();
502 #endif
503 #ifdef PSRAM_ENABLE
504 hal_psram_wakeup();
505 #endif
506 #ifdef CORE_SLEEP_POWER_DOWN
507 hal_cache_wakeup();
508 #endif
509 #endif
510
511 #ifdef CORE_SLEEP_POWER_DOWN
512 // Restore uart trace related cfg
513 hal_uart_wakeup();
514 hal_dma_wakeup();
515 #endif
516
517 // Restore modules (except for psram and flash)
518 #ifdef CHIP_SLEEP_CTRL_ENABLE
519 if (chip_wake_lock_map == 0) {
520 pmu_wakeup();
521 analog_wakeup();
522 }
523
524 hal_gpadc_wakeup();
525 #endif
526
527 #ifdef FAST_TIMER_COMPENSATE
528 hal_fast_timer_wakeup();
529 #endif
530
531 pm_notif_wakeup(mode);
532 // End of restoring modules
533
534 return ret;
535 }
536
537 // GCC has trouble in detecting static function usage in embedded ASM statements.
538 // The following function might be optimized away if there is no explicted call in C codes.
539 // Specifying "used" (or "noclone") attribute on the function can avoid the mistaken optimization.
hal_sleep_proc(int light_sleep)540 static enum HAL_SLEEP_STATUS_T SRAM_TEXT_LOC NOINLINE USED hal_sleep_proc(int light_sleep)
541 {
542 enum HAL_SLEEP_STATUS_T ret;
543 uint32_t prev_time = 0;
544 uint32_t cur_time;
545 uint32_t interval;
546 bool lpu_busy = false;
547 bool dma_busy = false;
548 POSSIBLY_UNUSED bool trace_busy = false;
549
550 ret = HAL_SLEEP_STATUS_LIGHT;
551
552 // Check the sleep conditions in interrupt-locked context
553 if (cpu_wake_lock_map || (lpu_busy = hal_cmu_lpu_busy())) {
554 // Cannot sleep
555 } else {
556 // Sleep hook
557 if (hal_sleep_exec_sleep_hook()) {
558 goto _exit_sleep;
559 }
560
561 if (sys_wake_lock_map || hal_sysfreq_busy() || (dma_busy = hal_dma_busy())) {
562 // Light sleep
563
564 if (stats_started) {
565 prev_time = hal_sys_timer_get();
566 #ifdef SYSFREQ_STATS
567 hal_sysfreq_add_freq_time(false, prev_time);
568 #endif
569 }
570
571 #ifdef NO_LIGHT_SLEEP
572 // WFI during USB ISO transfer might generate very weak (0.1 mV) 1K tone interference ???
573 while (!hal_sleep_irq_pending());
574 #else
575 #ifndef __ARM_ARCH_ISA_ARM
576 SCB->SCR = 0;
577 #endif
578 __DSB();
579 __WFI();
580 #endif
581
582 if (stats_started) {
583 cur_time = hal_sys_timer_get();
584 light_sleep_time += cur_time - prev_time;
585 #ifdef SYSFREQ_STATS
586 hal_sysfreq_add_freq_time(true, cur_time);
587 #endif
588 }
589 #ifdef DEBUG
590 } else if ((trace_busy = hal_trace_busy())) {
591 // Light sleep with trace busy only
592
593 if (stats_started) {
594 prev_time = hal_sys_timer_get();
595 #ifdef SYSFREQ_STATS
596 hal_sysfreq_add_freq_time(false, prev_time);
597 #endif
598 }
599
600 // No irq will be generated when trace becomes idle, so the trace status should
601 // be kept polling actively instead of entering WFI
602 while (!hal_sleep_irq_pending() && hal_trace_busy());
603
604 if (stats_started) {
605 cur_time = hal_sys_timer_get();
606 light_sleep_time += cur_time - prev_time;
607 #ifdef SYSFREQ_STATS
608 hal_sysfreq_add_freq_time(true, cur_time);
609 #endif
610 }
611
612 if (!hal_sleep_irq_pending()) {
613 goto _deep_sleep;
614 }
615 #endif
616 } else {
617 // Deep sleep
618
619 _deep_sleep: POSSIBLY_UNUSED;
620
621 if (light_sleep) {
622 ret = HAL_SLEEP_STATUS_DEEP;
623 } else {
624 ret = hal_sleep_lowpower_mode();
625 }
626 }
627 }
628
629 _exit_sleep:
630 if (stats_started) {
631 cur_time = hal_sys_timer_get();
632 interval = cur_time - stats_start_time;
633 if (interval >= stats_interval) {
634 if (light_sleep_time > UINT32_MAX / 100) {
635 light_sleep_ratio = (uint64_t)light_sleep_time * 100 / interval;
636 } else {
637 light_sleep_ratio = light_sleep_time * 100 / interval;
638 }
639 if (sys_deep_sleep_time > UINT32_MAX / 100) {
640 sys_deep_sleep_ratio = (uint64_t)sys_deep_sleep_time * 100 / interval;
641 } else {
642 sys_deep_sleep_ratio = sys_deep_sleep_time * 100 / interval;
643 }
644 if (chip_deep_sleep_time > UINT32_MAX / 100) {
645 chip_deep_sleep_ratio = (uint64_t)chip_deep_sleep_time * 100 / interval;
646 } else {
647 chip_deep_sleep_ratio = chip_deep_sleep_time * 100 / interval;
648 }
649 stats_valid = true;
650 light_sleep_time = 0;
651 sys_deep_sleep_time = 0;
652 chip_deep_sleep_time = 0;
653 stats_start_time = cur_time;
654 }
655 #ifdef SLEEP_STATS_TRACE
656 if (stats_valid && stats_trace_interval) {
657 if (cur_time - stats_trace_time >= stats_trace_interval) {
658 #ifdef DEBUG_SLEEP_USER
659 hal_dma_record_busy_chan();
660 #endif
661 TRACE(0, "CPU USAGE: busy=%d light=%d sys_deep=%d chip_deep=%d",
662 100 - (light_sleep_ratio + sys_deep_sleep_ratio + chip_deep_sleep_ratio),
663 light_sleep_ratio, sys_deep_sleep_ratio, chip_deep_sleep_ratio);
664 stats_trace_time = cur_time;
665 #ifdef DEBUG_SLEEP_USER
666 TRACE(0, "SLEEP USER: cpu=0x%X sys=0x%X chip=0x%X irq=0x%08X_%08X",
667 cpu_wake_lock_map, sys_wake_lock_map, chip_wake_lock_map,
668 (NVIC->ICPR[1] & NVIC->ISER[1]), (NVIC->ICPR[0] & NVIC->ISER[0]));
669 TRACE(0, "BUSY: LPU=%d DMA=%d TRACE=%d", lpu_busy, dma_busy, trace_busy);
670 hal_sysfreq_print_user_freq();
671 hal_dma_print_busy_chan();
672 #endif
673 #ifdef WAKEUP_SRC_STATS
674 hal_sleep_print_wakeup_src();
675 #endif
676 #ifdef CACHE_STATS
677 hal_cache_print_stats();
678 #endif
679 #ifdef SYSFREQ_STATS
680 hal_sysfreq_print_freq_stats();
681 #endif
682 }
683 }
684 #endif
685 }
686
687 return ret;
688 }
689
690 #ifndef __ARM_ARCH_ISA_ARM
hal_sleep_deep_sleep_wrapper(void)691 static enum HAL_SLEEP_STATUS_T SRAM_TEXT_LOC NOINLINE USED NAKED hal_sleep_deep_sleep_wrapper(void)
692 {
693 asm volatile(
694 "push {r4, lr} \n"
695 // Switch current stack pointer to MSP
696 "mrs r4, control \n"
697 "bic r4, #2 \n"
698 "msr control, r4 \n"
699 "isb \n"
700 "movs r0, #0 \n"
701 "bl hal_sleep_proc \n"
702 // Switch current stack pointer back to PSP
703 "orr r4, #2 \n"
704 "msr control, r4 \n"
705 "isb \n"
706 "pop {r4, pc} \n"
707 );
708
709 #ifndef __ARMCC_VERSION
710 return HAL_SLEEP_STATUS_LIGHT;
711 #endif
712 }
713 #endif
714
hal_sleep_enter_sleep(void)715 enum HAL_SLEEP_STATUS_T SRAM_TEXT_LOC hal_sleep_enter_sleep(void)
716 {
717 enum HAL_SLEEP_STATUS_T ret;
718 uint32_t lock;
719
720 ret = HAL_SLEEP_STATUS_LIGHT;
721
722 #ifdef NO_SLEEP
723 return ret;
724 #endif
725
726 lock = int_lock_global();
727
728 #ifndef __ARM_ARCH_ISA_ARM
729 if (__get_CONTROL() & 0x02) {
730 ret = hal_sleep_deep_sleep_wrapper();
731 } else
732 #endif
733 {
734 ret = hal_sleep_proc(false);
735 }
736
737 int_unlock_global(lock);
738
739 return ret;
740 }
741
hal_sleep_light_sleep(void)742 enum HAL_SLEEP_STATUS_T SRAM_TEXT_LOC hal_sleep_light_sleep(void)
743 {
744 enum HAL_SLEEP_STATUS_T ret;
745 uint32_t lock;
746
747 ret = HAL_SLEEP_STATUS_LIGHT;
748
749 #ifdef NO_SLEEP
750 return ret;
751 #endif
752
753 lock = int_lock_global();
754
755 ret = hal_sleep_proc(true);
756
757 int_unlock_global(lock);
758
759 return ret;
760 }
761
hal_cpu_wake_lock(enum HAL_CPU_WAKE_LOCK_USER_T user)762 int hal_cpu_wake_lock(enum HAL_CPU_WAKE_LOCK_USER_T user)
763 {
764 uint32_t lock;
765
766 if (user >= HAL_CPU_WAKE_LOCK_USER_QTY) {
767 return 1;
768 }
769
770 lock = int_lock();
771 cpu_wake_lock_map |= (1 << user);
772 int_unlock(lock);
773
774 return 0;
775 }
776
hal_cpu_wake_unlock(enum HAL_CPU_WAKE_LOCK_USER_T user)777 int hal_cpu_wake_unlock(enum HAL_CPU_WAKE_LOCK_USER_T user)
778 {
779 uint32_t lock;
780
781 if (user >= HAL_CPU_WAKE_LOCK_USER_QTY) {
782 return 1;
783 }
784
785 lock = int_lock();
786 cpu_wake_lock_map &= ~(1 << user);
787 int_unlock(lock);
788
789 return 0;
790 }
791
hal_sys_wake_lock(enum HAL_SYS_WAKE_LOCK_USER_T user)792 int hal_sys_wake_lock(enum HAL_SYS_WAKE_LOCK_USER_T user)
793 {
794 uint32_t lock;
795
796 if (user >= HAL_SYS_WAKE_LOCK_USER_QTY) {
797 return 1;
798 }
799
800 lock = int_lock();
801 sys_wake_lock_map |= (1 << user);
802 int_unlock(lock);
803
804 return 0;
805 }
806
hal_sys_wake_unlock(enum HAL_SYS_WAKE_LOCK_USER_T user)807 int hal_sys_wake_unlock(enum HAL_SYS_WAKE_LOCK_USER_T user)
808 {
809 uint32_t lock;
810
811 if (user >= HAL_SYS_WAKE_LOCK_USER_QTY) {
812 return 1;
813 }
814
815 lock = int_lock();
816 sys_wake_lock_map &= ~(1 << user);
817 int_unlock(lock);
818
819 return 0;
820 }
821
hal_chip_wake_lock(enum HAL_CHIP_WAKE_LOCK_USER_T user)822 int hal_chip_wake_lock(enum HAL_CHIP_WAKE_LOCK_USER_T user)
823 {
824 uint32_t lock;
825
826 if (user >= HAL_CHIP_WAKE_LOCK_USER_QTY) {
827 return 1;
828 }
829
830 lock = int_lock();
831 chip_wake_lock_map |= (1 << user);
832 int_unlock(lock);
833
834 return 0;
835 }
836
hal_chip_wake_unlock(enum HAL_CHIP_WAKE_LOCK_USER_T user)837 int hal_chip_wake_unlock(enum HAL_CHIP_WAKE_LOCK_USER_T user)
838 {
839 uint32_t lock;
840
841 if (user >= HAL_CHIP_WAKE_LOCK_USER_QTY) {
842 return 1;
843 }
844
845 lock = int_lock();
846 chip_wake_lock_map &= ~(1 << user);
847 int_unlock(lock);
848
849 return 0;
850 }
851
hal_sleep_power_down_enable(void)852 void hal_sleep_power_down_enable(void)
853 {
854 #ifdef CORE_SLEEP_POWER_DOWN
855 skip_power_down = false;
856 #endif
857 }
858
hal_sleep_power_down_disable(void)859 void hal_sleep_power_down_disable(void)
860 {
861 #ifdef CORE_SLEEP_POWER_DOWN
862 skip_power_down = true;
863 #endif
864 }
865
hal_pm_notif_register(enum HAL_PM_USER_TYPE_T user,HAL_PM_NOTIF_HANDLER handler)866 int hal_pm_notif_register(enum HAL_PM_USER_TYPE_T user, HAL_PM_NOTIF_HANDLER handler)
867 {
868 int i;
869 uint32_t lock;
870 int ret;
871
872 if (handler == NULL) {
873 ASSERT(false, "%s: handler cannot be NULL: user=%d", __func__, user);
874 return 1;
875 }
876
877 ret = 0;
878
879 lock = int_lock();
880
881 if (pm_user_cnt >= PM_NOTIF_HDLR_CNT) {
882 ASSERT(false, "%s: handler list full: user=%d handler=%p curCnt=%u", __func__, user, handler, pm_user_cnt);
883 ret = 2;
884 goto _exit;
885 }
886
887 for (i = 0; i < pm_user_cnt; i++) {
888 if (pm_notif[i] == handler) {
889 ASSERT(false, "%s: handler already registered: user=%d handler=%p existedUser=%d", __func__, user, handler, pm_user[i]);
890 ret = 3;
891 goto _exit;
892 }
893 }
894
895 if (pm_user_cnt == 0) {
896 pm_user[i] = user;
897 pm_notif[i] = handler;
898 } else {
899 for (i = pm_user_cnt; i >= 0; i--) {
900 if (i == 0 || pm_user[i - 1] > user) {
901 pm_user[i] = user;
902 pm_notif[i] = handler;
903 break;
904 } else {
905 pm_user[i] = pm_user[i - 1];
906 pm_notif[i] = pm_notif[i - 1];
907 }
908 }
909 }
910 pm_user_cnt++;
911
912 _exit:
913 int_unlock(lock);
914
915 return ret;
916 }
917
hal_pm_notif_deregister(enum HAL_PM_USER_TYPE_T user,HAL_PM_NOTIF_HANDLER handler)918 int hal_pm_notif_deregister(enum HAL_PM_USER_TYPE_T user, HAL_PM_NOTIF_HANDLER handler)
919 {
920 int i;
921 uint32_t lock;
922 int ret;
923
924 if (handler == NULL) {
925 return 1;
926 }
927
928 ret = 0;
929
930 lock = int_lock();
931
932 for (i = 0; i < pm_user_cnt; i++) {
933 if (pm_notif[i] == handler) {
934 break;
935 }
936 }
937
938 if (i >= pm_user_cnt) {
939 ret = 2;
940 goto _exit;
941 }
942
943 for (; (i + 1) < pm_user_cnt; i++) {
944 pm_user[i] = pm_user[i + 1];
945 pm_notif[i] = pm_notif[i + 1];
946 }
947 pm_user_cnt--;
948
949 _exit:
950 int_unlock(lock);
951
952 return ret;
953 }
954
955