1 /*
2 * Copyright (c) 2017 Oticon A/S
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <string.h>
7 #include <stdbool.h>
8 #include "time_machine_if.h"
9 #include "NRF_TIMER.h"
10 #include "NRF_HW_model_top.h"
11 #include "NRF_PPI.h"
12 #include "irq_ctrl.h"
13 #include "bs_tracing.h"
14
15 /*
16 * TIMER — Timer/counter
17 * https://infocenter.nordicsemi.com/topic/ps_nrf52833/timer.html?cp=4_1_0_5_27
18 */
19
20 /**
21 * Notes:
22 * * Counter mode is not fully supported (no CC match check)
23 * * For simplicity all 5 Timers have 6 functional CC registers
24 * In reality, Timers0-2 have only 4 CC registers, events and TASKS_CAPTURE
25 * * The functionality of TASK_SHUTDOWN is a bit of a guess
26 */
27
28 #define N_TIMERS 5
29 #define N_CC 6
30 NRF_TIMER_Type NRF_TIMER_regs[N_TIMERS];
31
32 static uint32_t TIMER_INTEN[N_TIMERS] = {0};
33 static bool Timer_running[N_TIMERS] = {false};
34
35 static bs_time_t Timer_counter_startT[N_TIMERS] = {TIME_NEVER}; //Time when the counter was started
36 static uint32_t Counter[N_TIMERS] = {0}; //Used in count mode, and in Timer mode during stops
37
38 bs_time_t Timer_TIMERs = TIME_NEVER;
39 static bs_time_t CC_timers[N_TIMERS][N_CC] = {{TIME_NEVER}};
40
41 /**
42 * Initialize the TIMER model
43 */
nrf_hw_model_timer_init()44 void nrf_hw_model_timer_init(){
45 memset(NRF_TIMER_regs, 0, sizeof(NRF_TIMER_regs));
46 for (int t = 0; t < N_TIMERS ; t++ ){
47 TIMER_INTEN[t] = 0;
48 Timer_running[t] = false;
49 Timer_counter_startT[t] = TIME_NEVER;
50 Counter[t] = 0;
51 for ( int cc = 0 ; cc < N_CC ; cc++){
52 CC_timers[t][cc] = TIME_NEVER;
53 }
54 }
55 Timer_TIMERs = TIME_NEVER;
56 }
57
58 /**
59 * Clean up the TIMER model before program exit
60 */
nrf_hw_model_timer_clean_up()61 void nrf_hw_model_timer_clean_up(){
62
63 }
64
65 /**
66 * Convert a time delta in us to the equivalent count accounting for the PRESCALER
67 */
time_to_counter(bs_time_t delta,int t)68 static uint32_t time_to_counter(bs_time_t delta, int t){
69 uint64_t ticks;
70 ticks = ( delta << 4 ) >> NRF_TIMER_regs[t].PRESCALER;
71 return ticks;
72 }
73
74 /**
75 * Convert a counter delta to us accounting for the PRESCALER
76 */
counter_to_time(uint64_t counter,int t)77 static bs_time_t counter_to_time(uint64_t counter, int t){
78 bs_time_t Elapsed;
79 Elapsed = ( counter << NRF_TIMER_regs[t].PRESCALER ) >> 4;
80 return Elapsed;
81 }
82
83 /**
84 * Return the counter mask (due to BITMODE) for this TIMER<t>
85 */
mask_from_bitmode(int t)86 static uint32_t mask_from_bitmode(int t){
87 switch (NRF_TIMER_regs[t].BITMODE){
88 case 0:
89 return 0xFFFF;
90 break;
91 case 1:
92 return 0xFF;
93 break;
94 case 2:
95 return 0xFFFFFF;
96 break;
97 default:
98 return 0xFFFFFFFF;
99 break;
100 }
101 }
102
103 /**
104 * Return the time in us it takes for the COUNTER to do 1 wrap
105 * given BITMODE
106 */
time_of_1_counter_wrap(int t)107 static uint64_t time_of_1_counter_wrap(int t){
108 return counter_to_time( (uint64_t)mask_from_bitmode(t) + 1,t);
109 }
110
111 /**
112 * Find the CC register timer (CC_timers[][]) which will trigger earliest (if any)
113 */
update_master_timer()114 static void update_master_timer(){
115 Timer_TIMERs = TIME_NEVER;
116 for ( int t = 0 ; t < N_TIMERS ; t++){
117 if ( ( Timer_running[t] == true ) && ( NRF_TIMER_regs[t].MODE == 0 ) ) {
118 for ( int cc = 0 ; cc < N_CC ; cc++){
119 if ( CC_timers[t][cc] < Timer_TIMERs ){
120 Timer_TIMERs = CC_timers[t][cc];
121 }
122 }
123 }
124 }
125 nrf_hw_find_next_timer_to_trigger();
126 }
127
128
129 /**
130 * Save in CC_timers[t][cc] the next time when this timer will match the CC[cc]
131 * register
132 */
update_cc_timer(int t,int cc)133 static void update_cc_timer(int t, int cc){
134 if ( ( Timer_running[t] == true ) && ( NRF_TIMER_regs[t].MODE == 0 ) ) {
135 bs_time_t next_match = Timer_counter_startT[t]
136 + counter_to_time(NRF_TIMER_regs[t].CC[cc], t);
137 while ( next_match <= tm_get_hw_time() ){
138 next_match += time_of_1_counter_wrap(t);
139 }
140 CC_timers[t][cc] = next_match;
141 } else {
142 CC_timers[t][cc] = TIME_NEVER;
143 }
144 }
145
update_all_cc_timers(int t)146 static void update_all_cc_timers(int t){
147 for (int cc = 0 ; cc < N_CC; cc++){
148 update_cc_timer(t,cc);
149 }
150 }
151
nrf_timer_TASK_START(int t)152 void nrf_timer_TASK_START(int t){
153 //Note: STATUS is missing in NRF_TIMER_Type
154 if ( Timer_running[t] == false ) {
155 Timer_running[t] = true;
156 if ( NRF_TIMER_regs[t].MODE == 0 ){ //Timer mode
157 Timer_counter_startT[t] = tm_get_hw_time() - counter_to_time(Counter[t], t); //If the counter is not zero at start, is like if the counter was started earlier
158 update_all_cc_timers(t);
159 update_master_timer();
160 }
161 }
162 }
163
nrf_timer0_TASK_START()164 void nrf_timer0_TASK_START() { nrf_timer_TASK_START(0); }
nrf_timer1_TASK_START()165 void nrf_timer1_TASK_START() { nrf_timer_TASK_START(1); }
nrf_timer2_TASK_START()166 void nrf_timer2_TASK_START() { nrf_timer_TASK_START(2); }
nrf_timer3_TASK_START()167 void nrf_timer3_TASK_START() { nrf_timer_TASK_START(3); }
nrf_timer4_TASK_START()168 void nrf_timer4_TASK_START() { nrf_timer_TASK_START(4); }
169
nrf_timer_TASK_STOP(int t)170 void nrf_timer_TASK_STOP(int t){
171 //Note: STATUS is missing in NRF_TIMER_Type
172 if (Timer_running[t] == true) {
173 Timer_running[t] = false;
174 Counter[t] = time_to_counter(tm_get_hw_time() - Timer_counter_startT[t], t); //we save the value when the counter was stoped in case it is started again without clearing it
175 for (int cc = 0 ; cc < N_CC ; cc++){
176 CC_timers[t][cc] = TIME_NEVER;
177 }
178 update_master_timer();
179 }
180 }
181
nrf_timer_TASK_SHUTDOWN(int t)182 void nrf_timer_TASK_SHUTDOWN(int t){
183 /*
184 * TASK_SHUTDOWN is not documented in newer SOCs
185 * In older ones it indicates it STOPS + it reduces power consumption
186 * but that it cannot be resumed after from where it was
187 * The assumption is that the internal count is lost/reset to 0
188 * Effectively making a SHUTDOWN logically equivalent to a STOP + CLEAR
189 */
190 //Note: STATUS is missing in NRF_TIMER_Type
191 Timer_running[t] = false;
192 Counter[t] = 0;
193 Timer_counter_startT[t] = TIME_NEVER;
194 for (int cc = 0 ; cc < N_CC ; cc++){
195 CC_timers[t][cc] = TIME_NEVER;
196 }
197 update_master_timer();
198 }
199
nrf_timer0_TASK_STOP()200 void nrf_timer0_TASK_STOP() { nrf_timer_TASK_STOP(0); }
nrf_timer1_TASK_STOP()201 void nrf_timer1_TASK_STOP() { nrf_timer_TASK_STOP(1); }
nrf_timer2_TASK_STOP()202 void nrf_timer2_TASK_STOP() { nrf_timer_TASK_STOP(2); }
nrf_timer3_TASK_STOP()203 void nrf_timer3_TASK_STOP() { nrf_timer_TASK_STOP(3); }
nrf_timer4_TASK_STOP()204 void nrf_timer4_TASK_STOP() { nrf_timer_TASK_STOP(4); }
205
nrf_timer_TASK_CAPTURE(int t,int cc_n)206 void nrf_timer_TASK_CAPTURE(int t, int cc_n){
207 if ( NRF_TIMER_regs[t].MODE != 0 ){ //Count mode
208 NRF_TIMER_regs[t].CC[cc_n] = Counter[t] & mask_from_bitmode(t);
209 } else { //Timer mode:
210 if ( Timer_counter_startT[t] == TIME_NEVER ){
211 bs_trace_warning_line_time("NRF HW TIMER%i TASK_CAPTURE[%i] "
212 "trigered on a timer which was never "
213 "started => you get garbage\n", t, cc_n);
214 }
215 bs_time_t Elapsed = tm_get_hw_time() - Timer_counter_startT[t];
216 NRF_TIMER_regs[t].CC[cc_n] = time_to_counter(Elapsed,t) & mask_from_bitmode(t);
217
218 //The new CC causes a new possible CC match time:
219 update_cc_timer(t, cc_n);
220 update_master_timer();
221 }
222 }
223
nrf_timer0_TASK_CAPTURE_0()224 void nrf_timer0_TASK_CAPTURE_0() { nrf_timer_TASK_CAPTURE(0,0); }
nrf_timer0_TASK_CAPTURE_1()225 void nrf_timer0_TASK_CAPTURE_1() { nrf_timer_TASK_CAPTURE(0,1); }
nrf_timer0_TASK_CAPTURE_2()226 void nrf_timer0_TASK_CAPTURE_2() { nrf_timer_TASK_CAPTURE(0,2); }
nrf_timer0_TASK_CAPTURE_3()227 void nrf_timer0_TASK_CAPTURE_3() { nrf_timer_TASK_CAPTURE(0,3); }
nrf_timer0_TASK_CAPTURE_4()228 void nrf_timer0_TASK_CAPTURE_4() { nrf_timer_TASK_CAPTURE(0,4); }
nrf_timer0_TASK_CAPTURE_5()229 void nrf_timer0_TASK_CAPTURE_5() { nrf_timer_TASK_CAPTURE(0,5); }
230
nrf_timer1_TASK_CAPTURE_0()231 void nrf_timer1_TASK_CAPTURE_0() { nrf_timer_TASK_CAPTURE(1,0); }
nrf_timer1_TASK_CAPTURE_1()232 void nrf_timer1_TASK_CAPTURE_1() { nrf_timer_TASK_CAPTURE(1,1); }
nrf_timer1_TASK_CAPTURE_2()233 void nrf_timer1_TASK_CAPTURE_2() { nrf_timer_TASK_CAPTURE(1,2); }
nrf_timer1_TASK_CAPTURE_3()234 void nrf_timer1_TASK_CAPTURE_3() { nrf_timer_TASK_CAPTURE(1,3); }
nrf_timer1_TASK_CAPTURE_4()235 void nrf_timer1_TASK_CAPTURE_4() { nrf_timer_TASK_CAPTURE(1,4); }
nrf_timer1_TASK_CAPTURE_5()236 void nrf_timer1_TASK_CAPTURE_5() { nrf_timer_TASK_CAPTURE(1,5); }
237
nrf_timer2_TASK_CAPTURE_0()238 void nrf_timer2_TASK_CAPTURE_0() { nrf_timer_TASK_CAPTURE(2,0); }
nrf_timer2_TASK_CAPTURE_1()239 void nrf_timer2_TASK_CAPTURE_1() { nrf_timer_TASK_CAPTURE(2,1); }
nrf_timer2_TASK_CAPTURE_2()240 void nrf_timer2_TASK_CAPTURE_2() { nrf_timer_TASK_CAPTURE(2,2); }
nrf_timer2_TASK_CAPTURE_3()241 void nrf_timer2_TASK_CAPTURE_3() { nrf_timer_TASK_CAPTURE(2,3); }
nrf_timer2_TASK_CAPTURE_4()242 void nrf_timer2_TASK_CAPTURE_4() { nrf_timer_TASK_CAPTURE(2,4); }
nrf_timer2_TASK_CAPTURE_5()243 void nrf_timer2_TASK_CAPTURE_5() { nrf_timer_TASK_CAPTURE(2,5); }
244
nrf_timer3_TASK_CAPTURE_0()245 void nrf_timer3_TASK_CAPTURE_0() { nrf_timer_TASK_CAPTURE(3,0); }
nrf_timer3_TASK_CAPTURE_1()246 void nrf_timer3_TASK_CAPTURE_1() { nrf_timer_TASK_CAPTURE(3,1); }
nrf_timer3_TASK_CAPTURE_2()247 void nrf_timer3_TASK_CAPTURE_2() { nrf_timer_TASK_CAPTURE(3,2); }
nrf_timer3_TASK_CAPTURE_3()248 void nrf_timer3_TASK_CAPTURE_3() { nrf_timer_TASK_CAPTURE(3,3); }
nrf_timer3_TASK_CAPTURE_4()249 void nrf_timer3_TASK_CAPTURE_4() { nrf_timer_TASK_CAPTURE(3,4); }
nrf_timer3_TASK_CAPTURE_5()250 void nrf_timer3_TASK_CAPTURE_5() { nrf_timer_TASK_CAPTURE(3,5); }
251
nrf_timer4_TASK_CAPTURE_0()252 void nrf_timer4_TASK_CAPTURE_0() { nrf_timer_TASK_CAPTURE(4,0); }
nrf_timer4_TASK_CAPTURE_1()253 void nrf_timer4_TASK_CAPTURE_1() { nrf_timer_TASK_CAPTURE(4,1); }
nrf_timer4_TASK_CAPTURE_2()254 void nrf_timer4_TASK_CAPTURE_2() { nrf_timer_TASK_CAPTURE(4,2); }
nrf_timer4_TASK_CAPTURE_3()255 void nrf_timer4_TASK_CAPTURE_3() { nrf_timer_TASK_CAPTURE(4,3); }
nrf_timer4_TASK_CAPTURE_4()256 void nrf_timer4_TASK_CAPTURE_4() { nrf_timer_TASK_CAPTURE(4,4); }
nrf_timer4_TASK_CAPTURE_5()257 void nrf_timer4_TASK_CAPTURE_5() { nrf_timer_TASK_CAPTURE(4,5); }
258
nrf_timer_TASK_CLEAR(int t)259 void nrf_timer_TASK_CLEAR(int t) {
260 Counter[t] = 0;
261 if (NRF_TIMER_regs[t].MODE == 0) {
262 //Timer mode:
263 Timer_counter_startT[t] = tm_get_hw_time();
264 update_all_cc_timers(t);
265 update_master_timer();
266 }
267 }
268
nrf_timer0_TASK_CLEAR()269 void nrf_timer0_TASK_CLEAR() { nrf_timer_TASK_CLEAR(0); }
nrf_timer1_TASK_CLEAR()270 void nrf_timer1_TASK_CLEAR() { nrf_timer_TASK_CLEAR(1); }
nrf_timer2_TASK_CLEAR()271 void nrf_timer2_TASK_CLEAR() { nrf_timer_TASK_CLEAR(2); }
nrf_timer3_TASK_CLEAR()272 void nrf_timer3_TASK_CLEAR() { nrf_timer_TASK_CLEAR(3); }
nrf_timer4_TASK_CLEAR()273 void nrf_timer4_TASK_CLEAR() { nrf_timer_TASK_CLEAR(4); }
274
nrf_timer_TASK_COUNT(int t)275 void nrf_timer_TASK_COUNT(int t){
276 if ( ( NRF_TIMER_regs[t].MODE != 0 ) && ( Timer_running[t] == true ) ){ //Count mode
277 Counter[t]++;
278 //TODO: check for possible compare match
279 } //Otherwise ignored
280 }
281
nrf_timer0_TASK_COUNT()282 void nrf_timer0_TASK_COUNT() { nrf_timer_TASK_COUNT(0); }
nrf_timer1_TASK_COUNT()283 void nrf_timer1_TASK_COUNT() { nrf_timer_TASK_COUNT(1); }
nrf_timer2_TASK_COUNT()284 void nrf_timer2_TASK_COUNT() { nrf_timer_TASK_COUNT(2); }
nrf_timer3_TASK_COUNT()285 void nrf_timer3_TASK_COUNT() { nrf_timer_TASK_COUNT(3); }
nrf_timer4_TASK_COUNT()286 void nrf_timer4_TASK_COUNT() { nrf_timer_TASK_COUNT(4); }
287
nrf_timer_regw_sideeffects_TASKS_START(int t)288 void nrf_timer_regw_sideeffects_TASKS_START(int t){
289 if ( NRF_TIMER_regs[t].TASKS_START ){
290 NRF_TIMER_regs[t].TASKS_START = 0;
291 nrf_timer_TASK_START(t);
292 }
293 }
294
nrf_timer_regw_sideeffects_TASKS_STOP(int t)295 void nrf_timer_regw_sideeffects_TASKS_STOP(int t) {
296 if (NRF_TIMER_regs[t].TASKS_STOP) {
297 NRF_TIMER_regs[t].TASKS_STOP = 0;
298 nrf_timer_TASK_STOP(t);
299 }
300 }
301
nrf_timer_regw_sideeffects_TASKS_SHUTDOWN(int t)302 void nrf_timer_regw_sideeffects_TASKS_SHUTDOWN(int t) {
303 if (NRF_TIMER_regs[t].TASKS_SHUTDOWN) {
304 NRF_TIMER_regs[t].TASKS_SHUTDOWN = 0;
305 nrf_timer_TASK_SHUTDOWN(t);
306 }
307 }
308
nrf_timer_regw_sideeffects_TASKS_CAPTURE(int t,int cc_n)309 void nrf_timer_regw_sideeffects_TASKS_CAPTURE(int t, int cc_n){
310 if ( NRF_TIMER_regs[t].TASKS_CAPTURE[cc_n] ){
311 NRF_TIMER_regs[t].TASKS_CAPTURE[cc_n] = 0;
312 nrf_timer_TASK_CAPTURE(t,cc_n);
313 }
314 }
315
nrf_timer_regw_sideeffects_TASKS_CLEAR(int t)316 void nrf_timer_regw_sideeffects_TASKS_CLEAR(int t) {
317 if (NRF_TIMER_regs[t].TASKS_CLEAR) {
318 NRF_TIMER_regs[t].TASKS_CLEAR = 0;
319 nrf_timer_TASK_CLEAR(t);
320 }
321 }
322
nrf_timer_regw_sideeffects_TASKS_COUNT(int t)323 void nrf_timer_regw_sideeffects_TASKS_COUNT(int t){
324 if ( NRF_TIMER_regs[t].TASKS_COUNT ){
325 NRF_TIMER_regs[t].TASKS_COUNT = 0;
326 nrf_timer_TASK_COUNT(t);
327 }
328 }
329
nrf_timer_regw_sideeffects_INTENSET(int t)330 void nrf_timer_regw_sideeffects_INTENSET(int t){
331 if ( NRF_TIMER_regs[t].INTENSET ){
332 TIMER_INTEN[t] |= NRF_TIMER_regs[t].INTENSET;
333 NRF_TIMER_regs[t].INTENSET = TIMER_INTEN[t];
334 }
335 }
336
nrf_timer_regw_sideeffects_INTENCLR(int t)337 void nrf_timer_regw_sideeffects_INTENCLR(int t){
338 if ( NRF_TIMER_regs[t].INTENCLR ){
339 TIMER_INTEN[t] &= ~NRF_TIMER_regs[t].INTENCLR;
340 NRF_TIMER_regs[t].INTENSET = TIMER_INTEN[t];
341 NRF_TIMER_regs[t].INTENCLR = 0;
342 }
343 }
344
nrf_timer_regw_sideeffects_CC(int t,int cc_n)345 void nrf_timer_regw_sideeffects_CC(int t, int cc_n){
346 if ( (Timer_running[t] == true) && ( NRF_TIMER_regs[t].MODE == 0 ) ) {
347 update_cc_timer(t, cc_n);
348 update_master_timer();
349 }
350 }
351
nrf_hw_model_timer_timer_triggered()352 void nrf_hw_model_timer_timer_triggered() {
353 for ( int t = 0 ; t < N_TIMERS ; t++) {
354 if ( !(( Timer_running[t] == true ) && ( NRF_TIMER_regs[t].MODE == 0 )) ) {
355 continue;
356 }
357 for ( int cc = 0 ; cc < N_CC ; cc++) {
358 if ( CC_timers[t][cc] != Timer_TIMERs ){ //This CC is not matching now
359 continue;
360 }
361
362 update_cc_timer(t,cc); //Next time it will match
363
364 if ( NRF_TIMER_regs[t].SHORTS & (TIMER_SHORTS_COMPARE0_CLEAR_Msk << cc) ) {
365 nrf_timer_TASK_CLEAR(t);
366 }
367 if ( NRF_TIMER_regs[t].SHORTS & (TIMER_SHORTS_COMPARE0_STOP_Msk << cc) ) {
368 nrf_timer_TASK_STOP(t);
369 }
370
371 NRF_TIMER_regs[t].EVENTS_COMPARE[cc] = 1;
372
373 ppi_event_types_t event_cc;
374 switch (t) {
375 case 0:
376 event_cc = TIMER0_EVENTS_COMPARE_0;
377 break;
378 case 1:
379 event_cc = TIMER1_EVENTS_COMPARE_0;
380 break;
381 case 2:
382 event_cc = TIMER2_EVENTS_COMPARE_0;
383 break;
384 case 3:
385 event_cc = TIMER3_EVENTS_COMPARE_0;
386 break;
387 case 4:
388 default: /* Just to silence a -Werror=maybe-uninitialized warning */
389 event_cc = TIMER4_EVENTS_COMPARE_0;
390 break;
391 }
392
393 nrf_ppi_event(event_cc + cc);
394
395 if ( TIMER_INTEN[t] & (TIMER_INTENSET_COMPARE0_Msk << cc) ){
396 int irq = TIMER0_IRQn;
397 switch (t){
398 case 0:
399 irq = TIMER0_IRQn;
400 break;
401 case 1:
402 irq = TIMER1_IRQn;
403 break;
404 case 2:
405 irq = TIMER2_IRQn;
406 break;
407 case 3:
408 irq = TIMER3_IRQn;
409 break;
410 case 4:
411 irq = TIMER4_IRQn;
412 break;
413 default:
414 bs_trace_error_line_time("NRF HW TIMER%i CC[%i] interrupt "
415 "triggered but there is no interrupt "
416 "mapped for it\n", t, cc);
417 break;
418 }
419 hw_irq_ctrl_set_irq(irq);
420 } //if interrupt enabled
421
422 } //for cc
423 }//for t(imer)
424 update_master_timer();
425 }
426