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