176 lines
4.7 KiB
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
|
|
|