1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #include "hardware/timer.h"
8 #include "hardware/irq.h"
9 #include "hardware/sync.h"
10 #include "hardware/claim.h"
11 
12 check_hw_layout(timer_hw_t, ints, TIMER_INTS_OFFSET);
13 
14 static hardware_alarm_callback_t alarm_callbacks[NUM_GENERIC_TIMERS][NUM_ALARMS];
15 static uint32_t target_hi[NUM_GENERIC_TIMERS][NUM_ALARMS];
16 static uint8_t timer_callbacks_pending[NUM_GENERIC_TIMERS];
17 
18 static_assert(NUM_ALARMS * NUM_GENERIC_TIMERS <= 8, "");
19 static uint8_t claimed[NUM_GENERIC_TIMERS];
20 
timer_hardware_alarm_claim(timer_hw_t * timer,uint alarm_num)21 void timer_hardware_alarm_claim(timer_hw_t *timer, uint alarm_num) {
22     check_hardware_alarm_num_param(alarm_num);
23     hw_claim_or_assert(&claimed[timer_get_index(timer)], alarm_num, "Hardware alarm %d already claimed");
24 }
25 
hardware_alarm_claim(uint alarm_num)26 void hardware_alarm_claim(uint alarm_num) {
27     timer_hardware_alarm_claim(PICO_DEFAULT_TIMER_INSTANCE(), alarm_num);
28 }
29 
timer_hardware_alarm_unclaim(timer_hw_t * timer,uint alarm_num)30 void timer_hardware_alarm_unclaim(timer_hw_t *timer, uint alarm_num) {
31     check_hardware_alarm_num_param(alarm_num);
32     hw_claim_clear(&claimed[timer_get_index(timer)], alarm_num);
33 }
34 
hardware_alarm_unclaim(uint alarm_num)35 void hardware_alarm_unclaim(uint alarm_num) {
36     timer_hardware_alarm_unclaim(PICO_DEFAULT_TIMER_INSTANCE(), alarm_num);
37 }
38 
timer_hardware_alarm_is_claimed(timer_hw_t * timer,uint alarm_num)39 bool timer_hardware_alarm_is_claimed(timer_hw_t *timer, uint alarm_num) {
40     check_hardware_alarm_num_param(alarm_num);
41     return hw_is_claimed(&claimed[timer_get_index(timer)], alarm_num);
42 }
43 
hardware_alarm_is_claimed(uint alarm_num)44 bool hardware_alarm_is_claimed(uint alarm_num) {
45     return timer_hardware_alarm_is_claimed(PICO_DEFAULT_TIMER_INSTANCE(), alarm_num);
46 }
47 
timer_hardware_alarm_claim_unused(timer_hw_t * timer,bool required)48 int timer_hardware_alarm_claim_unused(timer_hw_t *timer, bool required) {
49     return hw_claim_unused_from_range(&claimed[timer_get_index(timer)], required, 0, NUM_ALARMS - 1, "No alarms available");
50 }
51 
hardware_alarm_claim_unused(bool required)52 int hardware_alarm_claim_unused(bool required) {
53     return timer_hardware_alarm_claim_unused(PICO_DEFAULT_TIMER_INSTANCE(), required);
54 }
55 
56 /// tag::time_us_64[]
timer_time_us_64(timer_hw_t * timer)57 uint64_t timer_time_us_64(timer_hw_t *timer) {
58     // Need to make sure that the upper 32 bits of the timer
59     // don't change, so read that first
60     uint32_t hi = timer->timerawh;
61     uint32_t lo;
62     do {
63         // Read the lower 32 bits
64         lo = timer->timerawl;
65         // Now read the upper 32 bits again and
66         // check that it hasn't incremented. If it has loop around
67         // and read the lower 32 bits again to get an accurate value
68         uint32_t next_hi = timer->timerawh;
69         if (hi == next_hi) break;
70         hi = next_hi;
71     } while (true);
72     return ((uint64_t) hi << 32u) | lo;
73 }
74 /// end::time_us_64[]
75 
76 /// \tag::busy_wait[]
timer_busy_wait_us_32(timer_hw_t * timer,uint32_t delay_us)77 void timer_busy_wait_us_32(timer_hw_t *timer, uint32_t delay_us) {
78     if (0 <= (int32_t)delay_us) {
79         // we only allow 31 bits, otherwise we could have a race in the loop below with
80         // values very close to 2^32
81         uint32_t start = timer->timerawl;
82         while (timer->timerawl - start < delay_us) {
83             tight_loop_contents();
84         }
85     } else {
86         busy_wait_us(delay_us);
87     }
88 }
89 
timer_busy_wait_us(timer_hw_t * timer,uint64_t delay_us)90 void timer_busy_wait_us(timer_hw_t *timer, uint64_t delay_us) {
91     uint64_t base = timer_time_us_64(timer);
92     uint64_t target = base + delay_us;
93     if (target < base) {
94         target = (uint64_t)-1;
95     }
96     absolute_time_t t;
97     update_us_since_boot(&t, target);
98     timer_busy_wait_until(timer, t);
99 }
100 
timer_busy_wait_ms(timer_hw_t * timer,uint32_t delay_ms)101 void timer_busy_wait_ms(timer_hw_t *timer, uint32_t delay_ms)
102 {
103     if (delay_ms <= 0x7fffffffu / 1000) {
104         timer_busy_wait_us_32(timer, delay_ms * 1000);
105     } else {
106         timer_busy_wait_us(timer, delay_ms * 1000ull);
107     }
108 }
109 
timer_busy_wait_until(timer_hw_t * timer,absolute_time_t t)110 void timer_busy_wait_until(timer_hw_t *timer, absolute_time_t t) {
111     uint64_t target = to_us_since_boot(t);
112     uint32_t hi_target = (uint32_t)(target >> 32u);
113     uint32_t hi = timer->timerawh;
114     while (hi < hi_target) {
115         hi = timer->timerawh;
116         tight_loop_contents();
117     }
118     while (hi == hi_target && timer->timerawl < (uint32_t) target) {
119         hi = timer->timerawh;
120         tight_loop_contents();
121     }
122 }
123 /// \end::busy_wait[]
124 
time_us_64(void)125 uint64_t time_us_64(void) {
126     return timer_time_us_64(PICO_DEFAULT_TIMER_INSTANCE());
127 }
128 
busy_wait_us_32(uint32_t delay_us)129 void busy_wait_us_32(uint32_t delay_us) {
130     timer_busy_wait_us_32(PICO_DEFAULT_TIMER_INSTANCE(), delay_us);
131 }
132 
busy_wait_us(uint64_t delay_us)133 void busy_wait_us(uint64_t delay_us) {
134     timer_busy_wait_us(PICO_DEFAULT_TIMER_INSTANCE(), delay_us);
135 }
136 
busy_wait_ms(uint32_t delay_ms)137 void busy_wait_ms(uint32_t delay_ms)
138 {
139     timer_busy_wait_ms(PICO_DEFAULT_TIMER_INSTANCE(), delay_ms);
140 }
141 
busy_wait_until(absolute_time_t t)142 void busy_wait_until(absolute_time_t t) {
143     timer_busy_wait_until(PICO_DEFAULT_TIMER_INSTANCE(), t);
144 }
145 
146 /**
147  * Modification on the porting to Zephyr:
148  * Add parameter argument to enable referencing user data
149  * Publish as API.
150  */
hardware_alarm_irq_handler(void * data)151 void hardware_alarm_irq_handler(void* data) {
152     // Determine which timer this IRQ is for
153     uint irq_num = __get_current_exception() - VTABLE_FIRST_IRQ;
154     uint alarm_num = TIMER_ALARM_NUM_FROM_IRQ(irq_num);
155     check_hardware_alarm_num_param(alarm_num);
156     uint timer_num = TIMER_NUM_FROM_IRQ(irq_num);
157     timer_hw_t *timer = timer_get_instance(timer_num);
158     hardware_alarm_callback_t callback = NULL;
159 
160     spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER);
161     uint32_t save = spin_lock_blocking(lock);
162 
163     // Clear the timer IRQ (inside lock, because we check whether we have handled the IRQ yet in alarm_set by looking at the interrupt status
164     timer->intr = 1u << alarm_num;
165     // Clear any forced IRQ
166     hw_clear_bits(&timer->intf, 1u << alarm_num);
167 
168     // make sure the IRQ is still valid
169     if (timer_callbacks_pending[timer_num] & (1u << alarm_num)) {
170         // Now check whether we have a timer event to handle that isn't already obsolete (this could happen if we
171         // were already in the IRQ handler before someone else changed the timer setup
172         if (timer->timerawh >= target_hi[timer_num][alarm_num]) {
173             // we have reached the right high word as well as low word value
174             callback = alarm_callbacks[timer_num][alarm_num];
175             timer_callbacks_pending[timer_num] &= (uint8_t)~(1u << alarm_num);
176         } else {
177             // try again in 2^32 us
178             timer->alarm[alarm_num] = timer->alarm[alarm_num]; // re-arm the timer
179         }
180     }
181 
182     spin_unlock(lock, save);
183 
184     if (callback) {
185         callback(alarm_num, data);
186     }
187 }
188 
189 /**
190  * Modification on the porting to Zephyr:
191  * Don't add irq handler to interrupt vector in this function.
192  */
timer_hardware_alarm_set_callback(timer_hw_t * timer,uint alarm_num,hardware_alarm_callback_t callback)193 void timer_hardware_alarm_set_callback(timer_hw_t *timer, uint alarm_num, hardware_alarm_callback_t callback) {
194     // todo check current core owner
195     //  note this should probably be subsumed by irq_set_exclusive_handler anyway, since that
196     //  should disallow IRQ handlers on both cores
197     check_hardware_alarm_num_param(alarm_num);
198     uint timer_num = timer_get_index(timer);
199     spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER);
200     uint32_t save = spin_lock_blocking(lock);
201     if (callback) {
202         hw_set_bits(&timer->inte, 1u << alarm_num);
203         alarm_callbacks[timer_num][alarm_num] = callback;
204     } else {
205         alarm_callbacks[timer_num][alarm_num] = NULL;
206         timer_callbacks_pending[timer_num] &= (uint8_t)~(1u << alarm_num);
207     }
208     spin_unlock(lock, save);
209 }
210 
hardware_alarm_set_callback(uint alarm_num,hardware_alarm_callback_t callback)211 void hardware_alarm_set_callback(uint alarm_num, hardware_alarm_callback_t callback) {
212     timer_hardware_alarm_set_callback(PICO_DEFAULT_TIMER_INSTANCE(), alarm_num, callback);
213 }
214 
timer_hardware_alarm_set_target(timer_hw_t * timer,uint alarm_num,absolute_time_t target)215 bool timer_hardware_alarm_set_target(timer_hw_t *timer, uint alarm_num, absolute_time_t target) {
216     bool missed;
217     uint64_t now = timer_time_us_64(timer);
218     uint64_t t = to_us_since_boot(target);
219     if (now >= t) {
220         missed = true;
221     } else {
222         missed = false;
223         uint timer_num = timer_get_index(timer);
224 
225         // 1) actually set the hardware timer
226         spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER);
227         uint32_t save = spin_lock_blocking(lock);
228         uint8_t old_timer_callbacks_pending = timer_callbacks_pending[timer_num];
229         timer_callbacks_pending[timer_num] |= (uint8_t)(1u << alarm_num);
230         timer->intr = 1u << alarm_num; // clear any IRQ
231         timer->alarm[alarm_num] = (uint32_t) t;
232         // Set the alarm. Writing time should arm it
233         target_hi[timer_num][alarm_num] = (uint32_t)(t >> 32u);
234 
235         // 2) check for races
236         if (!(timer->armed & 1u << alarm_num)) {
237             // not armed, so has already fired .. IRQ must be pending (we are still under lock)
238             assert(timer->ints & 1u << alarm_num);
239         } else {
240             if (timer_time_us_64(timer) >= t) {
241                 // we are already at or past the right time; there is no point in us racing against the IRQ
242                 // we are about to generate. note however that, if there was already a timer pending before,
243                 // then we still let the IRQ fire, as whatever it was, is not handled by our setting missed=true here
244                 missed = true;
245                 if (timer_callbacks_pending[timer_num] != old_timer_callbacks_pending) {
246                     // disarm the timer
247                     timer->armed = 1u << alarm_num;
248                     // clear the IRQ...
249                     timer->intr = 1u << alarm_num;
250                     // ... including anything pending on the processor - perhaps unnecessary, but
251                     // our timer flag says we aren't expecting anything.
252                     irq_clear(timer_hardware_alarm_get_irq_num(timer, alarm_num));
253                     // and clear our flag so that if the IRQ handler is already active (because it is on
254                     // the other core) it will also skip doing anything
255                     timer_callbacks_pending[timer_num] = old_timer_callbacks_pending;
256                 }
257             }
258         }
259         spin_unlock(lock, save);
260         // note at this point any pending timer IRQ can likely run
261     }
262     return missed;
263 }
264 
hardware_alarm_set_target(uint alarm_num,absolute_time_t t)265 bool hardware_alarm_set_target(uint alarm_num, absolute_time_t t) {
266     return timer_hardware_alarm_set_target(PICO_DEFAULT_TIMER_INSTANCE(), alarm_num, t);
267 }
268 
timer_hardware_alarm_cancel(timer_hw_t * timer,uint alarm_num)269 void timer_hardware_alarm_cancel(timer_hw_t *timer, uint alarm_num) {
270     check_hardware_alarm_num_param(alarm_num);
271 
272     spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER);
273     uint32_t save = spin_lock_blocking(lock);
274     timer->armed = 1u << alarm_num;
275     timer_callbacks_pending[timer_get_index(timer)] &= (uint8_t)~(1u << alarm_num);
276     spin_unlock(lock, save);
277 }
278 
hardware_alarm_cancel(uint alarm_num)279 void hardware_alarm_cancel(uint alarm_num) {
280     timer_hardware_alarm_cancel(PICO_DEFAULT_TIMER_INSTANCE(), alarm_num);
281 }
282 
timer_hardware_alarm_force_irq(timer_hw_t * timer,uint alarm_num)283 void timer_hardware_alarm_force_irq(timer_hw_t *timer, uint alarm_num) {
284     check_hardware_alarm_num_param(alarm_num);
285     spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER);
286     uint32_t save = spin_lock_blocking(lock);
287     timer_callbacks_pending[timer_get_index(timer)] |= (uint8_t)(1u << alarm_num);
288     spin_unlock(lock, save);
289     hw_set_bits(&timer->intf, 1u << alarm_num);
290 }
291 
hardware_alarm_force_irq(uint alarm_num)292 void hardware_alarm_force_irq(uint alarm_num) {
293     timer_hardware_alarm_force_irq(PICO_DEFAULT_TIMER_INSTANCE(), alarm_num);
294 }
295