1 /*
2 * Copyright (c) 2019, Texas Instruments Incorporated
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT ti_cc13xx_cc26xx_rtc
8
9 /*
10 * TI SimpleLink CC13X2/CC26X2 RTC-based system timer
11 *
12 * This system timer implementation supports both tickless and ticking modes.
13 * RTC counts continually in 64-bit mode and timeouts are
14 * scheduled using the RTC comparator. An interrupt is triggered whenever
15 * the comparator value set is reached.
16 */
17
18 #include <soc.h>
19 #include <drivers/clock_control.h>
20 #include <drivers/timer/system_timer.h>
21 #include <sys_clock.h>
22
23 #include <driverlib/interrupt.h>
24 #include <driverlib/aon_rtc.h>
25 #include <driverlib/aon_event.h>
26
27 #define RTC_COUNTS_PER_SEC 0x100000000ULL
28
29 /* Number of counts per rtc timer cycle */
30 #define RTC_COUNTS_PER_CYCLE (RTC_COUNTS_PER_SEC / \
31 sys_clock_hw_cycles_per_sec())
32
33 /* Number of counts per system clock tick */
34 #define RTC_COUNTS_PER_TICK (RTC_COUNTS_PER_SEC / \
35 CONFIG_SYS_CLOCK_TICKS_PER_SEC)
36
37 /* Number of RTC cycles per system clock tick */
38 #define CYCLES_PER_TICK (sys_clock_hw_cycles_per_sec() / \
39 CONFIG_SYS_CLOCK_TICKS_PER_SEC)
40
41 /*
42 * Maximum number of ticks.
43 */
44 #define MAX_CYC 0x7FFFFFFFFFFFULL
45 #define MAX_TICKS (MAX_CYC / RTC_COUNTS_PER_TICK)
46
47 /*
48 * Due to the nature of clock synchronization, the comparator cannot be set
49 * to a value that is too close to the current time. This constant defines
50 * a safe threshold for the comparator.
51 */
52 #define COMPARE_MARGIN 6
53
54 /* RTC count of the last announce call, rounded down to tick boundary. */
55 static volatile uint64_t rtc_last;
56
57 #ifdef CONFIG_TICKLESS_KERNEL
58 static struct k_spinlock lock;
59 #else
60 static uint64_t nextThreshold = RTC_COUNTS_PER_TICK;
61 #endif /* CONFIG_TICKLESS_KERNEL */
62
63
setThreshold(uint32_t next)64 static void setThreshold(uint32_t next)
65 {
66 uint32_t now;
67 unsigned int key;
68
69 key = irq_lock();
70
71 /* get the current RTC count corresponding to compare window */
72 now = AONRTCCurrentCompareValueGet();
73
74 /* if next is too soon, set at least one RTC tick in future */
75 /* assume next never be more than half the maximum 32 bit count value */
76 if ((next - now) > (uint32_t)0x80000000) {
77 /* now is past next */
78 next = now + COMPARE_MARGIN;
79 } else if ((now + COMPARE_MARGIN - next) < (uint32_t)0x80000000) {
80 if (next < now + COMPARE_MARGIN) {
81 next = now + COMPARE_MARGIN;
82 }
83 }
84
85 /* set next compare threshold in RTC */
86 AONRTCCompareValueSet(AON_RTC_CH0, next);
87
88 irq_unlock(key);
89 }
90
rtc_isr(const void * arg)91 void rtc_isr(const void *arg)
92 {
93 #ifndef CONFIG_TICKLESS_KERNEL
94 uint64_t newThreshold;
95 uint32_t next;
96 #else
97 uint64_t ticks, currCount;
98 #endif
99
100 ARG_UNUSED(arg);
101
102 AONRTCEventClear(AON_RTC_CH0);
103
104 #ifdef CONFIG_TICKLESS_KERNEL
105 k_spinlock_key_t key = k_spin_lock(&lock);
106 currCount = (uint64_t)AONRTCCurrent64BitValueGet();
107 ticks = (currCount - rtc_last) / RTC_COUNTS_PER_TICK;
108
109 rtc_last += ticks * RTC_COUNTS_PER_TICK;
110 k_spin_unlock(&lock, key);
111
112 sys_clock_announce(ticks);
113
114 #else /* !CONFIG_TICKLESS_KERNEL */
115
116 /* calculate new 64-bit RTC count for next interrupt */
117 newThreshold = nextThreshold + RTC_COUNTS_PER_TICK;
118
119 next = (uint32_t)((uint64_t)newThreshold >> 16);
120 setThreshold(next);
121
122 nextThreshold = newThreshold;
123
124 rtc_last += RTC_COUNTS_PER_TICK;
125
126 sys_clock_announce(1);
127
128 #endif /* CONFIG_TICKLESS_KERNEL */
129 }
130
initDevice(void)131 static void initDevice(void)
132 {
133 AONRTCDisable();
134 AONRTCReset();
135
136 HWREG(AON_RTC_BASE + AON_RTC_O_SYNC) = 1;
137 /* read sync register to complete reset */
138 HWREG(AON_RTC_BASE + AON_RTC_O_SYNC);
139
140 AONRTCEventClear(AON_RTC_CH0);
141 IntPendClear(INT_AON_RTC_COMB);
142
143 HWREG(AON_RTC_BASE + AON_RTC_O_SYNC);
144 }
145
startDevice(void)146 static void startDevice(void)
147 {
148 uint32_t compare;
149 uint64_t period;
150 unsigned int key;
151
152 key = irq_lock();
153
154 /* reset timer */
155 AONRTCReset();
156 AONRTCEventClear(AON_RTC_CH0);
157 IntPendClear(INT_AON_RTC_COMB);
158
159 /*
160 * set the compare register to one period.
161 * For a very small period round up to interrupt upon 4th tick in
162 * compare register
163 */
164 period = RTC_COUNTS_PER_TICK;
165 if (period < 0x40000) {
166 compare = 0x4; /* 4 * 15.5us ~= 62us */
167 } else {
168 /* else, interrupt on first period expiration */
169 compare = period >> 16;
170 }
171
172 /* set the compare value at the RTC */
173 AONRTCCompareValueSet(AON_RTC_CH0, compare);
174
175 /* enable compare channel 0 */
176 AONEventMcuWakeUpSet(AON_EVENT_MCU_WU0, AON_EVENT_RTC0);
177 AONRTCChannelEnable(AON_RTC_CH0);
178 AONRTCCombinedEventConfig(AON_RTC_CH0);
179
180 /* start timer */
181 AONRTCEnable();
182
183 irq_unlock(key);
184 }
185
sys_clock_driver_init(const struct device * dev)186 int sys_clock_driver_init(const struct device *dev)
187 {
188 ARG_UNUSED(dev);
189
190 rtc_last = 0U;
191
192 initDevice();
193 startDevice();
194
195 /* Enable RTC interrupt. */
196 IRQ_CONNECT(DT_INST_IRQN(0),
197 DT_INST_IRQ(0, priority),
198 rtc_isr, 0, 0);
199 irq_enable(DT_INST_IRQN(0));
200
201 return 0;
202 }
203
sys_clock_set_timeout(int32_t ticks,bool idle)204 void sys_clock_set_timeout(int32_t ticks, bool idle)
205 {
206 ARG_UNUSED(idle);
207
208 #ifdef CONFIG_TICKLESS_KERNEL
209
210 ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : ticks;
211 ticks = CLAMP(ticks - 1, 0, (int32_t) MAX_TICKS);
212
213 k_spinlock_key_t key = k_spin_lock(&lock);
214
215 /* Compute number of RTC cycles until the next timeout. */
216 uint64_t count = AONRTCCurrent64BitValueGet();
217 uint64_t timeout = ticks * RTC_COUNTS_PER_TICK +
218 (count - rtc_last);
219
220 /* Round to the nearest tick boundary. */
221 timeout = (timeout + RTC_COUNTS_PER_TICK - 1) / RTC_COUNTS_PER_TICK
222 * RTC_COUNTS_PER_TICK;
223 timeout = MIN(timeout, MAX_CYC);
224 timeout += rtc_last;
225
226 /* Set the comparator */
227 setThreshold(timeout >> 16);
228
229 k_spin_unlock(&lock, key);
230 #endif /* CONFIG_TICKLESS_KERNEL */
231 }
232
sys_clock_elapsed(void)233 uint32_t sys_clock_elapsed(void)
234 {
235 uint32_t ret = (AONRTCCurrent64BitValueGet() - rtc_last) /
236 RTC_COUNTS_PER_TICK;
237
238 return ret;
239 }
240
sys_clock_cycle_get_32(void)241 uint32_t sys_clock_cycle_get_32(void)
242 {
243 return (AONRTCCurrent64BitValueGet() / RTC_COUNTS_PER_CYCLE)
244 & 0xFFFFFFFF;
245 }
246