blob: b64f63a3fd9f30f5b9ba917cf1b1a2d14f36ea89 [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
24#define TAG "AOCPU RTC"
25
yiting.dengac5b18d2023-04-25 11:13:26 +080026static TimerHandle_t xAlarmTimer;
27static int alarm_flags;
28
yiting.deng21d1aa42023-02-08 17:46:11 +080029static uint32_t gray_to_binary(uint32_t gray)
30{
31 uint32_t bcd = gray;
32 int size = sizeof(bcd) * 8;
33 int i;
34
35 for (i = 0; (1 << i) < size; i++)
36 bcd ^= bcd >> (1 << i);
37
38 return bcd;
39}
40
Xiaohu.Huang60950452022-03-12 22:51:01 +080041static void vRTCInterruptHandler(void)
42{
xiaohu.huang2beac512022-05-07 15:10:04 +080043 uint32_t buf[4] = { 0 };
yiting.deng4f79f4f2023-09-07 14:32:14 +080044 uint32_t reg_val;
Xiaohu.Huang60950452022-03-12 22:51:01 +080045
yiting.dengac5b18d2023-04-25 11:13:26 +080046 alarm_flags = 1;
yiting.deng4f79f4f2023-09-07 14:32:14 +080047 reg_val = REG32(RTC_DIG_INT_STATUS) & 0x1;
48 /* Clear alarm0 int status */
49 if (reg_val)
50 REG32(RTC_DIG_INT_CLR) = 0x1;
51
Xiaohu.Huang60950452022-03-12 22:51:01 +080052 printf("[%s]: rtc alarm fired\n", TAG);
53
54 buf[0] = RTC_WAKEUP;
55 STR_Wakeup_src_Queue_Send_FromISR(buf);
56}
57
58static uint32_t get_reboot_mode(void)
59{
60 uint32_t reg_val;
61 uint32_t reboot_mode;
62
63 reg_val = REG32(SYSCTRL_SEC_STATUS_REG31);
64 reboot_mode = ((reg_val >> 12) & 0xf);
65
66 return reboot_mode;
67}
68
69static void reset_rtc(void)
70{
71 uint32_t reg_val;
72
73 printf("[%s]: reset rtc\n", TAG);
74 /* Reset RTC */
75 reg_val = (1 << 0);
76 REG32(RESETCTRL_RESET4) = reg_val;
77 /* Mask RTC reset to prevent RTC being reset in the next reboot */
78 reg_val = REG32(RESETCTRL_RESET4_MASK);
79 reg_val |= (1 << 0);
80 REG32(RESETCTRL_RESET4_MASK) = reg_val;
81}
82
83static int get_rtc(uint32_t *val)
84{
85 if (!REG32(VRTC_STICKY_REG))
86 return -1;
Xiaohu.Huang60950452022-03-12 22:51:01 +080087
xiaohu.huang2beac512022-05-07 15:10:04 +080088 *(val) = REG32(VRTC_STICKY_REG);
Xiaohu.Huang60950452022-03-12 22:51:01 +080089 return 0;
90}
91
92static void set_rtc(uint32_t val)
93{
94 REG32(VRTC_STICKY_REG) = val;
95}
96
97void store_rtc(void)
98{
99 uint32_t reg_val;
100
yiting.deng21d1aa42023-02-08 17:46:11 +0800101 reg_val = REG32(RTC_DIG_REAL_TIME);
102#ifdef CONFIG_RTC_STORAGE_FORMAT_GRAY
103 reg_val = gray_to_binary(reg_val);
104#endif
Xiaohu.Huang60950452022-03-12 22:51:01 +0800105 REG32(VRTC_STICKY_REG) = reg_val;
106}
107
108void *MboxSetRTC(void *msg)
109{
110 unsigned int val = *(uint32_t *)msg;
xiaohu.huang2beac512022-05-07 15:10:04 +0800111
112 printf("[%s]: %s val=0x%x\n", TAG, __func__, val);
Xiaohu.Huang60950452022-03-12 22:51:01 +0800113 set_rtc(val);
114
115 return NULL;
116}
117
118void *MboxGetRTC(void *msg)
119{
120 uint32_t val = 0;
121
122 get_rtc(&val);
123 memset(msg, 0, MBOX_BUF_LEN);
124 *(uint32_t *)msg = val;
125
xiaohu.huang2beac512022-05-07 15:10:04 +0800126 printf("[%s]: %s val=0x%x\n", TAG, __func__, val);
Xiaohu.Huang60950452022-03-12 22:51:01 +0800127
128 return NULL;
129}
130
yiting.deng6ec1d642023-03-19 10:10:35 +0800131void rtc_enable_irq(void)
132{
yiting.dengbfc3f452023-05-18 16:22:40 +0800133 int ret, val;
yiting.dengac5b18d2023-04-25 11:13:26 +0800134 u32 alarm, time;
yiting.deng4f79f4f2023-09-07 14:32:14 +0800135 int irq_num;
136 uint32_t reg_val;
yiting.deng6ec1d642023-03-19 10:10:35 +0800137
yiting.deng4f79f4f2023-09-07 14:32:14 +0800138 irq_num = RTC_IRQ % 32;
139 reg_val = REG32(IRQCTRL_IRQ_LATCH4) >> irq_num & 0x1;
140 if (reg_val)
141 REG32(IRQCTRL_IRQ_LATCH_CLR4) |= (0x1 << irq_num);
yiting.dengac5b18d2023-04-25 11:13:26 +0800142 alarm = REG32(RTC_DIG_ALARM0_REG);
yiting.dengbfc3f452023-05-18 16:22:40 +0800143 time = REG32(RTC_DIG_REAL_TIME);
144#ifdef CONFIG_RTC_STORAGE_FORMAT_GRAY
145 alarm = gray_to_binary(alarm);
146 time = gray_to_binary(time);
147#endif
148 val = alarm - time;
149 if (val > 0) {
yiting.dengac5b18d2023-04-25 11:13:26 +0800150 ret = RegisterIrq(RTC_IRQ, 6, vRTCInterruptHandler);
151 if (ret)
152 printf("RTC_irq RegisterIrq error, ret = %d\n", ret);
153 EnableIrq(RTC_IRQ);
yiting.dengbfc3f452023-05-18 16:22:40 +0800154 printf("[%s]: alarm val=%d S\n", TAG, val);
155 if (xAlarmTimer != NULL) {
156 alarm = (val + 1) * 1000;
yiting.dengac5b18d2023-04-25 11:13:26 +0800157 xTimerChangePeriod(xAlarmTimer, pdMS_TO_TICKS(alarm), 0);
158 }
159 }
yiting.deng6ec1d642023-03-19 10:10:35 +0800160}
161
162void rtc_disable_irq(void)
163{
yiting.dengbfc3f452023-05-18 16:22:40 +0800164 int ret, val;
yiting.deng6ec1d642023-03-19 10:10:35 +0800165
yiting.deng4c21b172023-08-29 15:44:23 +0800166 val = GetIrqInner(RTC_IRQ);
yiting.dengbfc3f452023-05-18 16:22:40 +0800167 if (val > 0) {
yiting.dengac5b18d2023-04-25 11:13:26 +0800168 DisableIrq(RTC_IRQ);
169 ret = UnRegisterIrq(RTC_IRQ);
170 if (ret)
171 printf("RTC_irq UnRegisterIrq error, ret = %d\n", ret);
172 }
173}
174
175static void rtc_alarm_timer_handler(TimerHandle_t xAlarmTimer)
176{
177 static int rtc_irq, status;
yiting.deng4f79f4f2023-09-07 14:32:14 +0800178 int irq_num;
179 uint32_t reg_val;
yiting.dengac5b18d2023-04-25 11:13:26 +0800180
181 status = REG32(RTC_DIG_INT_STATUS) & 0x1;
182 if (status && !alarm_flags) {
yiting.deng4f79f4f2023-09-07 14:32:14 +0800183 printf("warning: rtc interrupt lost!trigger rtc interrupt manually!\n");
184 irq_num = RTC_IRQ % 32;
185 reg_val = REG32(IRQCTRL_IRQ_LATCH4) >> irq_num & 0x1;
186 printf("[%s]: timer read rtc irqctrl status: 0x%x !!\n", TAG, reg_val);
yiting.dengac5b18d2023-04-25 11:13:26 +0800187 rtc_irq = GetIrqInner(RTC_IRQ);
188 if (rtc_irq)
189 eclic_set_pending(rtc_irq);
190 }
191 alarm_flags = 0;
192}
193
194void alarm_clr(void)
195{
yiting.deng4f79f4f2023-09-07 14:32:14 +0800196 int irq_num;
197 uint32_t reg_val;
198
yiting.dengac5b18d2023-04-25 11:13:26 +0800199 if (xAlarmTimer != NULL)
200 xTimerStop(xAlarmTimer, 0);
yiting.deng4f79f4f2023-09-07 14:32:14 +0800201
202 irq_num = RTC_IRQ % 32;
203 reg_val = REG32(IRQCTRL_IRQ_LATCH4) >> irq_num & 0x1;
204 printf("[%s]: rtc irqctrl status: 0x%x !!\n", TAG, reg_val);
205 if (reg_val)
206 REG32(IRQCTRL_IRQ_LATCH_CLR4) |= (0x1 << irq_num);
207 reg_val = REG32(IRQCTRL_IRQ_LATCH4) >> irq_num & 0x1;
yiting.dengac5b18d2023-04-25 11:13:26 +0800208}
209
210static void rtc_alarm_timer_init(void)
211{
212 xAlarmTimer = xTimerCreate("RtcAlarmTimer", pdMS_TO_TICKS(1000),
213 pdFALSE, NULL, rtc_alarm_timer_handler);
yiting.deng6ec1d642023-03-19 10:10:35 +0800214}
215
Xiaohu.Huang60950452022-03-12 22:51:01 +0800216void rtc_init(void)
217{
218 int ret;
219 uint32_t reboot_mode;
220
221 printf("[%s]: init rtc\n", TAG);
Xiaohu.Huang60950452022-03-12 22:51:01 +0800222
xiaohu.huang2beac512022-05-07 15:10:04 +0800223 ret = xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL, MBX_CMD_SET_RTC, MboxSetRTC, 0);
Xiaohu.Huang60950452022-03-12 22:51:01 +0800224 if (ret == MBOX_CALL_MAX)
225 printf("[%s]: mbox cmd 0x%x register fail\n", TAG, MBX_CMD_SET_RTC);
226
xiaohu.huang2beac512022-05-07 15:10:04 +0800227 ret = xInstallRemoteMessageCallbackFeedBack(AOREE_CHANNEL, MBX_CMD_GET_RTC, MboxGetRTC, 1);
Xiaohu.Huang60950452022-03-12 22:51:01 +0800228 if (ret == MBOX_CALL_MAX)
229 printf("[%s]: mbox cmd 0x%x register fail\n", TAG, MBX_CMD_GET_RTC);
230
231 reboot_mode = get_reboot_mode();
232 if (reboot_mode == COLD_REBOOT)
233 reset_rtc();
yiting.dengac5b18d2023-04-25 11:13:26 +0800234
235 rtc_alarm_timer_init();
Xiaohu.Huang60950452022-03-12 22:51:01 +0800236}