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