lock_lfvx/bk_idk/middleware/driver/rtc/aon_rtc_driver.c
2025-10-10 16:07:00 +08:00

1559 lines
41 KiB
C

// Copyright 2020-2021 Beken
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <common/bk_include.h>
#include <os/mem.h>
#include <stdlib.h>
#include <stdio.h>
#include "string.h"
#include <driver/int.h>
#include "sys_driver.h"
#include "sys/time.h"
#include <driver/aon_rtc.h>
#include "aon_rtc_hal.h"
#include "aon_rtc_driver.h"
/*
* NOTES: System entery deepsleep or reboot, the aon rtc time should reserved.
* 1.When enter deep sleep, the DTCM power is lost,so have to save time to flash.
* 2.Write time to flash takes about 200us~3ms, When reboot system,the easy flash API call rtos_get_semaphore in ISR cause assert
* 3.When reboot system,DTCM doesn't loss power,so can save time in DTCM.
*/
#if CONFIG_AON_RTC_KEEP_TIME_SUPPORT
#include <modules/pm.h>
#include "reset_reason.h"
#if CONFIG_EASY_FLASH
#include "bk_ef.h"
#endif
#endif
#if CONFIG_AON_PMU
#include "aon_pmu_driver.h"
#endif
#define AON_RTC_UNIT_NUM (AON_RTC_HAL_UNIT_NUM)
#define AON_RTC_NAME ((uint8_t *)"aon_rtc")
typedef struct {
//aon_rtc_id_t id; //no needs it until now:the id is matched from APP,DRIVER,HAL,HW/SOC layer.
bool inited;
//uint8_t using_cnt; //remove it as only one HW can't for many APPs
aon_rtc_hal_t hal;
//Record APP param's
//bool period;
//uint32_t tick;
//Alarm list
alarm_node_t *alarm_head_p;
uint32_t alarm_node_cnt;
} aon_rtc_driver_t;
typedef struct {
aon_rtc_isr_t callback;
void *isr_param;
} aon_rtc_callback_t;
typedef struct {
alarm_node_t nodes[AON_RTC_MAX_ALARM_CNT];
uint64_t busy_bits;
} aon_rtc_nodes_memory_t;
static aon_rtc_driver_t s_aon_rtc[AON_RTC_UNIT_NUM] = {0};
static aon_rtc_callback_t s_aon_rtc_tick_isr[AON_RTC_UNIT_NUM] = {NULL};
static aon_rtc_callback_t s_aon_rtc_upper_isr[AON_RTC_UNIT_NUM] = {NULL};
static aon_rtc_nodes_memory_t *s_aon_rtc_nodes_p[AON_RTC_UNIT_NUM];
static uint64_t s_high_tick[AON_RTC_UNIT_NUM];
static void aon_rtc_interrupt_disable(aon_rtc_id_t id);
#define AONRTC_GET_SET_TIME_RTC_ID AON_RTC_ID_1
static int64_t s_boot_time_us = 0; //timeofday value
#if CONFIG_RTC_ANA_WAKEUP_SUPPORT
#define RTC_ANA_TIME_PERIOD_MAX 16
static uint32_t s_wkup_time_period = 0;
#endif
#define AON_RTC_OPS_SAFE_DELAY_US (125)
/*
* AON RTC uses 32k clock,and 3 cycles later can be clock sync.
* CPU clock is more faster then AON RTC, so software operates AON RTC register
* will be effect after 125 us(RTC 3+1 clock cycles).
* So if operate the same register in 125 us, the second operation will be failed.
*/
static void aon_rtc_delay_to_grantee_ops_safe()
{
extern void delay_us(UINT32 us);
delay_us(AON_RTC_OPS_SAFE_DELAY_US);
}
#ifdef CONFIG_EXTERN_32K
static uint32_t s_aon_rtc_clock_freq = AON_RTC_EXTERN_32K_CLOCK_FREQ;
#else
static uint32_t s_aon_rtc_clock_freq = AON_RTC_DEFAULT_CLOCK_FREQ;
#endif
static uint64_t s_time_base_us = 0;
static uint64_t s_time_base_tick = 0;
float bk_rtc_get_ms_tick_count(void) {
return (float)s_aon_rtc_clock_freq/1000;
}
uint32_t bk_rtc_get_clock_freq(void) {
return s_aon_rtc_clock_freq;
}
static inline uint64_t get_diff_time_us(void) {
uint64_t time_tick = bk_aon_rtc_get_current_tick(AONRTC_GET_SET_TIME_RTC_ID);
uint64_t time_diff = (time_tick - s_time_base_tick)*1000LL/bk_rtc_get_ms_tick_count();
return time_diff;
}
void bk_rtc_update_base_time(void) {
uint64_t time_tick = bk_aon_rtc_get_current_tick(AONRTC_GET_SET_TIME_RTC_ID);
uint64_t time_diff = (time_tick - s_time_base_tick)*1000LL/bk_rtc_get_ms_tick_count();
s_time_base_tick = time_tick;
s_time_base_us += time_diff;
// AON_RTC_LOGI("s_time_base_tick: 0x%x:0x%08x\r\n", (u32)(s_time_base_tick >> 32), (u32)(s_time_base_tick & 0xFFFFFFFF));
// AON_RTC_LOGI("s_time_base_us: 0x%x:0x%08x\r\n", (u32)(s_time_base_us >> 32), (u32)(s_time_base_us & 0xFFFFFFFF));
}
void bk_rtc_set_clock_freq(uint32_t clock_freq){
#if CONFIG_AON_RTC_DYNAMIC_CLOCK_SUPPORT
AON_RTC_LOGI("Set clock freq: %d\n", clock_freq);
if (clock_freq == s_aon_rtc_clock_freq) {
return;
}
uint32_t int_level = rtos_disable_int();
{
bk_rtc_update_base_time();
s_aon_rtc_clock_freq = clock_freq;
}
rtos_enable_int(int_level);
#endif
}
uint64_t bk_aon_rtc_get_us(void) {
uint64_t time_tick = bk_aon_rtc_get_current_tick(AONRTC_GET_SET_TIME_RTC_ID);
uint64_t time_diff = (time_tick - s_time_base_tick)*1000LL/bk_rtc_get_ms_tick_count();
uint64_t time_us = s_time_base_us + time_diff;
return time_us;
}
uint64_t bk_aon_rtc_get_ms(void) {
uint64_t time_tick = bk_aon_rtc_get_current_tick(AONRTC_GET_SET_TIME_RTC_ID);
uint64_t time_diff = (time_tick - s_time_base_tick)/bk_rtc_get_ms_tick_count();
uint64_t time_us = s_time_base_us + time_diff;
return time_us;
}
#if CONFIG_AON_RTC_KEEP_TIME_SUPPORT
static int32_t s_rtc_keep_tick_offset = 0x0;
#define AONRTC_DEEPSLEEP_KEEPTIME_EF_KEYNUM 2
static bool bk_rtc_get_aon_pmu_deepsleep_flag()
{
#if CONFIG_AON_PMU
return (aon_pmu_drv_reg_get(PMU_REG2) & BIT(BIT_SLEEP_FLAG_DEEP_SLEEP));
#endif
return false;
}
/*
* WARNING:
* This function is only called by AON RTC driver before deepsleep!!!
* WORKAROUND:
* aon rtc is 32bits counter, 37.4 hours will be data overflow.
* so before power lost, we should save the time value to flash.
* after system wakeup,restore the baked time.
*/
static bk_err_t aon_rtc_bake_entry_deepsleep_timeofday()
{
struct timeval rtc_keep_time = {0, 0};
//bake up current time to flash
#if CONFIG_EASY_FLASH
char *rtc_keep_time_key[2] = {"rtc_tv_sec", "rtc_tv_usec"};
char value[AONRTC_DEEPSLEEP_KEEPTIME_EF_KEYNUM * 16]; //uint32_t max digital num is 10, here set it 16
uint32_t data = 0;
uint32_t ret = 0;
#endif
AON_RTC_LOGD("%s[+]\r\n", __func__);
bk_rtc_gettimeofday(&rtc_keep_time, 0);
AON_RTC_LOGD("bake:tv_sec:%d,tv_usec:%d\n", rtc_keep_time.tv_sec, rtc_keep_time.tv_usec);
#if CONFIG_EASY_FLASH
memset(value, 0, sizeof(value));
for(int key_index = 0; key_index < AONRTC_DEEPSLEEP_KEEPTIME_EF_KEYNUM; key_index++)
{
if(key_index == 0)
data = rtc_keep_time.tv_sec;
else if(key_index == 1)
data = rtc_keep_time.tv_usec;
sprintf(value, "%d", data);
ret = ef_set_env(rtc_keep_time_key[key_index], value);
if(ret)
AON_RTC_LOGI("%s %s ret: %d\n",__func__, rtc_keep_time_key[key_index], ret);
AON_RTC_LOGD("%s %s\n",__func__, value);
}
ef_save_env();
#else
AON_RTC_LOGI("TODO:Please save the time to none lost memory\r\n", __func__);
#endif
return BK_OK;
}
static void aon_rtc_get_deepsleep_timeofday(struct timeval *time_p)
{
AON_RTC_LOGD("%s[+]\r\n", __func__);
#if CONFIG_EASY_FLASH
char *rtc_keep_time_key[2] = {"rtc_tv_sec", "rtc_tv_usec"};
char *value;
for(int key_index = 0; key_index < AONRTC_DEEPSLEEP_KEEPTIME_EF_KEYNUM; key_index++){
value = ef_get_env(rtc_keep_time_key[key_index]);
AON_RTC_LOGD("%s %s value:%s\r\n",__func__, rtc_keep_time_key[key_index], value);
if(key_index == 0)
time_p->tv_sec = atol(value);
else if(key_index == 1)
time_p->tv_usec = atol(value);
AON_RTC_LOGD("%s tv_sec:%d tv_usec:%d\n",__func__, time_p->tv_sec, time_p->tv_usec);
}
#else
AON_RTC_LOGI("TODO:%s\n");
#endif
}
static void aon_rtc_get_reboot_time(struct timeval *time_p)
{
time_p->tv_sec = *(uint32_t *)RTC_TIME_SEC_ADDR;
time_p->tv_usec = *(uint32_t *)RTC_TIME_USEC_ADDR;
AON_RTC_LOGD("%s[-]sec=%d,usec=%d\r\n", __func__, time_p->tv_sec, time_p->tv_usec);
}
/*
* WARNING:
* This function is only called by AON RTC driver before reboot!!!
* WORKAROUND:
* aon rtc is 32bits counter, 37.4 hours will be data overflow.
* so before reboot, we should save the time value to DTCM.
* after system reboot,restore the baked time.
*/
bk_err_t aon_rtc_enter_reboot(void)
{
struct timeval rtc_keep_time = {0, 0};
AON_RTC_LOGD("%s[+]\r\n", __func__);
//backup poweroff time
bk_rtc_gettimeofday(&rtc_keep_time, 0);
AON_RTC_LOGD("bake:tv_sec:%d,tv_usec:%d\n", rtc_keep_time.tv_sec, rtc_keep_time.tv_usec);
*(uint32_t *)RTC_TIME_SEC_ADDR = rtc_keep_time.tv_sec;
*(uint32_t *)RTC_TIME_USEC_ADDR = rtc_keep_time.tv_usec;
for (int id = AON_RTC_ID_1; id < AON_RTC_ID_MAX; id++) {
#if (CONFIG_SYSTEM_CTRL)
aon_rtc_interrupt_disable(id);
#endif
}
return BK_OK;
}
static void aon_rtc_compute_boot_timeofday(void)
{
struct timeval time = {0, 0};
AON_RTC_LOGD("%s[+]\r\n", __func__);
//deepsleep boot
if(bk_rtc_get_aon_pmu_deepsleep_flag())
{
aon_rtc_get_deepsleep_timeofday(&time);
//the time interval of deepsleep to wakeup time, tick offset
s_rtc_keep_tick_offset = aon_rtc_hal_get_counter_val(&s_aon_rtc[AON_RTC_ID_1].hal);
AON_RTC_LOGD("s_rtc_keep_tick_offset=%d\r\n", (uint32_t)s_rtc_keep_tick_offset);
s_boot_time_us = ((uint64_t)time.tv_sec)*1000000LL+time.tv_usec +
((uint64_t)(s_rtc_keep_tick_offset/bk_rtc_get_ms_tick_count()))*1000;
}
else if(bk_misc_get_reset_reason() != RESET_SOURCE_POWERON) //hot reboot
{
aon_rtc_get_reboot_time(&time);
s_boot_time_us = ((uint64_t)time.tv_sec)*1000000LL+time.tv_usec;
}
else //cold boot,power on
{
s_boot_time_us = 0;
AON_RTC_LOGD("power on\r\n");
}
//clear it
*(uint32_t *)RTC_TIME_SEC_ADDR = 0;
*(uint32_t *)RTC_TIME_USEC_ADDR = 0;
}
static void bk_rtc_keep_time_enter_deepsleep(void)
{
uint32_t tick_val_offset;
AON_RTC_LOGD("[+]%s\r\n", __func__);
aon_rtc_bake_entry_deepsleep_timeofday();
tick_val_offset = aon_rtc_hal_get_tick_val(&s_aon_rtc[AON_RTC_ID_1].hal)
- aon_rtc_hal_get_counter_val(&s_aon_rtc[AON_RTC_ID_1].hal);
//reset
aon_rtc_hal_reset_counter(&s_aon_rtc[AON_RTC_ID_1].hal);
//reset counter is the same register.
aon_rtc_delay_to_grantee_ops_safe();
//reset the nearest isr tick value, to confirm aon rtc can wakeup system
aon_rtc_hal_set_tick_val(&s_aon_rtc[AON_RTC_ID_1].hal, (uint32_t)tick_val_offset);
AON_RTC_LOGD("%s tick_val_offset:%x\n",__func__, tick_val_offset);
//reset release
if(aon_rtc_hal_is_counter_reset(&s_aon_rtc[AON_RTC_ID_1].hal)) {
AON_RTC_LOGD("%s:reset counter\n",__func__);
aon_rtc_hal_clear_reset_counter(&s_aon_rtc[AON_RTC_ID_1].hal);
} else
AON_RTC_LOGW("%s PLEASE reset counter\n",__func__);
AON_RTC_LOGD("[-]%s\r\n", __func__);
}
static void bk_rtc_keep_time_exit_deepsleep(void)
{
AON_RTC_LOGD("%s\r\n", __func__);
}
static void aon_rtc_register_deepsleep_cb(void)
{
pm_cb_conf_t aon_rtc_enter_config = {
.cb = (pm_cb)bk_rtc_keep_time_enter_deepsleep,
.args = NULL
};
pm_cb_conf_t aon_rtc_exit_config = {
.cb = (pm_cb)bk_rtc_keep_time_exit_deepsleep,
.args = NULL
};
bk_pm_sleep_register_cb(PM_MODE_DEEP_SLEEP, PM_DEV_ID_RTC, &aon_rtc_enter_config, &aon_rtc_exit_config);
}
#endif
bk_err_t bk_rtc_get_deepsleep_duration_seconds(uint32_t *deepsleep_seconds)
{
#if CONFIG_AON_RTC_KEEP_TIME_SUPPORT
*deepsleep_seconds = s_rtc_keep_tick_offset/(bk_rtc_get_ms_tick_count() * 1000);
return BK_OK;
#endif
return BK_FAIL;
}
static void alarm_dump_node(alarm_node_t *node_p)
{
#if CONFIG_AON_RTC_DEBUG
AON_RTC_LOGD("%s[+]\r\n", __func__);
AON_RTC_LOGD("node_p=0x%x\r\n", node_p);
if(node_p)
{
AON_RTC_LOGD("next=0x%x\r\n", node_p->next);
AON_RTC_LOGD("name=%s\r\n", node_p->name);
AON_RTC_LOGD("period_tick=0x%x\r\n", node_p->period_tick);
AON_RTC_LOGD("period_cnt=%d\r\n", node_p->period_cnt);
AON_RTC_LOGD("start_tick=0x%x\r\n", node_p->start_tick);
AON_RTC_LOGD("expired_tick=0x%x\r\n", node_p->expired_tick);
}
AON_RTC_LOGD("%s[-]\r\n", __func__);
#endif
}
static void alarm_dump_list(alarm_node_t *head_p)
{
#if CONFIG_AON_RTC_DEBUG
alarm_node_t *cur_p = head_p;
uint32_t count = 0;
uint32_t int_level = 0;
AON_RTC_LOGD("%s[+]\r\n", __func__);
int_level = rtos_disable_int();
while(cur_p)
{
alarm_dump_node(cur_p);
count++;
cur_p = cur_p->next;
}
rtos_enable_int(int_level);
AON_RTC_LOGD("node cnt=%d\r\n", count);
AON_RTC_LOGD("%s[-]\r\n", __func__);
#endif
}
static alarm_node_t* aon_rtc_request_node(aon_rtc_id_t id)
{
uint32_t i = 0;
AON_RTC_LOGD("%s[+]\r\n", __func__);
for(i = 0; i < AON_RTC_MAX_ALARM_CNT; i++)
{
if((s_aon_rtc_nodes_p[id]->busy_bits & (0x1<<i)) == 0)
{
AON_RTC_LOGD("%s[-]:node[%d]=0x%x\r\n", __func__, i, &s_aon_rtc_nodes_p[id]->nodes[i]);
s_aon_rtc_nodes_p[id]->busy_bits |= (0x1<<i);
return &s_aon_rtc_nodes_p[id]->nodes[i];
}
}
return NULL;
}
static void aon_rtc_release_node(aon_rtc_id_t id, alarm_node_t *node_p)
{
uint32_t i = 0;
AON_RTC_LOGD("%s[+]\r\n", __func__);
for(i = 0; i < AON_RTC_MAX_ALARM_CNT; i++)
{
if(&s_aon_rtc_nodes_p[id]->nodes[i] == node_p)
{
s_aon_rtc_nodes_p[id]->busy_bits &= ~(0x1<<i);
os_memset(&s_aon_rtc_nodes_p[id]->nodes[i], 0, sizeof(alarm_info_t));
AON_RTC_LOGD("%s[-]:node[%d]=0x%x\r\n", __func__, i, &s_aon_rtc_nodes_p[id]->nodes[i]);
break;
}
}
if(i >= AON_RTC_MAX_ALARM_CNT)
{
AON_RTC_LOGE("release node err\r\n");
}
}
static int32_t alarm_insert_node(aon_rtc_id_t id, alarm_node_t *node_p)
{
alarm_node_t *cur_p = NULL;
alarm_node_t *next_p = NULL;
uint32_t int_level = 0;
AON_RTC_LOGD("%s[+]cnt=%d\r\n", __func__, s_aon_rtc[id].alarm_node_cnt);
alarm_dump_list(s_aon_rtc[id].alarm_head_p);
int_level = rtos_disable_int();
//check whether the same name
cur_p = s_aon_rtc[id].alarm_head_p;
while(cur_p)
{
if(strncmp((const char *)cur_p->name, (const char *)node_p->name, ALARM_NAME_MAX_LEN) == 0)
{
AON_RTC_LOGE("name=%s has registered\r\n", node_p->name);
rtos_enable_int(int_level);
return -1;
}
cur_p = cur_p->next;
}
//search the node position
cur_p = s_aon_rtc[id].alarm_head_p;
//no node
if(cur_p == NULL)
{
s_aon_rtc[id].alarm_head_p = node_p;
s_aon_rtc[id].alarm_node_cnt++;
AON_RTC_LOGD("insert first node 0x%x,name=%s\r\n", node_p, node_p->name);
rtos_enable_int(int_level);
return 0;
}
//only one node
next_p = cur_p->next;
if(next_p == NULL)
{
if(cur_p->expired_tick <= node_p->expired_tick)
cur_p->next = node_p;
else
{
node_p->next = cur_p;
s_aon_rtc[id].alarm_head_p = node_p;
}
s_aon_rtc[id].alarm_node_cnt++;
rtos_enable_int(int_level);
//TODO:log debug
AON_RTC_LOGD("list total has two nodes\r\n");
return 0;
}
//more then 2 nodes
while(next_p)
{
if(cur_p->expired_tick <= node_p->expired_tick) //move after cur_p
{
if(next_p->expired_tick <= node_p->expired_tick) //search next
{
cur_p = next_p;
next_p = next_p->next;
continue;
}
else //insert
{
node_p->next = next_p;
cur_p->next = node_p;
s_aon_rtc[id].alarm_node_cnt++;
rtos_enable_int(int_level);
return 0;
}
}
else //insert before cur_p, means the first node, head
{
node_p->next = cur_p;
s_aon_rtc[id].alarm_head_p = node_p;
s_aon_rtc[id].alarm_node_cnt++;
rtos_enable_int(int_level);
return 0;
}
}
//the last one
cur_p->next = node_p;
s_aon_rtc[id].alarm_node_cnt++;
rtos_enable_int(int_level);
//dump list info
alarm_dump_list(s_aon_rtc[id].alarm_head_p);
AON_RTC_LOGD("%s[-]cnt=%d\r\n", __func__, s_aon_rtc[id].alarm_node_cnt);
return 0;
}
static alarm_node_t *alarm_remove_node(aon_rtc_id_t id, uint8_t *name_p)
{
alarm_node_t *cur_p = NULL;
alarm_node_t *previous_p = NULL;
alarm_node_t *remove_node_p = NULL;
uint32_t int_level = 0;
uint32_t node_cnt = 0;
AON_RTC_LOGD("%s[+]cnt=%d\r\n", __func__, s_aon_rtc[id].alarm_node_cnt);
int_level = rtos_disable_int();
//
previous_p = cur_p = s_aon_rtc[id].alarm_head_p;
while(cur_p)
{
//double check pointer is valid
node_cnt++;
BK_ASSERT(node_cnt <= AON_RTC_MAX_ALARM_CNT); /* ASSERT VERIFIED */
if(strncmp((const char *)cur_p->name, (const char *)name_p, ALARM_NAME_MAX_LEN) == 0)
{
//first one
if(previous_p == cur_p)
{
remove_node_p = s_aon_rtc[id].alarm_head_p;
s_aon_rtc[id].alarm_head_p = cur_p->next;
s_aon_rtc[id].alarm_node_cnt--;
AON_RTC_LOGD("free=0x%x,name=%s\r\n", cur_p, cur_p->name);
aon_rtc_release_node(id, cur_p);
break;
}
else
{
remove_node_p = cur_p;
previous_p->next = cur_p->next;
s_aon_rtc[id].alarm_node_cnt--;
AON_RTC_LOGD("free=0x%x,name=%s\r\n", cur_p, cur_p->name);
aon_rtc_release_node(id, cur_p);
break;
}
}
previous_p = cur_p;
cur_p = cur_p->next;
}
rtos_enable_int(int_level);
if(remove_node_p == NULL)
{
AON_RTC_LOGD("%s:can't find %s alarm\r\n", __func__, name_p);
}
//dump list info
alarm_dump_list(s_aon_rtc[id].alarm_head_p);
AON_RTC_LOGD("%s[-]cnt=%d\r\n", __func__, s_aon_rtc[id].alarm_node_cnt);
return remove_node_p;
}
static void alarm_update_expeired_nodes(aon_rtc_id_t id)
{
alarm_node_t *cur_p = NULL;
alarm_node_t *next_p = NULL;
uint32_t node_cnt = 0;
uint64_t cur_tick = 0;
uint32_t int_level = 0;
AON_RTC_LOGD("%s[+]cnt=%d\r\n", __func__, s_aon_rtc[id].alarm_node_cnt);
alarm_dump_list(s_aon_rtc[id].alarm_head_p);
int_level = rtos_disable_int();
//search the node position
cur_p = s_aon_rtc[id].alarm_head_p;
while(cur_p)
{
alarm_dump_node(cur_p);
alarm_dump_node(cur_p->next);
//double check pointer is valid
node_cnt++;
BK_ASSERT(node_cnt <= AON_RTC_MAX_ALARM_CNT); /* ASSERT VERIFIED */
next_p = cur_p->next;
cur_tick = bk_aon_rtc_get_current_tick(id);
//maybe callback runs too much time,so assume the time in bk_rtc_get_ms_tick_count() means has expired
if(cur_p->expired_tick <= cur_tick + AON_RTC_PRECISION_TICK)
{
if(cur_p->callback)
{
cur_p->callback(id, cur_p->name, cur_p->cb_param_p);
}
//last time alarm
if(cur_p->period_cnt == 1)
{
cur_p->period_cnt = 0;
s_aon_rtc[id].alarm_head_p = cur_p->next; //head move to next
s_aon_rtc[id].alarm_node_cnt--;
/*
* WARNING:As freertos doesn't support free memory in ISR context.
* The chip no needs to use a task for AON RTC which wastes some memory.
* so the APPLIACTION who calls bk_alarm_register should release the memory
* returns by bk_alarm_register.
*/
#if 0
AON_RTC_LOGD("last alarm:free=0x%x,name=%s\r\n", cur_p, cur_p->name);
os_free(cur_p);
#endif
aon_rtc_release_node(id, cur_p);
}
//loop timer
else
{
if(cur_p->period_cnt != ALARM_LOOP_FOREVER)
{
cur_p->period_cnt--;
AON_RTC_LOGD("%s left %d times \r\n", cur_p->name, cur_p->period_cnt);
}
//has next
if(next_p) //move to switable position
{
s_aon_rtc[id].alarm_head_p = cur_p->next; //head move to next
cur_p->expired_tick += cur_p->period_tick;
cur_p->next = NULL; //cur_p is removed
s_aon_rtc[id].alarm_node_cnt--; //it will ++ in alarm_insert_node
if(alarm_insert_node(id, cur_p) != 0)
{
AON_RTC_LOGE("alarm name=%s insert fail\r\n", cur_p->name);
rtos_enable_int(int_level);
return;
}
}
else //only self
{
//just update self expired time
cur_p->expired_tick += cur_p->period_tick;
AON_RTC_LOGD("%s update next expired time %d \r\n", cur_p->name, cur_p->expired_tick);
}
}
}
else //no expired
{
break;
}
cur_p = next_p; //TODO:maybe cur_p offset is too small and calback excutes too much time, here can't switch to next NODE.
alarm_dump_list(s_aon_rtc[id].alarm_head_p);
}
rtos_enable_int(int_level);
alarm_dump_list(s_aon_rtc[id].alarm_head_p);
AON_RTC_LOGD("%s[-]cnt=%d\r\n", __func__, s_aon_rtc[id].alarm_node_cnt);
}
bk_err_t bk_aon_rtc_register_tick_isr(aon_rtc_id_t id, aon_rtc_isr_t isr, void *param)
{
//AON_RTC_RETURN_ON_INVALID_ID(id);
uint32_t int_level = rtos_disable_int();
s_aon_rtc_tick_isr[id].callback = isr;
s_aon_rtc_tick_isr[id].isr_param = param;
rtos_enable_int(int_level);
return BK_OK;
}
/*
* aon rtc set tick uses 3 cycles of 32k in ASIC,
* cpu should check whether set tick success.
* If twice set tick in 3/32 ms, the second time set tick value will be failed.
*/
static void aon_rtc_set_tick(aon_rtc_hal_t *hal, uint32_t val)
{
uint64_t start_tick = 0, cur_tick = 0;
aon_rtc_hal_set_tick_val(hal, val);
start_tick = bk_aon_rtc_get_current_tick(AON_RTC_ID_1);
while(aon_rtc_hal_get_tick_val_lpo(hal) != val)
{
cur_tick = bk_aon_rtc_get_current_tick(AON_RTC_ID_1);
if(cur_tick - start_tick > AON_RTC_OPS_SAFE_DELAY_US)
{
AON_RTC_LOGE("%s:set tick timeout,set_tick=0x%x, lpo_tick=0x%x\r\n", __func__, val, aon_rtc_hal_get_tick_val_lpo(hal));
break;
}
aon_rtc_hal_set_tick_val(hal, val);
}
}
bk_err_t bk_aon_rtc_register_upper_isr(aon_rtc_id_t id, aon_rtc_isr_t isr, void *param)
{
//AON_RTC_RETURN_ON_INVALID_ID(id);
uint32_t int_level = rtos_disable_int();
s_aon_rtc_upper_isr[id].callback = isr;
s_aon_rtc_upper_isr[id].isr_param = param;
rtos_enable_int(int_level);
return BK_OK;
}
#if 0
static bk_err_t aon_rtc_isr_handler(aon_rtc_id_t id)
{
//uses tick as one time timer
if(aon_rtc_hal_get_tick_int_status(&s_aon_rtc[id].hal))
{
if (s_aon_rtc_tick_isr[id].callback) {
s_aon_rtc_tick_isr[id].callback(id, AON_RTC_NAME, s_aon_rtc_tick_isr[id].isr_param);
}
aon_rtc_hal_clear_tick_int_status(&s_aon_rtc[id].hal);
bk_aon_rtc_destroy(id);
}
//uses upper timer as period timer
if(aon_rtc_hal_get_upper_int_status(&s_aon_rtc[id].hal))
{
if (s_aon_rtc_upper_isr[id].callback) {
s_aon_rtc_upper_isr[id].callback(id, AON_RTC_NAME, s_aon_rtc_upper_isr[id].isr_param);
}
aon_rtc_hal_clear_upper_int_status(&s_aon_rtc[id].hal);
}
//TODO: clear NVIC/INTC/PLIC int pending status
return BK_OK;
}
#else
#if CONFIG_AON_RTC_DEBUG
#define AON_RTC_ISR_DEBUG_MAX_CNT (256)
static uint32_t s_isr_cnt = 0;
static uint32_t s_isr_debug_in_tick[AON_RTC_ISR_DEBUG_MAX_CNT];
static uint32_t s_isr_debug_out_tick[AON_RTC_ISR_DEBUG_MAX_CNT];
static uint32_t s_isr_debug_set_tick[AON_RTC_ISR_DEBUG_MAX_CNT];
#endif
static bk_err_t aon_rtc_isr_handler(aon_rtc_id_t id)
{
uint32_t int_level = rtos_disable_int();
#if CONFIG_AON_RTC_DEBUG
s_isr_debug_in_tick[(s_isr_cnt)%AON_RTC_ISR_DEBUG_MAX_CNT] = bk_aon_rtc_get_current_tick(id);
#endif
AON_RTC_LOGD("%s[+]\r\n", __func__);
//uses tick as one time timer
if(aon_rtc_hal_get_tick_int_status(&s_aon_rtc[id].hal))
{
//maybe the isr callback runs too much time and set next tick value too small, caused next isr can't response.
aon_rtc_hal_clear_tick_int_status(&s_aon_rtc[id].hal);
alarm_update_expeired_nodes(id);
//reset the timer tick
if(s_aon_rtc[id].alarm_head_p)
{
//+1:to assume set it valid,maybe aon rtc add 1 tick when set the value now.
//BK_ASSERT(bk_aon_rtc_get_current_tick(id) + 1/*AON_RTC_PRECISION_TICK*/ < s_aon_rtc[id].alarm_head_p->expired_tick); //4:reserve enough time to set the tick
if((bk_aon_rtc_get_current_tick(id) + 1 > s_aon_rtc[id].alarm_head_p->expired_tick))
{
AON_RTC_LOGE("next expired tick is invalid\r\n");
rtos_enable_int(int_level);
return BK_FAIL;
}
aon_rtc_set_tick(&s_aon_rtc[id].hal, (uint32_t)s_aon_rtc[id].alarm_head_p->expired_tick);
#if CONFIG_AON_RTC_DEBUG
s_isr_debug_set_tick[(s_isr_cnt)%AON_RTC_ISR_DEBUG_MAX_CNT] = (uint32_t)s_aon_rtc[id].alarm_head_p->expired_tick;
#endif
AON_RTC_LOGD("next tick=0x%x, cur_tick=0x%x\r\n", (uint32_t)s_aon_rtc[id].alarm_head_p->expired_tick, (uint32_t)bk_aon_rtc_get_current_tick(id));
}
else
{
aon_rtc_set_tick(&s_aon_rtc[id].hal, AON_RTC_ROUND_TICK);
AON_RTC_LOGD("no alarm:cur_tick=0x%x\r\n", (uint32_t)bk_aon_rtc_get_current_tick(id));
}
}
//uses upper timer as period timer
if(aon_rtc_hal_get_upper_int_status(&s_aon_rtc[id].hal))
{
s_high_tick[id]++;
AON_RTC_LOGI("32bits data overflow:high_tick=%d\r\n", (uint32_t)s_high_tick[id]);
if (s_aon_rtc_upper_isr[id].callback) {
s_aon_rtc_upper_isr[id].callback(id, AON_RTC_NAME, s_aon_rtc_upper_isr[id].isr_param);
}
aon_rtc_hal_clear_upper_int_status(&s_aon_rtc[id].hal);
}
//TODO: clear NVIC/INTC/PLIC int pending status
AON_RTC_LOGD("%s[-]\r\n", __func__);
#if CONFIG_AON_RTC_DEBUG
s_isr_debug_out_tick[(s_isr_cnt)%AON_RTC_ISR_DEBUG_MAX_CNT] = bk_aon_rtc_get_current_tick(id);
s_isr_cnt++;
#endif
rtos_enable_int(int_level);
return BK_OK;
}
#endif
static void aon_rtc1_isr_handler(void)
{
aon_rtc_isr_handler(AON_RTC_ID_1);
}
#if (SOC_AON_RTC_UNIT_NUM > 1)
static void aon_rtc2_isr_handler(void)
{
aon_rtc_isr_handler(AON_RTC_ID_2);
}
#endif
#if (CONFIG_SYSTEM_CTRL)
static void aon_rtc_interrupt_enable(aon_rtc_id_t id)
{
switch(id)
{
case AON_RTC_ID_1:
sys_drv_int_group2_enable(RTC_INTERRUPT_CTRL_BIT);
break;
#if (SOC_AON_RTC_UNIT_NUM > 1)
case AON_RTC_ID_2:
sys_drv_int_group2_enable(RTC1_INTERRUPT_CTRL_BIT);
break;
#endif
default:
break;
}
}
static void aon_rtc_interrupt_disable(aon_rtc_id_t id)
{
switch(id)
{
case AON_RTC_ID_1:
sys_drv_int_group2_disable(RTC_INTERRUPT_CTRL_BIT);
break;
#if (SOC_AON_RTC_UNIT_NUM > 1)
case AON_RTC_ID_2:
sys_drv_int_group2_disable(RTC1_INTERRUPT_CTRL_BIT);
break;
#endif
default:
break;
}
}
#endif
static bk_err_t aon_rtc_sw_init(aon_rtc_id_t id)
{
os_memset(&s_aon_rtc[id], 0, sizeof(s_aon_rtc[id]));
os_memset(&s_aon_rtc_tick_isr[id], 0, sizeof(s_aon_rtc_tick_isr[id]));
os_memset(&s_aon_rtc_upper_isr[id], 0, sizeof(s_aon_rtc_upper_isr[id]));
s_high_tick[id] = 0;
s_aon_rtc_nodes_p[id] = os_zalloc(sizeof(aon_rtc_nodes_memory_t));
if(s_aon_rtc_nodes_p[id] == NULL)
{
return BK_ERR_NO_MEM;
}
#if CONFIG_AON_RTC_KEEP_TIME_SUPPORT
aon_rtc_register_deepsleep_cb();
#endif
return BK_OK;
}
static void aon_rtc_hw_init(aon_rtc_id_t id)
{
aon_rtc_int_config_t int_config_table[] = AON_RTC_INT_CONFIG_TABLE;
aon_rtc_int_config_t *cur_int_cfg = &int_config_table[id];
AON_RTC_LOGD("%s[+]cur_tick=%d\r\n", __func__, (uint32_t)bk_aon_rtc_get_current_tick(id));
aon_rtc_hal_init(&s_aon_rtc[id].hal);
//set upper to max value
aon_rtc_hal_set_upper_val(&s_aon_rtc[id].hal, AON_RTC_ROUND_TICK);
aon_rtc_hal_enable_upper_int(&s_aon_rtc[id].hal);
bk_int_isr_register(cur_int_cfg->int_src, cur_int_cfg->isr, NULL);
#if (CONFIG_SYSTEM_CTRL)
aon_rtc_interrupt_enable(id);
#endif
aon_rtc_hal_start_counter(&s_aon_rtc[id].hal);
AON_RTC_LOGD("%s[-]cur_tick=%d\r\n", __func__, (uint32_t)bk_aon_rtc_get_current_tick(id));
}
bk_err_t bk_aon_rtc_driver_init(void)
{
AON_RTC_LOGD("%s[+]\r\n", __func__);
//TOTO: Enter critical protect
for (int id = AON_RTC_ID_1; id < AON_RTC_ID_MAX; id++) {
if(!s_aon_rtc[id].inited)
{
#if CONFIG_AON_RTC_KEEP_TIME_SUPPORT
if(id == AON_RTC_ID_1)
{
//get baked time which saved entry sleep/reboot
aon_rtc_compute_boot_timeofday();
}
#endif
aon_rtc_sw_init(id);
aon_rtc_hw_init(id);
s_aon_rtc[id].inited = true;
}
}
//TOTO: exit critical protect
AON_RTC_LOGD("%s[-]\r\n", __func__);
return BK_OK;
}
bk_err_t bk_aon_rtc_driver_deinit(void)
{
aon_rtc_int_config_t int_cfg_table[] = AON_RTC_INT_CONFIG_TABLE;
AON_RTC_LOGD("%s[+]\r\n", __func__);
for (int id = AON_RTC_ID_1; id < AON_RTC_ID_MAX; id++) {
if(s_aon_rtc[id].inited)
{
aon_rtc_hal_deinit(&s_aon_rtc[id].hal);
#if (CONFIG_SYSTEM_CTRL)
aon_rtc_interrupt_disable(id);
#endif
bk_int_isr_unregister(int_cfg_table[id].int_src);
if(s_aon_rtc_nodes_p[id] != NULL)
{
os_free(s_aon_rtc_nodes_p[id]);
s_aon_rtc_nodes_p[id] = NULL;
}
s_aon_rtc[id].inited = false;
}
}
#if CONFIG_AON_RTC_KEEP_TIME_SUPPORT
bk_pm_sleep_unregister_cb(PM_MODE_DEEP_SLEEP, PM_DEV_ID_RTC, true, true);
#endif
AON_RTC_LOGD("%s[-]\r\n", __func__);
return BK_OK;
}
#if 0 //remove it, only one HW can't be used for many APPs.
bk_err_t bk_aon_rtc_create(aon_rtc_id_t id, uint32_t tick, bool period)
{
//Avoid APP call this function before driver has done bk_aon_rtc_driver_init
if(s_aon_rtc[id].inited == false)
{
//TODO: logs: call aon_rtc_init first.
return BK_ERR_NOT_INIT;
}
if(s_aon_rtc[id].using_cnt)
{
//TODO: logs: call bk_aon_rtc_destroy first.
return BK_ERR_BUSY;
}
//TOTO: Enter critical protect
s_aon_rtc[id].using_cnt++;
s_aon_rtc[id].tick = tick;
s_aon_rtc[id].period = period;
//init HW
s_aon_rtc[id].hal.id = id;
aon_rtc_hal_init(&s_aon_rtc[id].hal);
if(period) //use upper value int
{
aon_rtc_hal_set_upper_val(&s_aon_rtc[id].hal, tick);
aon_rtc_hal_enable_upper_int(&s_aon_rtc[id].hal);
}
else
{
//confirm tick val <= upper value, or tick int never be entry.
aon_rtc_hal_set_upper_val(&s_aon_rtc[id].hal, AON_RTC_UPPER_VAL_MAX);
aon_rtc_set_tick(&s_aon_rtc[id].hal, tick);
aon_rtc_hal_enable_tick_int(&s_aon_rtc[id].hal);
}
//start to run
aon_rtc_start_run(id);
//TOTO: Exit critical protect
return BK_OK;
}
bk_err_t bk_aon_rtc_destroy(aon_rtc_id_t id)
{
//TOTO: Enter critical protect
if(s_aon_rtc[id].inited == false)
{
//TODO: logs: call aon_rtc_init first.
//TOTO: Exit critical protect
return BK_ERR_NOT_INIT;
}
if(s_aon_rtc[id].using_cnt == 0)
{
//TODO: logs: call bk_aon_rtc_create first.
//TOTO: Exit critical protect
return BK_ERR_NOT_INIT;
}
//stop HW before SW change value, avoid ISR status was update to INTC/NVIC/PLIC...
//but doesn't response ISR, after HW deinit, the ISR comes caused error.
aon_rtc_hal_deinit(&s_aon_rtc[id].hal);
s_aon_rtc[id].using_cnt = 0;
s_aon_rtc[id].tick = 0;
s_aon_rtc[id].period = false;
//TOTO: Exit critical protect
return BK_OK;
}
#endif
bk_err_t bk_alarm_register(aon_rtc_id_t id, alarm_info_t *alarm_info_p)
{
alarm_node_t *node_p = NULL;
uint32_t int_level = 0;
AON_RTC_LOGD("%s[+]\r\n", __func__);
if(id >= AON_RTC_ID_MAX)
{
AON_RTC_LOGE("%s:id=%d\r\n", __func__, id);
return BK_ERR_PARAM;
}
if(alarm_info_p == NULL)
{
return BK_ERR_PARAM;
}
if(alarm_info_p->period_tick < AON_RTC_PRECISION_TICK) //in protect area to reduce consume time before set tick.
{
AON_RTC_LOGE("period_tick should not smaller then %d\r\n", AON_RTC_PRECISION_TICK);
return BK_FAIL;
}
int_level = rtos_disable_int();
if(s_aon_rtc[id].alarm_node_cnt >= AON_RTC_MAX_ALARM_CNT)
{
rtos_enable_int(int_level);
AON_RTC_LOGE("alarm registered too much:%d\r\n", AON_RTC_MAX_ALARM_CNT);
return BK_FAIL;
}
//request a node
node_p = aon_rtc_request_node(id);
if(node_p == NULL)
{
rtos_enable_int(int_level);
AON_RTC_LOGE("alarm registered:no memory\r\n");
return BK_ERR_NO_MEM;
}
memset(node_p, 0, sizeof(alarm_node_t));
node_p->callback = alarm_info_p->callback;
node_p->cb_param_p = alarm_info_p->param_p;
memcpy(&node_p->name[0], alarm_info_p->name, ALARM_NAME_MAX_LEN);
node_p->name[ALARM_NAME_MAX_LEN] = 0;
node_p->start_tick = bk_aon_rtc_get_current_tick(id); //tick
node_p->period_tick = alarm_info_p->period_tick;
//BK_ASSERT(alarm_info_p->period_cnt);
if(alarm_info_p->period_cnt == 0)
{
rtos_enable_int(int_level);
AON_RTC_LOGE("no set period cnt\r\n");
return BK_ERR_PARAM;
}
node_p->period_cnt = alarm_info_p->period_cnt;
node_p->expired_tick = node_p->start_tick + (alarm_info_p->period_tick);
//push to alarm list
if(alarm_insert_node(id, node_p) != 0)
{
AON_RTC_LOGE("alarm name=%s has registered\r\n", alarm_info_p->name);
aon_rtc_release_node(id, node_p);
rtos_enable_int(int_level);
return BK_FAIL;
}
//reset the timer tick
if(node_p == s_aon_rtc[id].alarm_head_p) //insert node is the first one, should reset tick val
{
//+1:to assume set it valid,maybe aon rtc add 1 tick when set the value now.
//BK_ASSERT(bk_aon_rtc_get_current_tick(id) + 1/*AON_RTC_PRECISION_TICK*/ < s_aon_rtc[id].alarm_head_p->expired_tick); //4:reserve enough time to set the tick
if((bk_aon_rtc_get_current_tick(id) + 1 > s_aon_rtc[id].alarm_head_p->expired_tick))
{
rtos_enable_int(int_level);
AON_RTC_LOGE("next expired tick is invalid\r\n");
return BK_FAIL;
}
aon_rtc_set_tick(&s_aon_rtc[id].hal, (uint32_t)s_aon_rtc[id].alarm_head_p->expired_tick);
}
aon_rtc_hal_enable_tick_int(&s_aon_rtc[id].hal);
AON_RTC_LOGD("next tick=0x%x, cur_tick=0x%x\r\n", (uint32_t)s_aon_rtc[id].alarm_head_p->expired_tick, (uint32_t)bk_aon_rtc_get_current_tick(id));
rtos_enable_int(int_level);
AON_RTC_LOGD("%s[-]\r\n", __func__);
return BK_OK;
}
//the timer isn't expired, but app un-register it.
bk_err_t bk_alarm_unregister(aon_rtc_id_t id, uint8_t *name_p)
{
alarm_node_t *remove_node_p = NULL;
alarm_node_t *previous_head_node_p = NULL;
uint32_t int_level = 0;
AON_RTC_LOGD("%s[+]\r\n", __func__);
if(id >= AON_RTC_ID_MAX)
{
AON_RTC_LOGE("%s:id=%d\r\n", __func__, id);
return BK_ERR_PARAM;
}
int_level = rtos_disable_int();
previous_head_node_p = s_aon_rtc[id].alarm_head_p;
remove_node_p = alarm_remove_node(id, name_p);
//reset the timer tick
if(previous_head_node_p == remove_node_p) //the previous head is removed
{
if(s_aon_rtc[id].alarm_head_p) //new head exist
{
//+1:to assume set it valid,maybe aon rtc add 1 tick when set the value now.
//BK_ASSERT(bk_aon_rtc_get_current_tick(id) + 1/*AON_RTC_PRECISION_TICK*/ < s_aon_rtc[id].alarm_head_p->expired_tick); //reserve enough time to set the tick
if((bk_aon_rtc_get_current_tick(id) + 1 > s_aon_rtc[id].alarm_head_p->expired_tick))
{
rtos_enable_int(int_level);
AON_RTC_LOGE("next expired tick is invalid\r\n");
return BK_FAIL;
}
aon_rtc_set_tick(&s_aon_rtc[id].hal, (uint32_t)s_aon_rtc[id].alarm_head_p->expired_tick);
AON_RTC_LOGD("next tick=0x%x, cur_tick=0x%x\r\n", s_aon_rtc[id].alarm_head_p->expired_tick, bk_aon_rtc_get_current_tick(id));
}
else //has no nodes now
{
aon_rtc_hal_disable_tick_int(&s_aon_rtc[id].hal); //If the ISR at enable status, and the previous set tick time come, it will produce an Interrupt and maybe wakeup system.
// aon_rtc_set_tick(&s_aon_rtc[id].hal, AON_RTC_ROUND_TICK);
// AON_RTC_LOGD("no alarm:cur_tick=0x%x\r\n", bk_aon_rtc_get_current_tick(id));
}
}
rtos_enable_int(int_level);
AON_RTC_LOGD("%s[-]\r\n", __func__);
return BK_OK;
}
#if (CONFIG_AON_RTC && (!CONFIG_AON_RTC_MANY_USERS))
bk_err_t bk_aon_rtc_tick_init()
{
aon_rtc_hal_tick_init();
return BK_OK;
}
bk_err_t bk_aon_rtc_open_rtc_wakeup(rtc_tick_t period)
{
aon_rtc_hal_open_rtc_wakeup(period);
return BK_OK;
}
#endif
uint64_t bk_aon_rtc_get_current_tick(aon_rtc_id_t id)
{
if(id >= AON_RTC_ID_MAX)
{
AON_RTC_LOGE("%s:id=%d\r\n", __func__, id);
return 0;
}
return ((s_high_tick[id] << 32) + aon_rtc_hal_get_counter_val(&s_aon_rtc[id].hal));
}
#if CONFIG_ROSC_COMPENSATION
uint64_t bk_aon_rtc_get_current_tick_with_compensation(aon_rtc_id_t id)
{
uint64_t tick_val = bk_aon_rtc_get_current_tick(id);
return (tick_val + bk_rosc_32k_get_tick_diff(tick_val));
}
#endif
#if CONFIG_RTC_ANA_WAKEUP_SUPPORT
static int ana_wakesource_rtc_enter_cb(uint64_t sleep_time, void *args)
{
uint32_t period = s_wkup_time_period;
if (period >= RTC_ANA_TIME_PERIOD_MAX) {
AON_RTC_LOGE("rtc wakeup period range 0~15\r\n");
}
sys_drv_rtc_ana_wakeup_enable(period);
return 0;
}
bk_err_t bk_rtc_ana_register_wakeup_source(rtc_tick_t period)
{
pm_cb_conf_t enter_conf;
s_wkup_time_period = period;
AON_RTC_LOGI("regist wakeup source rtc period: %d\r\n", period);
enter_conf.cb = ana_wakesource_rtc_enter_cb;
enter_conf.args = NULL;
return bk_pm_sleep_register_cb(PM_MODE_SUPER_DEEP_SLEEP, PM_DEV_ID_RTC, &enter_conf, NULL);
}
#endif
#if CONFIG_AON_RTC_DEBUG
void bk_aon_rtc_timing_test(aon_rtc_id_t id, uint32_t round, uint32_t cycles, rtc_tick_t set_tick)
{
uint32_t int_level = 0;
uint32_t i = 0, j = 0;
uint32_t start_tick = 0, end_tick = 0;
uint64_t u64_start_tick = 0, u64_end_tick = 0;
uint32_t max_offset_tick = 0, min_offset_tick = 0xffffffff;
uint32_t fail_cnt = 0;
AON_RTC_LOGD("%s[+]\r\n", __func__);
int_level = rtos_disable_int();
//get uint32_t tick counter check
for(i = 0; i < round; i++)
{
start_tick = aon_rtc_hal_get_counter_val(&s_aon_rtc[id].hal);
for(j = 0; j < cycles; j++)
{
aon_rtc_hal_get_counter_val(&s_aon_rtc[id].hal);
}
end_tick = aon_rtc_hal_get_counter_val(&s_aon_rtc[id].hal);
if(min_offset_tick > end_tick - start_tick)
min_offset_tick = end_tick - start_tick;
if(max_offset_tick < end_tick - start_tick)
max_offset_tick = end_tick - start_tick;
}
AON_RTC_LOGI("Gettick uint32:%d rounds*%d times:max=%d,min=%d\r\n", i, j, max_offset_tick, min_offset_tick);
//get uint64_t tick counter check
max_offset_tick = 0;
min_offset_tick = 0xffffffff;
for(i = 0; i < round; i++)
{
u64_start_tick = bk_aon_rtc_get_current_tick(id);
for(j = 0; j < cycles; j++)
{
bk_aon_rtc_get_current_tick(id);
}
u64_end_tick = bk_aon_rtc_get_current_tick(id);
if(min_offset_tick > (uint32_t)(u64_end_tick - u64_start_tick))
min_offset_tick = (uint32_t)(u64_end_tick - u64_start_tick);
if(max_offset_tick < u64_end_tick - u64_start_tick)
max_offset_tick = u64_end_tick - u64_start_tick;
}
AON_RTC_LOGI("Gettick uint64:%d rounds*%d times:max=%d,min=%d\r\n", i, j, max_offset_tick, min_offset_tick);
//set tick val check
max_offset_tick = 0;
min_offset_tick = 0xffffffff;
for(i = 0; i < round; i++)
{
start_tick = aon_rtc_hal_get_counter_val(&s_aon_rtc[id].hal);
for(j = 0; j < cycles; j++)
{
aon_rtc_set_tick(&s_aon_rtc[id].hal, set_tick);
}
end_tick = aon_rtc_hal_get_counter_val(&s_aon_rtc[id].hal);
if(min_offset_tick > end_tick - start_tick)
min_offset_tick = end_tick - start_tick;
if(max_offset_tick < end_tick - start_tick)
max_offset_tick = end_tick - start_tick;
}
AON_RTC_LOGI("Settick:%d rounds*%d times:max=%d,min=%d\r\n", i, j, max_offset_tick, min_offset_tick);
fail_cnt = 0;
max_offset_tick = 0;
min_offset_tick = 0xffffffff;
for(i = 0; i < round; i++)
{
start_tick = aon_rtc_hal_get_counter_val(&s_aon_rtc[id].hal);
for(j = 0; j < cycles; j++)
{
aon_rtc_set_tick(&s_aon_rtc[id].hal, set_tick);
if(set_tick != aon_rtc_hal_get_tick_val(&s_aon_rtc[id].hal))
{
fail_cnt++;
}
}
end_tick = aon_rtc_hal_get_counter_val(&s_aon_rtc[id].hal);
if(min_offset_tick > end_tick - start_tick)
min_offset_tick = end_tick - start_tick;
if(max_offset_tick < end_tick - start_tick)
max_offset_tick = end_tick - start_tick;
}
AON_RTC_LOGI("Settick:%d rounds*%d times:max=%d,min=%d\r\n", i, j, max_offset_tick, min_offset_tick);
AON_RTC_LOGI("Settick:%d rounds*%d times:check fail_cnt=%d\r\n", i, j, fail_cnt);
rtos_enable_int(int_level);
AON_RTC_LOGD("%s[-]\r\n", __func__);
}
#endif
void bk_aon_rtc_dump(aon_rtc_id_t id)
{
#if CONFIG_AON_RTC_DEBUG
uint32_t i = 0, index = 0;
for(i = s_isr_cnt - AON_RTC_ISR_DEBUG_MAX_CNT; i < s_isr_cnt; i++)
{
index = i % AON_RTC_ISR_DEBUG_MAX_CNT;
for(volatile uint32_t j = 0; j < 1800; j++); //confirm log output normarlly
AON_RTC_LOGI("isr_in[%d]=0x%x,out=0x%x,set=0x%x\r\n", index, s_isr_debug_in_tick[index], s_isr_debug_out_tick[index], s_isr_debug_set_tick[index]);
}
#endif
aon_rtc_struct_dump();
alarm_dump_list(s_aon_rtc[id].alarm_head_p);
}
bk_err_t bk_rtc_gettimeofday(struct timeval *tv, void *ptz)
{
(void)ptz;
if(tv!=NULL)
{
uint64_t uCurTimeUs = s_boot_time_us + bk_aon_rtc_get_us();
tv->tv_sec=uCurTimeUs/1000000;
tv->tv_usec=uCurTimeUs%1000000;
AON_RTC_LOGD("s_boot_time_us:h=0x%x,l=0x%x \r\n", s_boot_time_us>>32, (uint32_t)s_boot_time_us);
AON_RTC_LOGD("%s sec=%d,us:%d\n", __func__, tv->tv_sec, tv->tv_usec);
} else
AON_RTC_LOGW("%s tv is null \r\n",__func__);
return BK_OK;
}
bk_err_t bk_rtc_settimeofday(const struct timeval *tv,const struct timezone *tz)
{
(void)tz;
if(tv)
{
uint64_t setTimeUs = ((uint64_t)tv->tv_sec)*1000000LL + tv->tv_usec ;
uint64_t getCurTimeUs = bk_aon_rtc_get_us();
s_boot_time_us = setTimeUs - getCurTimeUs;
AON_RTC_LOGD("%s:sec=%d us=%d\n", __func__, tv->tv_sec, tv->tv_usec);
AON_RTC_LOGD("get us:h=0x%x,l=0x%x\n", getCurTimeUs>>32, (uint32_t)getCurTimeUs);
}
return BK_OK;
}
#if CONFIG_AON_RTC_DEBUG
void bk_64bits_test(void)
{
uint64_t val_64bits = 0xffffffffffff;
uint64_t x1 = 0x111111111, x2 = 0x222222222, x3 = 0x333333333, t = 0;
uint32_t xh1 = 0x1, xl1 = 0x11111111;
//uint32_t xh2 = 0x2, xl2 = 0x22222222;
//uint32_t xh3 = 0x3, xl3 = 0x33333333;
//uint32_t th1 = 0, tl1 = 0;
t = xh1;
t = t<<32;
t += xl1;
if (t == 0x111111111)
{
AON_RTC_LOGD("left move 0x1<<32 is right\r\n");
}
if (t == x1)
{
AON_RTC_LOGD("uint64 compare is right\r\n");
}
if ((t & 0xffffffff) == xl1)
{
AON_RTC_LOGD("uint64 low 32bits is right\r\n");
}
if ((t >> 32) == xh1)
{
AON_RTC_LOGD("right move uint64 high 32bits is right\r\n");
}
if(x1 + x2 == x3)
{
AON_RTC_LOGD("uint64 add is right\r\n");
}
if(x3 - x2 == x1)
{
AON_RTC_LOGD("uint64 minus is right\r\n");
}
if((x1 * 2) == x2)
{
AON_RTC_LOGD("uint64 multi is right\r\n");
}
if((x2 / 2) == x1)
{
AON_RTC_LOGD("uint64 divide2 is right\r\n");
}
if((x2 / 32) == 0x11111111)
{
AON_RTC_LOGD("uint64 divide32 is right\r\n");
}
//pass:only output low 32 bits valid data
for(uint32_t i = 0; i < 64; i++)
AON_RTC_LOGD("0xffffffffffff>>%d == 0x%llx\r\n", i, val_64bits>>i); //64 bits printf is error
//print:BIT64(i) low 32 bits
for(uint32_t i = 0; i < 64; i++)
AON_RTC_LOGD("Bit[%d] = 0x%llx, &=0x%llx\r\n", i, BIT64(i), (val_64bits & BIT64(i)));
AON_RTC_LOGD("64bits move\r\n");
for(uint64_t i = 0; i < 64; i++)
AON_RTC_LOGD("Bit[%d] = 0x%llx, &=0x%llx\r\n", i, BIT64(i), (val_64bits & BIT64(i)));
AON_RTC_LOGD("32bits move\r\n");
val_64bits = 0xa0a0a0a0a0a0a0a0;
for(uint32_t i = 0; i < 64; i++)
{
uint64_t ret = val_64bits & BIT64(i);
AON_RTC_LOGD("ret[%d] = 0x%llx = 0x%llx \r\n", i, ret, ret); //print ret twice as 64 bits
}
AON_RTC_LOGD("64bits move\r\n");
val_64bits = 0xa0a0a0a0a0a0a0a0;
for(uint64_t i = 0; i < 64; i++)
{
uint64_t ret = val_64bits & BIT64(i);
AON_RTC_LOGD("ret[%d] = 0x%llx = 0x%llx \r\n", i, i, ret); //print i twice as 64 bits
}
}
#endif