• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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