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