tobudos-kernel/pm/tos_tickless.c

176 lines
4.7 KiB
C

/*----------------------------------------------------------------------------
* Tencent is pleased to support the open source community by making TencentOS
* available.
*
* Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
* If you have downloaded a copy of the TencentOS binary from Tencent, please
* note that the TencentOS binary is licensed under the BSD 3-Clause License.
*
* If you have downloaded a copy of the TencentOS source code from Tencent,
* please note that TencentOS source code is licensed under the BSD 3-Clause
* License, except for the third-party components listed below which are
* subject to different license terms. Your integration of TencentOS into your
* own projects may require compliance with the BSD 3-Clause License, as well
* as the other licenses applicable to the third-party components included
* within TencentOS.
*---------------------------------------------------------------------------*/
#include "tos_k.h"
#if TOS_CFG_TICKLESS_EN > 0u
__API__ void tos_tickless_wkup_alarm_install(k_cpu_lpwr_mode_t mode, k_tickless_wkup_alarm_t *wkup_alarm)
{
k_tickless_wkup_alarm[mode] = wkup_alarm;
}
__API__ k_err_t tos_tickless_wkup_alarm_init(k_cpu_lpwr_mode_t mode)
{
if (!k_tickless_wkup_alarm[mode]) {
return K_ERR_TICKLESS_WKUP_ALARM_NOT_INSTALLED;
}
if (!k_tickless_wkup_alarm[mode]->init) {
return K_ERR_TICKLESS_WKUP_ALARM_NO_INIT;
}
if (k_tickless_wkup_alarm[mode]->init() != 0) {
return K_ERR_TICKLESS_WKUP_ALARM_INIT_FAILED;
}
return K_ERR_NONE;
}
__KNL__ int tickless_wkup_alarm_is_installed(k_cpu_lpwr_mode_t mode)
{
return k_tickless_wkup_alarm[mode] != K_NULL;
}
__STATIC__ int tickless_wkup_alarm_setup(k_cpu_lpwr_mode_t mode, k_time_t expires)
{
if (k_tickless_wkup_alarm[mode] && k_tickless_wkup_alarm[mode]->setup) {
return k_tickless_wkup_alarm[mode]->setup(expires);
}
return -1;
}
__STATIC__ int tickless_wkup_alarm_dismiss(k_cpu_lpwr_mode_t mode)
{
if (k_tickless_wkup_alarm[mode] && k_tickless_wkup_alarm[mode]->dismiss) {
return k_tickless_wkup_alarm[mode]->dismiss();
}
return -1;
}
__STATIC__ k_time_t tickless_wkup_alarm_max_delay(k_cpu_lpwr_mode_t mode)
{
if (k_tickless_wkup_alarm[mode] && k_tickless_wkup_alarm[mode]->max_delay) {
return k_tickless_wkup_alarm[mode]->max_delay();
}
return (k_time_t)0u;
}
__STATIC__ k_time_t tickless_cpu_sleep_time_get(k_cpu_lpwr_mode_t lpwr_mode)
{
k_tick_t next_expires;
k_time_t time_sleep_ms, max_delay_ms;
/* the max time(in millisecond) we can sleep */
max_delay_ms = tickless_wkup_alarm_max_delay(lpwr_mode);
next_expires = knl_next_expires_get();
if (next_expires == TOS_TIME_FOREVER) {
return max_delay_ms;
}
/* how much time should we sleep(in millisecond) */
time_sleep_ms = (k_time_t)(next_expires * K_TIME_MILLISEC_PER_SEC / k_cpu_tick_per_second);
return time_sleep_ms > max_delay_ms ? max_delay_ms : time_sleep_ms;
}
__STATIC__ void tickless_tick_suspend(void)
{
cpu_systick_suspend();
cpu_systick_pending_reset();
}
__STATIC__ void tickless_tick_resume(void)
{
cpu_systick_suspend();
cpu_systick_reset();
cpu_systick_resume();
}
__STATIC__ void tickless_tick_fix(k_tick_t tick_sleep)
{
TOS_CPU_CPSR_ALLOC();
TOS_CPU_INT_DISABLE();
/* we wakeup from SLEEP mode, fix the system's tick & timer */
tick_update(tick_sleep);
#if TOS_CFG_TIMER_EN > 0u && TOS_CFG_TIMER_AS_PROC > 0u
soft_timer_update();
#endif
tickless_tick_resume();
TOS_CPU_INT_ENABLE();
}
__STATIC__ void tickless_enter(void)
{
tickless_tick_suspend();
}
__STATIC__ void tickless_leave(k_time_t time_sleep_ms)
{
k_tick_t tick_sleep;
/* how many "ticks" have we sleep */
tick_sleep = k_cpu_tick_per_second * time_sleep_ms / K_TIME_MILLISEC_PER_SEC;
tickless_tick_fix(tick_sleep);
knl_sched();
}
__KNL__ void tickless_proc(void)
{
TOS_CPU_CPSR_ALLOC();
k_time_t time_sleep;
k_cpu_lpwr_mode_t lpwr_mode;
lpwr_mode = pm_cpu_lpwr_mode_get();
if (lpwr_mode == TOS_LOW_POWER_MODE_NONE ||
!tickless_wkup_alarm_is_installed(lpwr_mode)) {
return;
}
TOS_CPU_INT_DISABLE();
time_sleep = tickless_cpu_sleep_time_get(lpwr_mode); /* in millisecond */
if (unlikely(time_sleep == (k_time_t)0)) {
TOS_CPU_INT_ENABLE();
return;
}
tickless_enter();
TOS_CPU_INT_ENABLE();
tickless_wkup_alarm_setup(lpwr_mode, time_sleep);
pm_cpu_lpwr_mode_enter(lpwr_mode);
tickless_wkup_alarm_dismiss(lpwr_mode);
tickless_leave(time_sleep);
}
__KNL__ void tickless_init(void)
{
pm_idle_pwr_mgr_mode_set(IDLE_POWER_MANAGER_MODE_TICKLESS);
tos_bsp_tickless_setup();
}
#endif