1 /*
2  * Copyright (c) 2024, Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /*
8  * GRTC - Global real-time counter
9  *
10  * This file provides the implementation of the nRF54 GRTC peripherals,
11  * (and initialize it at startup and frees it on exit),
12  * as described in the configuration (NHW_config.h)
13  *
14  * Each GRTC instance has a configurable number of compare capture (CC) registers,
15  * and interrupts (and domains).
16  *
17  * Note1: The GRTC (and its SYSCOUNTER) does NOT go to sleep.
18  *        And similarly there is no model of the low frequency/power
19  *        counter mechanism.
20  *        Note that, if everything is configured correctly, SW should
21  *        not notice this in practice.
22  *        So, KEEPRUNNING, TIMEOUT, WAKETIME & MODE.AUTOEN are ignored/irrelevant;
23  *        EVENTS_SYSCOUNTERVALID is set as soon as the GRTC is started and never
24  *        cleared to 0 by HW.
25  *        SYSCOUNTERH.BUSY always reads as 0.
26  *
27  *        TASK_STOP and TASK_CLEAR are not really modeled:
28  *        In the real counter STOPPING it (stopping the low freq. part), and trying to
29  *        interact with the high frequency part will cause trouble.
30  *        But there should be no real need or point of doing so. So we don't model
31  *        the weird behavior that can follow.
32  *        Similarly there is no real point of clearing it beyond reseting the
33  *        count before starting it (we assume the counter is started either
34  *        only once, or STARTed after CLEARing it).
35  *
36  * Note2: There is no model of the PWM functionality.
37  *        Its registers and tasks are just ignored.
38  *        EVENTS_PWMPERIODEND is not generated.
39  *
40  * Note3: There is no clock output functionality model.
41  *        Its related registers are just ignored.
42  *
43  * Note4: Split security and ownership are not modeled.
44  *        Everything is accessible from any MCU/owner and from any security
45  *        state without any constrain.
46  *
47  * Note5: The GRTC does not automatically start the LFCLK, it is just assumed started
48  *
49  * Note6: Unlike in real HW, TASK_START is immediate
50  *
51  */
52 
53 
54 #include <string.h>
55 #include <stdint.h>
56 #include "nsi_hw_scheduler.h"
57 #include "nsi_tasks.h"
58 #include "nsi_hws_models_if.h"
59 #include "bs_tracing.h"
60 #include "bs_oswrap.h"
61 #include "NHW_common_types.h"
62 #include "NHW_config.h"
63 #include "NHW_peri_types.h"
64 #include "NHW_DPPI.h"
65 #include "NHW_templates.h"
66 #include "irq_ctrl.h"
67 
68 struct grtc_status {
69   NRF_GRTC_Type *NRF_GRTC_regs;
70 
71   uint n_cc;  /* Number of CC registers */
72   uint n_domains;  /* Number of "domains" (owners) */
73 
74   uint n_int;  /* Number of interrupts */
75   struct nhw_irq_mapping *int_map; //[n_int]
76   bool *int_line_level; //[n_int]
77 
78   uint dppi_map;   //To which DPPI instance are this GRTC subscribe&publish ports connected to
79   //Which of the subscription ports are currently connected, and to which channel:
80   struct nhw_subsc_mem* subscribed;   //[n_cc]
81 
82   bool rt_counter_running;
83   bs_time_t GRTC_start_time;
84 
85   uint64_t SYSCOUNTER;
86   bs_time_t *SYSCOUNTER_read_deadline; /* Last microsecond before the SYSCOUNTERL would have wrapped*/
87 
88   bs_time_t *CC_timers; //[n_CCs] When each compare match is expected to happen
89 };
90 
91 static bs_time_t Timer_GRTC = TIME_NEVER;
92 static struct grtc_status nhw_grtc_st;
93 NRF_GRTC_Type NRF_GRTC_regs;
94 
95 static const ptrdiff_t grtc_int_pdiff = offsetof(NRF_GRTC_Type, INTENSET1) - offsetof(NRF_GRTC_Type, INTENSET0);
96 
97 static void nhw_GRTC_update_SYSCOUNTER(uint inst);
98 static void nhw_GRTC_update_master_timer(void);
99 static void nhw_GRTC_update_cc_timer(uint inst, int cc);
100 static void nhw_GRTC_update_all_cc_timers(uint inst);
101 
102 /**
103  * Initialize the GRTC model
104  */
nhw_grtc_init(void)105 static void nhw_grtc_init(void) {
106   /* Mapping of peripheral instance to DPPI instance */
107   const uint nhw_grtc_n_cc = NHW_GRTC_N_CC;
108   const uint nhw_GRTC_n_domains = NHW_GRTC_N_DOMAINS;
109   const uint nhw_GRTC_n_int = NHW_GRTC_N_INT;
110   struct nhw_irq_mapping nhw_GRTC_int_map[] = NHW_GRTC_INT_MAP;
111   const uint nhw_GRTC_dppi_map = NHW_GRTC_DPPI_MAP;
112 
113   memset(&NRF_GRTC_regs, 0, sizeof(NRF_GRTC_Type));
114   NRF_GRTC_regs.WAKETIME = GRTC_WAKETIME_ResetValue;
115 #if (NHW_GRTC_HAS_CLKOUT)
116   NRF_GRTC_regs.CLKCFG = GRTC_CLKCFG_ResetValue;
117 #endif
118 
119   nhw_grtc_st.NRF_GRTC_regs = &NRF_GRTC_regs;
120   nhw_grtc_st.n_cc = nhw_grtc_n_cc;
121   nhw_grtc_st.n_domains = nhw_GRTC_n_domains;
122   nhw_grtc_st.n_int = nhw_GRTC_n_int;
123   nhw_grtc_st.int_map = (struct nhw_irq_mapping *)bs_calloc(nhw_grtc_st.n_int, sizeof(struct nhw_irq_mapping));
124   memcpy(nhw_grtc_st.int_map, nhw_GRTC_int_map, sizeof(struct nhw_irq_mapping) * nhw_grtc_st.n_int);
125   nhw_grtc_st.int_line_level = (bool *)bs_calloc(nhw_grtc_st.n_int, sizeof(bool));
126   nhw_grtc_st.dppi_map = nhw_GRTC_dppi_map;
127   nhw_grtc_st.subscribed = (struct nhw_subsc_mem*)bs_calloc(nhw_grtc_n_cc, sizeof(struct nhw_subsc_mem));
128   nhw_grtc_st.rt_counter_running = false;
129   nhw_grtc_st.GRTC_start_time = 0;
130   nhw_grtc_st.SYSCOUNTER_read_deadline = (bs_time_t *)bs_calloc(nhw_grtc_st.n_domains, sizeof(bs_time_t));
131 
132 
133   nhw_grtc_st.CC_timers = (bs_time_t *)bs_calloc(nhw_grtc_st.n_cc, sizeof(bs_time_t));
134 
135   nhw_GRTC_update_all_cc_timers(0);
136 
137   nhw_GRTC_update_master_timer();
138 }
139 
140 NSI_TASK(nhw_grtc_init, HW_INIT, 100);
141 
142 /*
143  * Free all GRTC instances resources before program exit
144  */
nhw_grtc_free(void)145 static void nhw_grtc_free(void)
146 {
147   free(nhw_grtc_st.int_map);
148   nhw_grtc_st.int_map = NULL;
149   free(nhw_grtc_st.int_line_level);
150   nhw_grtc_st.int_line_level = NULL;
151   free(nhw_grtc_st.subscribed);
152   nhw_grtc_st.subscribed = NULL;
153   free(nhw_grtc_st.SYSCOUNTER_read_deadline);
154   nhw_grtc_st.SYSCOUNTER_read_deadline = NULL;
155   free(nhw_grtc_st.CC_timers);
156   nhw_grtc_st.CC_timers = NULL;
157 }
158 
159 NSI_TASK(nhw_grtc_free, ON_EXIT_PRE, 100);
160 
nhw_GRTC_check_valid_cc_index(uint inst,uint nbr,const char * type)161 static inline void nhw_GRTC_check_valid_cc_index(uint inst, uint nbr, const char *type)
162 {
163   if ((inst >= NHW_GRTC_TOTAL_INST) || (nbr >= nhw_grtc_st.n_cc) ) {
164     bs_trace_error_time_line("Attempted to access non existent %s %u (>= %u CC channels) in GRTC instance %u\n",
165                              type, nbr, nhw_grtc_st.n_cc, inst);
166   }
167 }
168 
nhw_GRTC_check_valid_irq_index(uint inst,uint nbr,const char * type)169 static inline void nhw_GRTC_check_valid_irq_index(uint inst, uint nbr, const char *type)
170 {
171   if ((inst >= NHW_GRTC_TOTAL_INST) || (nbr >= nhw_grtc_st.n_int) ) {
172     bs_trace_error_time_line("Attempted to access non existent %s %u (>= %u irqs) in GRTC instance %u\n",
173                              type, nbr, nhw_grtc_st.n_int, inst);
174   }
175 }
176 
nhw_GRTC_check_valid_domain_index(uint inst,uint nbr,const char * type)177 static inline void nhw_GRTC_check_valid_domain_index(uint inst, uint nbr, const char *type)
178 {
179   if ((inst >= NHW_GRTC_TOTAL_INST) || (nbr >= nhw_grtc_st.n_domains) ) {
180     bs_trace_error_time_line("Attempted to access non existent %s %u (>= %u domains) in GRTC instance %u\n",
181                              type, nbr, nhw_grtc_st.n_domains, inst);
182   }
183 }
184 
185 
nhw_GRTC_counter_to_time(uint inst,uint64_t value)186 static bs_time_t nhw_GRTC_counter_to_time(uint inst, uint64_t value) {
187   (void) inst;
188   return value + nhw_grtc_st.GRTC_start_time;
189 }
190 
191 /**
192  * Find the CC register timer (CC_timers[][]) which will trigger earliest (if any)
193  */
nhw_GRTC_update_master_timer(void)194 static void nhw_GRTC_update_master_timer(void) {
195   Timer_GRTC = TIME_NEVER;
196 
197   for (int cc = 0 ; cc < nhw_grtc_st.n_cc ; cc++) {
198     if (nhw_grtc_st.CC_timers[cc] < Timer_GRTC) {
199       Timer_GRTC = nhw_grtc_st.CC_timers[cc];
200     }
201   }
202   nsi_hws_find_next_event();
203 }
204 
205 /**
206  * Save in CC_timers[cc] when the GRTC SYSCOUNTER will match the CC[cc]
207  * register (the event/match condition is CC[cc] <= SYSCOUNTER)
208  */
nhw_GRTC_update_cc_timer(uint inst,int cc)209 static void nhw_GRTC_update_cc_timer(uint inst, int cc) {
210   (void) inst;
211   if (NRF_GRTC_regs.CC[cc].CCEN) {
212     uint64_t cc_value = ((uint64_t)NRF_GRTC_regs.CC[cc].CCH << 32) | NRF_GRTC_regs.CC[cc].CCL;
213     nhw_grtc_st.CC_timers[cc] = nhw_GRTC_counter_to_time(inst, cc_value);
214     if (nhw_grtc_st.CC_timers[cc] < nsi_hws_get_time()) {
215       nhw_grtc_st.CC_timers[cc] = nsi_hws_get_time();
216     }
217   } else {
218     nhw_grtc_st.CC_timers[cc] = TIME_NEVER;
219   }
220 }
221 
nhw_GRTC_update_all_cc_timers(uint inst)222 static void nhw_GRTC_update_all_cc_timers(uint inst) {
223   for (int cc = 0 ; cc < nhw_grtc_st.n_cc; cc++) {
224     nhw_GRTC_update_cc_timer(inst, cc);
225   }
226 }
227 
228 /**
229  * Check if any interrupt line for the GRTC needs to be raised or lowered
230  * (as a result of either the interrupt mask or the event register having
231  * been modified)
232  */
nhw_GRTC_eval_interrupt(uint inst)233 static void nhw_GRTC_eval_interrupt(uint inst)
234 {
235   (void) inst;
236   struct grtc_status *this = &nhw_grtc_st;
237   uint32_t *INTEN;
238   uint32_t *INTPEND;
239 
240   for (int irql = 0; irql < this->n_int; irql++) {
241     uint32_t event_bitmask = 0;
242     bool new_line_level;
243     INTEN =  (uint32_t *)((uintptr_t)&NRF_GRTC_regs.INTEN0 + irql*grtc_int_pdiff);
244     INTPEND= (uint32_t *)((uintptr_t)&NRF_GRTC_regs.INTPEND0 + irql*grtc_int_pdiff);
245 
246     for (int i = 0; i < this->n_cc; i++) {
247       if (NRF_GRTC_regs.EVENTS_COMPARE[i]) {
248         event_bitmask |= 1<<i;
249       }
250     }
251     if (NRF_GRTC_regs.EVENTS_SYSCOUNTERVALID) {
252       event_bitmask |= GRTC_INTENSET0_SYSCOUNTERVALID_Msk;
253     }
254 #if (NHW_GRTC_HAS_PWM)
255     if (NRF_GRTC_regs.EVENTS_PWMPERIODEND) {
256       event_bitmask |= GRTC_INTENSET0_PWMPERIODEND_Msk;
257     }
258 #endif
259     *INTPEND = event_bitmask & *INTEN;
260 
261     new_line_level = (*INTPEND != 0);
262 
263     hw_irq_ctrl_toggle_level_irq_line_if(&nhw_grtc_st.int_line_level[irql],
264                                          new_line_level,
265                                          &this->int_map[irql]);
266   }
267 }
268 
nhw_GRTC_signal_EVENTS_COMPARE(uint inst,uint n)269 static void nhw_GRTC_signal_EVENTS_COMPARE(uint inst, uint n) {
270   NRF_GRTC_regs.EVENTS_COMPARE[n] = 1;
271   nhw_GRTC_eval_interrupt(inst);
272 
273   nhw_dppi_event_signal_if(nhw_grtc_st.dppi_map,
274                            NRF_GRTC_regs.PUBLISH_COMPARE[n]);
275 }
276 
nhw_GRTC_signal_EVENTS_SYSCOUNTERVALID(uint inst)277 static void nhw_GRTC_signal_EVENTS_SYSCOUNTERVALID(uint inst) {
278   NRF_GRTC_regs.EVENTS_SYSCOUNTERVALID = 1;
279   nhw_GRTC_eval_interrupt(inst);
280   /* Not connected to DPPI */
281 }
282 
283 #if (NHW_GRTC_HAS_PWM)
284 //(Unused so far)
285 //static void nhw_GRTC_signal_EVENTS_PWMPERIODEND(uint inst) {
286 //  NRF_GRTC_regs.EVENTS_PWMPERIODEND = 1;
287 //  nhw_GRTC_eval_interrupt(inst);
288 //  /* Not connected to DPPI */
289 //}
290 #endif
291 
nhw_GRTC_TASK_START(uint inst)292 static void nhw_GRTC_TASK_START(uint inst) {
293   (void) inst;
294   nhw_grtc_st.rt_counter_running = true;
295   /* We assume the GRTC is started only once, or started after clearing */
296   nhw_grtc_st.GRTC_start_time = nsi_hws_get_time();
297 
298   nhw_GRTC_signal_EVENTS_SYSCOUNTERVALID(inst);
299 }
300 
nhw_GRTC_TASK_STOP(uint inst)301 static void nhw_GRTC_TASK_STOP(uint inst) {
302   (void) inst;
303   nhw_grtc_st.rt_counter_running = false;
304   bs_trace_warning_time_line("GRTC TASK_STOP is not properly supported.\n");
305 }
306 
nhw_GRTC_TASK_CLEAR(uint inst)307 static void nhw_GRTC_TASK_CLEAR(uint inst) {
308   (void) inst;
309   /* In real HW this would clear the RTCOUNTER.
310    * Here we do nothing, hoping that if it is called
311    * it is done while the counter is stopped */
312   if (nhw_grtc_st.rt_counter_running) {
313     bs_trace_warning_time_line("GRTC models, TASK_CLEAR not supported while GRTC is running\n");
314   }
315 }
316 
317 #if (NHW_GRTC_HAS_PWM)
nhw_GRTC_TASK_PWMSTART(uint inst)318 static void nhw_GRTC_TASK_PWMSTART(uint inst) {
319   /* Not modeled */
320   (void) inst;
321 }
322 
nhw_GRTC_TASK_PWMSTOP(uint inst)323 static void nhw_GRTC_TASK_PWMSTOP(uint inst) {
324   /* Not modeled */
325   (void) inst;
326 }
327 #endif
328 
nhw_GRTC_get_SYNCOUNTERL(uint inst)329 static inline uint32_t nhw_GRTC_get_SYNCOUNTERL(uint inst) {
330   (void) inst;
331   return nhw_grtc_st.SYSCOUNTER & UINT32_MAX;
332 }
333 
nhw_GRTC_get_counterhighword(uint64_t value)334 static inline uint32_t nhw_GRTC_get_counterhighword(uint64_t value) {
335   return (value >> 32) & (UINT32_MAX >> BS_MIN(64 - NHW_GRTC_SYSCOUNTER_BW, 32));
336 }
337 
nhw_GRTC_get_SYNCOUNTERH(uint inst)338 static inline uint32_t nhw_GRTC_get_SYNCOUNTERH(uint inst) {
339   (void) inst;
340   return nhw_GRTC_get_counterhighword(nhw_grtc_st.SYSCOUNTER);
341 }
342 
nhw_GRTC_TASK_CAPTURE(uint inst,uint n)343 static void nhw_GRTC_TASK_CAPTURE(uint inst, uint n) {
344   NRF_GRTC_regs.CC[n].CCEN = 0; /* Trigger the capture task disables the compare feature */
345   nhw_GRTC_update_cc_timer(inst, n);
346   nhw_GRTC_update_master_timer();
347 
348   nhw_GRTC_update_SYSCOUNTER(inst);
349   NRF_GRTC_regs.CC[n].CCL = nhw_GRTC_get_SYNCOUNTERL(inst);
350   NRF_GRTC_regs.CC[n].CCH = nhw_GRTC_get_SYNCOUNTERH(inst);
351 }
352 
353 NHW_SIDEEFFECTS_TASKS(GRTC, NRF_GRTC_regs., START)
354 NHW_SIDEEFFECTS_TASKS(GRTC, NRF_GRTC_regs., STOP)
355 NHW_SIDEEFFECTS_TASKS(GRTC, NRF_GRTC_regs., CLEAR)
356 #if (NHW_GRTC_HAS_PWM)
357 NHW_SIDEEFFECTS_TASKS(GRTC, NRF_GRTC_regs., PWMSTART)
358 NHW_SIDEEFFECTS_TASKS(GRTC, NRF_GRTC_regs., PWMSTOP)
359 #endif
360 
nhw_GRTC_regw_sideeffects_TASKS_CAPTURE(uint inst,uint n)361 void nhw_GRTC_regw_sideeffects_TASKS_CAPTURE(uint inst, uint n) {
362   if (NRF_GRTC_regs.TASKS_CAPTURE[n]) {
363     NRF_GRTC_regs.TASKS_CAPTURE[n] = 0;
364     nhw_GRTC_TASK_CAPTURE(inst, n);
365   }
366 }
367 
nhw_GRTC_taskcapture_wrap(void * param)368 static void nhw_GRTC_taskcapture_wrap(void* param) {
369   unsigned int inst = (uintptr_t)param >> 16;
370   uint cc_n = (uintptr_t)param & 0xFFFF;
371   nhw_GRTC_TASK_CAPTURE(inst, cc_n);
372 }
373 
nhw_GRTC_regw_sideeffects_SUBSCRIBE_CAPTURE(uint inst,uint cc_n)374 void nhw_GRTC_regw_sideeffects_SUBSCRIBE_CAPTURE(uint inst, uint cc_n) {
375   struct grtc_status *this = &nhw_grtc_st;
376 
377   nhw_GRTC_check_valid_cc_index(inst, cc_n, "SUBSCRIBE_CAPTURE");
378 
379   nhw_dppi_common_subscribe_sideeffect(this->dppi_map,
380                                        this->NRF_GRTC_regs->SUBSCRIBE_CAPTURE[cc_n],
381                                        &this->subscribed[cc_n],
382                                        nhw_GRTC_taskcapture_wrap,
383                                        (void*)((inst << 16) + cc_n));
384 }
385 
nhw_GRTC_regw_sideeffects_INTEN(uint inst,uint n)386 void nhw_GRTC_regw_sideeffects_INTEN(uint inst, uint n) {
387   nhw_GRTC_check_valid_irq_index(inst, n, "INTEN");
388 
389   uint32_t *INTENSET = (uint32_t *)((uintptr_t)&NRF_GRTC_regs.INTENSET0 + n*grtc_int_pdiff);
390   uint32_t *INTEN    = (uint32_t *)((uintptr_t)&NRF_GRTC_regs.INTEN0    + n*grtc_int_pdiff);
391 
392   *INTENSET = *INTEN;
393   nhw_GRTC_eval_interrupt(inst);
394 }
395 
nhw_GRTC_regw_sideeffects_INTENSET(uint inst,uint n)396 void nhw_GRTC_regw_sideeffects_INTENSET(uint inst, uint n) {
397   nhw_GRTC_check_valid_irq_index(inst, n, "INTENSET");
398 
399   uint32_t *INTENSET = (uint32_t *)((uintptr_t)&NRF_GRTC_regs.INTENSET0 + n*grtc_int_pdiff);
400   uint32_t *INTEN    = (uint32_t *)((uintptr_t)&NRF_GRTC_regs.INTEN0    + n*grtc_int_pdiff);
401 
402   if (*INTENSET) {
403     *INTEN   |= *INTENSET;
404     *INTENSET = *INTEN;
405     nhw_GRTC_eval_interrupt(inst);
406   }
407 }
408 
nhw_GRTC_regw_sideeffects_INTENCLR(uint inst,uint n)409 void nhw_GRTC_regw_sideeffects_INTENCLR(uint inst, uint n) {
410   nhw_GRTC_check_valid_irq_index(inst, n, "INTENCLR");
411 
412   uint32_t *INTENSET = (uint32_t *)((uintptr_t)&NRF_GRTC_regs.INTENSET0 + n*grtc_int_pdiff);
413   uint32_t *INTENCLR = (uint32_t *)((uintptr_t)&NRF_GRTC_regs.INTENCLR0 + n*grtc_int_pdiff);
414   uint32_t *INTEN    = (uint32_t *)((uintptr_t)&NRF_GRTC_regs.INTEN0    + n*grtc_int_pdiff);
415 
416   if (*INTENCLR) {
417     *INTEN   &= ~*INTENCLR;
418     *INTENSET = *INTEN;
419     *INTENCLR = 0; //We do not model reading the INTEN register thru the INTENCLR one
420     nhw_GRTC_eval_interrupt(inst);
421   }
422 }
423 
NHW_SIDEEFFECTS_EVENTS(GRTC)424 NHW_SIDEEFFECTS_EVENTS(GRTC)
425 
426 static void nhw_GRTC_update_SYSCOUNTER(uint inst) {
427   nhw_grtc_st.SYSCOUNTER = nsi_hws_get_time() - nhw_grtc_st.GRTC_start_time;
428 }
429 
nhw_GRTC_check_syscounter_en(uint inst,const char * msg)430 static void nhw_GRTC_check_syscounter_en(uint inst, const char *msg) {
431   if (!nhw_grtc_st.rt_counter_running) {
432     bs_trace_warning_time_line("The RT counter was not started while trying to %s\n", msg);
433     return;
434   }
435   if (!(NRF_GRTC_regs.MODE & GRTC_MODE_SYSCOUNTEREN_Msk)) {
436     bs_trace_warning_time_line("MODE.SYSCOUNTER was not enabled while trying to %s\n", msg);
437   }
438   return;
439 }
440 
nhw_GRTC_regr_sideeffects_SYSCOUNTERL(uint inst,uint n)441 uint32_t nhw_GRTC_regr_sideeffects_SYSCOUNTERL(uint inst, uint n)
442 {
443   nhw_GRTC_check_syscounter_en(inst, "read SYSCOUNTERL");
444   nhw_GRTC_check_valid_domain_index(inst, n, "SYSCOUNTERL");
445   nhw_GRTC_update_SYSCOUNTER(inst);
446   uint32_t value = nhw_GRTC_get_SYNCOUNTERL(inst);
447   uint64_t remain = (uint64_t)UINT32_MAX - value;
448 
449   nhw_grtc_st.SYSCOUNTER_read_deadline[n] = nsi_hws_get_time() + remain;
450 
451   NRF_GRTC_regs.SYSCOUNTER[n].SYSCOUNTERL = value;
452 
453   return value;
454 }
455 
nhw_GRTC_regr_sideeffects_SYSCOUNTERH(uint inst,uint n)456 uint32_t nhw_GRTC_regr_sideeffects_SYSCOUNTERH(uint inst, uint n)
457 {
458   nhw_GRTC_check_syscounter_en(inst, "read SYSCOUNTERH");
459   nhw_GRTC_check_valid_domain_index(inst, n, "SYSCOUNTERH");
460   nhw_GRTC_update_SYSCOUNTER(inst);
461   uint32_t value = nhw_GRTC_get_SYNCOUNTERH(inst);
462 
463   //Check for SYSCOUNTERL "wrap":
464   bs_time_t now = nsi_hws_get_time();
465   if (now > nhw_grtc_st.SYSCOUNTER_read_deadline[n]) {
466     value |= GRTC_SYSCOUNTER_SYSCOUNTERH_OVERFLOW_Msk;
467   }
468 
469   NRF_GRTC_regs.SYSCOUNTER[n].SYSCOUNTERH = value;
470 
471   return value;
472 }
473 
nhw_GRTC_regw_sideeffects_CC_CCADD(uint inst,uint cc)474 void nhw_GRTC_regw_sideeffects_CC_CCADD(uint inst, uint cc) {
475 
476   nhw_GRTC_check_valid_cc_index(inst, cc, "CC.CCADD");
477 
478   uint32_t offset = NRF_GRTC_regs.CC[cc].CCADD & GRTC_CC_CCADD_VALUE_Msk;
479   uint64_t value;
480   if (NRF_GRTC_regs.CC[cc].CCADD & GRTC_CC_CCADD_REFERENCE_Msk) { //Added to CC
481     value = ((uint64_t)NRF_GRTC_regs.CC[cc].CCH << 32) | NRF_GRTC_regs.CC[cc].CCL;
482   } else { //Added to SYSCOUNTER
483     nhw_GRTC_update_SYSCOUNTER(inst);
484     value = nhw_grtc_st.SYSCOUNTER;
485   }
486   value += offset;
487 
488   NRF_GRTC_regs.CC[cc].CCL = value & UINT32_MAX;
489   NRF_GRTC_regs.CC[cc].CCH = nhw_GRTC_get_counterhighword(value);
490 
491   NRF_GRTC_regs.CC[cc].CCEN = GRTC_CC_CCEN_ACTIVE_Msk; /* Writing to CCADD enables that compare channel */
492 
493   nhw_GRTC_update_cc_timer(inst, cc);
494   nhw_GRTC_update_master_timer();
495 }
496 
nhw_GRTC_regw_sideeffects_CC_CCEN(uint inst,uint cc)497 void nhw_GRTC_regw_sideeffects_CC_CCEN(uint inst, uint cc) {
498   nhw_GRTC_check_valid_cc_index(inst, cc, "CC.CCEN");
499 
500   nhw_GRTC_update_cc_timer(inst, cc);
501   nhw_GRTC_update_master_timer();
502 }
503 
nhw_GRTC_regw_sideeffects_CC_CCL(uint inst,uint cc)504 void nhw_GRTC_regw_sideeffects_CC_CCL(uint inst, uint cc) {
505   nhw_GRTC_check_valid_cc_index(inst, cc, "CC.CCL");
506 
507   NRF_GRTC_regs.CC[cc].CCEN = 0; /* Writing to CCL disables that compare channel */
508   nhw_GRTC_update_cc_timer(inst, cc);
509   nhw_GRTC_update_master_timer();
510 }
511 
nhw_GRTC_regw_sideeffects_CC_CCH(uint inst,uint cc)512 void nhw_GRTC_regw_sideeffects_CC_CCH(uint inst, uint cc) {
513   nhw_GRTC_check_valid_cc_index(inst, cc, "CC.CCH");
514 
515   NRF_GRTC_regs.CC[cc].CCEN = GRTC_CC_CCEN_ACTIVE_Msk; /* Writing to CCH enables that compare channel */
516 
517   nhw_GRTC_update_cc_timer(inst, cc);
518   nhw_GRTC_update_master_timer();
519 }
520 
nhw_GRTC_compare_reached(uint inst,uint cc)521 static void nhw_GRTC_compare_reached(uint inst, uint cc) {
522   if (NRF_GRTC_regs.CC[cc].CCEN == 0) {
523     bs_trace_warning_time_line("Programming error: CCEN was cleared without using the HAL\n");
524     return;
525   }
526   if ((cc==0) && NRF_GRTC_regs.INTERVAL) {
527     uint64_t value = ((uint64_t)NRF_GRTC_regs.CC[cc].CCH << 32) | NRF_GRTC_regs.CC[cc].CCL;
528     value += NRF_GRTC_regs.INTERVAL;
529     NRF_GRTC_regs.CC[cc].CCL = value & UINT32_MAX;
530     NRF_GRTC_regs.CC[cc].CCH = nhw_GRTC_get_counterhighword(value);
531   } else {
532     NRF_GRTC_regs.CC[cc].CCEN = 0;
533   }
534   nhw_GRTC_update_cc_timer(inst, cc);
535 
536   nhw_GRTC_signal_EVENTS_COMPARE(inst, cc);
537 }
538 
nhw_GRTC_timer_triggered(void)539 static void nhw_GRTC_timer_triggered(void) {
540   uint inst = 0, cc;
541   struct {
542     uint inst[NHW_GRTC_TOTAL_INST*NHW_GRTC_N_CC];
543     uint cc[NHW_GRTC_TOTAL_INST*NHW_GRTC_N_CC];
544     uint cnt;
545   } match;
546 
547   match.cnt = 0;
548 
549   for (cc = 0; cc < NHW_GRTC_N_CC; cc++) {
550     if (nhw_grtc_st.CC_timers[cc] == Timer_GRTC) {
551       match.inst[match.cnt] = inst;
552       match.cc[match.cnt] = cc;
553       match.cnt++;
554     }
555   }
556   while (match.cnt > 0) {
557     match.cnt--;
558     inst = match.inst[match.cnt];
559     cc = match.cc[match.cnt];
560     nhw_GRTC_compare_reached(inst ,cc);
561   }
562   nhw_GRTC_update_master_timer();
563 }
564 
565 NSI_HW_EVENT(Timer_GRTC, nhw_GRTC_timer_triggered, 50);
566