• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  * Copyright (c) 2022 Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
3  * All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  *****************************************************************************/
18 
19 #include <target_config.h>
20 
21 #include <los_arch_timer.h>
22 #include <los_compiler.h>
23 #include <los_pm.h>
24 #include <los_reg.h>
25 #include <los_task.h>
26 #include <los_timer.h>
27 
28 #include <B91/clock.h>
29 #include <B91/stimer.h>
30 #include <B91/sys.h>
31 
32 #include <B91/ext_driver/ext_pm.h>
33 
34 #include <stack/ble/ble.h>
35 
36 #include <inttypes.h>
37 
38 #define SYSTICKS_MAX_SLEEP     (0xFFFFFFFF >> 2)
39 #define MTICKS_MIN_SLEEP       (80)
40 #define MTICKS_CORRECTION_TIME (0)
41 #define MTICKS_RESERVE_TIME    (1 + MTICKS_CORRECTION_TIME)
42 
43 bool B91_system_suspend(UINT32 wake_stimer_tick);
44 
MticksToSysticks(UINT64 mticks)45 static inline UINT64 MticksToSysticks(UINT64 mticks)
46 {
47     return (mticks * SYSTEM_TIMER_TICK_1S) / OS_SYS_CLOCK;
48 }
49 
SysticksToMticks(UINT32 sticks)50 static inline UINT32 SysticksToMticks(UINT32 sticks)
51 {
52     return (UINT32)((UINT64)sticks * OS_SYS_CLOCK / SYSTEM_TIMER_TICK_1S);
53 }
54 
55 static UINT32 B91Suspend(VOID);
56 
57 static LosPmSysctrl g_sysctrl = {
58     .normalSuspend = B91Suspend,
59 };
60 
SetMtime(UINT64 time)61 static inline void SetMtime(UINT64 time)
62 {
63     HalIrqDisable(RISCV_MACH_TIMER_IRQ);
64     WRITE_UINT32(U32_MAX, MTIMER + MTIMER_HI_OFFSET);
65     WRITE_UINT32((UINT32)time, MTIMER);
66     WRITE_UINT32((UINT32)(time >> SHIFT_32_BIT), MTIMER + MTIMER_HI_OFFSET);
67     HalIrqEnable(RISCV_MACH_TIMER_IRQ);
68 }
69 
GetMtimeCompare(void)70 static inline UINT64 GetMtimeCompare(void)
71 {
72     return *(volatile UINT64 *)(MTIMERCMP);
73 }
74 
GetMtime(void)75 static inline UINT64 GetMtime(void)
76 {
77     const volatile UINT32 *const rl = (const volatile UINT32 *const)MTIMER;
78     const volatile UINT32 *const rh = (const volatile UINT32 *const)(MTIMER + sizeof(UINT32));
79     UINT32 mtimeL, mtimeH;
80     do {
81         mtimeH = *rh;
82         mtimeL = *rl;
83     } while (mtimeH != *rh);
84     return (((UINT64)mtimeH) << SHIFT_32_BIT) | mtimeL;
85 }
86 
87 /**
88  * @brief      	This function is used instead of the default sleep function
89  * ArchEnterSleep()
90  * @param[in]  	none.
91  * @return     	none.
92  */
B91Suspend(VOID)93 _attribute_ram_code_ static UINT32 B91Suspend(VOID)
94 {
95     UINT64 mcompare = GetMtimeCompare();
96     UINT64 mtick = GetMtime();
97     if ((mcompare - mtick) < (MTICKS_MIN_SLEEP + MTICKS_RESERVE_TIME)) {
98         return 0;
99     }
100 
101     while (uart_tx_is_busy(UART0) || uart_tx_is_busy(UART1)) {
102         LOS_Msleep(1);
103     }
104 
105     UINT32 intSave = LOS_IntLock();
106     mcompare = GetMtimeCompare();
107     mtick = GetMtime();
108     if ((mcompare - mtick) < MTICKS_MIN_SLEEP + MTICKS_RESERVE_TIME) {
109         LOS_IntRestore(intSave);
110         return 0;
111     }
112 
113     UINT64 systicksSleepTimeout = MticksToSysticks(mcompare - mtick);
114     if (systicksSleepTimeout > SYSTICKS_MAX_SLEEP) {
115         systicksSleepTimeout = SYSTICKS_MAX_SLEEP;
116     }
117     blc_pm_setWakeupSource(PM_WAKEUP_PAD);
118 
119     UINT32 sleepTick = stimer_get_tick();
120     if (B91_system_suspend(sleepTick + systicksSleepTimeout - MTICKS_RESERVE_TIME)) {
121         UINT32 span = SysticksToMticks(stimer_get_tick() - sleepTick) + MTICKS_CORRECTION_TIME;
122         mtick += span;
123         SetMtime(mtick);
124         uart_clr_tx_index(UART0);
125         uart_clr_tx_index(UART1);
126         uart_clr_rx_index(UART0);
127         uart_clr_rx_index(UART1);
128     }
129     LOS_IntRestore(intSave);
130     return 0;
131 }
132 
B91SuspendSleepInit(VOID)133 VOID B91SuspendSleepInit(VOID)
134 {
135     UINT32 ret = LOS_PmRegister(LOS_PM_TYPE_SYSCTRL, &g_sysctrl);
136     if (ret != LOS_OK) {
137         printf("Ret of PMRegister = %#x\r\n", ret);
138     } else {
139         printf("\r\n B91_SLEEP_init\r\n");
140     }
141 }
142 
B91_system_suspend(UINT32 wake_stimer_tick)143 _attribute_ram_code_ bool B91_system_suspend(UINT32 wake_stimer_tick)
144 {
145     bool result = false;
146 
147     extern bool blc_ll_isBleTaskIdle(void);
148     if (!blc_ll_isBleTaskIdle()) {
149         blc_pm_setAppWakeupLowPower(wake_stimer_tick, 1);
150         if (!blc_pm_handler()) {
151             result = true;
152         }
153         blc_pm_setAppWakeupLowPower(0, 0);
154     } else {
155         cpu_sleep_wakeup_32k_rc(SUSPEND_MODE, PM_WAKEUP_TIMER | PM_WAKEUP_PAD, wake_stimer_tick);
156         result = true;
157     }
158     return result;
159 }