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