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)28void pmu_acquire_wakelock(uint32_t nDeviceId) 29 { 30 wakelock |= BIT(nDeviceId); 31 } 32 pmu_release_wakelock(uint32_t nDeviceId)33void pmu_release_wakelock(uint32_t nDeviceId) 34 { 35 wakelock &= ~BIT(nDeviceId); 36 } 37 pmu_get_wakelock_status(void)38uint32_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)44uint32_t pmu_yield_os_check(void) 45 { 46 return system_can_yield; 47 } 48 CONFIG_FW_CRITICAL_CODE_SECTION freertos_ready_to_sleep(void)49int 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)72int 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)88uint32_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)112uint32_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)128static 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)138static 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)213static 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)221void 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)247void 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)281void cpu_pwr_up(void) 282 { 283 if (cpu_pwr_init_flag == 0) { 284 return; 285 } 286 } 287