blob: b3ead2c1565014dfd013a1d3d1d5a866278d9a4b [file] [log] [blame]
Xiaohu.Huang60950452022-03-12 22:51:01 +08001/*
2 * Copyright (c) 2021-2022 Amlogic, Inc. All rights reserved.
3 *
4 * SPDX-License-Identifier: MIT
5 */
6
7#include <stdio.h>
8#include <string.h>
9#include <unistd.h>
10#include "common.h"
11#include "rtc.h"
12#include "register.h"
13#include "FreeRTOS.h"
14#include "mailbox-api.h"
15#include "soc.h"
16#include "string.h"
17#include "interrupt.h"
18#include "suspend.h"
yiting.deng21d1aa42023-02-08 17:46:11 +080019#include "rtc_register.h"
yiting.dengac5b18d2023-04-25 11:13:26 +080020#include "timers.h"
21#include "interrupt_control_eclic.h"
Xiaohu.Huang60950452022-03-12 22:51:01 +080022
23#undef TAG
yiting.dengc40d0cf2024-12-04 17:05:56 +080024#define TAG "RTC"
25
26#ifdef RTC_DEBUG
27#define RTC_DBG(...) printf(__VA_ARGS__)
28#else
29#define RTC_DBG(...)
30#endif
Xiaohu.Huang60950452022-03-12 22:51:01 +080031
yiting.dengac5b18d2023-04-25 11:13:26 +080032static TimerHandle_t xAlarmTimer;
33static int alarm_flags;
34
yiting.deng21d1aa42023-02-08 17:46:11 +080035static uint32_t gray_to_binary(uint32_t gray)
36{
37 uint32_t bcd = gray;
38 int size = sizeof(bcd) * 8;
39 int i;
40
41 for (i = 0; (1 << i) < size; i++)
42 bcd ^= bcd >> (1 << i);
43
44 return bcd;
45}
46
Xiaohu.Huang60950452022-03-12 22:51:01 +080047static void vRTCInterruptHandler(void)
48{
xiaohu.huang2beac512022-05-07 15:10:04 +080049 uint32_t buf[4] = { 0 };
yiting.deng4f79f4f2023-09-07 14:32:14 +080050 uint32_t reg_val;
Xiaohu.Huang60950452022-03-12 22:51:01 +080051
yiting.dengac5b18d2023-04-25 11:13:26 +080052 alarm_flags = 1;
yiting.deng4f79f4f2023-09-07 14:32:14 +080053 reg_val = REG32(RTC_DIG_INT_STATUS) & 0x1;
54 /* Clear alarm0 int status */
55 if (reg_val)
56 REG32(RTC_DIG_INT_CLR) = 0x1;
57
Xiaohu.Huang60950452022-03-12 22:51:01 +080058 printf("[%s]: rtc alarm fired\n", TAG);
59
60 buf[0] = RTC_WAKEUP;
61 STR_Wakeup_src_Queue_Send_FromISR(buf);
62}
63
64static uint32_t get_reboot_mode(void)
65{
66 uint32_t reg_val;
67 uint32_t reboot_mode;
68
69 reg_val = REG32(SYSCTRL_SEC_STATUS_REG31);
70 reboot_mode = ((reg_val >> 12) & 0xf);
71
72 return reboot_mode;
73}
74
75static void reset_rtc(void)
76{
77 uint32_t reg_val;
78
79 printf("[%s]: reset rtc\n", TAG);
80 /* Reset RTC */
81 reg_val = (1 << 0);
82 REG32(RESETCTRL_RESET4) = reg_val;
83 /* Mask RTC reset to prevent RTC being reset in the next reboot */
84 reg_val = REG32(RESETCTRL_RESET4_MASK);
85 reg_val |= (1 << 0);
86 REG32(RESETCTRL_RESET4_MASK) = reg_val;
87}
88
89static int get_rtc(uint32_t *val)
90{
91 if (!REG32(VRTC_STICKY_REG))
92 return -1;
Xiaohu.Huang60950452022-03-12 22:51:01 +080093
xiaohu.huang2beac512022-05-07 15:10:04 +080094 *(val) = REG32(VRTC_STICKY_REG);
Xiaohu.Huang60950452022-03-12 22:51:01 +080095 return 0;
96}
97
98static void set_rtc(uint32_t val)
99{
100 REG32(VRTC_STICKY_REG) = val;
101}
102
103void store_rtc(void)
104{
105 uint32_t reg_val;
106
yiting.deng21d1aa42023-02-08 17:46:11 +0800107 reg_val = REG32(RTC_DIG_REAL_TIME);
108#ifdef CONFIG_RTC_STORAGE_FORMAT_GRAY
109 reg_val = gray_to_binary(reg_val);
110#endif
Xiaohu.Huang60950452022-03-12 22:51:01 +0800111 REG32(VRTC_STICKY_REG) = reg_val;
112}
113
114void *MboxSetRTC(void *msg)
115{
116 unsigned int val = *(uint32_t *)msg;
xiaohu.huang2beac512022-05-07 15:10:04 +0800117
yiting.dengc40d0cf2024-12-04 17:05:56 +0800118 RTC_DBG("[%s]: %s val=0x%x\n", TAG, __func__, val);
Xiaohu.Huang60950452022-03-12 22:51:01 +0800119 set_rtc(val);
120
121 return NULL;
122}
123
124void *MboxGetRTC(void *msg)
125{
126 uint32_t val = 0;
127
128 get_rtc(&val);
129 memset(msg, 0, MBOX_BUF_LEN);
130 *(uint32_t *)msg = val;
131
yiting.dengc40d0cf2024-12-04 17:05:56 +0800132 RTC_DBG("[%s]: %s val=0x%x\n", TAG, __func__, val);
Xiaohu.Huang60950452022-03-12 22:51:01 +0800133
134 return NULL;
135}
136
yiting.deng6ec1d642023-03-19 10:10:35 +0800137void rtc_enable_irq(void)
138{
yiting.dengbfc3f452023-05-18 16:22:40 +0800139 int ret, val;
yiting.dengac5b18d2023-04-25 11:13:26 +0800140 u32 alarm, time;
yiting.deng4f79f4f2023-09-07 14:32:14 +0800141 int irq_num;
142 uint32_t reg_val;
yiting.deng6ec1d642023-03-19 10:10:35 +0800143
yiting.deng4f79f4f2023-09-07 14:32:14 +0800144 irq_num = RTC_IRQ % 32;
145 reg_val = REG32(IRQCTRL_IRQ_LATCH4) >> irq_num & 0x1;
146 if (reg_val)
147 REG32(IRQCTRL_IRQ_LATCH_CLR4) |= (0x1 << irq_num);
yiting.dengac5b18d2023-04-25 11:13:26 +0800148 alarm = REG32(RTC_DIG_ALARM0_REG);
yiting.dengbfc3f452023-05-18 16:22:40 +0800149 time = REG32(RTC_DIG_REAL_TIME);
150#ifdef CONFIG_RTC_STORAGE_FORMAT_GRAY
151 alarm = gray_to_binary(alarm);
152 time = gray_to_binary(time);
153#endif
154 val = alarm - time;
155 if (val > 0) {
yiting.dengac5b18d2023-04-25 11:13:26 +0800156 ret = RegisterIrq(RTC_IRQ, 6, vRTCInterruptHandler);
157 if (ret)
yiting.dengc40d0cf2024-12-04 17:05:56 +0800158 printf("RTC_irq Register err, ret = %d\n", ret);
yiting.dengac5b18d2023-04-25 11:13:26 +0800159 EnableIrq(RTC_IRQ);
yiting.dengbfc3f452023-05-18 16:22:40 +0800160 printf("[%s]: alarm val=%d S\n", TAG, val);
161 if (xAlarmTimer != NULL) {
162 alarm = (val + 1) * 1000;
yiting.dengac5b18d2023-04-25 11:13:26 +0800163 xTimerChangePeriod(xAlarmTimer, pdMS_TO_TICKS(alarm), 0);
164 }
165 }
yiting.deng6ec1d642023-03-19 10:10:35 +0800166}
167
168void rtc_disable_irq(void)
169{
yiting.dengbfc3f452023-05-18 16:22:40 +0800170 int ret, val;
yiting.deng6ec1d642023-03-19 10:10:35 +0800171
yiting.deng4c21b172023-08-29 15:44:23 +0800172 val = GetIrqInner(RTC_IRQ);
yiting.dengbfc3f452023-05-18 16:22:40 +0800173 if (val > 0) {
yiting.dengac5b18d2023-04-25 11:13:26 +0800174 DisableIrq(RTC_IRQ);
175 ret = UnRegisterIrq(RTC_IRQ);
176 if (ret)
yiting.dengc40d0cf2024-12-04 17:05:56 +0800177 printf("RTC_irq UnRegister err, ret = %d\n", ret);
yiting.dengac5b18d2023-04-25 11:13:26 +0800178 }
179}
180
181static void rtc_alarm_timer_handler(TimerHandle_t xAlarmTimer)
182{
183 static int rtc_irq, status;
yiting.deng4f79f4f2023-09-07 14:32:14 +0800184 int irq_num;
185 uint32_t reg_val;
yiting.dengac5b18d2023-04-25 11:13:26 +0800186
187 status = REG32(RTC_DIG_INT_STATUS) & 0x1;
188 if (status && !alarm_flags) {
yiting.dengc40d0cf2024-12-04 17:05:56 +0800189 printf("warning: rtc irq lost! trigger it manually!\n");
yiting.deng4f79f4f2023-09-07 14:32:14 +0800190 irq_num = RTC_IRQ % 32;
191 reg_val = REG32(IRQCTRL_IRQ_LATCH4) >> irq_num & 0x1;
yiting.dengc40d0cf2024-12-04 17:05:56 +0800192 printf("[%s]: irqctrl status: 0x%x !!\n", TAG, reg_val);
yiting.dengac5b18d2023-04-25 11:13:26 +0800193 rtc_irq = GetIrqInner(RTC_IRQ);
194 if (rtc_irq)
195 eclic_set_pending(rtc_irq);
196 }
197 alarm_flags = 0;
198}
199
200void alarm_clr(void)
201{
yiting.deng4f79f4f2023-09-07 14:32:14 +0800202 int irq_num;
203 uint32_t reg_val;
204
yiting.dengac5b18d2023-04-25 11:13:26 +0800205 if (xAlarmTimer != NULL)
206 xTimerStop(xAlarmTimer, 0);
yiting.deng4f79f4f2023-09-07 14:32:14 +0800207
208 irq_num = RTC_IRQ % 32;
209 reg_val = REG32(IRQCTRL_IRQ_LATCH4) >> irq_num & 0x1;
yiting.dengc40d0cf2024-12-04 17:05:56 +0800210 printf("[%s]: irqctrl status: 0x%x !!\n", TAG, reg_val);
yiting.deng4f79f4f2023-09-07 14:32:14 +0800211 if (reg_val)
212 REG32(IRQCTRL_IRQ_LATCH_CLR4) |= (0x1 << irq_num);
213 reg_val = REG32(IRQCTRL_IRQ_LATCH4) >> irq_num & 0x1;
yiting.dengac5b18d2023-04-25 11:13:26 +0800214}
215
216static void rtc_alarm_timer_init(void)
217{
218 xAlarmTimer = xTimerCreate("RtcAlarmTimer", pdMS_TO_TICKS(1000),
219 pdFALSE, NULL, rtc_alarm_timer_handler);
yiting.deng6ec1d642023-03-19 10:10:35 +0800220}
221
Xiaohu.Huang60950452022-03-12 22:51:01 +0800222void rtc_init(void)
223{
Xiaohu.Huang60950452022-03-12 22:51:01 +0800224 uint32_t reboot_mode;
225
yiting.dengc40d0cf2024-12-04 17:05:56 +0800226 RTC_DBG("[%s]: init rtc\n", TAG);
Xiaohu.Huang60950452022-03-12 22:51:01 +0800227
Yao Jie549b0092024-12-16 14:51:43 +0800228 xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL, MBX_CMD_SET_RTC, MboxSetRTC, 0);
Xiaohu.Huang60950452022-03-12 22:51:01 +0800229
Yao Jie549b0092024-12-16 14:51:43 +0800230 xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL, MBX_CMD_GET_RTC, MboxGetRTC, 1);
Xiaohu.Huang60950452022-03-12 22:51:01 +0800231
232 reboot_mode = get_reboot_mode();
233 if (reboot_mode == COLD_REBOOT)
234 reset_rtc();
yiting.dengac5b18d2023-04-25 11:13:26 +0800235
236 rtc_alarm_timer_init();
Xiaohu.Huang60950452022-03-12 22:51:01 +0800237}