Contiki-NG
Loading...
Searching...
No Matches
nrf_802154_platform_sl_lptimer.c
1/*
2 * Copyright (c) 2026, RISE Research Institutes of Sweden AB
3 * All rights reserved.
4 *
5 * Author: Joakim Eriksson <joakim.eriksson@ri.se>
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 *
9 * Low Power Timer + SL Timer + Timer Coordinator for nrf_802154 on nRF54L15.
10 *
11 * The application core on nRF54L15 does not expose a classic RTC instance,
12 * so this backend uses TIMER20 at 1 MHz instead. The scheduling semantics
13 * preserved here -- safe compare programming, exact-vs-adjusted scheduling,
14 * pending IRQ replay after critical sections, and a dedicated hardware-task
15 * compare channel -- are inspired by Zephyr's nrf_rtc_timer.
16 */
17
18#include "nrf_802154_sl_timer.h"
19#include "platform/nrf_802154_platform_sl_lptimer.h"
20#include "timer/nrf_802154_timer_coord.h"
21#include "helpers/nrfx_gppi.h"
22#include "hal/nrf_timer.h"
23#include "nrf.h"
24
25#include <stdbool.h>
26#include <stdint.h>
27
28#define LP_TIMER NRF_TIMER20
29#define LP_TIMER_IRQn TIMER20_IRQn
30#define LP_TIMER_IRQ_PRIORITY 1
31
32#define CAPTURE_CC 0
33#define ALARM_CC 1
34#define SYNC_CC 2
35#define HW_TASK_CC 3
36
37#define COUNTER_HALF_SPAN (UINT64_C(1) << 31)
38#define COUNTER_WRAP (UINT64_C(1) << 32)
39#define MIN_TICKS_FROM_NOW 8U
40#define SYNC_MARGIN_TICKS 8U
41
42#define FORCE_MASK_ALARM (1UL << ALARM_CC)
43#define FORCE_MASK_SYNC (1UL << SYNC_CC)
44
45static volatile bool alarm_pending;
46static volatile bool sync_pending;
47static uint32_t critical_section_depth;
48static uint32_t force_isr_mask;
49
50/* Active software timers, ordered by trigger_time. */
51static nrf_802154_sl_timer_t *alarm_head;
52static uint64_t alarm_target_lpticks;
53static uint64_t sync_fire_lpticks;
54
55enum hw_task_state {
56 HW_TASK_STATE_IDLE,
57 HW_TASK_STATE_SETTING_UP,
58 HW_TASK_STATE_READY,
59 HW_TASK_STATE_UPDATING,
60 HW_TASK_STATE_CLEANING,
61};
62
63static enum hw_task_state hw_task_state;
64static uint32_t hw_task_ppi_channel = NRF_802154_SL_HW_TASK_PPI_INVALID;
65static uint64_t hw_task_fire_lpticks;
66
67static bool timer_initialized;
68static uint64_t timer_time_upper;
69static uint32_t timer_last_low;
70/*---------------------------------------------------------------------------*/
71static inline uint32_t
72irq_lock_local(void)
73{
74 uint32_t primask = __get_PRIMASK();
75
76 __disable_irq();
77 __DMB();
78
79 return primask;
80}
81/*---------------------------------------------------------------------------*/
82static inline void
83irq_unlock_local(uint32_t primask)
84{
85 __DMB();
86 __set_PRIMASK(primask);
87}
88/*---------------------------------------------------------------------------*/
89static inline nrf_802154_sl_timer_t *
90timer_next_get(nrf_802154_sl_timer_t *timer)
91{
92 return (nrf_802154_sl_timer_t *)(uintptr_t)timer->priv.placeholder[0];
93}
94/*---------------------------------------------------------------------------*/
95static inline void
96timer_next_set(nrf_802154_sl_timer_t *timer, nrf_802154_sl_timer_t *next)
97{
98 timer->priv.placeholder[0] = (uint64_t)(uintptr_t)next;
99}
100/*---------------------------------------------------------------------------*/
101static inline bool
102timer_is_active(nrf_802154_sl_timer_t *timer)
103{
104 return timer->priv.placeholder[1] != 0U;
105}
106/*---------------------------------------------------------------------------*/
107static inline void
108timer_active_set(nrf_802154_sl_timer_t *timer, bool active)
109{
110 timer->priv.placeholder[1] = active ? 1U : 0U;
111}
112/*---------------------------------------------------------------------------*/
113__attribute__((weak)) void
114nrf_802154_sl_timestamper_synchronized(void)
115{
116}
117/*---------------------------------------------------------------------------*/
118static inline bool
119hw_task_state_set_locked(enum hw_task_state expected, enum hw_task_state new_state)
120{
121 if(hw_task_state != expected) {
122 return false;
123 }
124
125 hw_task_state = new_state;
126 return true;
127}
128/*---------------------------------------------------------------------------*/
129static inline uint32_t
130timer_event_address_get(uint8_t cc_channel)
131{
132 return nrf_timer_event_address_get(LP_TIMER, nrf_timer_compare_event_get(cc_channel));
133}
134/*---------------------------------------------------------------------------*/
135static inline bool
136timer_event_check_cc(uint8_t cc_channel)
137{
138 return nrf_timer_event_check(LP_TIMER, nrf_timer_compare_event_get(cc_channel));
139}
140/*---------------------------------------------------------------------------*/
141static inline void
142timer_event_clear_cc(uint8_t cc_channel)
143{
144 nrf_timer_event_clear(LP_TIMER, nrf_timer_compare_event_get(cc_channel));
145}
146/*---------------------------------------------------------------------------*/
147static inline uint32_t
148timer_int_mask_get(uint8_t cc_channel)
149{
150 return nrf_timer_compare_int_get(cc_channel);
151}
152/*---------------------------------------------------------------------------*/
153static inline void
154timer_compare_int_enable(uint8_t cc_channel)
155{
156 nrf_timer_int_enable(LP_TIMER, timer_int_mask_get(cc_channel));
157}
158/*---------------------------------------------------------------------------*/
159static inline void
160timer_compare_int_disable(uint8_t cc_channel)
161{
162 nrf_timer_int_disable(LP_TIMER, timer_int_mask_get(cc_channel));
163}
164/*---------------------------------------------------------------------------*/
165static inline bool
166timer_compare_int_lock(uint8_t cc_channel)
167{
168 bool enabled = (nrf_timer_int_enable_check(LP_TIMER, timer_int_mask_get(cc_channel)) != 0U);
169
170 timer_compare_int_disable(cc_channel);
171 __DMB();
172 __ISB();
173
174 return enabled;
175}
176/*---------------------------------------------------------------------------*/
177static inline void
178timer_compare_int_unlock(uint8_t cc_channel, bool key)
179{
180 if(key) {
181 timer_compare_int_enable(cc_channel);
182 if(force_isr_mask & (1UL << cc_channel)) {
183 NVIC_SetPendingIRQ(LP_TIMER_IRQn);
184 }
185 }
186}
187/*---------------------------------------------------------------------------*/
188static inline uint64_t
189timer_time_get_locked(void)
190{
191 uint32_t low;
192
193 nrf_timer_task_trigger(LP_TIMER, nrf_timer_capture_task_get(CAPTURE_CC));
194 low = nrf_timer_cc_get(LP_TIMER, NRF_TIMER_CC_CHANNEL0);
195
196 if(low < timer_last_low) {
197 timer_time_upper += COUNTER_WRAP;
198 }
199
200 timer_last_low = low;
201
202 return timer_time_upper | low;
203}
204/*---------------------------------------------------------------------------*/
205static uint64_t
206timer_time_get(void)
207{
208 uint32_t primask = irq_lock_local();
209 uint64_t now = timer_time_get_locked();
210 irq_unlock_local(primask);
211 return now;
212}
213/*---------------------------------------------------------------------------*/
214static inline bool
215target_is_too_distant(uint64_t now, uint64_t target)
216{
217 return (target > now) && ((target - now) > COUNTER_HALF_SPAN);
218}
219/*---------------------------------------------------------------------------*/
220static int
221timer_compare_set_locked(uint8_t cc_channel, uint64_t target, bool exact)
222{
223 uint64_t now = timer_time_get_locked();
224
225 if(target_is_too_distant(now, target)) {
226 return -1;
227 }
228
229 if(target <= now) {
230 if(exact) {
231 return -1;
232 }
233
234 force_isr_mask |= (1UL << cc_channel);
235 timer_event_clear_cc(cc_channel);
236 return 0;
237 }
238
239 {
240 uint32_t low_now = (uint32_t)now;
241 uint32_t cc_value = (uint32_t)target;
242 uint32_t min_cc = low_now + MIN_TICKS_FROM_NOW;
243
244 if((int32_t)(cc_value - min_cc) <= 0) {
245 if(exact) {
246 return -1;
247 }
248
249 cc_value = min_cc;
250 }
251
252 force_isr_mask &= ~(1UL << cc_channel);
253 timer_event_clear_cc(cc_channel);
254 nrf_timer_cc_set(LP_TIMER, (nrf_timer_cc_channel_t)cc_channel, cc_value);
255 }
256
257 return 0;
258}
259/*---------------------------------------------------------------------------*/
260static inline bool
261hw_task_triggered_check_locked(uint64_t now)
262{
263 return timer_event_check_cc(HW_TASK_CC) || now >= hw_task_fire_lpticks;
264}
265/*---------------------------------------------------------------------------*/
266static inline void
267hw_task_ppi_bind_locked(uint32_t ppi_channel)
268{
269 if(ppi_channel == NRF_802154_SL_HW_TASK_PPI_INVALID) {
270 return;
271 }
272
273 nrfx_gppi_event_endpoint_setup((uint8_t)ppi_channel, timer_event_address_get(HW_TASK_CC));
274}
275/*---------------------------------------------------------------------------*/
276static inline void
277hw_task_ppi_unbind_locked(uint32_t ppi_channel)
278{
279 if(ppi_channel == NRF_802154_SL_HW_TASK_PPI_INVALID) {
280 return;
281 }
282
283 nrfx_gppi_event_endpoint_clear((uint8_t)ppi_channel, timer_event_address_get(HW_TASK_CC));
284}
285/*---------------------------------------------------------------------------*/
286static void
287alarm_reschedule_locked(void)
288{
289 if(alarm_head == NULL) {
290 alarm_pending = false;
291 alarm_target_lpticks = 0;
292 force_isr_mask &= ~FORCE_MASK_ALARM;
293 timer_compare_int_disable(ALARM_CC);
294 timer_event_clear_cc(ALARM_CC);
295 return;
296 }
297
298 alarm_pending = true;
299 alarm_target_lpticks = alarm_head->trigger_time;
300
301 (void)timer_compare_set_locked(ALARM_CC, alarm_target_lpticks, false);
302
303 if(critical_section_depth == 0U) {
304 timer_compare_int_enable(ALARM_CC);
305 if((force_isr_mask & FORCE_MASK_ALARM) != 0U) {
306 NVIC_SetPendingIRQ(LP_TIMER_IRQn);
307 }
308 }
309}
310/*---------------------------------------------------------------------------*/
311static void
312sync_schedule_locked(uint64_t fire_lpticks)
313{
314 sync_pending = true;
315 sync_fire_lpticks = fire_lpticks;
316
317 (void)timer_compare_set_locked(SYNC_CC, sync_fire_lpticks, false);
318
319 if(critical_section_depth == 0U) {
320 timer_compare_int_enable(SYNC_CC);
321 if((force_isr_mask & FORCE_MASK_SYNC) != 0U) {
322 NVIC_SetPendingIRQ(LP_TIMER_IRQn);
323 }
324 }
325}
326/*---------------------------------------------------------------------------*/
327static nrf_802154_sl_timer_ret_t
328timer_remove_locked(nrf_802154_sl_timer_t *timer)
329{
330 nrf_802154_sl_timer_t *prev = NULL;
331 nrf_802154_sl_timer_t *curr = alarm_head;
332
333 while(curr != NULL) {
334 if(curr == timer) {
335 nrf_802154_sl_timer_t *next = timer_next_get(curr);
336
337 if(prev == NULL) {
338 alarm_head = next;
339 } else {
340 timer_next_set(prev, next);
341 }
342
343 timer_next_set(curr, NULL);
344 timer_active_set(curr, false);
345 alarm_reschedule_locked();
346 return NRF_802154_SL_TIMER_RET_SUCCESS;
347 }
348
349 prev = curr;
350 curr = timer_next_get(curr);
351 }
352
353 return NRF_802154_SL_TIMER_RET_INACTIVE;
354}
355/*---------------------------------------------------------------------------*/
356static void
357alarm_process(void)
358{
359 while(true) {
360 nrf_802154_sl_timer_t *timer;
361 uint32_t primask = irq_lock_local();
362 uint64_t now = timer_time_get_locked();
363
364 timer = alarm_head;
365
366 if(timer == NULL) {
367 alarm_pending = false;
368 alarm_target_lpticks = 0;
369 irq_unlock_local(primask);
370 break;
371 }
372
373 if(timer->trigger_time > now) {
374 alarm_reschedule_locked();
375 irq_unlock_local(primask);
376 break;
377 }
378
379 alarm_head = timer_next_get(timer);
380 timer_next_set(timer, NULL);
381 timer_active_set(timer, false);
382 alarm_reschedule_locked();
383
384 irq_unlock_local(primask);
385
386 if((timer->action_type & NRF_802154_SL_TIMER_ACTION_TYPE_CALLBACK) &&
387 timer->action.callback.callback != NULL) {
388 timer->action.callback.callback(timer);
389 }
390 }
391}
392/*---------------------------------------------------------------------------*/
393static void
394sync_process(uint64_t now)
395{
396 if(sync_pending && now >= sync_fire_lpticks) {
397 sync_pending = false;
398 nrf_802154_sl_timestamper_synchronized();
399 }
400}
401/*---------------------------------------------------------------------------*/
402void
403TIMER20_IRQHandler(void)
404{
405 bool alarm_forced = (force_isr_mask & FORCE_MASK_ALARM) != 0U;
406 bool sync_forced = (force_isr_mask & FORCE_MASK_SYNC) != 0U;
407 bool alarm_event = timer_event_check_cc(ALARM_CC);
408 bool sync_event = timer_event_check_cc(SYNC_CC);
409
410 if(alarm_event) {
411 timer_event_clear_cc(ALARM_CC);
412 }
413 if(sync_event) {
414 timer_event_clear_cc(SYNC_CC);
415 }
416
417 force_isr_mask &= ~(FORCE_MASK_ALARM | FORCE_MASK_SYNC);
418
419 if(alarm_forced || alarm_event) {
420 alarm_process();
421 }
422
423 if(sync_forced || sync_event) {
424 sync_process(timer_time_get());
425 }
426}
427/*---------------------------------------------------------------------------*/
428void
429nrf_802154_platform_sl_lp_timer_init(void)
430{
431 uint32_t primask;
432
433 primask = irq_lock_local();
434
435 alarm_pending = false;
436 sync_pending = false;
437 critical_section_depth = 0;
438 force_isr_mask = 0;
439 alarm_target_lpticks = 0;
440 sync_fire_lpticks = 0;
441 hw_task_state = HW_TASK_STATE_IDLE;
442 hw_task_ppi_channel = NRF_802154_SL_HW_TASK_PPI_INVALID;
443 hw_task_fire_lpticks = 0;
444 timer_time_upper = 0;
445 timer_last_low = 0;
446
447 if(!timer_initialized) {
448 nrf_timer_task_trigger(LP_TIMER, NRF_TIMER_TASK_STOP);
449 nrf_timer_task_trigger(LP_TIMER, NRF_TIMER_TASK_CLEAR);
450 nrf_timer_shorts_set(LP_TIMER, 0);
451 nrf_timer_mode_set(LP_TIMER, NRF_TIMER_MODE_TIMER);
452 nrf_timer_bit_width_set(LP_TIMER, NRF_TIMER_BIT_WIDTH_32);
453 nrf_timer_prescaler_set(LP_TIMER, NRF_TIMER_FREQ_1MHz);
454
455 timer_event_clear_cc(ALARM_CC);
456 timer_event_clear_cc(SYNC_CC);
457 timer_event_clear_cc(HW_TASK_CC);
458 timer_compare_int_disable(ALARM_CC);
459 timer_compare_int_disable(SYNC_CC);
460 nrf_timer_task_trigger(LP_TIMER, NRF_TIMER_TASK_START);
461
462 NVIC_SetPriority(LP_TIMER_IRQn, LP_TIMER_IRQ_PRIORITY);
463 NVIC_ClearPendingIRQ(LP_TIMER_IRQn);
464 NVIC_EnableIRQ(LP_TIMER_IRQn);
465
466 timer_initialized = true;
467 }
468
469 irq_unlock_local(primask);
470}
471/*---------------------------------------------------------------------------*/
472void
473nrf_802154_platform_sl_lp_timer_deinit(void)
474{
475 uint32_t primask = irq_lock_local();
476
477 alarm_pending = false;
478 sync_pending = false;
479 critical_section_depth = 0;
480 force_isr_mask = 0;
481 hw_task_state = HW_TASK_STATE_IDLE;
482 hw_task_ppi_channel = NRF_802154_SL_HW_TASK_PPI_INVALID;
483 hw_task_fire_lpticks = 0;
484
485 if(timer_initialized) {
486 timer_compare_int_disable(ALARM_CC);
487 timer_compare_int_disable(SYNC_CC);
488 timer_event_clear_cc(ALARM_CC);
489 timer_event_clear_cc(SYNC_CC);
490 timer_event_clear_cc(HW_TASK_CC);
491 nrf_timer_task_trigger(LP_TIMER, NRF_TIMER_TASK_STOP);
492 nrf_timer_task_trigger(LP_TIMER, NRF_TIMER_TASK_CLEAR);
493 }
494
495 irq_unlock_local(primask);
496}
497/*---------------------------------------------------------------------------*/
498uint64_t
499nrf_802154_platform_sl_lptimer_current_lpticks_get(void)
500{
501 return timer_time_get();
502}
503/*---------------------------------------------------------------------------*/
504uint64_t
505nrf_802154_platform_sl_lptimer_us_to_lpticks_convert(uint64_t us, bool round_up)
506{
507 (void)round_up;
508 return us;
509}
510/*---------------------------------------------------------------------------*/
511uint64_t
512nrf_802154_platform_sl_lptimer_lpticks_to_us_convert(uint64_t lpticks)
513{
514 return lpticks;
515}
516/*---------------------------------------------------------------------------*/
517void
518nrf_802154_platform_sl_lptimer_schedule_at(uint64_t fire_lpticks)
519{
520 uint32_t primask = irq_lock_local();
521
522 alarm_pending = true;
523 alarm_target_lpticks = fire_lpticks;
524 (void)timer_compare_set_locked(ALARM_CC, fire_lpticks, false);
525
526 if(critical_section_depth == 0U) {
527 timer_compare_int_enable(ALARM_CC);
528 if((force_isr_mask & FORCE_MASK_ALARM) != 0U) {
529 NVIC_SetPendingIRQ(LP_TIMER_IRQn);
530 }
531 }
532
533 irq_unlock_local(primask);
534}
535/*---------------------------------------------------------------------------*/
536void
537nrf_802154_platform_sl_lptimer_disable(void)
538{
539 uint32_t primask = irq_lock_local();
540
541 alarm_pending = false;
542 alarm_target_lpticks = 0;
543 force_isr_mask &= ~FORCE_MASK_ALARM;
544 timer_compare_int_disable(ALARM_CC);
545 timer_event_clear_cc(ALARM_CC);
546
547 irq_unlock_local(primask);
548}
549/*---------------------------------------------------------------------------*/
550void
551nrf_802154_platform_sl_lptimer_critical_section_enter(void)
552{
553 uint32_t primask = irq_lock_local();
554
555 critical_section_depth++;
556
557 if(critical_section_depth == 1U) {
558 timer_compare_int_disable(ALARM_CC);
559 timer_compare_int_disable(SYNC_CC);
560 }
561
562 irq_unlock_local(primask);
563}
564/*---------------------------------------------------------------------------*/
565void
566nrf_802154_platform_sl_lptimer_critical_section_exit(void)
567{
568 uint32_t primask = irq_lock_local();
569
570 if(critical_section_depth != 0U) {
571 critical_section_depth--;
572 }
573
574 if(critical_section_depth == 0U) {
575 if(sync_pending) {
576 timer_compare_int_enable(SYNC_CC);
577 if(timer_event_check_cc(SYNC_CC) || ((force_isr_mask & FORCE_MASK_SYNC) != 0U)) {
578 NVIC_SetPendingIRQ(LP_TIMER_IRQn);
579 }
580 }
581
582 if(alarm_pending) {
583 timer_compare_int_enable(ALARM_CC);
584 if(timer_event_check_cc(ALARM_CC) || ((force_isr_mask & FORCE_MASK_ALARM) != 0U)) {
585 NVIC_SetPendingIRQ(LP_TIMER_IRQn);
586 }
587 }
588 }
589
590 irq_unlock_local(primask);
591}
592/*---------------------------------------------------------------------------*/
593nrf_802154_sl_lptimer_platform_result_t
594nrf_802154_platform_sl_lptimer_hw_task_prepare(uint64_t fire_lpticks,
595 uint32_t ppi_channel)
596{
597 uint32_t primask = irq_lock_local();
598 uint64_t now = timer_time_get_locked();
599 int rc;
600
601 if(!hw_task_state_set_locked(HW_TASK_STATE_IDLE, HW_TASK_STATE_SETTING_UP)) {
602 irq_unlock_local(primask);
603 return NRF_802154_SL_LPTIMER_PLATFORM_NO_RESOURCES;
604 }
605
606 hw_task_ppi_unbind_locked(hw_task_ppi_channel);
607 hw_task_ppi_channel = NRF_802154_SL_HW_TASK_PPI_INVALID;
608 hw_task_fire_lpticks = fire_lpticks;
609 timer_event_clear_cc(HW_TASK_CC);
610
611 if(target_is_too_distant(now, fire_lpticks)) {
612 hw_task_state = HW_TASK_STATE_IDLE;
613 irq_unlock_local(primask);
614 return NRF_802154_SL_LPTIMER_PLATFORM_TOO_DISTANT;
615 }
616
617 rc = timer_compare_set_locked(HW_TASK_CC, fire_lpticks, true);
618 if(rc != 0) {
619 hw_task_state = HW_TASK_STATE_IDLE;
620 irq_unlock_local(primask);
621 return NRF_802154_SL_LPTIMER_PLATFORM_TOO_LATE;
622 }
623
624 if(hw_task_triggered_check_locked(timer_time_get_locked())) {
625 hw_task_state = HW_TASK_STATE_IDLE;
626 irq_unlock_local(primask);
627 return NRF_802154_SL_LPTIMER_PLATFORM_TOO_LATE;
628 }
629
630 hw_task_ppi_bind_locked(ppi_channel);
631 hw_task_ppi_channel = ppi_channel;
632 hw_task_state = HW_TASK_STATE_READY;
633
634 irq_unlock_local(primask);
635
636 return NRF_802154_SL_LPTIMER_PLATFORM_SUCCESS;
637}
638/*---------------------------------------------------------------------------*/
639nrf_802154_sl_lptimer_platform_result_t
640nrf_802154_platform_sl_lptimer_hw_task_cleanup(void)
641{
642 uint32_t primask = irq_lock_local();
643
644 if(!hw_task_state_set_locked(HW_TASK_STATE_READY, HW_TASK_STATE_CLEANING)) {
645 irq_unlock_local(primask);
646 return NRF_802154_SL_LPTIMER_PLATFORM_WRONG_STATE;
647 }
648
649 timer_event_clear_cc(HW_TASK_CC);
650 hw_task_ppi_unbind_locked(hw_task_ppi_channel);
651 hw_task_ppi_channel = NRF_802154_SL_HW_TASK_PPI_INVALID;
652 hw_task_state = HW_TASK_STATE_IDLE;
653
654 irq_unlock_local(primask);
655
656 return NRF_802154_SL_LPTIMER_PLATFORM_SUCCESS;
657}
658/*---------------------------------------------------------------------------*/
659nrf_802154_sl_lptimer_platform_result_t
660nrf_802154_platform_sl_lptimer_hw_task_update_ppi(uint32_t ppi_channel)
661{
662 bool too_late;
663 uint32_t primask = irq_lock_local();
664
665 if(!hw_task_state_set_locked(HW_TASK_STATE_READY, HW_TASK_STATE_UPDATING)) {
666 irq_unlock_local(primask);
667 return NRF_802154_SL_LPTIMER_PLATFORM_WRONG_STATE;
668 }
669
670 hw_task_ppi_unbind_locked(hw_task_ppi_channel);
671 hw_task_ppi_bind_locked(ppi_channel);
672 hw_task_ppi_channel = ppi_channel;
673 too_late = hw_task_triggered_check_locked(timer_time_get_locked());
674 hw_task_state = HW_TASK_STATE_READY;
675
676 irq_unlock_local(primask);
677
678 return too_late ? NRF_802154_SL_LPTIMER_PLATFORM_TOO_LATE :
679 NRF_802154_SL_LPTIMER_PLATFORM_SUCCESS;
680}
681/*---------------------------------------------------------------------------*/
682void
683nrf_802154_platform_sl_lptimer_sync_schedule_now(void)
684{
685 uint32_t primask = irq_lock_local();
686 uint64_t now = timer_time_get_locked();
687
688 sync_schedule_locked(now + SYNC_MARGIN_TICKS);
689
690 irq_unlock_local(primask);
691}
692/*---------------------------------------------------------------------------*/
693void
694nrf_802154_platform_sl_lptimer_sync_schedule_at(uint64_t fire_lpticks)
695{
696 uint32_t primask = irq_lock_local();
697
698 sync_schedule_locked(fire_lpticks);
699
700 irq_unlock_local(primask);
701}
702/*---------------------------------------------------------------------------*/
703void
704nrf_802154_platform_sl_lptimer_sync_abort(void)
705{
706 uint32_t primask = irq_lock_local();
707
708 sync_pending = false;
709 force_isr_mask &= ~FORCE_MASK_SYNC;
710 timer_compare_int_disable(SYNC_CC);
711 timer_event_clear_cc(SYNC_CC);
712
713 irq_unlock_local(primask);
714}
715/*---------------------------------------------------------------------------*/
716uint32_t
717nrf_802154_platform_sl_lptimer_sync_event_get(void)
718{
719 return timer_event_address_get(SYNC_CC);
720}
721/*---------------------------------------------------------------------------*/
722uint64_t
723nrf_802154_platform_sl_lptimer_sync_lpticks_get(void)
724{
725 return sync_fire_lpticks;
726}
727/*---------------------------------------------------------------------------*/
728uint32_t
729nrf_802154_platform_sl_lptimer_granularity_get(void)
730{
731 return 1U;
732}
733/*---------------------------------------------------------------------------*/
734void
735nrf_802154_sl_timer_module_init(void)
736{
737 alarm_head = NULL;
738 nrf_802154_platform_sl_lp_timer_init();
739}
740/*---------------------------------------------------------------------------*/
741void
742nrf_802154_sl_timer_module_uninit(void)
743{
744 alarm_head = NULL;
745}
746/*---------------------------------------------------------------------------*/
747uint64_t
748nrf_802154_sl_timer_current_time_get(void)
749{
750 return timer_time_get();
751}
752/*---------------------------------------------------------------------------*/
753void
754nrf_802154_sl_timer_init(nrf_802154_sl_timer_t *p_timer)
755{
756 timer_next_set(p_timer, NULL);
757 timer_active_set(p_timer, false);
758}
759/*---------------------------------------------------------------------------*/
760void
761nrf_802154_sl_timer_deinit(nrf_802154_sl_timer_t *p_timer)
762{
763 (void)nrf_802154_sl_timer_remove(p_timer);
764}
765/*---------------------------------------------------------------------------*/
766nrf_802154_sl_timer_ret_t
767nrf_802154_sl_timer_add(nrf_802154_sl_timer_t *p_timer)
768{
769 uint32_t primask = irq_lock_local();
770 nrf_802154_sl_timer_t *prev = NULL;
771 nrf_802154_sl_timer_t *curr = alarm_head;
772 uint64_t now = timer_time_get_locked();
773
774 if(target_is_too_distant(now, p_timer->trigger_time)) {
775 irq_unlock_local(primask);
776 return NRF_802154_SL_TIMER_RET_TOO_DISTANT;
777 }
778
779 if(timer_is_active(p_timer)) {
780 (void)timer_remove_locked(p_timer);
781 }
782
783 while(curr != NULL && curr->trigger_time <= p_timer->trigger_time) {
784 prev = curr;
785 curr = timer_next_get(curr);
786 }
787
788 timer_next_set(p_timer, curr);
789 timer_active_set(p_timer, true);
790
791 if(prev == NULL) {
792 alarm_head = p_timer;
793 alarm_reschedule_locked();
794 } else {
795 timer_next_set(prev, p_timer);
796 }
797
798 irq_unlock_local(primask);
799
800 return NRF_802154_SL_TIMER_RET_SUCCESS;
801}
802/*---------------------------------------------------------------------------*/
803nrf_802154_sl_timer_ret_t
804nrf_802154_sl_timer_remove(nrf_802154_sl_timer_t *p_timer)
805{
806 nrf_802154_sl_timer_ret_t ret;
807 uint32_t primask = irq_lock_local();
808
809 ret = timer_remove_locked(p_timer);
810
811 irq_unlock_local(primask);
812
813 return ret;
814}
815/*---------------------------------------------------------------------------*/
816nrf_802154_sl_timer_ret_t
817nrf_802154_sl_timer_update_ppi(nrf_802154_sl_timer_t *p_timer, uint32_t ppi_chn)
818{
819 (void)p_timer;
820 (void)ppi_chn;
821 return NRF_802154_SL_TIMER_RET_SUCCESS;
822}
823/*---------------------------------------------------------------------------*/
824void
825nrf_802154_timer_coord_init(void)
826{
827}
828/*---------------------------------------------------------------------------*/
829void
830nrf_802154_timer_coord_uninit(void)
831{
832}
833/*---------------------------------------------------------------------------*/
834void
835nrf_802154_timer_coord_start(void)
836{
837}
838/*---------------------------------------------------------------------------*/
839void
840nrf_802154_timer_coord_stop(void)
841{
842}
843/*---------------------------------------------------------------------------*/
844void
845nrf_802154_timer_coord_timestamp_prepare(const nrf_802154_sl_event_handle_t *p_event)
846{
847 (void)p_event;
848}
849/*---------------------------------------------------------------------------*/
850bool
851nrf_802154_timer_coord_timestamp_get(uint64_t *p_timestamp)
852{
853 (void)p_timestamp;
854 return false;
855}
856/*---------------------------------------------------------------------------*/
A timer.
Definition timer.h:84