1 /*
2  * Copyright (c) 2020 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdbool.h>
8 #include <stdint.h>
9 #include "hw_models_top.h"
10 #include "board_soc.h"
11 #include "board_irq.h"
12 #include "irq_ctrl.h"
13 
14 uint64_t hw_counter_timer;
15 
16 static bool counter_running;
17 static uint64_t counter_value;
18 static uint64_t counter_target;
19 static uint64_t counter_period;
20 static uint64_t counter_wrap;
21 
22 /**
23  * Initialize the counter with prescaler of HW
24  */
hw_counter_init(void)25 void hw_counter_init(void)
26 {
27 	hw_counter_timer = NEVER;
28 	counter_target = NEVER;
29 	counter_value = 0;
30 	counter_running = false;
31 	counter_period = NEVER;
32 	counter_wrap = NEVER;
33 }
34 
hw_counter_triggered(void)35 void hw_counter_triggered(void)
36 {
37 	if (!counter_running) {
38 		hw_counter_timer = NEVER;
39 		return;
40 	}
41 
42 	hw_counter_timer = hwm_get_time() + counter_period;
43 	counter_value = (counter_value + 1) % counter_wrap;
44 
45 	if (counter_value == counter_target) {
46 		hw_irq_ctrl_set_irq(COUNTER_EVENT_IRQ);
47 	}
48 }
49 
50 /**
51  * Configures the counter period.
52  * The counter will be incremented every 'period' microseconds.
53  */
hw_counter_set_period(uint64_t period)54 void hw_counter_set_period(uint64_t period)
55 {
56 	counter_period = period;
57 }
58 
59 /*
60  * Set the count value at which the counter will wrap
61  * The counter will count up to  (counter_wrap-1), i.e.:
62  * 0, 1, 2,.., (counter_wrap - 1), 0
63  */
hw_counter_set_wrap_value(uint64_t wrap_value)64 void hw_counter_set_wrap_value(uint64_t wrap_value)
65 {
66 	counter_wrap = wrap_value;
67 }
68 
69 /**
70  * Starts the counter. It must be previously configured with
71  * hw_counter_set_period() and hw_counter_set_target().
72  */
hw_counter_start(void)73 void hw_counter_start(void)
74 {
75 	if (counter_running) {
76 		return;
77 	}
78 
79 	counter_running = true;
80 
81 	hw_counter_timer = hwm_get_time() + counter_period;
82 	hwm_find_next_timer();
83 }
84 
85 /**
86  * Stops the counter at current value.
87  * On the next call to hw_counter_start, the counter will
88  * start from the value at which it was stopped.
89  */
hw_counter_stop(void)90 void hw_counter_stop(void)
91 {
92 	counter_running = false;
93 	hw_counter_timer = NEVER;
94 	hwm_find_next_timer();
95 }
96 
hw_counter_is_started(void)97 bool hw_counter_is_started(void)
98 {
99 	return counter_running;
100 }
101 
102 /**
103  * Returns the current counter value.
104  */
hw_counter_get_value(void)105 uint64_t hw_counter_get_value(void)
106 {
107 	return counter_value;
108 }
109 
110 /**
111  * Resets the counter value.
112  */
hw_counter_reset(void)113 void hw_counter_reset(void)
114 {
115 	counter_value = 0;
116 }
117 
118 /**
119  * Configures the counter to generate an interrupt
120  * when its count value reaches target.
121  */
hw_counter_set_target(uint64_t target)122 void hw_counter_set_target(uint64_t target)
123 {
124 	counter_target = target;
125 }
126