/* * Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved. * * SPDX-License-Identifier: MIT */ #include #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(); }