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 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 (uint 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 (uint 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 (uint 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 (uint i = 0; i < this->n_cc; i++) {
247 if (NRF_GRTC_regs.EVENTS_COMPARE[i]) {
248 event_bitmask |= 1<<i;
249 }
250 }
251 #if (GRTC_INTENSET0_SYSCOUNTERVALID_Msk)
252 if (NRF_GRTC_regs.EVENTS_SYSCOUNTERVALID) {
253 event_bitmask |= GRTC_INTENSET0_SYSCOUNTERVALID_Msk;
254 }
255 #endif
256 #if (NHW_GRTC_HAS_PWM)
257 if (NRF_GRTC_regs.EVENTS_PWMPERIODEND) {
258 event_bitmask |= GRTC_INTENSET0_PWMPERIODEND_Msk;
259 }
260 #endif
261 *INTPEND = event_bitmask & *INTEN;
262
263 new_line_level = (*INTPEND != 0);
264
265 hw_irq_ctrl_toggle_level_irq_line_if(&nhw_grtc_st.int_line_level[irql],
266 new_line_level,
267 &this->int_map[irql]);
268 }
269 }
270
nhw_GRTC_signal_EVENTS_COMPARE(uint inst,uint n)271 static void nhw_GRTC_signal_EVENTS_COMPARE(uint inst, uint n) {
272 NRF_GRTC_regs.EVENTS_COMPARE[n] = 1;
273 nhw_GRTC_eval_interrupt(inst);
274
275 nhw_dppi_event_signal_if(nhw_grtc_st.dppi_map,
276 NRF_GRTC_regs.PUBLISH_COMPARE[n]);
277 }
278
nhw_GRTC_signal_EVENTS_SYSCOUNTERVALID(uint inst)279 static void nhw_GRTC_signal_EVENTS_SYSCOUNTERVALID(uint inst) {
280 #if (GRTC_INTENSET0_SYSCOUNTERVALID_Msk)
281 NRF_GRTC_regs.EVENTS_SYSCOUNTERVALID = 1;
282 nhw_GRTC_eval_interrupt(inst);
283 /* Not connected to DPPI */
284 #else
285 (void) inst;
286 #endif
287 }
288
289 #if (NHW_GRTC_HAS_PWM)
290 //(Unused so far)
291 //static void nhw_GRTC_signal_EVENTS_PWMPERIODEND(uint inst) {
292 // NRF_GRTC_regs.EVENTS_PWMPERIODEND = 1;
293 // nhw_GRTC_eval_interrupt(inst);
294 // /* Not connected to DPPI */
295 //}
296 #endif
297
nhw_GRTC_TASK_START(uint inst)298 static void nhw_GRTC_TASK_START(uint inst) {
299 (void) inst;
300 nhw_grtc_st.rt_counter_running = true;
301 /* We assume the GRTC is started only once, or started after clearing */
302 nhw_grtc_st.GRTC_start_time = nsi_hws_get_time();
303
304 nhw_GRTC_signal_EVENTS_SYSCOUNTERVALID(inst);
305 }
306
nhw_GRTC_TASK_STOP(uint inst)307 static void nhw_GRTC_TASK_STOP(uint inst) {
308 (void) inst;
309 nhw_grtc_st.rt_counter_running = false;
310 bs_trace_warning_time_line("GRTC TASK_STOP is not properly supported.\n");
311 }
312
nhw_GRTC_TASK_CLEAR(uint inst)313 static void nhw_GRTC_TASK_CLEAR(uint inst) {
314 (void) inst;
315 /* In real HW this would clear the RTCOUNTER.
316 * Here we do nothing, hoping that if it is called
317 * it is done while the counter is stopped */
318 if (nhw_grtc_st.rt_counter_running) {
319 bs_trace_warning_time_line("GRTC models, TASK_CLEAR not supported while GRTC is running\n");
320 }
321 }
322
323 #if (NHW_GRTC_HAS_PWM)
nhw_GRTC_TASK_PWMSTART(uint inst)324 static void nhw_GRTC_TASK_PWMSTART(uint inst) {
325 /* Not modeled */
326 (void) inst;
327 }
328
nhw_GRTC_TASK_PWMSTOP(uint inst)329 static void nhw_GRTC_TASK_PWMSTOP(uint inst) {
330 /* Not modeled */
331 (void) inst;
332 }
333 #endif
334
nhw_GRTC_get_SYNCOUNTERL(uint inst)335 static inline uint32_t nhw_GRTC_get_SYNCOUNTERL(uint inst) {
336 (void) inst;
337 return nhw_grtc_st.SYSCOUNTER & UINT32_MAX;
338 }
339
nhw_GRTC_get_counterhighword(uint64_t value)340 static inline uint32_t nhw_GRTC_get_counterhighword(uint64_t value) {
341 return (value >> 32) & (UINT32_MAX >> BS_MIN(64 - NHW_GRTC_SYSCOUNTER_BW, 32));
342 }
343
nhw_GRTC_get_SYNCOUNTERH(uint inst)344 static inline uint32_t nhw_GRTC_get_SYNCOUNTERH(uint inst) {
345 (void) inst;
346 return nhw_GRTC_get_counterhighword(nhw_grtc_st.SYSCOUNTER);
347 }
348
nhw_GRTC_TASK_CAPTURE(uint inst,uint n)349 static void nhw_GRTC_TASK_CAPTURE(uint inst, uint n) {
350 NRF_GRTC_regs.CC[n].CCEN = 0; /* Trigger the capture task disables the compare feature */
351 nhw_GRTC_update_cc_timer(inst, n);
352 nhw_GRTC_update_master_timer();
353
354 nhw_GRTC_update_SYSCOUNTER(inst);
355 NRF_GRTC_regs.CC[n].CCL = nhw_GRTC_get_SYNCOUNTERL(inst);
356 NRF_GRTC_regs.CC[n].CCH = nhw_GRTC_get_SYNCOUNTERH(inst);
357 }
358
359 NHW_SIDEEFFECTS_TASKS(GRTC, NRF_GRTC_regs., START)
360 NHW_SIDEEFFECTS_TASKS(GRTC, NRF_GRTC_regs., STOP)
361 NHW_SIDEEFFECTS_TASKS(GRTC, NRF_GRTC_regs., CLEAR)
362 #if (NHW_GRTC_HAS_PWM)
363 NHW_SIDEEFFECTS_TASKS(GRTC, NRF_GRTC_regs., PWMSTART)
364 NHW_SIDEEFFECTS_TASKS(GRTC, NRF_GRTC_regs., PWMSTOP)
365 #endif
366
nhw_GRTC_regw_sideeffects_TASKS_CAPTURE(uint inst,uint n)367 void nhw_GRTC_regw_sideeffects_TASKS_CAPTURE(uint inst, uint n) {
368 if (NRF_GRTC_regs.TASKS_CAPTURE[n]) {
369 NRF_GRTC_regs.TASKS_CAPTURE[n] = 0;
370 nhw_GRTC_TASK_CAPTURE(inst, n);
371 }
372 }
373
nhw_GRTC_taskcapture_wrap(void * param)374 static void nhw_GRTC_taskcapture_wrap(void* param) {
375 unsigned int inst = (uintptr_t)param >> 16;
376 uint cc_n = (uintptr_t)param & 0xFFFF;
377 nhw_GRTC_TASK_CAPTURE(inst, cc_n);
378 }
379
nhw_GRTC_regw_sideeffects_SUBSCRIBE_CAPTURE(uint inst,uint cc_n)380 void nhw_GRTC_regw_sideeffects_SUBSCRIBE_CAPTURE(uint inst, uint cc_n) {
381 struct grtc_status *this = &nhw_grtc_st;
382
383 nhw_GRTC_check_valid_cc_index(inst, cc_n, "SUBSCRIBE_CAPTURE");
384
385 nhw_dppi_common_subscribe_sideeffect(this->dppi_map,
386 this->NRF_GRTC_regs->SUBSCRIBE_CAPTURE[cc_n],
387 &this->subscribed[cc_n],
388 nhw_GRTC_taskcapture_wrap,
389 (void*)((inst << 16) + cc_n));
390 }
391
nhw_GRTC_regw_sideeffects_INTEN(uint inst,uint n)392 void nhw_GRTC_regw_sideeffects_INTEN(uint inst, uint n) {
393 nhw_GRTC_check_valid_irq_index(inst, n, "INTEN");
394
395 uint32_t *INTENSET = (uint32_t *)((uintptr_t)&NRF_GRTC_regs.INTENSET0 + n*grtc_int_pdiff);
396 uint32_t *INTEN = (uint32_t *)((uintptr_t)&NRF_GRTC_regs.INTEN0 + n*grtc_int_pdiff);
397
398 *INTENSET = *INTEN;
399 nhw_GRTC_eval_interrupt(inst);
400 }
401
nhw_GRTC_regw_sideeffects_INTENSET(uint inst,uint n)402 void nhw_GRTC_regw_sideeffects_INTENSET(uint inst, uint n) {
403 nhw_GRTC_check_valid_irq_index(inst, n, "INTENSET");
404
405 uint32_t *INTENSET = (uint32_t *)((uintptr_t)&NRF_GRTC_regs.INTENSET0 + n*grtc_int_pdiff);
406 uint32_t *INTEN = (uint32_t *)((uintptr_t)&NRF_GRTC_regs.INTEN0 + n*grtc_int_pdiff);
407
408 if (*INTENSET) {
409 *INTEN |= *INTENSET;
410 *INTENSET = *INTEN;
411 nhw_GRTC_eval_interrupt(inst);
412 }
413 }
414
nhw_GRTC_regw_sideeffects_INTENCLR(uint inst,uint n)415 void nhw_GRTC_regw_sideeffects_INTENCLR(uint inst, uint n) {
416 nhw_GRTC_check_valid_irq_index(inst, n, "INTENCLR");
417
418 uint32_t *INTENSET = (uint32_t *)((uintptr_t)&NRF_GRTC_regs.INTENSET0 + n*grtc_int_pdiff);
419 uint32_t *INTENCLR = (uint32_t *)((uintptr_t)&NRF_GRTC_regs.INTENCLR0 + n*grtc_int_pdiff);
420 uint32_t *INTEN = (uint32_t *)((uintptr_t)&NRF_GRTC_regs.INTEN0 + n*grtc_int_pdiff);
421
422 if (*INTENCLR) {
423 *INTEN &= ~*INTENCLR;
424 *INTENSET = *INTEN;
425 *INTENCLR = 0; //We do not model reading the INTEN register thru the INTENCLR one
426 nhw_GRTC_eval_interrupt(inst);
427 }
428 }
429
NHW_SIDEEFFECTS_EVENTS(GRTC)430 NHW_SIDEEFFECTS_EVENTS(GRTC)
431
432 static void nhw_GRTC_update_SYSCOUNTER(uint inst) {
433 (void) inst;
434 nhw_grtc_st.SYSCOUNTER = nsi_hws_get_time() - nhw_grtc_st.GRTC_start_time;
435 }
436
nhw_GRTC_check_syscounter_en(uint inst,const char * msg)437 static void nhw_GRTC_check_syscounter_en(uint inst, const char *msg) {
438 (void) inst;
439 if (!nhw_grtc_st.rt_counter_running) {
440 bs_trace_warning_time_line("The RT counter was not started while trying to %s\n", msg);
441 return;
442 }
443 if (!(NRF_GRTC_regs.MODE & GRTC_MODE_SYSCOUNTEREN_Msk)) {
444 bs_trace_warning_time_line("MODE.SYSCOUNTER was not enabled while trying to %s\n", msg);
445 }
446 return;
447 }
448
nhw_GRTC_regr_sideeffects_SYSCOUNTERL(uint inst,uint n)449 uint32_t nhw_GRTC_regr_sideeffects_SYSCOUNTERL(uint inst, uint n)
450 {
451 nhw_GRTC_check_syscounter_en(inst, "read SYSCOUNTERL");
452 nhw_GRTC_check_valid_domain_index(inst, n, "SYSCOUNTERL");
453 nhw_GRTC_update_SYSCOUNTER(inst);
454 uint32_t value = nhw_GRTC_get_SYNCOUNTERL(inst);
455 uint64_t remain = (uint64_t)UINT32_MAX - value;
456
457 nhw_grtc_st.SYSCOUNTER_read_deadline[n] = nsi_hws_get_time() + remain;
458
459 NRF_GRTC_regs.SYSCOUNTER[n].SYSCOUNTERL = value;
460
461 return value;
462 }
463
nhw_GRTC_regr_sideeffects_SYSCOUNTERH(uint inst,uint n)464 uint32_t nhw_GRTC_regr_sideeffects_SYSCOUNTERH(uint inst, uint n)
465 {
466 nhw_GRTC_check_syscounter_en(inst, "read SYSCOUNTERH");
467 nhw_GRTC_check_valid_domain_index(inst, n, "SYSCOUNTERH");
468 nhw_GRTC_update_SYSCOUNTER(inst);
469 uint32_t value = nhw_GRTC_get_SYNCOUNTERH(inst);
470
471 //Check for SYSCOUNTERL "wrap":
472 bs_time_t now = nsi_hws_get_time();
473 if (now > nhw_grtc_st.SYSCOUNTER_read_deadline[n]) {
474 value |= GRTC_SYSCOUNTER_SYSCOUNTERH_OVERFLOW_Msk;
475 }
476
477 NRF_GRTC_regs.SYSCOUNTER[n].SYSCOUNTERH = value;
478
479 return value;
480 }
481
nhw_GRTC_regw_sideeffects_CC_CCADD(uint inst,uint cc)482 void nhw_GRTC_regw_sideeffects_CC_CCADD(uint inst, uint cc) {
483
484 nhw_GRTC_check_valid_cc_index(inst, cc, "CC.CCADD");
485
486 uint32_t offset = NRF_GRTC_regs.CC[cc].CCADD & GRTC_CC_CCADD_VALUE_Msk;
487 uint64_t value;
488 if (NRF_GRTC_regs.CC[cc].CCADD & GRTC_CC_CCADD_REFERENCE_Msk) { //Added to CC
489 value = ((uint64_t)NRF_GRTC_regs.CC[cc].CCH << 32) | NRF_GRTC_regs.CC[cc].CCL;
490 } else { //Added to SYSCOUNTER
491 nhw_GRTC_update_SYSCOUNTER(inst);
492 value = nhw_grtc_st.SYSCOUNTER;
493 }
494 value += offset;
495
496 NRF_GRTC_regs.CC[cc].CCL = value & UINT32_MAX;
497 NRF_GRTC_regs.CC[cc].CCH = nhw_GRTC_get_counterhighword(value);
498
499 NRF_GRTC_regs.CC[cc].CCEN = GRTC_CC_CCEN_ACTIVE_Msk; /* Writing to CCADD enables that compare channel */
500
501 nhw_GRTC_update_cc_timer(inst, cc);
502 nhw_GRTC_update_master_timer();
503 }
504
nhw_GRTC_regw_sideeffects_CC_CCEN(uint inst,uint cc)505 void nhw_GRTC_regw_sideeffects_CC_CCEN(uint inst, uint cc) {
506 nhw_GRTC_check_valid_cc_index(inst, cc, "CC.CCEN");
507
508 nhw_GRTC_update_cc_timer(inst, cc);
509 nhw_GRTC_update_master_timer();
510 }
511
nhw_GRTC_regw_sideeffects_CC_CCL(uint inst,uint cc)512 void nhw_GRTC_regw_sideeffects_CC_CCL(uint inst, uint cc) {
513 nhw_GRTC_check_valid_cc_index(inst, cc, "CC.CCL");
514
515 NRF_GRTC_regs.CC[cc].CCEN = 0; /* Writing to CCL disables that compare channel */
516 nhw_GRTC_update_cc_timer(inst, cc);
517 nhw_GRTC_update_master_timer();
518 }
519
nhw_GRTC_regw_sideeffects_CC_CCH(uint inst,uint cc)520 void nhw_GRTC_regw_sideeffects_CC_CCH(uint inst, uint cc) {
521 nhw_GRTC_check_valid_cc_index(inst, cc, "CC.CCH");
522
523 NRF_GRTC_regs.CC[cc].CCEN = GRTC_CC_CCEN_ACTIVE_Msk; /* Writing to CCH enables that compare channel */
524
525 nhw_GRTC_update_cc_timer(inst, cc);
526 nhw_GRTC_update_master_timer();
527 }
528
nhw_GRTC_compare_reached(uint inst,uint cc)529 static void nhw_GRTC_compare_reached(uint inst, uint cc) {
530 if (NRF_GRTC_regs.CC[cc].CCEN == 0) {
531 bs_trace_warning_time_line("Programming error: CCEN was cleared without using the HAL\n");
532 return;
533 }
534 if ((cc==0) && NRF_GRTC_regs.INTERVAL) {
535 uint64_t value = ((uint64_t)NRF_GRTC_regs.CC[cc].CCH << 32) | NRF_GRTC_regs.CC[cc].CCL;
536 value += NRF_GRTC_regs.INTERVAL;
537 NRF_GRTC_regs.CC[cc].CCL = value & UINT32_MAX;
538 NRF_GRTC_regs.CC[cc].CCH = nhw_GRTC_get_counterhighword(value);
539 } else {
540 NRF_GRTC_regs.CC[cc].CCEN = 0;
541 }
542 nhw_GRTC_update_cc_timer(inst, cc);
543
544 nhw_GRTC_signal_EVENTS_COMPARE(inst, cc);
545 }
546
nhw_GRTC_timer_triggered(void)547 static void nhw_GRTC_timer_triggered(void) {
548 uint inst = 0, cc;
549 struct {
550 uint inst[NHW_GRTC_TOTAL_INST*NHW_GRTC_N_CC];
551 uint cc[NHW_GRTC_TOTAL_INST*NHW_GRTC_N_CC];
552 uint cnt;
553 } match;
554
555 match.cnt = 0;
556
557 for (cc = 0; cc < NHW_GRTC_N_CC; cc++) {
558 if (nhw_grtc_st.CC_timers[cc] == Timer_GRTC) {
559 match.inst[match.cnt] = inst;
560 match.cc[match.cnt] = cc;
561 match.cnt++;
562 }
563 }
564 while (match.cnt > 0) {
565 match.cnt--;
566 inst = match.inst[match.cnt];
567 cc = match.cc[match.cnt];
568 nhw_GRTC_compare_reached(inst ,cc);
569 }
570 nhw_GRTC_update_master_timer();
571 }
572
573 NSI_HW_EVENT(Timer_GRTC, nhw_GRTC_timer_triggered, 50);
574