1 #include <k_api.h>
2 #include "sys_api.h"
3 #include "sleep_ex_api.h"
4 //#include "alios_service.h"
5 
6 uint32_t missing_tick = 0;
7 
8 static uint32_t wakelock     = DEFAULT_WAKELOCK;
9 static uint32_t sleepwakelock_timeout     = 0;
10 static u32 system_can_yield = 1; /* default is can */
11 static uint32_t sleep_type = SLEEP_PG; /* 0 is power gate, 1 is clock gate */
12 static uint32_t max_sleep_time = 0; /* if user want wakeup peridically, can set this timer*/
13 KM4SLEEP_ParamDef sleep_param;
14 
15 static uint32_t deepwakelock     = DEFAULT_DEEP_WAKELOCK;
16 static uint32_t deepwakelock_timeout     = 0;
17 static uint32_t sysactive_timeout_temp = 0;
18 static uint32_t sysactive_timeout_flag = 0;
19 
20 static int           cpu_pwr_init_flag = 0;
21 static kspinlock_t cpu_pwr_spin;
22 static uint32_t wakeup_time_ms = 0;
23 
24 uint32_t missing_tick_alios = 0;
25 
26 
27 u32 tickless_debug = 0;
pmu_acquire_wakelock(uint32_t nDeviceId)28 void pmu_acquire_wakelock(uint32_t nDeviceId)
29 {
30         wakelock |= BIT(nDeviceId);
31 }
32 
pmu_release_wakelock(uint32_t nDeviceId)33 void pmu_release_wakelock(uint32_t nDeviceId)
34 {
35         wakelock &= ~BIT(nDeviceId);
36 }
37 
pmu_get_wakelock_status(void)38 uint32_t pmu_get_wakelock_status(void)
39 {
40         return wakelock;
41 }
42 
43 /* can not yield CPU under suspend/resume process */
pmu_yield_os_check(void)44 uint32_t pmu_yield_os_check(void)
45 {
46 	return system_can_yield;
47 }
48 CONFIG_FW_CRITICAL_CODE_SECTION
freertos_ready_to_sleep(void)49 int freertos_ready_to_sleep(void)
50 {
51 	u32 current_tick = SYSTIMER_TickGet();
52 
53 	/* timeout */
54 	if (current_tick < sleepwakelock_timeout) {
55 		return FALSE;
56 	}
57 
58 	if (wakelock == 0) {
59 		return TRUE;
60 	}
61 	else
62 		return FALSE;
63 }
64 
65 /*
66  *  It is called in freertos pre_sleep_processing.
67  *
68  *  @return  true  : System is ready to check conditions that if it can enter dsleep.
69  *           false : System can't enter deep sleep.
70  **/
71 CONFIG_FW_CRITICAL_CODE_SECTION
freertos_ready_to_dsleep(void)72 int freertos_ready_to_dsleep(void)
73 {
74 	u32 current_tick = SYSTIMER_TickGet();
75 
76 	/* timeout */
77 	if (current_tick < deepwakelock_timeout) {
78 		return FALSE;
79 	}
80 
81 	if (deepwakelock == 0)
82 		return TRUE;
83 	else
84 		return FALSE;
85 }
86 #define AliOS_ready_to_sleep           freertos_ready_to_sleep
87 
pmu_set_sysactive_time(uint32_t timeout)88 uint32_t pmu_set_sysactive_time(uint32_t timeout)
89 {
90 	u32 TimeOut = 0;
91 
92 	if(sysactive_timeout_flag){
93 		if (timeout > sysactive_timeout_temp) {
94 			sysactive_timeout_temp = timeout;
95 		}
96 		return 1;
97 	}
98 
99 	if(sysactive_timeout_temp > timeout) {
100 		timeout = sysactive_timeout_temp;
101 	}
102 	sysactive_timeout_temp = 0;
103 
104 	TimeOut =  SYSTIMER_TickGet() + timeout; //xTaskGetTickCount() + timeout;
105 
106 	if (TimeOut > sleepwakelock_timeout) {
107 		sleepwakelock_timeout = TimeOut;
108 	}
109 	return 0;
110 }
111 
pmu_yield_os_set(int value)112 uint32_t pmu_yield_os_set(int value)
113 {
114 	system_can_yield = value;
115 }
116 
117 /*
118  *  It is called in idle task.
119  *
120  *  @return  true  : System is ready to check conditions that if it can enter sleep.
121  *           false : System keep awake.
122  **/
123 
124 
125 /**
126  * tickless_announce_n() is called to announces elapsed ticks to the kernel.
127  */
tickless_announce_n(tick_t n_ticks)128 static void tickless_announce_n(tick_t n_ticks)
129 {
130     tick_list_update((tick_t)n_ticks);
131 }
132 
133 /**
134  * tickless_enter() is called when a CPU is going to enter idle state, a one
135  * shot interrupt is planned at sametime which is used to wake up CPU.
136  * @return  N/A
137  */
tickless_enter(void)138 static void tickless_enter(void)
139 {
140 	uint32_t tick_before_sleep;
141 	uint32_t tick_passed;
142 	uint32_t tick_after_sleep;
143 	volatile uint32_t ms_passed = 0;
144 	uint32_t ms_before_sleep = SYSTIMER_GetPassTime(0);
145 	uint32_t wakeup_time_ms = 0;
146 
147 	if (freertos_ready_to_dsleep()) {
148 		sleep_param.sleep_time = 0;// do not wake on system schedule tick
149 		sleep_param.dlps_enable = ENABLE;
150 	} else {
151 		sleep_param.sleep_time = max_sleep_time;//*expected_idle_time;
152 		max_sleep_time = 0;
153 		sleep_param.dlps_enable = DISABLE;
154 	}
155 	sleep_param.sleep_type = sleep_type;
156 
157 	//*expected_idle_time = 0;
158 
159 	/*  Store gtimer timestamp before sleep */
160 	tick_before_sleep = SYSTIMER_TickGet();
161 	sysactive_timeout_flag = 1;
162 
163 	IPCM0_DEV->IPCx_USR[IPC_INT_CHAN_SHELL_SWITCH] = 0x00000000;
164 	InterruptDis(UART_LOG_IRQ);
165 
166 	//BKUP_Set(BKUP_REG0, BIT_KM4_WAKE_DELAY);
167 
168 	if (sleep_type == SLEEP_PG) {
169 		SOCPS_SleepPG();
170 	} else {
171 		SOCPS_SleepCG();
172 	}
173 
174 	//BKUP_Clear(BKUP_REG0, BIT_KM4_WAKE_DELAY);
175 
176 	/*  update kernel tick by calculating passed tick from gtimer */
177 	/*  get current gtimer timestamp */
178 	tick_after_sleep = SYSTIMER_TickGet();
179 
180 	/*  calculated passed time */
181 	if (tick_after_sleep > tick_before_sleep) {
182 		tick_passed = tick_after_sleep - tick_before_sleep;
183 	} else {
184 		/*  overflow */
185 		tick_passed = (0xffffffff - tick_before_sleep) + tick_after_sleep;
186 	}
187 
188 	tick_passed += missing_tick;
189 	missing_tick = tick_passed & 0x1F;
190 
191 	/* timer clock is 32768, 0x20 is 1ms */
192 	ms_passed = (((tick_passed & 0xFFFFFFE0) * 1000)/32768);
193 	tickless_announce_n(ms_passed); /*  update kernel tick */
194 
195 	wakeup_time_ms = SYSTIMER_GetPassTime(0);
196 
197 	sysactive_timeout_flag = 0;
198 	pmu_set_sysactive_time(2);
199 
200 	if (tickless_debug) {
201 		DBG_8195A("m4 sleeped:[%d] ms\n", wakeup_time_ms - ms_before_sleep);
202 	}
203 }
204 
205 /**
206  * tickless_exit() is called when a CPU gets interrupted. If it determeines
207  * that the system is waking up from tickless idle, it re-enables tick
208  * interrupts and stop the one shot interrupt plan, also announces elapsed
209  * ticks to the kernel.
210  *
211  * @return  N/A
212  */
tickless_exit(void)213 static void tickless_exit(void)
214 {
215 }
216 
217 
218 /**
219  * cpu_pwrmgmt_init() is the entry of whole cpu power manamgement system.
220  */
cpu_pwrmgmt_init(void)221 void cpu_pwrmgmt_init(void)
222 {
223     /* avoid reentry */
224     if (cpu_pwr_init_flag) {
225         return;
226     }
227 
228 //    tickless_debug = 1;
229 
230     krhino_spin_lock_init(&cpu_pwr_spin);
231 
232     /* create cpu power management framework and cpu topology structure */
233     //cpu_pwr_hal_lib_init();
234 
235     /* init cpu tickless framework */
236     //tickless_init();
237 
238     /* save the job complete flag */
239     cpu_pwr_init_flag = 1;
240 }
241 
242 /**
243  * cpu_pwr_down() is invoked from idle task when it detects that the kernel
244  * can go idle.  cpu_pwr_down() checks the current cpu idle mode and put
245  * cpu into lower power mode according different idle mode.
246  */
cpu_pwr_down(void)247 void cpu_pwr_down(void)
248 {
249     if (cpu_pwr_init_flag == 0) {
250         return;
251     }
252 
253     krhino_spin_lock_irq_save(&cpu_pwr_spin);
254     pmu_yield_os_set(0);
255     SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
256 
257 
258     if(!AliOS_ready_to_sleep()){
259 	SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
260         pmu_yield_os_set(1);
261         krhino_spin_unlock_irq_restore(&cpu_pwr_spin);
262         return;
263     }
264 
265 	/* Enter a critical section but don't use the taskENTER_CRITICAL()
266 	method as that will mask interrupts that should exit sleep mode. */
267 	//__asm volatile( "cpsid i" );
268 
269     tickless_enter();
270 
271    	/* Re-enable interrupts - see comments above the cpsid instruction()
272 	above. */
273 	//__asm volatile( "cpsie i" );
274 
275     SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
276     pmu_yield_os_set(1);
277     krhino_spin_unlock_irq_restore(&cpu_pwr_spin);
278 
279 }
280 
cpu_pwr_up(void)281 void cpu_pwr_up(void)
282 {
283     if (cpu_pwr_init_flag == 0) {
284         return;
285     }
286 }
287