1 /*
2  * Copyright (c) 2017 Oticon A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "NRF_CLOCK.h"
7 #include <string.h>
8 #include <stdint.h>
9 #include "time_machine_if.h"
10 #include "NRF_HW_model_top.h"
11 #include "NRF_PPI.h"
12 #include "NRF_RTC.h"
13 #include "irq_ctrl.h"
14 
15 /*
16  * CLOCK — Clock control
17  * https://infocenter.nordicsemi.com/topic/ps_nrf52833/clock.html?cp=4_1_0_4_3
18  *
19  * Notes:
20  *
21  * 1. EVENTS_CTSTARTED/STOPPED not supported
22  *
23  * 2. The clocks are ready in 1 delta cycle (i.e. almost instantaneously),
24  *    HFXODEBOUNCE and LFXODEBOUNCE are ignored
25  */
26 
27 //Note: We assume the 32.768 KHz clock does not drift relative to the 64MHz one
28 // which would only happen if they had the same source or there was a tracking
29 // and adjustment loop of one based on the other
30 
31 NRF_CLOCK_Type NRF_CLOCK_regs;
32 static uint32_t CLOCK_INTEN = 0; //interrupt enable
33 
34 bs_time_t Timer_CLOCK_LF = TIME_NEVER; //LF clock timer
35 bs_time_t Timer_CLOCK_HF = TIME_NEVER;
36 static bool LF_Clock_started = false;
37 
38 static enum { Stopped, Starting, Started, Stopping} HF_Clock_state = Stopped;
39 
40 uint64_t next_lf_tick = 0; // when will the LF clock tick with 9 bits per us resolution
41 // note that this will wrap at ((1e-6/2^9)*2^64)/3600/24/365 ~= 1142 years
42 //=> this model will break after 1142 years of simulated time
43 
nrf_clock_init()44 void nrf_clock_init(){
45   memset(&NRF_CLOCK_regs, 0, sizeof(NRF_CLOCK_regs));
46   LF_Clock_started = false;
47   HF_Clock_state = Stopped;
48   Timer_CLOCK_LF = TIME_NEVER;
49   Timer_CLOCK_HF = TIME_NEVER;
50 }
51 
nrf_clock_clean_up()52 void nrf_clock_clean_up(){
53 
54 }
55 
nrf_clock_TASKS_LFCLKSTART()56 void nrf_clock_TASKS_LFCLKSTART(){
57   NRF_CLOCK_regs.LFCLKSRCCOPY = NRF_CLOCK_regs.LFCLKSRC & CLOCK_LFCLKSRC_SRC_Msk;
58   NRF_CLOCK_regs.LFCLKRUN = CLOCK_LFCLKRUN_STATUS_Msk;
59 
60   Timer_CLOCK_LF = tm_get_hw_time(); //we assume the clock is ready in 1 delta
61   //I guess we could assume some delay here.. but there is little need for this in this controller
62   nrf_hw_find_next_timer_to_trigger();
63 
64 }
65 
nrf_clock_TASKS_HFCLKSTART()66 void nrf_clock_TASKS_HFCLKSTART(){
67   if ( ( HF_Clock_state == Stopped ) || ( HF_Clock_state == Stopping ) ) {
68     HF_Clock_state = Starting;
69     NRF_CLOCK_regs.HFCLKRUN = CLOCK_HFCLKRUN_STATUS_Msk;
70     Timer_CLOCK_HF = tm_get_hw_time(); //we assume the clock is ready in 1 delta
71     //I guess we could assume some delay here.. but there is little need for this in this controller
72     nrf_hw_find_next_timer_to_trigger();
73   }
74 }
75 
nrf_clock_TASKS_HFCLKSTOP()76 void nrf_clock_TASKS_HFCLKSTOP(){
77   if ( ( HF_Clock_state == Started ) || ( HF_Clock_state == Starting ) ) {
78     NRF_CLOCK_regs.HFCLKRUN = 0;
79     HF_Clock_state = Stopping;
80     Timer_CLOCK_HF = tm_get_hw_time(); //we assume the clock is ready in 1 delta
81     //I guess we could assume some delay here.. but there is little need for this in this controller
82     nrf_hw_find_next_timer_to_trigger();
83   }
84 }
85 
nrf_clock_reqw_sideeffects_INTENSET()86 void nrf_clock_reqw_sideeffects_INTENSET(){
87   if ( NRF_CLOCK_regs.INTENSET ){
88     CLOCK_INTEN |= NRF_CLOCK_regs.INTENSET;
89     NRF_CLOCK_regs.INTENSET = CLOCK_INTEN;
90   }
91 }
92 
nrf_clock_reqw_sideeffects_INTENCLR()93 void nrf_clock_reqw_sideeffects_INTENCLR(){
94   if ( NRF_CLOCK_regs.INTENCLR ){
95     CLOCK_INTEN  &= ~NRF_CLOCK_regs.INTENCLR;
96     NRF_CLOCK_regs.INTENSET = CLOCK_INTEN;
97     NRF_CLOCK_regs.INTENCLR = 0;
98   }
99 }
100 
nrf_clock_reqw_sideeffects_TASKS_LFCLKSTART()101 void nrf_clock_reqw_sideeffects_TASKS_LFCLKSTART(){
102   if ( NRF_CLOCK_regs.TASKS_LFCLKSTART ){
103     NRF_CLOCK_regs.TASKS_LFCLKSTART = 0;
104     nrf_clock_TASKS_LFCLKSTART();
105   }
106 }
107 
nrf_clock_reqw_sideeffects_TASKS_LFCLKSTOP()108 void nrf_clock_reqw_sideeffects_TASKS_LFCLKSTOP() {
109   // There is no effect of turning the clock off that is actually modeled
110   if ( NRF_CLOCK_regs.TASKS_LFCLKSTOP ){
111     NRF_CLOCK_regs.LFCLKRUN = 0;
112   }
113 }
114 
nrf_clock_reqw_sideeffects_TASKS_HFCLKSTART()115 void nrf_clock_reqw_sideeffects_TASKS_HFCLKSTART(){
116   if ( NRF_CLOCK_regs.TASKS_HFCLKSTART ){
117     NRF_CLOCK_regs.TASKS_HFCLKSTART = 0;
118     nrf_clock_TASKS_HFCLKSTART();
119   }
120 }
121 
nrf_clock_reqw_sideeffects_TASKS_HFCLKSTOP()122 void nrf_clock_reqw_sideeffects_TASKS_HFCLKSTOP(){
123   if ( NRF_CLOCK_regs.TASKS_HFCLKSTOP ){
124     NRF_CLOCK_regs.TASKS_HFCLKSTOP = 0;
125     nrf_clock_TASKS_HFCLKSTOP();
126   }
127 }
128 
nrf_clock_regw_sideeffects()129 void nrf_clock_regw_sideeffects(){
130 
131   nrf_clock_reqw_sideeffects_INTENSET();
132 
133   nrf_clock_reqw_sideeffects_INTENCLR();
134 
135   nrf_clock_reqw_sideeffects_TASKS_LFCLKSTART();
136 
137   nrf_clock_reqw_sideeffects_TASKS_HFCLKSTART();
138 }
139 
nrf_clock_LFTimer_triggered()140 void nrf_clock_LFTimer_triggered(){
141   //We just assume the enable comes with the first tick of the clock
142 
143   if ( LF_Clock_started == false ){
144     LF_Clock_started = true;
145 
146     NRF_CLOCK_regs.LFCLKSTAT = CLOCK_LFCLKSTAT_STATE_Msk
147                           | (NRF_CLOCK_regs.LFCLKSRCCOPY << CLOCK_LFCLKSTAT_SRC_Pos);
148 
149     NRF_CLOCK_regs.EVENTS_LFCLKSTARTED = 1;
150     nrf_ppi_event(CLOCK_EVENTS_LFCLKSTARTED);
151     if ( CLOCK_INTEN & CLOCK_INTENSET_LFCLKSTARTED_Msk ){
152       hw_irq_ctrl_set_irq(POWER_CLOCK_IRQn);
153     }
154 
155     nrf_rtc_notify_first_lf_tick();
156   }
157 
158   Timer_CLOCK_LF = TIME_NEVER;
159   nrf_hw_find_next_timer_to_trigger();
160 }
161 
nrf_clock_HFTimer_triggered()162 void nrf_clock_HFTimer_triggered(){
163   if ( HF_Clock_state == Starting ){
164     HF_Clock_state = Started;
165 
166     NRF_CLOCK_regs.HFCLKSTAT = CLOCK_HFCLKSTAT_STATE_Msk
167                                | ( CLOCK_HFCLKSTAT_SRC_Xtal << CLOCK_HFCLKSTAT_SRC_Pos);
168 
169     NRF_CLOCK_regs.EVENTS_HFCLKSTARTED = 1;
170     nrf_ppi_event(CLOCK_EVENTS_HFCLKSTARTED);
171     if ( CLOCK_INTEN & CLOCK_INTENSET_HFCLKSTARTED_Msk ){
172       hw_irq_ctrl_set_irq(POWER_CLOCK_IRQn);
173     }
174 
175   } else if ( HF_Clock_state == Stopping ){
176     HF_Clock_state = Stopped;
177     NRF_CLOCK_regs.HFCLKSTAT = 0;
178   }
179 
180   Timer_CLOCK_HF = TIME_NEVER;
181   nrf_hw_find_next_timer_to_trigger();
182 }
183