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