1 /*
2 * Copyright (c) 2017 Oticon A/S
3 * Copyright (c) 2023 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 /**
9 * This is a model of a fake HW device which is used by the k_busy_wait() function
10 * replacement. It is a timer which will awake the embedded CPU even if interrupts are
11 * locked (it does not have an associated irq vector, it simply awakes the CPU)
12 *
13 * N instances of this timer are present, one for each embedded CPU.
14 */
15
16 #include "bs_types.h"
17 #include "irq_ctrl.h"
18 #include "nsi_hw_scheduler.h"
19 #include "nsi_tasks.h"
20 #include "nsi_hws_models_if.h"
21 #include "NHW_common_types.h"
22 #include "NHW_config.h"
23
24 struct ftimer_status_t {
25 bs_time_t event_time;
26 };
27
28 static bs_time_t Timer_fake_timer = TIME_NEVER;
29 /* Mapping of peripheral instance to {int controller instance, int number} */
30 static struct nhw_irq_mapping nhw_faketimer_irq_map[NHW_FAKE_TIMER_TOTAL_INST] = NHW_FAKE_TIMER_INT_MAP;
31 static struct ftimer_status_t ftimer_st[NHW_FAKE_TIMER_TOTAL_INST];
32
33 /*
34 * Initialize all fake timer instances for this SOC
35 */
nhw_fake_timer_init(void)36 static void nhw_fake_timer_init(void)
37 {
38 for (int i = 0; i < NHW_FAKE_TIMER_TOTAL_INST ; i++ ) {
39 ftimer_st[i].event_time = TIME_NEVER;
40 }
41 }
42
43 NSI_TASK(nhw_fake_timer_init, HW_INIT, 10);
44
nhw_fake_timer_update_main_timer(void)45 static void nhw_fake_timer_update_main_timer(void)
46 {
47 Timer_fake_timer = ftimer_st[0].event_time;
48
49 #if (NHW_FAKE_TIMER_TOTAL_INST > 1)
50 for (int i = 1; i < NHW_FAKE_TIMER_TOTAL_INST ; i++ ) {
51 if (ftimer_st[i].event_time < Timer_fake_timer){
52 Timer_fake_timer = ftimer_st[i].event_time;
53 }
54 }
55 #endif
56
57 nsi_hws_find_next_event();
58 }
59
60 /**
61 * The timer HW will awake the CPU (without an interrupt) at least when <time>
62 * comes (it may awake it earlier)
63 *
64 * If there was a previous request for an earlier time, the old one will prevail
65 *
66 * This is meant for k_busy_wait() like functionality
67 */
nhw_fake_timer_wake_in_time(unsigned int inst,bs_time_t time)68 void nhw_fake_timer_wake_in_time(unsigned int inst, bs_time_t time)
69 {
70 if (ftimer_st[inst].event_time > time) {
71 ftimer_st[inst].event_time = time;
72 nhw_fake_timer_update_main_timer();
73 }
74 }
75
nhw_fake_timer_triggered(void)76 static void nhw_fake_timer_triggered(void)
77 {
78 for (int i = 0; i < NHW_FAKE_TIMER_TOTAL_INST ; i++ ) {
79 if (Timer_fake_timer >= ftimer_st[i].event_time) {
80 ftimer_st[i].event_time = TIME_NEVER;
81 hw_irq_ctrl_set_irq(nhw_faketimer_irq_map[i].cntl_inst,
82 PHONY_HARD_IRQ);
83 }
84 }
85
86 nhw_fake_timer_update_main_timer();
87 }
88
89 NSI_HW_EVENT(Timer_fake_timer, nhw_fake_timer_triggered, 0 /* Purposely the first */);
90