blob: b3ead2c1565014dfd013a1d3d1d5a866278d9a4b [file] [log] [blame] [edit]
/*
* Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
*
* SPDX-License-Identifier: MIT
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "common.h"
#include "rtc.h"
#include "register.h"
#include "FreeRTOS.h"
#include "mailbox-api.h"
#include "soc.h"
#include "string.h"
#include "interrupt.h"
#include "suspend.h"
#include "rtc_register.h"
#include "timers.h"
#include "interrupt_control_eclic.h"
#undef TAG
#define TAG "RTC"
#ifdef RTC_DEBUG
#define RTC_DBG(...) printf(__VA_ARGS__)
#else
#define RTC_DBG(...)
#endif
static TimerHandle_t xAlarmTimer;
static int alarm_flags;
static uint32_t gray_to_binary(uint32_t gray)
{
uint32_t bcd = gray;
int size = sizeof(bcd) * 8;
int i;
for (i = 0; (1 << i) < size; i++)
bcd ^= bcd >> (1 << i);
return bcd;
}
static void vRTCInterruptHandler(void)
{
uint32_t buf[4] = { 0 };
uint32_t reg_val;
alarm_flags = 1;
reg_val = REG32(RTC_DIG_INT_STATUS) & 0x1;
/* Clear alarm0 int status */
if (reg_val)
REG32(RTC_DIG_INT_CLR) = 0x1;
printf("[%s]: rtc alarm fired\n", TAG);
buf[0] = RTC_WAKEUP;
STR_Wakeup_src_Queue_Send_FromISR(buf);
}
static uint32_t get_reboot_mode(void)
{
uint32_t reg_val;
uint32_t reboot_mode;
reg_val = REG32(SYSCTRL_SEC_STATUS_REG31);
reboot_mode = ((reg_val >> 12) & 0xf);
return reboot_mode;
}
static void reset_rtc(void)
{
uint32_t reg_val;
printf("[%s]: reset rtc\n", TAG);
/* Reset RTC */
reg_val = (1 << 0);
REG32(RESETCTRL_RESET4) = reg_val;
/* Mask RTC reset to prevent RTC being reset in the next reboot */
reg_val = REG32(RESETCTRL_RESET4_MASK);
reg_val |= (1 << 0);
REG32(RESETCTRL_RESET4_MASK) = reg_val;
}
static int get_rtc(uint32_t *val)
{
if (!REG32(VRTC_STICKY_REG))
return -1;
*(val) = REG32(VRTC_STICKY_REG);
return 0;
}
static void set_rtc(uint32_t val)
{
REG32(VRTC_STICKY_REG) = val;
}
void store_rtc(void)
{
uint32_t reg_val;
reg_val = REG32(RTC_DIG_REAL_TIME);
#ifdef CONFIG_RTC_STORAGE_FORMAT_GRAY
reg_val = gray_to_binary(reg_val);
#endif
REG32(VRTC_STICKY_REG) = reg_val;
}
void *MboxSetRTC(void *msg)
{
unsigned int val = *(uint32_t *)msg;
RTC_DBG("[%s]: %s val=0x%x\n", TAG, __func__, val);
set_rtc(val);
return NULL;
}
void *MboxGetRTC(void *msg)
{
uint32_t val = 0;
get_rtc(&val);
memset(msg, 0, MBOX_BUF_LEN);
*(uint32_t *)msg = val;
RTC_DBG("[%s]: %s val=0x%x\n", TAG, __func__, val);
return NULL;
}
void rtc_enable_irq(void)
{
int ret, val;
u32 alarm, time;
int irq_num;
uint32_t reg_val;
irq_num = RTC_IRQ % 32;
reg_val = REG32(IRQCTRL_IRQ_LATCH4) >> irq_num & 0x1;
if (reg_val)
REG32(IRQCTRL_IRQ_LATCH_CLR4) |= (0x1 << irq_num);
alarm = REG32(RTC_DIG_ALARM0_REG);
time = REG32(RTC_DIG_REAL_TIME);
#ifdef CONFIG_RTC_STORAGE_FORMAT_GRAY
alarm = gray_to_binary(alarm);
time = gray_to_binary(time);
#endif
val = alarm - time;
if (val > 0) {
ret = RegisterIrq(RTC_IRQ, 6, vRTCInterruptHandler);
if (ret)
printf("RTC_irq Register err, ret = %d\n", ret);
EnableIrq(RTC_IRQ);
printf("[%s]: alarm val=%d S\n", TAG, val);
if (xAlarmTimer != NULL) {
alarm = (val + 1) * 1000;
xTimerChangePeriod(xAlarmTimer, pdMS_TO_TICKS(alarm), 0);
}
}
}
void rtc_disable_irq(void)
{
int ret, val;
val = GetIrqInner(RTC_IRQ);
if (val > 0) {
DisableIrq(RTC_IRQ);
ret = UnRegisterIrq(RTC_IRQ);
if (ret)
printf("RTC_irq UnRegister err, ret = %d\n", ret);
}
}
static void rtc_alarm_timer_handler(TimerHandle_t xAlarmTimer)
{
static int rtc_irq, status;
int irq_num;
uint32_t reg_val;
status = REG32(RTC_DIG_INT_STATUS) & 0x1;
if (status && !alarm_flags) {
printf("warning: rtc irq lost! trigger it manually!\n");
irq_num = RTC_IRQ % 32;
reg_val = REG32(IRQCTRL_IRQ_LATCH4) >> irq_num & 0x1;
printf("[%s]: irqctrl status: 0x%x !!\n", TAG, reg_val);
rtc_irq = GetIrqInner(RTC_IRQ);
if (rtc_irq)
eclic_set_pending(rtc_irq);
}
alarm_flags = 0;
}
void alarm_clr(void)
{
int irq_num;
uint32_t reg_val;
if (xAlarmTimer != NULL)
xTimerStop(xAlarmTimer, 0);
irq_num = RTC_IRQ % 32;
reg_val = REG32(IRQCTRL_IRQ_LATCH4) >> irq_num & 0x1;
printf("[%s]: irqctrl status: 0x%x !!\n", TAG, reg_val);
if (reg_val)
REG32(IRQCTRL_IRQ_LATCH_CLR4) |= (0x1 << irq_num);
reg_val = REG32(IRQCTRL_IRQ_LATCH4) >> irq_num & 0x1;
}
static void rtc_alarm_timer_init(void)
{
xAlarmTimer = xTimerCreate("RtcAlarmTimer", pdMS_TO_TICKS(1000),
pdFALSE, NULL, rtc_alarm_timer_handler);
}
void rtc_init(void)
{
uint32_t reboot_mode;
RTC_DBG("[%s]: init rtc\n", TAG);
xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL, MBX_CMD_SET_RTC, MboxSetRTC, 0);
xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL, MBX_CMD_GET_RTC, MboxGetRTC, 1);
reboot_mode = get_reboot_mode();
if (reboot_mode == COLD_REBOOT)
reset_rtc();
rtc_alarm_timer_init();
}