1 /*
2  * Copyright (c) 2016 Nordic Semiconductor ASA
3  * Copyright (c) 2016 Vinayak Kariappa Chettimada
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <stdint.h>
9 
10 #include "hal/cntr.h"
11 
12 #include "hal/debug.h"
13 
14 #if !defined(CONFIG_BT_CTLR_NRF_GRTC)
15 #include <hal/nrf_rtc.h>
16 #ifndef NRF_RTC
17 #if defined(CONFIG_SOC_COMPATIBLE_NRF54LX)
18 #define NRF_RTC NRF_RTC10
19 #else /* !CONFIG_SOC_COMPATIBLE_NRF54LX */
20 #define NRF_RTC NRF_RTC0
21 #endif /* !CONFIG_SOC_COMPATIBLE_NRF54LX */
22 #endif /* !NRF_RTC */
23 #else /* CONFIG_BT_CTLR_NRF_GRTC */
24 #include <hal/nrf_grtc.h>
25 #endif /* CONFIG_BT_CTLR_NRF_GRTC */
26 
27 static uint8_t _refcount;
28 
cntr_init(void)29 void cntr_init(void)
30 {
31 #if defined(CONFIG_BT_CTLR_NRF_GRTC)
32 #if defined(CONFIG_BT_CTLR_NRF_GRTC_START)
33 	NRF_GRTC->MODE = (GRTC_MODE_SYSCOUNTEREN_Disabled <<
34 			  GRTC_MODE_SYSCOUNTEREN_Pos) &
35 			 GRTC_MODE_SYSCOUNTEREN_Msk;
36 
37 	nrf_grtc_task_trigger(NRF_GRTC, NRF_GRTC_TASK_CLEAR);
38 
39 #if defined(CONFIG_BT_CTLR_NRF_GRTC_KEEPRUNNING)
40 	NRF_GRTC->KEEPRUNNING =
41 		(GRTC_KEEPRUNNING_REQUEST1_Active <<
42 		 GRTC_KEEPRUNNING_REQUEST1_Pos) &
43 		GRTC_KEEPRUNNING_REQUEST1_Msk;
44 	NRF_GRTC->TIMEOUT = 0U;
45 	NRF_GRTC->INTERVAL = 0U;
46 	NRF_GRTC->WAKETIME = 4U;
47 #endif /* CONFIG_BT_CTLR_NRF_GRTC_KEEPRUNNING */
48 
49 	NRF_GRTC->CLKCFG = ((GRTC_CLKCFG_CLKSEL_LFXO <<
50 			     GRTC_CLKCFG_CLKSEL_Pos) &
51 			    GRTC_CLKCFG_CLKSEL_Msk) |
52 			   ((GRTC_CLKCFG_CLKFASTDIV_Min <<
53 			     GRTC_CLKCFG_CLKFASTDIV_Pos) &
54 			    GRTC_CLKCFG_CLKFASTDIV_Msk);
55 #endif /* CONFIG_BT_CTLR_NRF_GRTC_START */
56 
57 	nrf_grtc_event_clear(NRF_GRTC, HAL_CNTR_GRTC_EVENT_COMPARE_TICKER);
58 
59 	/* FIXME: Replace with nrf_grtc_int_enable when is available,
60 	 *        with ability to select/set IRQ group.
61 	 *        Shared interrupts is an option? It may add ISR latencies?
62 	 */
63 	NRF_GRTC->INTENSET1 = HAL_CNTR_GRTC_INTENSET_COMPARE_TICKER_Msk;
64 	if (IS_ENABLED(CONFIG_SOC_SERIES_BSIM_NRF54LX)) {
65 		extern void nhw_GRTC_regw_sideeffects_INTENSET(uint32_t inst, uint32_t n);
66 
67 		nhw_GRTC_regw_sideeffects_INTENSET(0, 1);
68 	}
69 
70 #if defined(CONFIG_BT_CTLR_NRF_GRTC_START)
71 	NRF_GRTC->MODE = ((GRTC_MODE_SYSCOUNTEREN_Enabled <<
72 			   GRTC_MODE_SYSCOUNTEREN_Pos) &
73 			  GRTC_MODE_SYSCOUNTEREN_Msk) |
74 #if defined(CONFIG_BT_CTLR_NRF_GRTC_AUTOEN_CPUACTIVE)
75 			 ((GRTC_MODE_AUTOEN_CpuActive <<
76 			   GRTC_MODE_AUTOEN_Pos) &
77 			  GRTC_MODE_AUTOEN_Msk) |
78 #endif /* CONFIG_BT_CTLR_NRF_GRTC_AUTOEN_CPUACTIVE */
79 #if defined(CONFIG_BT_CTLR_NRF_GRTC_AUTOEN_DEFAULT)
80 			 ((GRTC_MODE_AUTOEN_Default <<
81 			   GRTC_MODE_AUTOEN_Pos) &
82 			  GRTC_MODE_AUTOEN_Msk) |
83 #endif /* CONFIG_BT_CTLR_NRF_GRTC_AUTOEN_DEFAULT */
84 			 0U;
85 
86 	nrf_grtc_task_trigger(NRF_GRTC, NRF_GRTC_TASK_START);
87 #endif /* CONFIG_BT_CTLR_NRF_GRTC_START */
88 
89 #else /* !CONFIG_BT_CTLR_NRF_GRTC */
90 	NRF_RTC->PRESCALER = 0;
91 	nrf_rtc_event_enable(NRF_RTC, RTC_EVTENSET_COMPARE0_Msk);
92 	nrf_rtc_int_enable(NRF_RTC, RTC_INTENSET_COMPARE0_Msk);
93 #endif /* !CONFIG_BT_CTLR_NRF_GRTC */
94 }
95 
cntr_start(void)96 uint32_t cntr_start(void)
97 {
98 	if (_refcount++) {
99 		return 1;
100 	}
101 
102 #if defined(CONFIG_BT_CTLR_NRF_GRTC)
103 	/* TODO: if we own and start GRTC, implement start here */
104 #else /* !CONFIG_BT_CTLR_NRF_GRTC */
105 	nrf_rtc_task_trigger(NRF_RTC, NRF_RTC_TASK_START);
106 #endif /* !CONFIG_BT_CTLR_NRF_GRTC */
107 
108 	return 0;
109 }
110 
cntr_stop(void)111 uint32_t cntr_stop(void)
112 {
113 	LL_ASSERT(_refcount);
114 
115 	if (--_refcount) {
116 		return 1;
117 	}
118 
119 #if defined(CONFIG_BT_CTLR_NRF_GRTC)
120 	/* TODO: if we own and stop GRTC, implement stop here */
121 #else /* !CONFIG_BT_CTLR_NRF_GRTC */
122 	nrf_rtc_task_trigger(NRF_RTC, NRF_RTC_TASK_STOP);
123 #endif /* !CONFIG_BT_CTLR_NRF_GRTC */
124 
125 	return 0;
126 }
127 
cntr_cnt_get(void)128 uint32_t cntr_cnt_get(void)
129 {
130 #if defined(CONFIG_BT_CTLR_NRF_GRTC)
131 	uint32_t cntr_l, cntr_h, cntr_h_overflow;
132 
133 	/* NOTE: For a 32-bit implementation, L value is read after H
134 	 *       to avoid another L value after SYSCOUNTER gets ready.
135 	 *       If both H and L values are desired, then swap the order and
136 	 *       ensure that L value does not change when H value is read.
137 	 */
138 	do {
139 		cntr_h = nrf_grtc_sys_counter_high_get(NRF_GRTC);
140 		cntr_l = nrf_grtc_sys_counter_low_get(NRF_GRTC);
141 		cntr_h_overflow = nrf_grtc_sys_counter_high_get(NRF_GRTC);
142 	} while ((cntr_h & GRTC_SYSCOUNTER_SYSCOUNTERH_BUSY_Msk) ||
143 		 (cntr_h_overflow & GRTC_SYSCOUNTER_SYSCOUNTERH_OVERFLOW_Msk));
144 
145 	return cntr_l;
146 #else /* !CONFIG_BT_CTLR_NRF_GRTC */
147 	return nrf_rtc_counter_get(NRF_RTC);
148 #endif /* !CONFIG_BT_CTLR_NRF_GRTC */
149 }
150 
cntr_cmp_set(uint8_t cmp,uint32_t value)151 void cntr_cmp_set(uint8_t cmp, uint32_t value)
152 {
153 #if defined(CONFIG_BT_CTLR_NRF_GRTC)
154 	uint32_t cntr_l, cntr_h, cntr_h_overflow, stale;
155 
156 	/* NOTE: We are going to use TASKS_CAPTURE to read current
157 	 *       SYSCOUNTER H and L, so that COMPARE registers can be set
158 	 *       considering that we need to set H compare value too.
159 	 */
160 
161 	/* Read current syscounter value */
162 	do {
163 		cntr_h = nrf_grtc_sys_counter_high_get(NRF_GRTC);
164 		cntr_l = nrf_grtc_sys_counter_low_get(NRF_GRTC);
165 		cntr_h_overflow = nrf_grtc_sys_counter_high_get(NRF_GRTC);
166 	} while ((cntr_h & GRTC_SYSCOUNTER_SYSCOUNTERH_BUSY_Msk) ||
167 		 (cntr_h_overflow & GRTC_SYSCOUNTER_SYSCOUNTERH_OVERFLOW_Msk));
168 
169 	/* Disable capture/compare */
170 	nrf_grtc_sys_counter_compare_event_disable(NRF_GRTC, cmp);
171 
172 	/* Set a stale value in capture value */
173 	stale = cntr_l - 1U;
174 	NRF_GRTC->CC[cmp].CCL = stale;
175 
176 	/* Trigger a capture */
177 	nrf_grtc_task_trigger(NRF_GRTC, (NRF_GRTC_TASK_CAPTURE_0 + (cmp * sizeof(uint32_t))));
178 
179 	/* Wait to get a new L value */
180 	do {
181 		cntr_l = NRF_GRTC->CC[cmp].CCL;
182 	} while (cntr_l == stale);
183 
184 	/* Read H value */
185 	cntr_h = NRF_GRTC->CC[cmp].CCH;
186 
187 	/* NOTE: HERE, we have cntr_h and cntr_l in sync. */
188 
189 	/* Handle rollover between current and expected value */
190 	if (value < cntr_l) {
191 		cntr_h++;
192 	}
193 
194 	/* Set compare register values */
195 	nrf_grtc_sys_counter_cc_set(NRF_GRTC, cmp,
196 				    ((((uint64_t)cntr_h & GRTC_CC_CCH_CCH_Msk) << 32) | value));
197 
198 	/* Enable compare */
199 	nrf_grtc_sys_counter_compare_event_enable(NRF_GRTC, cmp);
200 
201 #else /* !CONFIG_BT_CTLR_NRF_GRTC */
202 	nrf_rtc_cc_set(NRF_RTC, cmp, value);
203 #endif /* !CONFIG_BT_CTLR_NRF_GRTC */
204 }
205