1 /*
2 * Copyright (c) 2017 Oticon A/S
3 * Copyright (c) 2023 Nordic Semiconductor ASA
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 /*
9 * CLOCK - Clock control
10 * https://infocenter.nordicsemi.com/topic/ps_nrf52833/clock.html?cp=5_1_0_4_3
11 * https://infocenter.nordicsemi.com/topic/ps_nrf5340/chapters/clock/doc/clock.html?cp=4_0_0_3_10
12 * POWER - POWER control
13 * https://infocenter.nordicsemi.com/topic/ps_nrf52833/power.html?cp=5_1_0_4_2
14 * https://infocenter.nordicsemi.com/topic/ps_nrf5340/chapters/power/doc/power.html?cp=4_0_0_3_5
15 * RESET - RESET control
16 * https://infocenter.nordicsemi.com/topic/ps_nrf5340/chapters/reset/doc/reset.html?cp=4_0_0_3_9
17 *
18 * Notes POWER / RESET:
19 * 1. The POWER and (nrf5340) RESET peripherals are just stubs with no functionality
20 *
21 * Note: CLOCK:
22 * 1. The clocks are ready in 1 delta cycle (i.e. almost instantaneously),
23 * HFXODEBOUNCE and LFXODEBOUNCE are ignored together with the XTALs
24 * power up times
25 *
26 * 2. The models do not check the requirement of having the HFXO clock running to be
27 * able to run the radio. The radio models will run just fine without it.
28 *
29 * 3. The LFRC oscillator calibration TASK_CAL finishes in 1 delta cycle.
30 * The models do not do anything during the LFRC calibration (apart from
31 * generating the done event/interrupt).
32 *
33 * 4. We assume the 32.768 KHz clock does not drift relative to the 64MHz one.
34 * This would only be the case if they had the same source or there was a tracking
35 * and adjustment loop of one based on the other.
36 *
37 * 5. LFCLKSRC is ignored (beyond copying LFCLKSRC.SRC to LFCLKSRCCOPY and LFCLKSTAT)
38 *
39 * 6. TRACECONFIG is ignored
40 *
41 * 7. The calibration timer timing is exact: it will take exactly CTIV*0.25s to
42 * finish.
43 *
44 * 8. After TASK_CTSTART EVENTS_CTSTARTED is raised immediately,
45 * After TASK_CTSTOP EVENTS_CTSTOPPED is raised immediately.
46 *
47 * 9. For the nrf5340 CLOCK. Almost all new functionality is missing
48 * (beyond connection to the DPPI, and having one instance per core)
49 * * The extra app core clocks are not implemented yet (Audio or 192M)
50 * * Automatic HW clock requests are not implemented yet
51 */
52
53 #include <string.h>
54 #include <stdint.h>
55 #include "NHW_common_types.h"
56 #include "NHW_config.h"
57 #include "NHW_peri_types.h"
58 #include "NHW_CLOCK.h"
59 #include "nsi_hw_scheduler.h"
60 #include "NHW_xPPI.h"
61 #include "NHW_RTC.h"
62 #include "irq_ctrl.h"
63 #include "bs_tracing.h"
64 #include "bs_utils.h"
65 #include "nsi_tasks.h"
66 #include "nsi_hws_models_if.h"
67
68 enum clock_states {Stopped = 0, Starting, Started, Stopping};
69
70 struct clkpwr_status {
71 NRF_CLOCK_Type *CLOCK_regs;
72 NRF_POWER_Type *POWER_regs;
73 #if (NHW_CLKPWR_HAS_RESET)
74 NRF_RESET_Type *RESET_regs;
75 #endif
76
77 uint inst;
78
79 uint32_t INTEN; //interrupt enable
80
81 bs_time_t Timer_CLOCK_LF;
82 bs_time_t Timer_CLOCK_HF;
83 bs_time_t Timer_LF_cal;
84 bs_time_t Timer_caltimer;
85
86 enum clock_states HF_Clock_state;
87 enum clock_states LF_Clock_state;
88 enum clock_states LF_cal_state;
89 enum clock_states caltimer_state;
90
91 #if (NHW_HAS_DPPI)
92 uint dppi_map; //To which DPPI instance are this CLOCK/POWER subscribe&publish ports connected to
93 //Which of the subscription ports are currently connected, and to which channel:
94 struct nhw_subsc_mem subscribed_HFCLKSTART;
95 struct nhw_subsc_mem subscribed_HFCLKSTOP;
96 struct nhw_subsc_mem subscribed_LFCLKSTART;
97 struct nhw_subsc_mem subscribed_LFCLKSTOP;
98 struct nhw_subsc_mem subscribed_CAL;
99 struct nhw_subsc_mem subscribed_HFCLKAUDIOSTART;
100 struct nhw_subsc_mem subscribed_HFCLKAUDIOSTOP;
101 struct nhw_subsc_mem subscribed_HFCLK192MSTART;
102 struct nhw_subsc_mem subscribed_HFCLK192MSTOP;
103 #endif
104 };
105
106 static bs_time_t Timer_PWRCLK = TIME_NEVER;
107 static struct clkpwr_status nhw_clkpwr_st[NHW_CLKPWR_TOTAL_INST];
108 union NRF_CLKPWR_Type NRF_CLKPWR_regs[NHW_CLKPWR_TOTAL_INST];
109
110 NRF_CLOCK_Type *NRF_CLOCK_regs[NHW_CLKPWR_TOTAL_INST];
111 NRF_POWER_Type *NRF_POWER_regs[NHW_CLKPWR_TOTAL_INST];
112 #if (NHW_CLKPWR_HAS_RESET)
113 NRF_RESET_Type *NRF_RESET_regs[NHW_CLKPWR_TOTAL_INST];
114 #endif /* (NHW_CLKPWR_HAS_RESET) */
115
116 void nhw_clock_HFTimer_triggered(struct clkpwr_status *this);
117 void nhw_clock_LFTimer_triggered(struct clkpwr_status *this);
118
nhw_clock_update_master_timer(void)119 static void nhw_clock_update_master_timer(void) {
120
121 Timer_PWRCLK = TIME_NEVER;
122
123 for (int i = 0; i < NHW_CLKPWR_TOTAL_INST; i++) {
124 struct clkpwr_status * c_el = &nhw_clkpwr_st[i];
125
126 bs_time_t t1 = BS_MIN(c_el->Timer_CLOCK_HF, c_el->Timer_CLOCK_LF);
127 bs_time_t t2 = BS_MIN(c_el->Timer_LF_cal, c_el->Timer_caltimer);
128
129 bs_time_t el_min = BS_MIN(t1, t2);
130 if (el_min < Timer_PWRCLK) {
131 Timer_PWRCLK = el_min;
132 }
133 }
134
135 nsi_hws_find_next_event();
136 }
137
nhw_clock_init(void)138 static void nhw_clock_init(void) {
139 #if (NHW_HAS_DPPI)
140 /* Mapping of peripheral instance to DPPI instance */
141 uint nhw_clkpwr_dppi_map[NHW_CLKPWR_TOTAL_INST] = NHW_CLKPWR_DPPI_MAP;
142 #endif
143
144 memset(NRF_CLKPWR_regs, 0, sizeof(NRF_CLKPWR_regs));
145
146 for (int i = 0; i < NHW_CLKPWR_TOTAL_INST; i++) {
147 struct clkpwr_status * c_el = &nhw_clkpwr_st[i];
148
149 c_el->inst = i;
150
151 NRF_CLOCK_regs[i] = (NRF_CLOCK_Type *)&NRF_CLKPWR_regs[i];
152 c_el->CLOCK_regs = (NRF_CLOCK_Type *)&NRF_CLKPWR_regs[i];
153 NRF_POWER_regs[i] = (NRF_POWER_Type *)&NRF_CLKPWR_regs[i];
154 c_el->POWER_regs = (NRF_POWER_Type *)&NRF_CLKPWR_regs[i];
155 #if (NHW_CLKPWR_HAS_RESET)
156 NRF_RESET_regs[i] = (NRF_RESET_Type *)&NRF_CLKPWR_regs[i];
157 c_el->RESET_regs = (NRF_RESET_Type *)&NRF_CLKPWR_regs[i];
158 #endif /* (NHW_CLKPWR_HAS_RESET) */
159
160 c_el->Timer_CLOCK_LF = TIME_NEVER;
161 c_el->Timer_CLOCK_HF = TIME_NEVER;
162 c_el->Timer_LF_cal = TIME_NEVER;
163 c_el->Timer_caltimer = TIME_NEVER;
164
165 c_el->HF_Clock_state = Stopped;
166 c_el->LF_Clock_state = Stopped;
167 c_el->LF_cal_state = Stopped;
168 c_el->caltimer_state = Stopped;
169 #if (NHW_HAS_DPPI)
170 c_el->dppi_map = nhw_clkpwr_dppi_map[i];
171 #endif
172
173 #if defined(CLOCK_HFXODEBOUNCE_HFXODEBOUNCE_Pos)
174 NRF_CLOCK_regs[i]->HFXODEBOUNCE = 0x00000010;
175 #endif
176 }
177 }
178
179 NSI_TASK(nhw_clock_init, HW_INIT, 100);
180
nhw_pwrclk_eval_interrupt(int inst)181 static void nhw_pwrclk_eval_interrupt(int inst) {
182 /* Mapping of peripheral instance to {int controller instance, int number} */
183 static struct nhw_irq_mapping nhw_clock_irq_map[NHW_CLKPWR_TOTAL_INST] = NHW_CLKPWR_INT_MAP;
184 static bool clock_int_line[NHW_CLKPWR_TOTAL_INST]; /* Is the CLOCK currently driving its interrupt line high */
185 bool new_int_line = false;
186
187 struct clkpwr_status *this = &nhw_clkpwr_st[inst];
188
189 #define check_interrupt(x) \
190 if (NRF_CLOCK_regs[inst]->EVENTS_##x \
191 && (this->INTEN & CLOCK_INTENCLR_##x##_Msk)){ \
192 new_int_line = true; \
193 } \
194
195 check_interrupt(HFCLKSTARTED);
196 check_interrupt(LFCLKSTARTED);
197 check_interrupt(DONE);
198 #if (NHW_CLKPWR_HAS_CALTIMER)
199 check_interrupt(CTTO);
200 check_interrupt(CTSTARTED);
201 check_interrupt(CTSTOPPED);
202 #endif /* NHW_CLKPWR_HAS_CALTIMER */
203 #if (NHW_CLKPWR_HAS_HFCLKAUDIOCLK)
204 check_interrupt(HFCLKAUDIOSTARTED);
205 #endif
206 #if (NHW_CLKPWR_HAS_HFCLK192MCLK)
207 check_interrupt(HFCLK192MSTARTED);
208 #endif
209
210 if (clock_int_line[inst] == false && new_int_line == true) {
211 clock_int_line[inst] = true;
212 hw_irq_ctrl_raise_level_irq_line(nhw_clock_irq_map[inst].cntl_inst,
213 nhw_clock_irq_map[inst].int_nbr);
214 } else if (clock_int_line[inst] == true && new_int_line == false) {
215 clock_int_line[inst] = false;
216 hw_irq_ctrl_lower_level_irq_line(nhw_clock_irq_map[inst].cntl_inst,
217 nhw_clock_irq_map[inst].int_nbr);
218 }
219 }
220
221 #if (NHW_HAS_PPI)
222 #define nhw_clock_signal_handler(x) \
223 static void nhw_clock_signal_##x(int i) { \
224 NRF_CLOCK_regs[i]->EVENTS_##x = 1; \
225 nhw_pwrclk_eval_interrupt(i); \
226 nrf_ppi_event(CLOCK_EVENTS_##x); \
227 }
228 #else
229 #define nhw_clock_signal_handler(x) \
230 static void nhw_clock_signal_##x(int i) { \
231 NRF_CLOCK_regs[i]->EVENTS_##x = 1; \
232 nhw_pwrclk_eval_interrupt(i); \
233 nhw_dppi_event_signal_if(nhw_clkpwr_st[i].dppi_map, \
234 NRF_CLOCK_regs[i]->PUBLISH_##x);\
235 }
236 #endif
237
238 /*
239 * CLOCK POWER & RESET do not have shortcuts, so all we need to do
240 * is set the corresponding event and evaluate the interrupt.
241 */
242 nhw_clock_signal_handler(HFCLKSTARTED)
nhw_clock_signal_handler(LFCLKSTARTED)243 nhw_clock_signal_handler(LFCLKSTARTED)
244 nhw_clock_signal_handler(DONE)
245 #if (NHW_CLKPWR_HAS_CALTIMER)
246 nhw_clock_signal_handler(CTTO)
247 nhw_clock_signal_handler(CTSTARTED)
248 nhw_clock_signal_handler(CTSTOPPED)
249 #endif /* NHW_CLKPWR_HAS_CALTIMER */
250 #if (NHW_CLKPWR_HAS_HFCLKAUDIOCLK)
251 //nhw_clock_signal_handler(HFCLKAUDIOSTARTED)
252 #endif
253 #if (NHW_CLKPWR_HAS_HFCLK192MCLK)
254 //nhw_clock_signal_handler(HFCLK192MSTARTED)
255 #endif
256
257 void nhw_clock_TASKS_LFCLKSTART(uint inst) {
258 struct clkpwr_status *this = &nhw_clkpwr_st[inst];
259 NRF_CLOCK_Type *CLOCK_regs = this->CLOCK_regs;
260
261 CLOCK_regs->LFCLKSRCCOPY = CLOCK_regs->LFCLKSRC & CLOCK_LFCLKSRC_SRC_Msk;
262 CLOCK_regs->LFCLKRUN = CLOCK_LFCLKRUN_STATUS_Msk;
263 this->LF_Clock_state = Starting;
264
265 this->Timer_CLOCK_LF = nsi_hws_get_time(); //we assume the clock is ready in 1 delta
266 nhw_clock_update_master_timer();
267 }
268
nhw_clock_TASKS_LFCLKSTOP(uint inst)269 void nhw_clock_TASKS_LFCLKSTOP(uint inst) {
270 // There is no effect of turning the clock off that is actually modeled
271 if ((NRF_CLOCK_regs[inst]->LFCLKSTAT & CLOCK_LFCLKRUN_STATUS_Msk) == 0) { /* LCOV_EXCL_START */
272 bs_trace_info_line(3, "%s(%u) Triggered LF oscillator stop while the clock was not running "
273 "(the model does not have a problem with this, but this is against "
274 "the spec)\n", __func__, inst);
275 } /* LCOV_EXCL_STOP */
276
277 struct clkpwr_status *this = &nhw_clkpwr_st[inst];
278
279 if ((this->LF_Clock_state == Started) || (this->LF_Clock_state == Starting)) {
280 NRF_CLOCK_regs[inst]->LFCLKRUN = 0;
281 this->LF_Clock_state = Stopping;
282 /* Instantaneous stop */
283 nhw_clock_LFTimer_triggered(this);
284 }
285 }
286
nhw_clock_TASKS_HFCLKSTART(uint inst)287 void nhw_clock_TASKS_HFCLKSTART(uint inst) {
288 struct clkpwr_status *this = &nhw_clkpwr_st[inst];
289
290 if ((this->HF_Clock_state == Stopped ) || (this->HF_Clock_state == Stopping)) {
291 this->HF_Clock_state = Starting;
292 NRF_CLOCK_regs[inst]->HFCLKRUN = CLOCK_HFCLKRUN_STATUS_Msk;
293 this->Timer_CLOCK_HF = nsi_hws_get_time(); //we assume the clock is ready in 1 delta
294 nhw_clock_update_master_timer();
295 }
296 }
297
nhw_clock_TASKS_HFCLKSTOP(uint inst)298 void nhw_clock_TASKS_HFCLKSTOP(uint inst) {
299 struct clkpwr_status *this = &nhw_clkpwr_st[inst];
300
301 if ((this->HF_Clock_state == Started) || (this->HF_Clock_state == Starting)) {
302 NRF_CLOCK_regs[inst]->HFCLKRUN = 0;
303 this->HF_Clock_state = Stopping;
304 /* Instantaneous stop */
305 nhw_clock_HFTimer_triggered(this);
306 }
307 }
308
309 #define HAS_CLOCK_CHECK(CLK_NAME) \
310 bool has_this_clock[NHW_CLKPWR_TOTAL_INST] = NHW_CLKPWR_HAS_##CLK_NAME##CLK_I;\
311 if (!has_this_clock[inst]) { \
312 bs_trace_error_time_line("CLOCK#%i does not have " \
313 "this type of clock (" #CLK_NAME ")", inst); \
314 }
315
nhw_clock_TASKS_HFCLKAUDIOSTART(uint inst)316 void nhw_clock_TASKS_HFCLKAUDIOSTART(uint inst) {
317 HAS_CLOCK_CHECK(HFCLKAUDIO);
318
319 bs_trace_warning_time_line("%s not yet implemented\n", __func__);
320 }
321
nhw_clock_TASKS_HFCLKAUDIOSTOP(uint inst)322 void nhw_clock_TASKS_HFCLKAUDIOSTOP(uint inst) {
323 HAS_CLOCK_CHECK(HFCLKAUDIO);
324
325 bs_trace_warning_time_line("%s not yet implemented\n", __func__);
326 }
327
nhw_clock_TASKS_HFCLK192MSTART(uint inst)328 void nhw_clock_TASKS_HFCLK192MSTART(uint inst) {
329 HAS_CLOCK_CHECK(HFCLK192M);
330
331 bs_trace_warning_time_line("%s not yet implemented\n", __func__);
332 }
333
nhw_clock_TASKS_HFCLK192MSTOP(uint inst)334 void nhw_clock_TASKS_HFCLK192MSTOP(uint inst) {
335 HAS_CLOCK_CHECK(HFCLK192M);
336
337 bs_trace_warning_time_line("%s not yet implemented\n", __func__);
338 }
339
340
nhw_clock_TASKS_CAL(uint inst)341 void nhw_clock_TASKS_CAL(uint inst) {
342 struct clkpwr_status *this = &nhw_clkpwr_st[inst];
343
344 if (this->HF_Clock_state != Started) { /* LCOV_EXCL_START */
345 bs_trace_warning_line("%s(%u): Triggered RC oscillator calibration with the HF CLK stopped "
346 "(the model does not have a problem with this, but this is against "
347 "the spec)\n", __func__, inst);
348 } /* LCOV_EXCL_STOP */
349
350 this->LF_cal_state = Started; //We don't check for re-triggers, as we are going to be done right away
351 this->Timer_LF_cal = nsi_hws_get_time(); //we assume the calibration is done in 1 delta
352 nhw_clock_update_master_timer();
353 }
354
355 #if (NHW_CLKPWR_HAS_CALTIMER)
nhw_clock_TASKS_CTSTART(uint inst)356 void nhw_clock_TASKS_CTSTART(uint inst) {
357 struct clkpwr_status *this = &nhw_clkpwr_st[inst];
358
359 if ( this->caltimer_state == Started ) { /* LCOV_EXCL_START */
360 bs_trace_warning_line("%s(%u) Calibration timer was already running. "
361 "Raising CTSTARTED event immediately. "
362 "Timeout is not affected.\n", __func__, inst);
363 } else { /* LCOV_EXCL_STOP */
364 this->caltimer_state = Started;
365 this->Timer_caltimer = nsi_hws_get_time() + (bs_time_t)NRF_CLOCK_regs[inst]->CTIV * 250000;
366 nhw_clock_update_master_timer();
367 }
368 nhw_clock_signal_CTSTARTED(inst);
369 }
370
nhw_clock_TASKS_CTSTOP(uint inst)371 void nhw_clock_TASKS_CTSTOP(uint inst) {
372 struct clkpwr_status *this = &nhw_clkpwr_st[inst];
373
374 if ( this->caltimer_state == Stopped ) { /* LCOV_EXCL_START */
375 bs_trace_info_line(3, "%s(%u) Calibration timer was already stopped. "
376 "Raising CTSTOPPED event immediately.\n", __func__, inst);
377 } /* LCOV_EXCL_STOP */
378 this->caltimer_state = Stopped;
379 this->Timer_caltimer = TIME_NEVER;
380 nhw_clock_update_master_timer();
381 nhw_clock_signal_CTSTOPPED(inst);
382 }
383 #endif /* NHW_CLKPWR_HAS_CALTIMER */
384
nhw_CLOCK_regw_sideeffects_INTENSET(uint i)385 void nhw_CLOCK_regw_sideeffects_INTENSET(uint i) {
386 if (NRF_CLOCK_regs[i]->INTENSET) { /* LCOV_EXCL_BR_LINE */
387 struct clkpwr_status *this = &nhw_clkpwr_st[i];
388
389 this->INTEN |= NRF_CLOCK_regs[i]->INTENSET;
390 NRF_CLOCK_regs[i]->INTENSET = this->INTEN;
391 nhw_pwrclk_eval_interrupt(i);
392 }
393 }
394
nhw_CLOCK_regw_sideeffects_INTENCLR(uint i)395 void nhw_CLOCK_regw_sideeffects_INTENCLR(uint i) {
396 if (NRF_CLOCK_regs[i]->INTENCLR) { /* LCOV_EXCL_BR_LINE */
397 struct clkpwr_status *this = &nhw_clkpwr_st[i];
398
399 this->INTEN &= ~NRF_CLOCK_regs[i]->INTENCLR;
400 NRF_CLOCK_regs[i]->INTENSET = this->INTEN;
401 NRF_CLOCK_regs[i]->INTENCLR = 0;
402 nhw_pwrclk_eval_interrupt(i);
403 }
404 }
405
406 #define nhw_clock_regw_sideeffects_TASKS_(x) \
407 void nhw_CLOCK_regw_sideeffects_TASKS_##x(uint i) { \
408 if (NRF_CLOCK_regs[i]->TASKS_##x) { /* LCOV_EXCL_BR_LINE */\
409 NRF_CLOCK_regs[i]->TASKS_##x = 0; \
410 nhw_clock_TASKS_##x(i); \
411 } \
412 }
413
414 nhw_clock_regw_sideeffects_TASKS_(LFCLKSTART)
nhw_clock_regw_sideeffects_TASKS_(LFCLKSTOP)415 nhw_clock_regw_sideeffects_TASKS_(LFCLKSTOP)
416 nhw_clock_regw_sideeffects_TASKS_(HFCLKSTART)
417 nhw_clock_regw_sideeffects_TASKS_(HFCLKSTOP)
418
419 #if (NHW_CLKPWR_HAS_HFCLKAUDIOCLK)
420 nhw_clock_regw_sideeffects_TASKS_(HFCLKAUDIOSTART)
421 nhw_clock_regw_sideeffects_TASKS_(HFCLKAUDIOSTOP)
422 #endif
423 #if (NHW_CLKPWR_HAS_HFCLK192MCLK)
424 nhw_clock_regw_sideeffects_TASKS_(HFCLK192MSTART)
425 nhw_clock_regw_sideeffects_TASKS_(HFCLK192MSTOP)
426 #endif
427 nhw_clock_regw_sideeffects_TASKS_(CAL)
428 #if (NHW_CLKPWR_HAS_CALTIMER)
429 nhw_clock_regw_sideeffects_TASKS_(CTSTART)
430 nhw_clock_regw_sideeffects_TASKS_(CTSTOP)
431 #endif /* NHW_CLKPWR_HAS_CALTIMER */
432
433 void nhw_pwrclk_regw_sideeffects_EVENTS_all(uint i) {
434 nhw_pwrclk_eval_interrupt(i);
435 }
436
nhw_clock_LFTimer_triggered(struct clkpwr_status * this)437 void nhw_clock_LFTimer_triggered(struct clkpwr_status *this) {
438 NRF_CLOCK_Type *CLOCK_regs = this->CLOCK_regs;
439
440 //For simplicity we assume the enable comes at the same instant as the first
441 //tick of the clock so we start ticking in this same instant
442
443 if (this->LF_Clock_state == Starting) { /* LCOV_EXCL_BR_LINE */
444 CLOCK_regs->LFCLKSTAT = CLOCK_LFCLKSTAT_STATE_Msk
445 | (CLOCK_regs->LFCLKSRCCOPY << CLOCK_LFCLKSTAT_SRC_Pos);
446
447 nhw_clock_signal_LFCLKSTARTED(this->inst);
448
449 nhw_rtc_notify_first_lf_tick();
450 } else if (this->LF_Clock_state == Stopping) {
451 this->LF_Clock_state = Stopped;
452 CLOCK_regs->LFCLKSTAT = 0;
453 }
454
455 this->Timer_CLOCK_LF = TIME_NEVER;
456 nhw_clock_update_master_timer();
457 }
458
459 #ifndef CLOCK_HFCLKSTAT_SRC_Xtal
460 #define CLOCK_HFCLKSTAT_SRC_Xtal CLOCK_HFCLKSTAT_SRC_HFXO /* Bit name change from 52 -> 53 series but same meaning*/
461 #endif
462
nhw_clock_HFTimer_triggered(struct clkpwr_status * this)463 void nhw_clock_HFTimer_triggered(struct clkpwr_status *this) {
464 NRF_CLOCK_Type *CLOCK_regs = this->CLOCK_regs;
465
466 if ( this->HF_Clock_state == Starting ){
467 this->HF_Clock_state = Started;
468
469 CLOCK_regs->HFCLKSTAT = CLOCK_HFCLKSTAT_STATE_Msk
470 | ( CLOCK_HFCLKSTAT_SRC_Xtal << CLOCK_HFCLKSTAT_SRC_Pos);
471
472 nhw_clock_signal_HFCLKSTARTED(this->inst);
473
474 } else if ( this->HF_Clock_state == Stopping ){
475 this->HF_Clock_state = Stopped;
476 CLOCK_regs->HFCLKSTAT = 0;
477 }
478
479 this->Timer_CLOCK_HF = TIME_NEVER;
480 nhw_clock_update_master_timer();
481 }
482
nhw_clock_LF_cal_triggered(struct clkpwr_status * this)483 void nhw_clock_LF_cal_triggered(struct clkpwr_status *this) {
484 this->LF_cal_state = Stopped;
485 this->Timer_LF_cal = TIME_NEVER;
486 nhw_clock_update_master_timer();
487
488 nhw_clock_signal_DONE(this->inst);
489 }
490
491 #if (NHW_CLKPWR_HAS_CALTIMER)
nhw_clock_caltimer_triggered(struct clkpwr_status * this)492 void nhw_clock_caltimer_triggered(struct clkpwr_status *this) {
493
494 if (this->caltimer_state != Started) { /* LCOV_EXCL_START */
495 bs_trace_error_time_line("%s: programming error\n", __func__);
496 } /* LCOV_EXCL_STOP */
497 this->caltimer_state = Stopped;
498 this->Timer_caltimer = TIME_NEVER;
499 nhw_clock_update_master_timer();
500 nhw_clock_signal_CTTO(this->inst);
501 }
502 #endif /* NHW_CLKPWR_HAS_CALTIMER */
503
nhw_pwrclk_timer_triggered(void)504 static void nhw_pwrclk_timer_triggered(void) {
505 bool any = false;
506 for (int i = 0; i < NHW_CLKPWR_TOTAL_INST; i++) {
507 struct clkpwr_status * c_el = &nhw_clkpwr_st[i];
508 if (Timer_PWRCLK == c_el->Timer_CLOCK_HF) {
509 nhw_clock_HFTimer_triggered(c_el);
510 any = true;
511 } else if (Timer_PWRCLK == c_el->Timer_CLOCK_LF) {
512 nhw_clock_LFTimer_triggered(c_el);
513 any = true;
514 } else if (Timer_PWRCLK == c_el->Timer_LF_cal) {
515 nhw_clock_LF_cal_triggered(c_el);
516 any = true;
517 #if (NHW_CLKPWR_HAS_CALTIMER)
518 } else if (Timer_PWRCLK == c_el->Timer_caltimer) {
519 nhw_clock_caltimer_triggered(c_el);
520 any = true;
521 #endif
522 }
523 }
524 if (!any) { /* LCOV_EXCL_START */
525 bs_trace_error_time_line("%s programming error\n", __func__);
526 } /* LCOV_EXCL_STOP */
527 }
528
529 NSI_HW_EVENT(Timer_PWRCLK, nhw_pwrclk_timer_triggered, 50);
530
531 #if (NHW_HAS_DPPI)
532
533 #define NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(TASK_N) \
534 static void nhw_clock_task##TASK_N##_wrap(void* param) \
535 { \
536 nhw_clock_TASKS_##TASK_N((int) param); \
537 } \
538 \
539 void nhw_CLOCK_regw_sideeffects_SUBSCRIBE_##TASK_N(uint inst) \
540 { \
541 struct clkpwr_status *this = &nhw_clkpwr_st[inst]; \
542 \
543 nhw_dppi_common_subscribe_sideeffect(this->dppi_map, \
544 this->CLOCK_regs->SUBSCRIBE_##TASK_N, \
545 &this->subscribed_##TASK_N, \
546 nhw_clock_task##TASK_N##_wrap, \
547 (void*) inst); \
548 }
549
550 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKSTART)
NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKSTOP)551 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKSTOP)
552 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(LFCLKSTART)
553 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(LFCLKSTOP)
554 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(CAL)
555 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKAUDIOSTART)
556 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKAUDIOSTOP)
557 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLK192MSTART)
558 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLK192MSTOP)
559
560 #endif /* NHW_HAS_DPPI */
561
562 #if (NHW_HAS_PPI)
563 void nhw_clock0_TASKS_LFCLKSTART(void) { nhw_clock_TASKS_LFCLKSTART(0); }
nhw_clock0_TASKS_LFCLKSTOP(void)564 void nhw_clock0_TASKS_LFCLKSTOP(void) { nhw_clock_TASKS_LFCLKSTOP(0); }
nhw_clock0_TASKS_HFCLKSTART(void)565 void nhw_clock0_TASKS_HFCLKSTART(void) { nhw_clock_TASKS_HFCLKSTART(0); }
nhw_clock0_TASKS_HFCLKSTOP(void)566 void nhw_clock0_TASKS_HFCLKSTOP(void) { nhw_clock_TASKS_HFCLKSTOP(0); }
nhw_clock0_TASKS_CAL(void)567 void nhw_clock0_TASKS_CAL(void) { nhw_clock_TASKS_CAL(0); }
nhw_clock0_TASKS_CTSTART(void)568 void nhw_clock0_TASKS_CTSTART(void) { nhw_clock_TASKS_CTSTART(0); }
nhw_clock0_TASKS_CTSTOP(void)569 void nhw_clock0_TASKS_CTSTOP(void) { nhw_clock_TASKS_CTSTOP(0); }
570 #endif /* (NHW_HAS_PPI) */
571