1 /*
2 * Copyright (c) 2006-2024, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2024-03-04 ShichengChu the first version
9 */
10
11 #include <rtthread.h>
12 #include <rtdevice.h>
13
14 #define DBG_TAG "DRV.RTC"
15 #define DBG_LVL DBG_WARNING
16 #include <rtdbg.h>
17
18 #include "pinctrl.h"
19 #include "mmio.h"
20 #include "drv_ioremap.h"
21
22 #define CVI_RTC_BASE 0x05026000U
23 #define RTC_ALARM_O 17
24 #define CVI_RTC_CTRL_BASE 0x05025000U
25 #define CLK_EN_0 0x03002000U
26 #define CLK_RTC_25M_BIT (1 << 8)
27
28 /* CVITEK RTC registers */
29 #define CVI_RTC_ANA_CALIB 0x0
30 #define CVI_RTC_SEC_PULSE_GEN 0x4
31 #define CVI_RTC_ALARM_TIME 0x8
32 #define CVI_RTC_ALARM_ENABLE 0xC
33 #define CVI_RTC_SET_SEC_CNTR_VALUE 0x10
34 #define CVI_RTC_SET_SEC_CNTR_TRIG 0x14
35 #define CVI_RTC_SEC_CNTR_VALUE 0x18
36 #define CVI_RTC_APB_RDATA_SEL 0x3C
37 #define CVI_RTC_POR_DB_MAGIC_KEY 0x68
38 #define CVI_RTC_EN_PWR_WAKEUP 0xBC
39 #define CVI_RTC_PWR_DET_SEL 0x140
40
41 /* CVITEK RTC MACRO registers */
42 #define RTC_MACRO_DA_CLEAR_ALL 0x480
43 #define RTC_MACRO_DA_SOC_READY 0x48C
44 #define RTC_MACRO_RO_T 0x4A8
45 #define RTC_MACRO_RG_SET_T 0x498
46
47 /* CVITEK RTC CTRL registers */
48 #define CVI_RTC_FC_COARSE_EN 0x40
49 #define CVI_RTC_FC_COARSE_CAL 0x44
50 #define CVI_RTC_FC_FINE_EN 0x48
51 #define CVI_RTC_FC_FINE_CAL 0x50
52
53 #define RTC_SEC_MAX_VAL 0xFFFFFFFF
54
55 #define RTC_OFFSET_SN 0x5201800
56 #define RTC_ALARM_IRQ_NUM 0x11
57
58 struct rtc_device_object
59 {
60 rt_rtc_dev_t rtc_dev;
61 rt_ubase_t base;
62 };
63
64 static struct rtc_device_object rtc_device;
65
66 #define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
67
68 typedef struct {
69 int tm_sec; ///< Second. [0-59]
70 int tm_min; ///< Minute. [0-59]
71 int tm_hour; ///< Hour. [0-23]
72 int tm_mday; ///< Day. [1-31]
73 int tm_mon; ///< Month. [0-11]
74 int tm_year; ///< Year-1900. [70- ] !NOTE:Set 100 mean 2000
75 int tm_wday; ///< Day of week. [0-6 ] !NOTE:Set 0 mean Sunday
76 int tm_yday; ///< Days in year.[0-365] !NOTE:Set 0 mean January 1st
77 } cvi_rtc_time_t;
78
79 static const unsigned char cvi_rtc_days_in_month[] = {
80 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
81 };
82
is_leap_year(unsigned int year)83 static inline int is_leap_year(unsigned int year)
84 {
85 return (!(year % 4) && (year % 100)) || !(year % 400);
86 }
87
rtc_month_days(unsigned int month,unsigned int year)88 static int rtc_month_days(unsigned int month, unsigned int year)
89 {
90 return cvi_rtc_days_in_month[month] + (is_leap_year(year) && month == 1);
91 }
92
hal_cvi_rtc_clk_set(int enable)93 static void hal_cvi_rtc_clk_set(int enable)
94 {
95 uint32_t clk_state;
96 rt_ubase_t clk = (rt_ubase_t)DRV_IOREMAP((void *)CLK_EN_0, 0x1000);
97
98 clk_state = mmio_read_32(clk);
99
100 if(enable)
101 clk_state |= CLK_RTC_25M_BIT;
102 else
103 clk_state &= ~(CLK_RTC_25M_BIT);
104
105 mmio_write_32(clk, clk_state);
106 }
107
hal_cvi_rtc_enable_sec_counter(uintptr_t rtc_base)108 static void hal_cvi_rtc_enable_sec_counter(uintptr_t rtc_base)
109 {
110 uint32_t value = 0;
111
112 value = mmio_read_32(rtc_base + CVI_RTC_SEC_PULSE_GEN) & 0x7FFFFFFF;
113 mmio_write_32(rtc_base + CVI_RTC_SEC_PULSE_GEN, value);
114
115 value = mmio_read_32(rtc_base + CVI_RTC_ANA_CALIB) & 0x7FFFFFFF;
116 mmio_write_32(rtc_base + CVI_RTC_ANA_CALIB, value);
117
118 mmio_read_32(rtc_base + CVI_RTC_SEC_CNTR_VALUE);
119 mmio_write_32(rtc_base + CVI_RTC_ALARM_ENABLE, 0x0);
120 }
121
hal_cvi_rtc_set_time(uintptr_t rtc_base,unsigned long sec)122 static void hal_cvi_rtc_set_time(uintptr_t rtc_base, unsigned long sec)
123 {
124 mmio_write_32(rtc_base + CVI_RTC_SET_SEC_CNTR_VALUE, sec);
125 mmio_write_32(rtc_base + CVI_RTC_SET_SEC_CNTR_TRIG, 1);
126 mmio_write_32(rtc_base + RTC_MACRO_RG_SET_T, sec);
127 mmio_write_32(rtc_base + RTC_MACRO_DA_CLEAR_ALL, 1);
128 mmio_write_32(rtc_base + RTC_MACRO_DA_SOC_READY, 1);
129 mmio_write_32(rtc_base + RTC_MACRO_DA_CLEAR_ALL, 0);
130 mmio_write_32(rtc_base + RTC_MACRO_RG_SET_T, 0);
131 mmio_write_32(rtc_base + RTC_MACRO_DA_SOC_READY, 0);
132 }
133
hal_cvi_rtc_get_time_sec(uintptr_t rtc_base,unsigned long * ret_sec)134 static int hal_cvi_rtc_get_time_sec(uintptr_t rtc_base,unsigned long *ret_sec)
135 {
136 int ret = 0;
137 unsigned long sec;
138 unsigned long sec_ro_t;
139
140 sec = mmio_read_32(rtc_base + CVI_RTC_SEC_CNTR_VALUE);
141 sec_ro_t = mmio_read_32(rtc_base + RTC_MACRO_RO_T);
142
143 LOG_D("sec=%lx, sec_ro_t=%lx\n", sec, sec_ro_t);
144
145 if (sec_ro_t > 0x30000000) {
146 sec = sec_ro_t;
147 // Writeback to SEC CVI_RTC_SEC_CNTR_VALUE
148 mmio_write_32(rtc_base + CVI_RTC_SET_SEC_CNTR_VALUE, sec);
149 mmio_write_32(rtc_base + CVI_RTC_SET_SEC_CNTR_TRIG, 1);
150 } else if (sec < 0x30000000) {
151 LOG_D("RTC invalid time\n");
152 ret = -EINVAL;
153 }
154
155 *ret_sec = sec;
156
157 return ret;
158 }
159
div_u64_rem(uint64_t dividend,uint32_t divisor,uint32_t * remainder)160 static inline int64_t div_u64_rem(uint64_t dividend, uint32_t divisor, uint32_t *remainder)
161 {
162 *remainder = dividend % divisor;
163 return dividend / divisor;
164 }
165
166 /*
167 * rtc_time_to_tm64 - Converts time64_t to rtc_time.
168 * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
169 */
rtc_time64_to_tm(int64_t time,cvi_rtc_time_t * cvi_tm)170 static void rtc_time64_to_tm(int64_t time, cvi_rtc_time_t *cvi_tm)
171 {
172 unsigned int month, year, secs;
173 int days;
174
175 /* time must be positive */
176 days = div_u64_rem(time, 86400, &secs);
177
178 /* day of the week, 1970-01-01 was a Thursday */
179 cvi_tm->tm_wday = (days + 4) % 7;
180
181 year = 1970 + days / 365;
182 days -= (year - 1970) * 365
183 + LEAPS_THRU_END_OF(year - 1)
184 - LEAPS_THRU_END_OF(1970 - 1);
185 while (days < 0) {
186 year -= 1;
187 days += 365 + is_leap_year(year);
188 }
189 cvi_tm->tm_year = year - 1900;
190 cvi_tm->tm_yday = days + 1;
191
192 for (month = 0; month < 11; month++) {
193 int newdays;
194
195 newdays = days - rtc_month_days(month, year);
196 if (newdays < 0)
197 break;
198 days = newdays;
199 }
200 cvi_tm->tm_mon = month;
201 cvi_tm->tm_mday = days + 1;
202
203 cvi_tm->tm_hour = secs / 3600;
204 secs -= cvi_tm->tm_hour * 3600;
205 cvi_tm->tm_min = secs / 60;
206 cvi_tm->tm_sec = secs - cvi_tm->tm_min * 60;
207 }
208
mktime64(const unsigned int year0,const unsigned int mon0,const unsigned int day,const unsigned int hour,const unsigned int min,const unsigned int sec)209 static int64_t mktime64(const unsigned int year0, const unsigned int mon0,
210 const unsigned int day, const unsigned int hour,
211 const unsigned int min, const unsigned int sec)
212 {
213 unsigned int mon = mon0, year = year0;
214
215 /* 1..12 -> 11,12,1..10 */
216 if (0 >= (int) (mon -= 2)) {
217 mon += 12; /* Puts Feb last since it has leap day */
218 year -= 1;
219 }
220
221 return ((((int64_t)
222 (year/4 - year/100 + year/400 + 367*mon/12 + day) +
223 year*365 - 719499
224 )*24 + hour /* now have hours - midnight tomorrow handled here */
225 )*60 + min /* now have minutes */
226 )*60 + sec; /* finally seconds */
227 }
228
229 /*
230 * rtc_tm_to_time64 - Converts rtc_time to time64_t.
231 * Convert Gregorian date to seconds since 01-01-1970 00:00:00.
232 */
rtc_tm_to_time64(const cvi_rtc_time_t * cvi_tm)233 static int64_t rtc_tm_to_time64(const cvi_rtc_time_t *cvi_tm)
234 {
235 return mktime64(cvi_tm->tm_year + 1900, cvi_tm->tm_mon + 1, cvi_tm->tm_mday,
236 cvi_tm->tm_hour, cvi_tm->tm_min, cvi_tm->tm_sec);
237 }
238
_rtc_get_timeval(struct timeval * tv)239 static rt_err_t _rtc_get_timeval(struct timeval *tv)
240 {
241 unsigned long sec;
242 cvi_rtc_time_t t = {0};
243 struct tm tm_new = {0};
244
245 hal_cvi_rtc_get_time_sec(rtc_device.base, &sec);
246 rtc_time64_to_tm(sec, &t);
247
248 tm_new.tm_sec = t.tm_sec;
249 tm_new.tm_min = t.tm_min;
250 tm_new.tm_hour = t.tm_hour;
251 tm_new.tm_wday = t.tm_wday;
252 tm_new.tm_mday = t.tm_mday;
253 tm_new.tm_mon = t.tm_mon;
254 tm_new.tm_year = t.tm_year;
255
256 tv->tv_sec = timegm(&tm_new);
257
258 return RT_EOK;
259 }
260
_rtc_init(void)261 static rt_err_t _rtc_init(void)
262 {
263 hal_cvi_rtc_clk_set(1);
264 hal_cvi_rtc_enable_sec_counter(rtc_device.base);
265
266 return RT_EOK;
267 }
268
_rtc_get_secs(time_t * sec)269 static rt_err_t _rtc_get_secs(time_t *sec)
270 {
271 struct timeval tv;
272
273 _rtc_get_timeval(&tv);
274 *(time_t *) sec = tv.tv_sec;
275 LOG_D("RTC: get rtc_time %d", *sec);
276
277 return RT_EOK;
278 }
279
_rtc_set_secs(time_t * sec)280 static rt_err_t _rtc_set_secs(time_t *sec)
281 {
282 rt_err_t result = RT_EOK;
283 cvi_rtc_time_t t = {0};
284 struct tm tm = {0};
285 unsigned long set_sec;
286
287 gmtime_r(sec, &tm);
288
289 t.tm_sec = tm.tm_sec;
290 t.tm_min = tm.tm_min;
291 t.tm_hour = tm.tm_hour;
292 t.tm_mday = tm.tm_mday;
293 t.tm_mon = tm.tm_mon;
294 t.tm_year = tm.tm_year;
295 t.tm_wday = tm.tm_wday;
296
297 set_sec = rtc_tm_to_time64(&t);
298 hal_cvi_rtc_set_time(rtc_device.base, set_sec);
299
300 return result;
301 }
302
303 #ifdef RT_USING_ALARM
rtc_alarm_enable(rt_bool_t enable)304 static void rtc_alarm_enable(rt_bool_t enable)
305 {
306 mmio_write_32(rtc_device.base + CVI_RTC_ALARM_ENABLE, enable);
307 }
308
rt_hw_rtc_isr(int irqno,void * param)309 static void rt_hw_rtc_isr(int irqno, void *param)
310 {
311 rt_interrupt_enter();
312
313 /* send event to alarm */
314 rt_alarm_update(&rtc_device.rtc_dev.parent, 1);
315 /* clear alarm */
316 rtc_alarm_enable(0);
317
318 rt_interrupt_leave();
319 }
320
_rtc_get_alarm(struct rt_rtc_wkalarm * alarm)321 static rt_err_t _rtc_get_alarm(struct rt_rtc_wkalarm *alarm)
322 {
323 if (alarm == RT_NULL)
324 return -RT_ERROR;
325
326 unsigned long int sec;
327 cvi_rtc_time_t t = {0};
328
329 sec = mmio_read_32(rtc_device.base + CVI_RTC_ALARM_TIME);
330 rtc_time64_to_tm(sec, &t);
331
332 alarm->tm_sec = t.tm_sec;
333 alarm->tm_min = t.tm_min;
334 alarm->tm_hour = t.tm_hour;
335 alarm->tm_mday = t.tm_mday;
336 alarm->tm_mon = t.tm_mon;
337 alarm->tm_year = t.tm_year;
338 LOG_D("GET_ALARM %d:%d:%d", alarm->tm_hour, alarm->tm_min, alarm->tm_sec);
339
340 return RT_EOK;
341 }
342
_rtc_set_alarm(struct rt_rtc_wkalarm * alarm)343 static rt_err_t _rtc_set_alarm(struct rt_rtc_wkalarm *alarm)
344 {
345 if (alarm == RT_NULL)
346 return -RT_ERROR;
347
348 cvi_rtc_time_t t = {0};
349 unsigned long int set_sec;
350
351 if (alarm->enable){
352 t.tm_sec = alarm->tm_sec;
353 t.tm_min = alarm->tm_min;
354 t.tm_hour = alarm->tm_hour;
355 t.tm_mday = alarm->tm_mday;
356 t.tm_mon = alarm->tm_mon;
357 t.tm_year = alarm->tm_year;
358
359 set_sec = rtc_tm_to_time64(&t);
360 mmio_write_32(rtc_device.base + CVI_RTC_ALARM_TIME, set_sec);
361
362 LOG_D("GET_ALARM %d:%d:%d", alarm->tm_hour, alarm->tm_min, alarm->tm_sec);
363 }
364
365 rtc_alarm_enable(alarm->enable);
366
367 return RT_EOK;
368 }
369 #endif
370
371 static const struct rt_rtc_ops _rtc_ops =
372 {
373 _rtc_init,
374 _rtc_get_secs,
375 _rtc_set_secs,
376 #ifdef RT_USING_ALARM
377 _rtc_get_alarm,
378 _rtc_set_alarm,
379 #else
380 RT_NULL,
381 RT_NULL,
382 #endif
383 _rtc_get_timeval,
384 RT_NULL,
385 };
386
rt_hw_rtc_init(void)387 static int rt_hw_rtc_init(void)
388 {
389 rt_err_t result;
390
391 rtc_device.rtc_dev.ops = &_rtc_ops;
392
393 rtc_device.base = CVI_RTC_BASE;
394 rtc_device.base = (rt_ubase_t)DRV_IOREMAP((void *)rtc_device.base, 0x1000);
395
396 result = rt_hw_rtc_register(&rtc_device.rtc_dev, "rtc", RT_DEVICE_FLAG_RDWR, RT_NULL);
397 if (result != RT_EOK)
398 {
399 LOG_E("rtc register err code: %d", result);
400 return result;
401 }
402
403 #ifdef RT_USING_ALARM
404 rt_hw_interrupt_install(RTC_ALARM_IRQ_NUM, rt_hw_rtc_isr, RT_NULL, "rtc");
405 rt_hw_interrupt_umask(RTC_ALARM_IRQ_NUM);
406 #endif
407
408 LOG_D("rtc init success");
409
410 return RT_EOK;
411 }
412 INIT_DEVICE_EXPORT(rt_hw_rtc_init);
413