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_TIMERS];
15 static uint32_t target_hi[NUM_TIMERS];
16 static uint8_t timer_callbacks_pending;
17 
18 static_assert(NUM_TIMERS <= 4, "");
19 static uint8_t claimed;
20 
hardware_alarm_claim(uint alarm_num)21 void hardware_alarm_claim(uint alarm_num) {
22     check_hardware_alarm_num_param(alarm_num);
23     hw_claim_or_assert(&claimed, alarm_num, "Hardware alarm %d already claimed");
24 }
25 
hardware_alarm_unclaim(uint alarm_num)26 void hardware_alarm_unclaim(uint alarm_num) {
27     check_hardware_alarm_num_param(alarm_num);
28     hw_claim_clear(&claimed, alarm_num);
29 }
30 
hardware_alarm_is_claimed(uint alarm_num)31 bool hardware_alarm_is_claimed(uint alarm_num) {
32     check_hardware_alarm_num_param(alarm_num);
33     return hw_is_claimed(&claimed, alarm_num);
34 }
35 
hardware_alarm_claim_unused(bool required)36 int hardware_alarm_claim_unused(bool required) {
37     return hw_claim_unused_from_range(&claimed, required, 0, NUM_TIMERS - 1, "No timers available");
38 }
39 
40 /// tag::time_us_64[]
time_us_64()41 uint64_t time_us_64() {
42     // Need to make sure that the upper 32 bits of the timer
43     // don't change, so read that first
44     uint32_t hi = timer_hw->timerawh;
45     uint32_t lo;
46     do {
47         // Read the lower 32 bits
48         lo = timer_hw->timerawl;
49         // Now read the upper 32 bits again and
50         // check that it hasn't incremented. If it has loop around
51         // and read the lower 32 bits again to get an accurate value
52         uint32_t next_hi = timer_hw->timerawh;
53         if (hi == next_hi) break;
54         hi = next_hi;
55     } while (true);
56     return ((uint64_t) hi << 32u) | lo;
57 }
58 /// end::time_us_64[]
59 
60 /// \tag::busy_wait[]
busy_wait_us_32(uint32_t delay_us)61 void busy_wait_us_32(uint32_t delay_us) {
62     if (0 <= (int32_t)delay_us) {
63         // we only allow 31 bits, otherwise we could have a race in the loop below with
64         // values very close to 2^32
65         uint32_t start = timer_hw->timerawl;
66         while (timer_hw->timerawl - start < delay_us) {
67             tight_loop_contents();
68         }
69     } else {
70         busy_wait_us(delay_us);
71     }
72 }
73 
busy_wait_us(uint64_t delay_us)74 void busy_wait_us(uint64_t delay_us) {
75     uint64_t base = time_us_64();
76     uint64_t target = base + delay_us;
77     if (target < base) {
78         target = (uint64_t)-1;
79     }
80     absolute_time_t t;
81     update_us_since_boot(&t, target);
82     busy_wait_until(t);
83 }
84 
busy_wait_ms(uint32_t delay_ms)85 void busy_wait_ms(uint32_t delay_ms)
86 {
87     if (delay_ms <= 0x7fffffffu / 1000) {
88         busy_wait_us_32(delay_ms * 1000);
89     } else {
90         busy_wait_us(delay_ms * 1000ull);
91     }
92 }
93 
busy_wait_until(absolute_time_t t)94 void busy_wait_until(absolute_time_t t) {
95     uint64_t target = to_us_since_boot(t);
96     uint32_t hi_target = (uint32_t)(target >> 32u);
97     uint32_t hi = timer_hw->timerawh;
98     while (hi < hi_target) {
99         hi = timer_hw->timerawh;
100         tight_loop_contents();
101     }
102     while (hi == hi_target && timer_hw->timerawl < (uint32_t) target) {
103         hi = timer_hw->timerawh;
104         tight_loop_contents();
105     }
106 }
107 /// \end::busy_wait[]
108 
harware_alarm_irq_number(uint alarm_num)109 static inline uint harware_alarm_irq_number(uint alarm_num) {
110     return TIMER_IRQ_0 + alarm_num;
111 }
112 
hardware_alarm_irq_handler(void)113 static void hardware_alarm_irq_handler(void) {
114     // Determine which timer this IRQ is for
115     uint alarm_num = __get_current_exception() - VTABLE_FIRST_IRQ - TIMER_IRQ_0;
116     check_hardware_alarm_num_param(alarm_num);
117 
118     hardware_alarm_callback_t callback = NULL;
119 
120     spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER);
121     uint32_t save = spin_lock_blocking(lock);
122     // 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
123     timer_hw->intr = 1u << alarm_num;
124     // Clear any forced IRQ
125     hw_clear_bits(&timer_hw->intf, 1u << alarm_num);
126 
127     // make sure the IRQ is still valid
128     if (timer_callbacks_pending & (1u << alarm_num)) {
129         // Now check whether we have a timer event to handle that isn't already obsolete (this could happen if we
130         // were already in the IRQ handler before someone else changed the timer setup
131         if (timer_hw->timerawh >= target_hi[alarm_num]) {
132             // we have reached the right high word as well as low word value
133             callback = alarm_callbacks[alarm_num];
134             timer_callbacks_pending &= (uint8_t)~(1u << alarm_num);
135         } else {
136             // try again in 2^32 us
137             timer_hw->alarm[alarm_num] = timer_hw->alarm[alarm_num]; // re-arm the timer
138         }
139     }
140 
141     spin_unlock(lock, save);
142 
143     if (callback) {
144         callback(alarm_num);
145     }
146 }
147 
hardware_alarm_set_callback(uint alarm_num,hardware_alarm_callback_t callback)148 void hardware_alarm_set_callback(uint alarm_num, hardware_alarm_callback_t callback) {
149     // todo check current core owner
150     //  note this should probably be subsumed by irq_set_exclusive_handler anyway, since that
151     //  should disallow IRQ handlers on both cores
152     check_hardware_alarm_num_param(alarm_num);
153     uint irq_num = harware_alarm_irq_number(alarm_num);
154     spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER);
155     uint32_t save = spin_lock_blocking(lock);
156     if (callback) {
157         if (hardware_alarm_irq_handler != irq_get_vtable_handler(irq_num)) {
158             // note that set_exclusive will silently allow you to set the handler to the same thing
159             // since it is idempotent, which means we don't need to worry about locking ourselves
160             irq_set_exclusive_handler(irq_num, hardware_alarm_irq_handler);
161             irq_set_enabled(irq_num, true);
162             // Enable interrupt in block and at processor
163             hw_set_bits(&timer_hw->inte, 1u << alarm_num);
164         }
165         alarm_callbacks[alarm_num] = callback;
166     } else {
167         alarm_callbacks[alarm_num] = NULL;
168         timer_callbacks_pending &= (uint8_t)~(1u << alarm_num);
169         irq_remove_handler(irq_num, hardware_alarm_irq_handler);
170         irq_set_enabled(irq_num, false);
171     }
172     spin_unlock(lock, save);
173 }
174 
hardware_alarm_set_target(uint alarm_num,absolute_time_t target)175 bool hardware_alarm_set_target(uint alarm_num, absolute_time_t target) {
176     bool missed;
177     uint64_t now = time_us_64();
178     uint64_t t = to_us_since_boot(target);
179     if (now >= t) {
180         missed = true;
181     } else {
182         missed = false;
183 
184         // 1) actually set the hardware timer
185         spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER);
186         uint32_t save = spin_lock_blocking(lock);
187         uint8_t old_timer_callbacks_pending = timer_callbacks_pending;
188         timer_callbacks_pending |= (uint8_t)(1u << alarm_num);
189         timer_hw->intr = 1u << alarm_num; // clear any IRQ
190         timer_hw->alarm[alarm_num] = (uint32_t) t;
191         // Set the alarm. Writing time should arm it
192         target_hi[alarm_num] = (uint32_t)(t >> 32u);
193 
194         // 2) check for races
195         if (!(timer_hw->armed & 1u << alarm_num)) {
196             // not armed, so has already fired .. IRQ must be pending (we are still under lock)
197             assert(timer_hw->ints & 1u << alarm_num);
198         } else {
199             if (time_us_64() >= t) {
200                 // we are already at or past the right time; there is no point in us racing against the IRQ
201                 // we are about to generate. note however that, if there was already a timer pending before,
202                 // then we still let the IRQ fire, as whatever it was, is not handled by our setting missed=true here
203                 missed = true;
204                 if (timer_callbacks_pending != old_timer_callbacks_pending) {
205                     // disarm the timer
206                     timer_hw->armed = 1u << alarm_num;
207                     // clear the IRQ...
208                     timer_hw->intr = 1u << alarm_num;
209                     // ... including anything pending on the processor - perhaps unnecessary, but
210                     // our timer flag says we aren't expecting anything.
211                     irq_clear(harware_alarm_irq_number(alarm_num));
212                     // and clear our flag so that if the IRQ handler is already active (because it is on
213                     // the other core) it will also skip doing anything
214                     timer_callbacks_pending = old_timer_callbacks_pending;
215                 }
216             }
217         }
218         spin_unlock(lock, save);
219         // note at this point any pending timer IRQ can likely run
220     }
221     return missed;
222 }
223 
hardware_alarm_cancel(uint alarm_num)224 void hardware_alarm_cancel(uint alarm_num) {
225     check_hardware_alarm_num_param(alarm_num);
226 
227     spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER);
228     uint32_t save = spin_lock_blocking(lock);
229     timer_hw->armed = 1u << alarm_num;
230     timer_callbacks_pending &= (uint8_t)~(1u << alarm_num);
231     spin_unlock(lock, save);
232 }
233 
hardware_alarm_force_irq(uint alarm_num)234 void hardware_alarm_force_irq(uint alarm_num) {
235     check_hardware_alarm_num_param(alarm_num);
236     spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_TIMER);
237     uint32_t save = spin_lock_blocking(lock);
238     timer_callbacks_pending |= (uint8_t)(1u << alarm_num);
239     spin_unlock(lock, save);
240     hw_set_bits(&timer_hw->intf, 1u << alarm_num);
241 }