1 /*
2 * Copyright (c) 2017 The Fuchsia Authors.
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8
9 #include <platform/timer_capture.h>
10
11 #include <arch/arm/cm.h>
12 #include <assert.h>
13 #include <platform/rcc.h>
14
15 typedef enum {
16 STM32_TIM_NOT_FOUND = -1,
17 STM32_TIM1_INDEX = 0,
18 STM32_TIM2_INDEX,
19 STM32_TIM3_INDEX,
20 STM32_TIM6_INDEX,
21 STM32_TIM7_INDEX,
22 STM32_TIM14_INDEX,
23 STM32_TIM15_INDEX,
24 STM32_TIM16_INDEX,
25 STM32_TIM17_INDEX,
26 STM32_NUM_TIMERS,
27 } stm32_timer_index_t;
28
29 typedef TIM_TypeDef stm32_timer_regs_t;
30
31 #define STM32_TIMER_FLAGS_32_BIT (1 << 0)
32 typedef struct stm32_timer_config_ {
33 stm32_timer_regs_t *regs;
34 uint32_t flags;
35 stm32_rcc_clk_t clock;
36 int irq;
37 } stm32_timer_config_t;
38
39 static const stm32_timer_config_t stm32_timer_config[] = {
40 #ifdef TIM1
41 [STM32_TIM1_INDEX] = {
42 .regs = TIM1,
43 .flags = 0,
44 .clock = STM32_RCC_CLK_TIM1,
45 // TIM1 has two interrupts. This one and TIM1_BRK_UP_TRG_COM_IRQn.
46 // This will need to be supported when more than just capture is
47 // supported.
48 .irq = TIM1_CC_IRQn,
49 },
50 #endif
51 #ifdef TIM2
52 [STM32_TIM2_INDEX] = {
53 .regs = TIM2,
54 .flags = STM32_TIMER_FLAGS_32_BIT,
55 .clock = STM32_RCC_CLK_TIM2,
56 .irq = TIM2_IRQn,
57 },
58 #endif
59 #ifdef TIM3
60 [STM32_TIM3_INDEX] = {
61 .regs = TIM3,
62 .flags = 0,
63 .clock = STM32_RCC_CLK_TIM3,
64 .irq = TIM3_IRQn,
65 },
66 #endif
67 #ifdef TIM6
68 [STM32_TIM6_INDEX] = {
69 .regs = TIM6,
70 .flags = 0,
71 .clock = STM32_RCC_CLK_TIM6,
72 .irq = TIM6_IRQn,
73 },
74 #endif
75 #ifdef TIM7
76 [STM32_TIM7_INDEX] = {
77 .regs = TIM7,
78 .flags = 0,
79 .clock = STM32_RCC_CLK_TIM7,
80 .irq = TIM7_IRQn,
81 },
82 #endif
83 #ifdef TIM14
84 [STM32_TIM14_INDEX] = {
85 .regs = TIM14,
86 .flags = 0,
87 .clock = STM32_RCC_CLK_TIM14,
88 .irq = TIM14_IRQn,
89 },
90 #endif
91 #ifdef TIM15
92 [STM32_TIM15_INDEX] = {
93 .regs = TIM15,
94 .flags = 0,
95 .clock = STM32_RCC_CLK_TIM15,
96 .irq = TIM15_IRQn,
97 },
98 #endif
99 #ifdef TIM16
100 [STM32_TIM16_INDEX] = {
101 .regs = TIM16,
102 .flags = 0,
103 .clock = STM32_RCC_CLK_TIM16,
104 .irq = TIM16_IRQn,
105 },
106 #endif
107 #ifdef TIM17
108 [STM32_TIM17_INDEX] = {
109 .regs = TIM17,
110 .flags = 0,
111 .clock = STM32_RCC_CLK_TIM17,
112 .irq = TIM17_IRQn,
113 },
114 #endif
115 };
116
117 static stm32_timer_capture_t *stm32_timer_capture_data[STM32_NUM_TIMERS];
118
stm32_timer_enable(const stm32_timer_config_t * config)119 static void stm32_timer_enable(const stm32_timer_config_t *config) {
120 stm32_rcc_set_enable(config->clock, true);
121 }
122
stm32_timer_get_index(int timer)123 static stm32_timer_index_t stm32_timer_get_index(int timer) {
124 switch (timer) {
125 case 1:
126 return STM32_TIM1_INDEX;
127 case 2:
128 return STM32_TIM2_INDEX;
129 case 3:
130 return STM32_TIM3_INDEX;
131 case 6:
132 return STM32_TIM6_INDEX;
133 case 7:
134 return STM32_TIM7_INDEX;
135 case 14:
136 return STM32_TIM14_INDEX;
137 case 15:
138 return STM32_TIM15_INDEX;
139 case 16:
140 return STM32_TIM16_INDEX;
141 case 17:
142 return STM32_TIM17_INDEX;
143 default:
144 return STM32_TIM_NOT_FOUND;
145 }
146 }
147
stm32_timer_get_config(int timer)148 static const stm32_timer_config_t *stm32_timer_get_config(int timer) {
149 stm32_timer_index_t index = stm32_timer_get_index(timer);
150 if (index == STM32_TIM_NOT_FOUND) {
151 return NULL;
152 }
153 return &stm32_timer_config[index];
154 }
155
stm32_timer_is_32_bit(int timer)156 static bool stm32_timer_is_32_bit(int timer) {
157 switch (timer) {
158 case 2:
159 return true;
160 default:
161 return false;
162 }
163 }
164
stm32_timer_capture_setup_chan(stm32_timer_capture_t * tc,int chan)165 static void stm32_timer_capture_setup_chan(stm32_timer_capture_t *tc, int chan) {
166 stm32_timer_regs_t *regs = tc->config->regs;
167 volatile uint32_t *ccmr = chan & 0x2 ? ®s->CCMR2 : ®s->CCMR1;
168 int shift = 8 * (chan & 1);
169
170 uint32_t val = *ccmr;
171 val &= 0xff << shift;
172 val |= TIM_CCMR1_CC1S_0 << shift;
173 *ccmr = val;
174
175 uint32_t config = TIM_CCER_CC1E;
176 uint32_t flags = tc->chan[chan].flags;
177 if (flags & STM32_TIMER_CAPTURE_CHAN_FLAG_FALLING) {
178 config |= TIM_CCER_CC1P;
179 if (flags & STM32_TIMER_CAPTURE_CHAN_FLAG_RISING) {
180 config |= TIM_CCER_CC1NP;
181 }
182 }
183
184 shift = 4 * (chan & 3);
185 val = regs->CCER;
186 val &= 0xf << shift;
187 val |= config << shift;
188 regs->CCER = val;
189 }
190
stm32_timer_get_ccr(stm32_timer_capture_t * tc,int chan)191 static uint32_t stm32_timer_get_ccr(stm32_timer_capture_t *tc, int chan) {
192 assert(0 <= chan && chan <= 3);
193 switch (chan) {
194 case 0:
195 return tc->config->regs->CCR1;
196 case 1:
197 return tc->config->regs->CCR2;
198 case 2:
199 return tc->config->regs->CCR3;
200 default: // 3
201 return tc->config->regs->CCR4;
202 }
203 }
204
stm32_timer_inc_overflow(stm32_timer_capture_t * tc,uint64_t overflow)205 static uint64_t stm32_timer_inc_overflow(stm32_timer_capture_t *tc, uint64_t overflow) {
206 uint64_t inc;
207 if (tc->config->flags & STM32_TIMER_FLAGS_32_BIT) {
208 inc = 0x100000000ULL;
209 } else {
210 inc = 0x10000ULL;
211 }
212 return overflow + inc;
213 }
214
stm32_timer_median_val(stm32_timer_capture_t * tc)215 static uint32_t stm32_timer_median_val(stm32_timer_capture_t *tc) {
216 if (tc->config->flags & STM32_TIMER_FLAGS_32_BIT) {
217 return 0x7fffffff;
218 } else {
219 return 0x7fff;
220 }
221 }
222
223 // Assumes interrupts are disabled.
stm32_timer_calc_value(stm32_timer_capture_t * tc,uint32_t sr,uint32_t val)224 static uint64_t stm32_timer_calc_value(stm32_timer_capture_t *tc, uint32_t sr, uint32_t val) {
225 uint64_t overflow = tc->overflow;
226 // Since we could be processing an overflow and capture interrupts at the
227 // same time, we don't know the ordering of the two. Here we assume
228 // that if the capture event occurred in the lower half of the counter
229 // range, the overflow happened before the capture.
230 if (sr & TIM_SR_UIF && val < stm32_timer_median_val(tc)) {
231 overflow = stm32_timer_inc_overflow(tc, overflow);
232 }
233 return overflow | val;
234 }
235
stm32_timer_capture_chan_irq(stm32_timer_capture_t * tc,uint32_t sr,int chan)236 static bool stm32_timer_capture_chan_irq(stm32_timer_capture_t *tc, uint32_t sr, int chan) {
237 if (tc->chan[chan].cb == NULL) {
238 return false;
239 }
240 if (sr & (TIM_SR_CC1IF << chan)) {
241 uint32_t val = stm32_timer_get_ccr(tc, chan);
242 return tc->chan[chan].cb(stm32_timer_calc_value(tc, sr, val));
243 }
244 return false;
245 }
246
stm32_timer_capture_irq(stm32_timer_index_t index)247 static void stm32_timer_capture_irq(stm32_timer_index_t index) {
248 arm_cm_irq_entry();
249 bool resched = false;
250
251 stm32_timer_capture_t *tc = stm32_timer_capture_data[index];
252 if (tc == NULL) {
253 goto out;
254 }
255
256 uint32_t sr = tc->config->regs->SR;
257 uint32_t irq_ack = ~0U;
258
259 // Since these read their corresponding CCR registers, the status flags
260 // do not need to be explicitly cleared.
261 resched |= stm32_timer_capture_chan_irq(tc, sr, 0);
262 resched |= stm32_timer_capture_chan_irq(tc, sr, 1);
263 resched |= stm32_timer_capture_chan_irq(tc, sr, 2);
264 resched |= stm32_timer_capture_chan_irq(tc, sr, 3);
265
266
267 // We process overflow after compares in order to handle overflow race
268 // detection there.
269 spin_lock_saved_state_t state;
270 spin_lock_irqsave(&tc->overflow_lock, state);
271 if (sr & TIM_SR_UIF) {
272 tc->overflow = stm32_timer_inc_overflow(tc, tc->overflow);
273 irq_ack &= ~TIM_SR_UIF;
274 }
275 tc->config->regs->SR = irq_ack;
276 spin_unlock_irqrestore(&tc->overflow_lock, state);
277
278 out:
279 arm_cm_irq_exit(resched);
280 }
281
stm32_TIM1_IRQ(void)282 void stm32_TIM1_IRQ(void) {
283 stm32_timer_capture_irq(STM32_TIM1_INDEX);
284 }
285
stm32_TIM2_IRQ(void)286 void stm32_TIM2_IRQ(void) {
287 stm32_timer_capture_irq(STM32_TIM2_INDEX);
288 }
289
stm32_TIM3_IRQ(void)290 void stm32_TIM3_IRQ(void) {
291 stm32_timer_capture_irq(STM32_TIM3_INDEX);
292 }
293
stm32_TIM6_IRQ(void)294 void stm32_TIM6_IRQ(void) {
295 stm32_timer_capture_irq(STM32_TIM6_INDEX);
296 }
297
stm32_TIM7_IRQ(void)298 void stm32_TIM7_IRQ(void) {
299 stm32_timer_capture_irq(STM32_TIM7_INDEX);
300 }
301
stm32_TIM14_IRQ(void)302 void stm32_TIM14_IRQ(void) {
303 stm32_timer_capture_irq(STM32_TIM14_INDEX);
304 }
305
stm32_TIM15_IRQ(void)306 void stm32_TIM15_IRQ(void) {
307 stm32_timer_capture_irq(STM32_TIM15_INDEX);
308 }
309
stm32_TIM16_IRQ(void)310 void stm32_TIM16_IRQ(void) {
311 stm32_timer_capture_irq(STM32_TIM16_INDEX);
312 }
313
stm32_TIM17_IRQ(void)314 void stm32_TIM17_IRQ(void) {
315 stm32_timer_capture_irq(STM32_TIM17_INDEX);
316 }
317
stm32_timer_capture_setup(stm32_timer_capture_t * tc,int timer,uint16_t prescaler)318 status_t stm32_timer_capture_setup(stm32_timer_capture_t *tc, int timer, uint16_t prescaler) {
319 assert(prescaler > 0);
320
321 tc->config = stm32_timer_get_config(timer);
322 if (tc->config == NULL) {
323 return ERR_NOT_FOUND;
324 }
325
326 stm32_timer_enable(tc->config);
327
328 stm32_timer_capture_data[stm32_timer_get_index(timer)] = tc;
329
330 tc->overflow = 0;
331 spin_lock_init(&tc->overflow_lock);
332
333 tc->config->regs->CR1 = 0;
334
335 // The prescaler value applied by hardware is PSC + 1.
336 tc->config->regs->PSC = prescaler > 0 ? prescaler - 1 : 0;
337
338 uint32_t dier = TIM_DIER_UIE;
339
340 int i;
341 for (i = 0; i < 4; i++) {
342 if (tc->chan[i].flags & STM32_TIMER_CAPTURE_CHAN_FLAG_ENABLE) {
343 dier |= TIM_DIER_CC1IE << i;
344 stm32_timer_capture_setup_chan(tc, i);
345 }
346 }
347
348 tc->config->regs->DIER = dier;
349 tc->config->regs->CR1 |= TIM_CR1_CEN;
350
351 NVIC_EnableIRQ(tc->config->irq);
352
353 return NO_ERROR;
354 }
355
stm32_timer_capture_get_counter(stm32_timer_capture_t * tc)356 uint64_t stm32_timer_capture_get_counter(stm32_timer_capture_t *tc) {
357 // Protect against tc->overflow being updated while we calculate the value.
358 spin_lock_saved_state_t state;
359 spin_lock_irqsave(&tc->overflow_lock, state);
360
361 uint32_t cnt = tc->config->regs->CNT;
362 uint32_t sr = tc->config->regs->SR;
363 uint64_t value = stm32_timer_calc_value(tc, sr, cnt);
364
365 spin_unlock_irqrestore(&tc->overflow_lock, state);
366 return value;
367 }
368
stm32_timer_init(void)369 void stm32_timer_init(void) {
370 }
371
stm32_timer_early_init(void)372 void stm32_timer_early_init(void) {
373 }
374