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