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()44void 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()52void nrf_clock_clean_up(){ 53 54 } 55 nrf_clock_TASKS_LFCLKSTART()56void 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()66void 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()76void 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()86void 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()93void 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()101void 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()108void 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()115void 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()122void 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()129void 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()140void 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()162void 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