Files
2026-08-24 10:03:24 +08:00

270 lines
5.6 KiB
C

/*
* Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*/
#include <stdio.h>
#include "common.h"
#include "vrtc.h"
#include "timer_source.h"
#include "register.h"
#include "FreeRTOS.h"
#include "mailbox-api.h"
#include "timers.h"
#include "suspend.h"
#include "soc.h"
#include "string.h"
#include "semphr.h"
#include "stick_mem.h"
#include "interrupt_control_eclic.h"
#define RTC_ALARM_MAX \
((uint32_t)((uint64_t)((TickType_t)~(TickType_t)0) * 1000 / configTICK_RATE_HZ / 1000))
#undef TAG
#define TAG "VRTC"
#ifdef VRTC_DEBUG
#define VRTC_DBG(...) printf(__VA_ARGS__)
#else
#define VRTC_DBG(...)
#endif
static uint32_t ulCurTime, ulBaseTime;
static TimerHandle_t xRTCUpdTimer;
static void prvRtcSet(uint32_t ulValue)
{
taskENTER_CRITICAL();
#ifdef CONFIG_STICK_MEM
if (stick_mem_write(STICK_VRTC, ulValue))
printf("[%s]: set vrtc failed\n", TAG);
#else
REG32(VRTC_STICKY_REG) = ulValue;
#endif
taskEXIT_CRITICAL();
}
static void prvRtcGet(uint32_t *ulValue)
{
taskENTER_CRITICAL();
#ifdef CONFIG_STICK_MEM
if (stick_mem_read(STICK_VRTC, (unsigned int *)ulValue))
printf("[%s]: get vrtc failed\n", TAG);
#else
*ulValue = REG32(VRTC_STICKY_REG);
#endif
taskEXIT_CRITICAL();
}
static void prvRtcSecToTm(uint32_t sec, struct rtc_time *tm)
{
uint32_t min;
tm->tm_sec = sec % 60;
min = sec / 60;
tm->tm_min = min % 60;
}
void vPoweroffGetRtcMinSec(char *time)
{
uint32_t secs;
struct rtc_time tm;
if (power_mode == 0xf) {
prvRtcGet(&secs);
prvRtcSecToTm(secs, &tm);
sprintf(time, "%02d", tm.tm_min);
sprintf(time+2, "%02d", tm.tm_sec);
} else {
printf("not poweroff mode, invalid called!\n");
time = NULL;
}
}
static void prvRtcUpdHandler(TimerHandle_t xTimer)
{
(void)xTimer;
ulCurTime += (timere_read() - ulBaseTime);
ulBaseTime = timere_read();
prvRtcSet(ulCurTime);
}
static void prvRtcUpdStart(void)
{
if (xRTCUpdTimer)
xTimerStart(xRTCUpdTimer, 0);
}
static void prvRtcUpdStop(void)
{
if (xRTCUpdTimer)
xTimerStop(xRTCUpdTimer, 0);
}
static void prvRtcUpdInit(void)
{
xRTCUpdTimer = xTimerCreate("UpdRTCTimer", pdMS_TO_TICKS(1000), pdTRUE,
NULL, prvRtcUpdHandler);
prvRtcGet(&ulCurTime);
ulBaseTime = timere_read();
prvRtcUpdStart();
}
static void xMboxSetRtc(void *msg)
{
unsigned int val = *(uint32_t *)msg;
VRTC_DBG("[%s]: %s val=%u\n", TAG, __func__, val);
prvRtcUpdStop();
prvRtcSet(val);
ulCurTime = val;
ulBaseTime = timere_read();
prvRtcUpdStart();
}
static void xMboxGetRtc(void *msg)
{
uint32_t val = 0;
prvRtcGet(&val);
memset(msg, 0, MBOX_BUF_LEN);
*(uint32_t *)msg = val;
VRTC_DBG("[%s]: %s val=%u\n", TAG, __func__, val);
}
#ifndef CONFIG_DISABLE_RTC_WAKEUP
static TimerHandle_t xRTCAlarmTimer;
#ifdef VRTC_TIMER_CTRL
/* separate new/old alarm set method */
static int alarm_mbox_enabled;
#endif
void vRtcAlarmSet(void)
{
uint32_t val = 0;
if (xRTCAlarmTimer) {
if (xTimerIsTimerActive(xRTCAlarmTimer)) {
val = (xTimerGetExpiryTime(xRTCAlarmTimer) - xTaskGetTickCount()) /
configTICK_RATE_HZ;
} else {
val = REG32(VRTC_PARA_REG);
if (val) {
if (val > RTC_ALARM_MAX) {
printf("[%s]: alarm %u exceeds max\n", TAG, val);
val = RTC_ALARM_MAX;
}
xTimerChangePeriod(xRTCAlarmTimer,
pdMS_TO_TICKS((uint64_t)val * 1000), 0);
}
}
if (val)
printf("[%s]: alarm val=%d S\n", TAG, val);
}
}
void vRtcAlarmClr(void)
{
if (xRTCAlarmTimer && xTimerIsTimerActive(xRTCAlarmTimer))
xTimerStop(xRTCAlarmTimer, 0);
}
static void prvRtcAlarmHandler(TimerHandle_t xTimer)
{
uint32_t buf[4] = {0};
#ifdef VRTC_TIMER_CTRL
uint32_t reg = 0;
#endif
(void)xTimer;
REG32(VRTC_PARA_REG) = 0;
if (get_suspend_flag()) {
buf[0] = RTC_WAKEUP;
printf("[%s]: vrtc alarm fired\n", TAG);
STR_Wakeup_src_Queue_Send(buf);
}
#ifdef VRTC_TIMER_CTRL
if (alarm_mbox_enabled) {
/* set timer threshold parm */
reg = FIELD_PREP(VRTC_TIMER_THRESHOLD_MASK, VRTC_TIMER_THRESHOLD_COUNT);
REG32(VRTC_TIMER) = reg;
/* enable timer(vrtc used) */
REG32(VRTC_TIMER_CTRL) |= VRTC_TIMER_ENABLE;
}
#endif
}
void vRtcAlarmInit(void)
{
xRTCAlarmTimer = xTimerCreate("Timer", pdMS_TO_TICKS(1000), pdFALSE,
NULL, prvRtcAlarmHandler);
}
#ifdef VRTC_TIMER_CTRL
static void xMboxEnableRtcAlarm(void *msg)
{
uint32_t val = *(uint32_t *)msg;
uint32_t alarm;
VRTC_DBG("[%s]: %s val=%u\n", TAG, __func__, val);
if (xRTCAlarmTimer) {
if (val) {
alarm = REG32(VRTC_PARA_REG);
if (alarm) {
if (alarm > RTC_ALARM_MAX) {
printf("[%s]: alarm %u exceeds max\n", TAG, alarm);
alarm = RTC_ALARM_MAX;
}
xTimerChangePeriod(xRTCAlarmTimer,
pdMS_TO_TICKS((uint64_t)alarm * 1000), 0);
alarm_mbox_enabled = 1;
}
} else {
/* disable timer(vrtc used) */
REG32(VRTC_TIMER_CTRL) &= ~VRTC_TIMER_ENABLE;
if (xTimerIsTimerActive(xRTCAlarmTimer))
xTimerStop(xRTCAlarmTimer, 0);
alarm_mbox_enabled = 0;
}
}
}
#endif
#endif
void vRtcInit(void)
{
#ifdef VRTC_TIMER_CTRL
u32 reg = 0;
#endif
VRTC_DBG("[%s]: init vrtc\n", TAG);
xInstallRemoteMessageCallbackFeedBack(REE2AO_CHANNEL,
MBX_CMD_SET_RTC, (void *)xMboxSetRtc, 0);
xInstallRemoteMessageCallbackFeedBack(REE2AO_CHANNEL,
MBX_CMD_GET_RTC, (void *)xMboxGetRtc, 1);
#ifndef CONFIG_DISABLE_RTC_WAKEUP
#ifdef VRTC_TIMER_CTRL
/* enable vrtc alarm mbox callback */
xInstallRemoteMessageCallbackFeedBack(REE2AO_CHANNEL,
MBX_CMD_RTC_ENABLE_ALARM, (void *)xMboxEnableRtcAlarm, 0);
/* config timerd param */
reg = REG32(VRTC_TIMER_CTRL);
reg |= (FIELD_PREP(VRTC_TIMER_CLK_SEL, VRTC_TIMER_CLK_1US) |
FIELD_PREP(VRTC_TIMER_MODE, VRTC_TIMER_MODE_ONESHOT));
reg &= ~VRTC_TIMER_ENABLE;
REG32(VRTC_TIMER_CTRL) = reg;
#endif
vRtcAlarmInit();
#endif
prvRtcUpdInit();
}