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
nhw_clock_update_master_timer(void)116 static void nhw_clock_update_master_timer(void) {
117
118 Timer_PWRCLK = TIME_NEVER;
119
120 for (int i = 0; i < NHW_CLKPWR_TOTAL_INST; i++) {
121 struct clkpwr_status * c_el = &nhw_clkpwr_st[i];
122
123 bs_time_t t1 = BS_MIN(c_el->Timer_CLOCK_HF, c_el->Timer_CLOCK_LF);
124 bs_time_t t2 = BS_MIN(c_el->Timer_LF_cal, c_el->Timer_caltimer);
125
126 bs_time_t el_min = BS_MIN(t1, t2);
127 if (el_min < Timer_PWRCLK) {
128 Timer_PWRCLK = el_min;
129 }
130 }
131
132 nsi_hws_find_next_event();
133 }
134
nhw_clock_init(void)135 static void nhw_clock_init(void) {
136 #if (NHW_HAS_DPPI)
137 /* Mapping of peripheral instance to DPPI instance */
138 uint nhw_clkpwr_dppi_map[NHW_CLKPWR_TOTAL_INST] = NHW_CLKPWR_DPPI_MAP;
139 #endif
140
141 memset(NRF_CLKPWR_regs, 0, sizeof(NRF_CLKPWR_regs));
142
143 for (int i = 0; i < NHW_CLKPWR_TOTAL_INST; i++) {
144 struct clkpwr_status * c_el = &nhw_clkpwr_st[i];
145
146 c_el->inst = i;
147
148 NRF_CLOCK_regs[i] = (NRF_CLOCK_Type *)&NRF_CLKPWR_regs[i];
149 c_el->CLOCK_regs = (NRF_CLOCK_Type *)&NRF_CLKPWR_regs[i];
150 NRF_POWER_regs[i] = (NRF_POWER_Type *)&NRF_CLKPWR_regs[i];
151 c_el->POWER_regs = (NRF_POWER_Type *)&NRF_CLKPWR_regs[i];
152 #if (NHW_CLKPWR_HAS_RESET)
153 NRF_RESET_regs[i] = (NRF_RESET_Type *)&NRF_CLKPWR_regs[i];
154 c_el->RESET_regs = (NRF_RESET_Type *)&NRF_CLKPWR_regs[i];
155 #endif /* (NHW_CLKPWR_HAS_RESET) */
156
157 c_el->Timer_CLOCK_LF = TIME_NEVER;
158 c_el->Timer_CLOCK_HF = TIME_NEVER;
159 c_el->Timer_LF_cal = TIME_NEVER;
160 c_el->Timer_caltimer = TIME_NEVER;
161
162 c_el->HF_Clock_state = Stopped;
163 c_el->LF_Clock_state = Stopped;
164 c_el->LF_cal_state = Stopped;
165 c_el->caltimer_state = Stopped;
166 #if (NHW_HAS_DPPI)
167 c_el->dppi_map = nhw_clkpwr_dppi_map[i];
168 #endif
169
170 #if defined(CLOCK_HFXODEBOUNCE_HFXODEBOUNCE_Pos)
171 NRF_CLOCK_regs[i]->HFXODEBOUNCE = 0x00000010;
172 #endif
173 }
174 }
175
176 NSI_TASK(nhw_clock_init, HW_INIT, 100);
177
nhw_pwrclk_eval_interrupt(int inst)178 static void nhw_pwrclk_eval_interrupt(int inst) {
179 /* Mapping of peripheral instance to {int controller instance, int number} */
180 static struct nhw_irq_mapping nhw_clock_irq_map[NHW_CLKPWR_TOTAL_INST] = NHW_CLKPWR_INT_MAP;
181 static bool clock_int_line[NHW_CLKPWR_TOTAL_INST]; /* Is the CLOCK currently driving its interrupt line high */
182 bool new_int_line = false;
183
184 struct clkpwr_status *this = &nhw_clkpwr_st[inst];
185
186 #define check_interrupt(x) \
187 if (NRF_CLOCK_regs[inst]->EVENTS_##x \
188 && (this->INTEN & CLOCK_INTENCLR_##x##_Msk)){ \
189 new_int_line = true; \
190 } \
191
192 check_interrupt(HFCLKSTARTED);
193 check_interrupt(LFCLKSTARTED);
194 check_interrupt(DONE);
195 #if (NHW_CLKPWR_HAS_CALTIMER)
196 check_interrupt(CTTO);
197 check_interrupt(CTSTARTED);
198 check_interrupt(CTSTOPPED);
199 #endif /* NHW_CLKPWR_HAS_CALTIMER */
200 #if (NHW_CLKPWR_HAS_HFCLKAUDIOCLK)
201 check_interrupt(HFCLKAUDIOSTARTED);
202 #endif
203 #if (NHW_CLKPWR_HAS_HFCLK192MCLK)
204 check_interrupt(HFCLK192MSTARTED);
205 #endif
206
207 if (clock_int_line[inst] == false && new_int_line == true) {
208 clock_int_line[inst] = true;
209 hw_irq_ctrl_raise_level_irq_line(nhw_clock_irq_map[inst].cntl_inst,
210 nhw_clock_irq_map[inst].int_nbr);
211 } else if (clock_int_line[inst] == true && new_int_line == false) {
212 clock_int_line[inst] = false;
213 hw_irq_ctrl_lower_level_irq_line(nhw_clock_irq_map[inst].cntl_inst,
214 nhw_clock_irq_map[inst].int_nbr);
215 }
216 }
217
218 #if (NHW_HAS_PPI)
219 #define nhw_clock_signal_handler(x) \
220 static void nhw_clock_signal_##x(int i) { \
221 NRF_CLOCK_regs[i]->EVENTS_##x = 1; \
222 nhw_pwrclk_eval_interrupt(i); \
223 nrf_ppi_event(CLOCK_EVENTS_##x); \
224 }
225 #else
226 #define nhw_clock_signal_handler(x) \
227 static void nhw_clock_signal_##x(int i) { \
228 NRF_CLOCK_regs[i]->EVENTS_##x = 1; \
229 nhw_pwrclk_eval_interrupt(i); \
230 nhw_dppi_event_signal_if(nhw_clkpwr_st[i].dppi_map, \
231 NRF_CLOCK_regs[i]->PUBLISH_##x);\
232 }
233 #endif
234
235 /*
236 * CLOCK POWER & RESET do not have shortcuts, so all we need to do
237 * is set the corresponding event and evaluate the interrupt.
238 */
239 nhw_clock_signal_handler(HFCLKSTARTED)
nhw_clock_signal_handler(LFCLKSTARTED)240 nhw_clock_signal_handler(LFCLKSTARTED)
241 nhw_clock_signal_handler(DONE)
242 #if (NHW_CLKPWR_HAS_CALTIMER)
243 nhw_clock_signal_handler(CTTO)
244 nhw_clock_signal_handler(CTSTARTED)
245 nhw_clock_signal_handler(CTSTOPPED)
246 #endif /* NHW_CLKPWR_HAS_CALTIMER */
247 #if (NHW_CLKPWR_HAS_HFCLKAUDIOCLK)
248 //nhw_clock_signal_handler(HFCLKAUDIOSTARTED)
249 #endif
250 #if (NHW_CLKPWR_HAS_HFCLK192MCLK)
251 //nhw_clock_signal_handler(HFCLK192MSTARTED)
252 #endif
253
254 void nhw_clock_TASKS_LFCLKSTART(uint inst) {
255 struct clkpwr_status *this = &nhw_clkpwr_st[inst];
256 NRF_CLOCK_Type *CLOCK_regs = this->CLOCK_regs;
257
258 CLOCK_regs->LFCLKSRCCOPY = CLOCK_regs->LFCLKSRC & CLOCK_LFCLKSRC_SRC_Msk;
259 CLOCK_regs->LFCLKRUN = CLOCK_LFCLKRUN_STATUS_Msk;
260 this->LF_Clock_state = Starting;
261
262 this->Timer_CLOCK_LF = nsi_hws_get_time(); //we assume the clock is ready in 1 delta
263 nhw_clock_update_master_timer();
264 }
265
nhw_clock_TASKS_LFCLKSTOP(uint inst)266 void nhw_clock_TASKS_LFCLKSTOP(uint inst) {
267 // There is no effect of turning the clock off that is actually modeled
268 if ((NRF_CLOCK_regs[inst]->LFCLKSTAT & CLOCK_LFCLKRUN_STATUS_Msk) == 0) { /* LCOV_EXCL_START */
269 bs_trace_info_line(3, "%s(%u) Triggered LF oscillator stop while the clock was not running "
270 "(the model does not have a problem with this, but this is against "
271 "the spec)\n", __func__, inst);
272 } /* LCOV_EXCL_STOP */
273
274 struct clkpwr_status *this = &nhw_clkpwr_st[inst];
275
276 if ((this->LF_Clock_state == Started) || (this->LF_Clock_state == Starting)) {
277 NRF_CLOCK_regs[inst]->LFCLKRUN = 0;
278 this->LF_Clock_state = Stopping;
279 this->Timer_CLOCK_LF = nsi_hws_get_time(); //we assume the clock is stopped in 1 delta
280 nhw_clock_update_master_timer();
281 }
282 }
283
nhw_clock_TASKS_HFCLKSTART(uint inst)284 void nhw_clock_TASKS_HFCLKSTART(uint inst) {
285 struct clkpwr_status *this = &nhw_clkpwr_st[inst];
286
287 if ((this->HF_Clock_state == Stopped ) || (this->HF_Clock_state == Stopping)) {
288 this->HF_Clock_state = Starting;
289 NRF_CLOCK_regs[inst]->HFCLKRUN = CLOCK_HFCLKRUN_STATUS_Msk;
290 this->Timer_CLOCK_HF = nsi_hws_get_time(); //we assume the clock is ready in 1 delta
291 nhw_clock_update_master_timer();
292 }
293 }
294
nhw_clock_TASKS_HFCLKSTOP(uint inst)295 void nhw_clock_TASKS_HFCLKSTOP(uint inst) {
296 struct clkpwr_status *this = &nhw_clkpwr_st[inst];
297
298 if ((this->HF_Clock_state == Started) || (this->HF_Clock_state == Starting)) {
299 NRF_CLOCK_regs[inst]->HFCLKRUN = 0;
300 this->HF_Clock_state = Stopping;
301 this->Timer_CLOCK_HF = nsi_hws_get_time(); //we assume the clock is stopped in 1 delta
302 nhw_clock_update_master_timer();
303 }
304 }
305
306 #define HAS_CLOCK_CHECK(CLK_NAME) \
307 bool has_this_clock[NHW_CLKPWR_TOTAL_INST] = NHW_CLKPWR_HAS_##CLK_NAME##CLK_I;\
308 if (!has_this_clock[inst]) { \
309 bs_trace_error_time_line("CLOCK#%i does not have " \
310 "this type of clock (" #CLK_NAME ")", inst); \
311 }
312
nhw_clock_TASKS_HFCLKAUDIOSTART(uint inst)313 void nhw_clock_TASKS_HFCLKAUDIOSTART(uint inst) {
314 HAS_CLOCK_CHECK(HFCLKAUDIO);
315
316 bs_trace_warning_time_line("%s not yet implemented\n", __func__);
317 }
318
nhw_clock_TASKS_HFCLKAUDIOSTOP(uint inst)319 void nhw_clock_TASKS_HFCLKAUDIOSTOP(uint inst) {
320 HAS_CLOCK_CHECK(HFCLKAUDIO);
321
322 bs_trace_warning_time_line("%s not yet implemented\n", __func__);
323 }
324
nhw_clock_TASKS_HFCLK192MSTART(uint inst)325 void nhw_clock_TASKS_HFCLK192MSTART(uint inst) {
326 HAS_CLOCK_CHECK(HFCLK192M);
327
328 bs_trace_warning_time_line("%s not yet implemented\n", __func__);
329 }
330
nhw_clock_TASKS_HFCLK192MSTOP(uint inst)331 void nhw_clock_TASKS_HFCLK192MSTOP(uint inst) {
332 HAS_CLOCK_CHECK(HFCLK192M);
333
334 bs_trace_warning_time_line("%s not yet implemented\n", __func__);
335 }
336
337
nhw_clock_TASKS_CAL(uint inst)338 void nhw_clock_TASKS_CAL(uint inst) {
339 struct clkpwr_status *this = &nhw_clkpwr_st[inst];
340
341 if (this->HF_Clock_state != Started) { /* LCOV_EXCL_START */
342 bs_trace_warning_line("%s(%u): Triggered RC oscillator calibration with the HF CLK stopped "
343 "(the model does not have a problem with this, but this is against "
344 "the spec)\n", __func__, inst);
345 } /* LCOV_EXCL_STOP */
346
347 this->LF_cal_state = Started; //We don't check for re-triggers, as we are going to be done right away
348 this->Timer_LF_cal = nsi_hws_get_time(); //we assume the calibration is done in 1 delta
349 nhw_clock_update_master_timer();
350 }
351
352 #if (NHW_CLKPWR_HAS_CALTIMER)
nhw_clock_TASKS_CTSTART(uint inst)353 void nhw_clock_TASKS_CTSTART(uint inst) {
354 struct clkpwr_status *this = &nhw_clkpwr_st[inst];
355
356 if ( this->caltimer_state == Started ) { /* LCOV_EXCL_START */
357 bs_trace_warning_line("%s(%u) Calibration timer was already running. "
358 "Raising CTSTARTED event immediately. "
359 "Timeout is not affected.\n", __func__, inst);
360 } else { /* LCOV_EXCL_STOP */
361 this->caltimer_state = Started;
362 this->Timer_caltimer = nsi_hws_get_time() + (bs_time_t)NRF_CLOCK_regs[inst]->CTIV * 250000;
363 nhw_clock_update_master_timer();
364 }
365 nhw_clock_signal_CTSTARTED(inst);
366 }
367
nhw_clock_TASKS_CTSTOP(uint inst)368 void nhw_clock_TASKS_CTSTOP(uint inst) {
369 struct clkpwr_status *this = &nhw_clkpwr_st[inst];
370
371 if ( this->caltimer_state == Stopped ) { /* LCOV_EXCL_START */
372 bs_trace_info_line(3, "%s(%u) Calibration timer was already stopped. "
373 "Raising CTSTOPPED event immediately.\n", __func__, inst);
374 } /* LCOV_EXCL_STOP */
375 this->caltimer_state = Stopped;
376 this->Timer_caltimer = TIME_NEVER;
377 nhw_clock_update_master_timer();
378 nhw_clock_signal_CTSTOPPED(inst);
379 }
380 #endif /* NHW_CLKPWR_HAS_CALTIMER */
381
nhw_clock_regw_sideeffects_INTENSET(uint i)382 void nhw_clock_regw_sideeffects_INTENSET(uint i) {
383 if (NRF_CLOCK_regs[i]->INTENSET) { /* LCOV_EXCL_BR_LINE */
384 struct clkpwr_status *this = &nhw_clkpwr_st[i];
385
386 this->INTEN |= NRF_CLOCK_regs[i]->INTENSET;
387 NRF_CLOCK_regs[i]->INTENSET = this->INTEN;
388 nhw_pwrclk_eval_interrupt(i);
389 }
390 }
391
nhw_clock_regw_sideeffects_INTENCLR(uint i)392 void nhw_clock_regw_sideeffects_INTENCLR(uint i) {
393 if (NRF_CLOCK_regs[i]->INTENCLR) { /* LCOV_EXCL_BR_LINE */
394 struct clkpwr_status *this = &nhw_clkpwr_st[i];
395
396 this->INTEN &= ~NRF_CLOCK_regs[i]->INTENCLR;
397 NRF_CLOCK_regs[i]->INTENSET = this->INTEN;
398 NRF_CLOCK_regs[i]->INTENCLR = 0;
399 nhw_pwrclk_eval_interrupt(i);
400 }
401 }
402
403 #define nhw_clock_regw_sideeffects_TASKS_(x) \
404 void nhw_clock_regw_sideeffects_TASKS_##x(uint i) { \
405 if (NRF_CLOCK_regs[i]->TASKS_##x) { /* LCOV_EXCL_BR_LINE */\
406 NRF_CLOCK_regs[i]->TASKS_##x = 0; \
407 nhw_clock_TASKS_##x(i); \
408 } \
409 }
410
411 nhw_clock_regw_sideeffects_TASKS_(LFCLKSTART)
nhw_clock_regw_sideeffects_TASKS_(LFCLKSTOP)412 nhw_clock_regw_sideeffects_TASKS_(LFCLKSTOP)
413 nhw_clock_regw_sideeffects_TASKS_(HFCLKSTART)
414 nhw_clock_regw_sideeffects_TASKS_(HFCLKSTOP)
415
416 #if (NHW_CLKPWR_HAS_HFCLKAUDIOCLK)
417 nhw_clock_regw_sideeffects_TASKS_(HFCLKAUDIOSTART)
418 nhw_clock_regw_sideeffects_TASKS_(HFCLKAUDIOSTOP)
419 #endif
420 #if (NHW_CLKPWR_HAS_HFCLK192MCLK)
421 nhw_clock_regw_sideeffects_TASKS_(HFCLK192MSTART)
422 nhw_clock_regw_sideeffects_TASKS_(HFCLK192MSTOP)
423 #endif
424 nhw_clock_regw_sideeffects_TASKS_(CAL)
425 #if (NHW_CLKPWR_HAS_CALTIMER)
426 nhw_clock_regw_sideeffects_TASKS_(CTSTART)
427 nhw_clock_regw_sideeffects_TASKS_(CTSTOP)
428 #endif /* NHW_CLKPWR_HAS_CALTIMER */
429
430 void nhw_pwrclk_regw_sideeffects_EVENTS_all(uint i) {
431 nhw_pwrclk_eval_interrupt(i);
432 }
433
nhw_clock_LFTimer_triggered(struct clkpwr_status * this)434 void nhw_clock_LFTimer_triggered(struct clkpwr_status *this) {
435 NRF_CLOCK_Type *CLOCK_regs = this->CLOCK_regs;
436
437 //For simplicity we assume the enable comes at the same instant as the first
438 //tick of the clock so we start ticking in this same instant
439
440 if (this->LF_Clock_state == Starting) { /* LCOV_EXCL_BR_LINE */
441 CLOCK_regs->LFCLKSTAT = CLOCK_LFCLKSTAT_STATE_Msk
442 | (CLOCK_regs->LFCLKSRCCOPY << CLOCK_LFCLKSTAT_SRC_Pos);
443
444 nhw_clock_signal_LFCLKSTARTED(this->inst);
445
446 nhw_rtc_notify_first_lf_tick();
447 } else if (this->LF_Clock_state == Stopping) {
448 this->LF_Clock_state = Stopped;
449 CLOCK_regs->LFCLKSTAT &= ~CLOCK_LFCLKSTAT_STATE_Msk;
450 }
451
452 this->Timer_CLOCK_LF = TIME_NEVER;
453 nhw_clock_update_master_timer();
454 }
455
456 #ifndef CLOCK_HFCLKSTAT_SRC_Xtal
457 #define CLOCK_HFCLKSTAT_SRC_Xtal CLOCK_HFCLKSTAT_SRC_HFXO /* Bit name change from 52 -> 53 series but same meaning*/
458 #endif
459
nhw_clock_HFTimer_triggered(struct clkpwr_status * this)460 void nhw_clock_HFTimer_triggered(struct clkpwr_status *this) {
461 NRF_CLOCK_Type *CLOCK_regs = this->CLOCK_regs;
462
463 if ( this->HF_Clock_state == Starting ){
464 this->HF_Clock_state = Started;
465
466 CLOCK_regs->HFCLKSTAT = CLOCK_HFCLKSTAT_STATE_Msk
467 | ( CLOCK_HFCLKSTAT_SRC_Xtal << CLOCK_HFCLKSTAT_SRC_Pos);
468
469 nhw_clock_signal_HFCLKSTARTED(this->inst);
470
471 } else if ( this->HF_Clock_state == Stopping ){
472 this->HF_Clock_state = Stopped;
473 CLOCK_regs->HFCLKSTAT = 0;
474 }
475
476 this->Timer_CLOCK_HF = TIME_NEVER;
477 nhw_clock_update_master_timer();
478 }
479
nhw_clock_LF_cal_triggered(struct clkpwr_status * this)480 void nhw_clock_LF_cal_triggered(struct clkpwr_status *this) {
481 this->LF_cal_state = Stopped;
482 this->Timer_LF_cal = TIME_NEVER;
483 nhw_clock_update_master_timer();
484
485 nhw_clock_signal_DONE(this->inst);
486 }
487
488 #if (NHW_CLKPWR_HAS_CALTIMER)
nhw_clock_caltimer_triggered(struct clkpwr_status * this)489 void nhw_clock_caltimer_triggered(struct clkpwr_status *this) {
490
491 if (this->caltimer_state != Started) { /* LCOV_EXCL_START */
492 bs_trace_error_time_line("%s: programming error\n", __func__);
493 } /* LCOV_EXCL_STOP */
494 this->caltimer_state = Stopped;
495 this->Timer_caltimer = TIME_NEVER;
496 nhw_clock_update_master_timer();
497 nhw_clock_signal_CTTO(this->inst);
498 }
499 #endif /* NHW_CLKPWR_HAS_CALTIMER */
500
nhw_pwrclk_timer_triggered(void)501 static void nhw_pwrclk_timer_triggered(void) {
502 bool any = false;
503 for (int i = 0; i < NHW_CLKPWR_TOTAL_INST; i++) {
504 struct clkpwr_status * c_el = &nhw_clkpwr_st[i];
505 if (Timer_PWRCLK == c_el->Timer_CLOCK_HF) {
506 nhw_clock_HFTimer_triggered(c_el);
507 any = true;
508 } else if (Timer_PWRCLK == c_el->Timer_CLOCK_LF) {
509 nhw_clock_LFTimer_triggered(c_el);
510 any = true;
511 } else if (Timer_PWRCLK == c_el->Timer_LF_cal) {
512 nhw_clock_LF_cal_triggered(c_el);
513 any = true;
514 #if (NHW_CLKPWR_HAS_CALTIMER)
515 } else if (Timer_PWRCLK == c_el->Timer_caltimer) {
516 nhw_clock_caltimer_triggered(c_el);
517 any = true;
518 #endif
519 }
520 }
521 if (!any) { /* LCOV_EXCL_START */
522 bs_trace_error_time_line("%s programming error\n", __func__);
523 } /* LCOV_EXCL_STOP */
524 }
525
526 NSI_HW_EVENT(Timer_PWRCLK, nhw_pwrclk_timer_triggered, 50);
527
528 #if (NHW_HAS_DPPI)
529
530 #define NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(TASK_N) \
531 static void nhw_clock_task##TASK_N##_wrap(void* param) \
532 { \
533 nhw_clock_TASKS_##TASK_N((int) param); \
534 } \
535 \
536 void nhw_clock_regw_sideeffects_SUBSCRIBE_##TASK_N(uint inst) \
537 { \
538 struct clkpwr_status *this = &nhw_clkpwr_st[inst]; \
539 \
540 nhw_dppi_common_subscribe_sideeffect(this->dppi_map, \
541 this->CLOCK_regs->SUBSCRIBE_##TASK_N, \
542 &this->subscribed_##TASK_N, \
543 nhw_clock_task##TASK_N##_wrap, \
544 (void*) inst); \
545 }
546
547 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKSTART)
NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKSTOP)548 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKSTOP)
549 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(LFCLKSTART)
550 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(LFCLKSTOP)
551 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(CAL)
552 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKAUDIOSTART)
553 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLKAUDIOSTOP)
554 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLK192MSTART)
555 NRF_CLOCK_REGW_SIDEFFECTS_SUBSCRIBE(HFCLK192MSTOP)
556
557 #endif /* NHW_HAS_DPPI */
558
559 #if (NHW_HAS_PPI)
560 void nhw_clock0_TASKS_LFCLKSTART(void) { nhw_clock_TASKS_LFCLKSTART(0); }
nhw_clock0_TASKS_LFCLKSTOP(void)561 void nhw_clock0_TASKS_LFCLKSTOP(void) { nhw_clock_TASKS_LFCLKSTOP(0); }
nhw_clock0_TASKS_HFCLKSTART(void)562 void nhw_clock0_TASKS_HFCLKSTART(void) { nhw_clock_TASKS_HFCLKSTART(0); }
nhw_clock0_TASKS_HFCLKSTOP(void)563 void nhw_clock0_TASKS_HFCLKSTOP(void) { nhw_clock_TASKS_HFCLKSTOP(0); }
nhw_clock0_TASKS_CAL(void)564 void nhw_clock0_TASKS_CAL(void) { nhw_clock_TASKS_CAL(0); }
nhw_clock0_TASKS_CTSTART(void)565 void nhw_clock0_TASKS_CTSTART(void) { nhw_clock_TASKS_CTSTART(0); }
nhw_clock0_TASKS_CTSTOP(void)566 void nhw_clock0_TASKS_CTSTOP(void) { nhw_clock_TASKS_CTSTOP(0); }
567 #endif /* (NHW_HAS_PPI) */
568