#include "FreeRTOS.h" #include "freertos_pmu.h" #include #include "platform_autoconf.h" #include "sys_api.h" #include "sleep_ex_api.h" #ifndef portNVIC_SYSTICK_CURRENT_VALUE_REG #define portNVIC_SYSTICK_CURRENT_VALUE_REG ( * ( ( volatile uint32_t * ) 0xe000e018 ) ) #endif uint32_t missing_tick = 0; static uint32_t wakelock = DEFAULT_WAKELOCK; static uint32_t wakeup_event = DEFAULT_WAKEUP_EVENT; typedef struct { uint32_t nDeviceId; PSM_HOOK_FUN sleep_hook_fun; void* sleep_param_ptr; PSM_HOOK_FUN wakeup_hook_fun; void* wakeup_param_ptr; } PSM_DD_HOOK_INFO; #define MAX_PSM_DD_HOOK_INFO_SIZE 8 uint32_t psm_dd_hook_info_size = 0; PSM_DD_HOOK_INFO psm_dd_hook_infos[MAX_PSM_DD_HOOK_INFO_SIZE]; static uint8_t last_wakelock_state[32] = { DEFAULT_WAKELOCK & 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static uint32_t last_acquire_wakelock_time[32] = {0}; static uint32_t hold_wakelock_time[32] = {0}; static uint32_t base_sys_time = 0; static uint32_t sys_sleep_time = 0; unsigned char reserve_pll = 0; unsigned char generate_wakelock_stats = 0; /* ++++++++ FreeRTOS macro implementation ++++++++ */ /* * It is called in idle task. * * @return true : System is ready to check conditions that if it can enter sleep. * false : System keep awake. **/ /* * It is called when freertos is going to sleep. * At this moment, all sleep conditons are satisfied. All freertos' sleep pre-processing are done. * * @param expected_idle_time : The time that FreeRTOS expect to sleep. * If we set this value to 0 then FreeRTOS will do nothing in its sleep function. **/ void freertos_pre_sleep_processing(unsigned int *expected_idle_time) { #ifdef CONFIG_SOC_PS_MODULE uint32_t i; uint32_t stime; uint32_t tick_before_sleep; uint32_t tick_after_sleep; uint32_t tick_passed; uint32_t backup_systick_reg; unsigned char IsDramOn = 1; unsigned char suspend_sdram = 1; /* To disable freertos sleep function and use our sleep function, * we can set original expected idle time to 0. */ stime = *expected_idle_time; *expected_idle_time = 0; for (i=0; i tick_before_sleep) { tick_passed = tick_after_sleep - tick_before_sleep; } else { // overflow tick_passed = (0xffffffff - tick_before_sleep) + tick_after_sleep; } /* If there is a rapid interrupt (<1ms), it makes tick_passed less than 1ms. * The tick_passed would be rounded and make OS can't step tick. * We collect the rounded tick_passed into missing_tick and step tick properly. * */ tick_passed += missing_tick; if (tick_passed > stime * 1000) { missing_tick = tick_passed - stime * 1000; tick_passed = stime * 1000; } else { missing_tick = tick_passed % 1000; } // update kernel tick vTaskStepTick( tick_passed/1000 ); } sys_sleep_time += tick_passed/1000; for (i=0; i 0) { sprintf(pcWriteBuffer, "%x\t\t%d\r\n", i, hold_wakelock_time[i]); } } pcWriteBuffer += strlen( pcWriteBuffer ); } sprintf(pcWriteBuffer, "time passed: %d ms, system sleep %d ms\r\n", current_timestamp - base_sys_time, sys_sleep_time); } } void pmu_clean_wakelock_stat() { uint32_t i; base_sys_time = osKernelSysTick(); for (i=0; i<32; i++) { hold_wakelock_time[i] = 0; if (last_wakelock_state[i] == 1) { last_acquire_wakelock_time[i] = base_sys_time; } } sys_sleep_time = 0; } void pmu_add_wakeup_event(uint32_t event) { wakeup_event |= event; } void pmu_del_wakeup_event(uint32_t event) { wakeup_event &= ~event; // To fulfill tickless design, system timer is required to be wakeup event wakeup_event |= SLEEP_WAKEUP_BY_STIMER; } void pmu_register_sleep_callback(uint32_t nDeviceId, PSM_HOOK_FUN sleep_hook_fun, void* sleep_param_ptr, PSM_HOOK_FUN wakeup_hook_fun, void* wakeup_param_ptr) { uint32_t i; for (i=0; i 1) { // if we have more than 2 items, just swap the last item into current slot psm_dd_hook_infos[i].nDeviceId = psm_dd_hook_infos[psm_dd_hook_info_size-1].nDeviceId; psm_dd_hook_infos[i].sleep_hook_fun = psm_dd_hook_infos[psm_dd_hook_info_size-1].sleep_hook_fun; psm_dd_hook_infos[i].sleep_param_ptr = psm_dd_hook_infos[psm_dd_hook_info_size-1].sleep_param_ptr; psm_dd_hook_infos[i].wakeup_hook_fun = psm_dd_hook_infos[psm_dd_hook_info_size-1].wakeup_hook_fun; psm_dd_hook_infos[i].wakeup_param_ptr = psm_dd_hook_infos[psm_dd_hook_info_size-1].wakeup_param_ptr; // Then erase the last item psm_dd_hook_infos[psm_dd_hook_info_size-1].nDeviceId = 0; psm_dd_hook_infos[psm_dd_hook_info_size-1].sleep_hook_fun = NULL; psm_dd_hook_infos[psm_dd_hook_info_size-1].sleep_param_ptr = NULL; psm_dd_hook_infos[psm_dd_hook_info_size-1].wakeup_hook_fun = NULL; psm_dd_hook_infos[psm_dd_hook_info_size-1].wakeup_param_ptr = NULL; } else { // we only have one item, just erase it psm_dd_hook_infos[i].nDeviceId = 0; psm_dd_hook_infos[i].sleep_hook_fun = NULL; psm_dd_hook_infos[i].sleep_param_ptr = NULL; psm_dd_hook_infos[i].wakeup_hook_fun = NULL; psm_dd_hook_infos[i].wakeup_param_ptr = NULL; } psm_dd_hook_info_size--; break; } } } void pmu_set_pll_reserved(unsigned char reserve) { reserve_pll = reserve; }