1 /*
2 * Copyright (c) 2020 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdint.h>
8 #include <errno.h>
9 #include <soc.h>
10 #include <zephyr/devicetree.h>
11 #include <zephyr/sys/util_macro.h>
12 #include <hal/nrf_radio.h>
13 #include <hal/nrf_gpio.h>
14 #include <hal/ccm.h>
15
16 #include "pdu_df.h"
17 #include "lll/pdu_vendor.h"
18 #include "pdu.h"
19
20 #include "radio_nrf5.h"
21 #include "radio.h"
22 #include "radio_df.h"
23 #include "radio_internal.h"
24
25 /* Devicetree node identifier for the radio node. */
26 #define RADIO_NODE DT_NODELABEL(radio)
27
28 /* Value to set for unconnected antenna GPIO pins. */
29 #define DFE_PSEL_NOT_SET 0xFF
30 /* Number of PSEL_DFEGPIO[n] registers in the radio peripheral. */
31 #define MAX_DFE_GPIO 8
32 /* Run a macro 'fn' on each available DFE GPIO index, from 0 to
33 * MAX_DFE_GPIO-1, with the given parenthesized separator.
34 */
35 #define FOR_EACH_DFE_GPIO(fn, sep) \
36 FOR_EACH(fn, sep, 0, 1, 2, 3, 4, 5, 6, 7)
37
38 /* Index of antenna id in antenna switching pattern used for GUARD and REFERENCE period */
39 #define GUARD_REF_ANTENNA_PATTERN_IDX 0U
40
41 /* Direction Finding antenna matrix configuration */
42 struct df_ant_cfg {
43 uint8_t ant_num;
44 /* Selection of GPIOs to be used to switch antennas by Radio */
45 uint8_t dfe_gpio[MAX_DFE_GPIO];
46 };
47
48 #define DFE_GPIO_PSEL(idx) \
49 NRF_DT_GPIOS_TO_PSEL_OR(RADIO_NODE, dfegpio##idx##_gpios, \
50 DFE_PSEL_NOT_SET)
51
52 #define DFE_GPIO_PIN_DISCONNECT (RADIO_PSEL_DFEGPIO_CONNECT_Disconnected << \
53 RADIO_PSEL_DFEGPIO_CONNECT_Pos)
54
55 #define HAS_DFE_GPIO(idx) DT_NODE_HAS_PROP(RADIO_NODE, dfegpio##idx##_gpios)
56
57 /* The number of dfegpio[n]-gpios properties which are set. */
58 #define DFE_GPIO_NUM (FOR_EACH_DFE_GPIO(HAS_DFE_GPIO, (+)))
59
60 /* The minimum number of antennas required to enable antenna switching. */
61 #define MIN_ANTENNA_NUM 2
62
63 /* The maximum number of antennas supported by the number of
64 * dfegpio[n]-gpios properties which are set.
65 */
66 #if (DFE_GPIO_NUM > 0)
67 #define MAX_ANTENNA_NUM BIT(DFE_GPIO_NUM)
68 #else
69 #define MAX_ANTENNA_NUM 0
70 #endif
71
radio_df_pdu_antenna_switch_pattern_get(void)72 uint8_t radio_df_pdu_antenna_switch_pattern_get(void)
73 {
74 return PDU_ANTENNA;
75 }
76
77 #if defined(CONFIG_BT_CTLR_DF_ANT_SWITCH_TX) || \
78 defined(CONFIG_BT_CTLR_DF_ANT_SWITCH_RX)
79
80 /*
81 * Check that we have an antenna switch pattern for the DFE idle
82 * state. (In DFE idle state, the radio peripheral transmits or
83 * receives PDUs.)
84 */
85
86 #define HAS_PDU_ANTENNA DT_NODE_HAS_PROP(RADIO_NODE, dfe_pdu_antenna)
87
88 BUILD_ASSERT(HAS_PDU_ANTENNA,
89 "Missing antenna pattern used to select antenna for PDU Tx "
90 "during the DFE Idle state. "
91 "Set the dfe-pdu-antenna devicetree property.");
92
radio_df_ant_switch_pattern_set(const uint8_t * patterns,uint8_t len)93 void radio_df_ant_switch_pattern_set(const uint8_t *patterns, uint8_t len)
94 {
95 /* SWITCHPATTERN is like a moving pointer to an underlying buffer.
96 * Each write stores a value and moves the pointer to new free position.
97 * When read it returns number of stored elements since last write to
98 * CLEARPATTERN. There is no need to use a subscript operator.
99 *
100 * Some storage entries in the buffer has special purpose for DFE
101 * extension in radio:
102 * - SWITCHPATTERN[0] for idle period (PDU Tx/Rx),
103 * - SWITCHPATTERN[1] for guard and reference period,
104 * - SWITCHPATTERN[2] and following for switch-sampling slots.
105 * Due to that in SWITCHPATTER[0] there is stored a pattern provided by
106 * DTS property dfe_pdu_antenna. This limits number of supported antenna
107 * switch patterns by one.
108 */
109 NRF_RADIO->SWITCHPATTERN = PDU_ANTENNA;
110 for (uint8_t idx = 0; idx < len; ++idx) {
111 NRF_RADIO->SWITCHPATTERN = patterns[idx];
112 }
113
114 /* Store antenna id used for GUARD and REFERENCE period at the end of SWITCHPATTERN buffer.
115 * It is required to apply reference antenna id when user provided switchpattern is
116 * exhausted.
117 * Maximum length of the switch pattern provided to this function is at maximum lower by one
118 * than capacity of SWITCHPATTERN buffer. Hence there is always space for reference antenna
119 * id after end of switch pattern.
120 */
121 NRF_RADIO->SWITCHPATTERN = patterns[GUARD_REF_ANTENNA_PATTERN_IDX];
122 }
123
124 /*
125 * Check that the number of antennas has been set, and that enough
126 * pins are configured to represent each pattern for the given number
127 * of antennas.
128 */
129
130 #define HAS_ANTENNA_NUM DT_NODE_HAS_PROP(RADIO_NODE, dfe_antenna_num)
131
132 BUILD_ASSERT(HAS_ANTENNA_NUM,
133 "You must set the dfe-antenna-num property in the radio node "
134 "to enable antenna switching.");
135
136 #define ANTENNA_NUM DT_PROP_OR(RADIO_NODE, dfe_antenna_num, 0)
137
138 BUILD_ASSERT(!HAS_ANTENNA_NUM || (ANTENNA_NUM <= MAX_ANTENNA_NUM),
139 "Insufficient number of GPIO pins configured. "
140 "Set more dfegpio[n]-gpios properties.");
141 BUILD_ASSERT(!HAS_ANTENNA_NUM || (ANTENNA_NUM >= MIN_ANTENNA_NUM),
142 "Insufficient number of antennas provided. "
143 "Increase the dfe-antenna-num property.");
144
145 /*
146 * Check that each dfegpio[n]-gpios property has a zero flags cell.
147 */
148
149 #define ASSERT_DFE_GPIO_FLAGS_ARE_ZERO(idx) \
150 BUILD_ASSERT(DT_GPIO_FLAGS(RADIO_NODE, dfegpio##idx##_gpios) == 0, \
151 "The flags cell in each dfegpio[n]-gpios " \
152 "property must be zero.")
153
154 FOR_EACH_DFE_GPIO(ASSERT_DFE_GPIO_FLAGS_ARE_ZERO, (;));
155
156 /* Stores the dfegpio[n]-gpios property values.
157 */
158 const static struct df_ant_cfg ant_cfg = {
159 .ant_num = ANTENNA_NUM,
160 .dfe_gpio = { FOR_EACH_DFE_GPIO(DFE_GPIO_PSEL, (,)) }
161 };
162
163 /* @brief Function configures Radio with information about GPIO pins that may be
164 * used to drive antenna switching during CTE Tx/RX.
165 *
166 * Sets up DF related PSEL.DFEGPIO registers to give possibility to Radio
167 * to drive antennas switches.
168 *
169 */
radio_df_ant_switching_pin_sel_cfg(void)170 void radio_df_ant_switching_pin_sel_cfg(void)
171 {
172 uint8_t pin_sel;
173
174 for (uint8_t idx = 0; idx < MAX_DFE_GPIO; ++idx) {
175 pin_sel = ant_cfg.dfe_gpio[idx];
176
177 if (pin_sel != DFE_PSEL_NOT_SET) {
178 nrf_radio_dfe_pattern_pin_set(NRF_RADIO,
179 pin_sel,
180 idx);
181 } else {
182 nrf_radio_dfe_pattern_pin_set(NRF_RADIO,
183 DFE_GPIO_PIN_DISCONNECT,
184 idx);
185 }
186 }
187 }
188
189 #if defined(CONFIG_BT_CTLR_DF_INIT_ANT_SEL_GPIOS)
190 /* @brief Function configures GPIO pins that will be used by Direction Finding
191 * Extension for antenna switching.
192 *
193 * Function configures antenna selection GPIO pins in GPIO peripheral.
194 * Also sets pin outputs to match state in SWITCHPATTERN[0] that is used
195 * to enable antenna for PDU Rx/Tx. That has to prevent glitches when
196 * DFE is powered off after end of transmission.
197 *
198 * @return Zero in case of success, other value in case of failure.
199 */
radio_df_ant_switching_gpios_cfg(void)200 void radio_df_ant_switching_gpios_cfg(void)
201 {
202 uint8_t pin_sel;
203
204 for (uint8_t idx = 0; idx < MAX_DFE_GPIO; ++idx) {
205 pin_sel = ant_cfg.dfe_gpio[idx];
206 if (pin_sel != DFE_PSEL_NOT_SET) {
207 nrf_gpio_cfg_output(pin_sel);
208
209 if (BIT(idx) & PDU_ANTENNA) {
210 nrf_gpio_pin_set(pin_sel);
211 } else {
212 nrf_gpio_pin_clear(pin_sel);
213 }
214 }
215 }
216 }
217 #endif /* CONFIG_BT_CTLR_DF_INIT_ANT_SEL_GPIOS */
218 #endif /* CONFIG_BT_CTLR_DF_ANT_SWITCH_TX || CONFIG_BT_CTLR_DF_ANT_SWITCH_RX */
219
220 /* @brief Function provides number of available antennas for Direction Finding.
221 *
222 * The number of antennas is hardware defined. It is provided via devicetree.
223 *
224 * If antenna switching is not enabled then there must be a single antenna
225 * responsible for PDU reception and transmission.
226 *
227 * @return Number of available antennas.
228 */
radio_df_ant_num_get(void)229 uint8_t radio_df_ant_num_get(void)
230 {
231 #if defined(CONFIG_BT_CTLR_DF_ANT_SWITCH_TX) || \
232 defined(CONFIG_BT_CTLR_DF_ANT_SWITCH_RX)
233 return ant_cfg.ant_num;
234 #else
235 return 1U;
236 #endif
237 }
238
radio_df_mode_set(uint8_t mode)239 static inline void radio_df_mode_set(uint8_t mode)
240 {
241 NRF_RADIO->DFEMODE &= ~RADIO_DFEMODE_DFEOPMODE_Msk;
242 NRF_RADIO->DFEMODE |= ((mode << RADIO_DFEMODE_DFEOPMODE_Pos)
243 & RADIO_DFEMODE_DFEOPMODE_Msk);
244 }
245
radio_df_mode_set_aoa(void)246 void radio_df_mode_set_aoa(void)
247 {
248 radio_df_mode_set(NRF_RADIO_DFE_OP_MODE_AOA);
249 }
250
radio_df_mode_set_aod(void)251 void radio_df_mode_set_aod(void)
252 {
253 radio_df_mode_set(NRF_RADIO_DFE_OP_MODE_AOD);
254 }
255
radio_df_ctrl_set(uint8_t cte_len,uint8_t switch_spacing,uint8_t sample_spacing,uint8_t phy)256 static inline void radio_df_ctrl_set(uint8_t cte_len,
257 uint8_t switch_spacing,
258 uint8_t sample_spacing,
259 uint8_t phy)
260 {
261 uint16_t sample_offset;
262 uint32_t conf;
263
264 /* Complete setup is done on purpose, to be sure that there isn't left
265 * any unexpected state in the register.
266 */
267 conf = ((((uint32_t)cte_len << RADIO_DFECTRL1_NUMBEROF8US_Pos) &
268 RADIO_DFECTRL1_NUMBEROF8US_Msk) |
269 ((uint32_t)RADIO_DFECTRL1_DFEINEXTENSION_CRC <<
270 RADIO_DFECTRL1_DFEINEXTENSION_Pos) |
271 ((uint32_t)switch_spacing << RADIO_DFECTRL1_TSWITCHSPACING_Pos) |
272 ((uint32_t)NRF_RADIO_DFECTRL_SAMPLE_SPACING_1US <<
273 RADIO_DFECTRL1_TSAMPLESPACINGREF_Pos) |
274 ((uint32_t)NRF_RADIO_DFECTRL_SAMPLE_TYPE_IQ <<
275 RADIO_DFECTRL1_SAMPLETYPE_Pos) |
276 ((uint32_t)sample_spacing << RADIO_DFECTRL1_TSAMPLESPACING_Pos) |
277 (((uint32_t)0 << RADIO_DFECTRL1_AGCBACKOFFGAIN_Pos) &
278 RADIO_DFECTRL1_AGCBACKOFFGAIN_Msk));
279
280 NRF_RADIO->DFECTRL1 = conf;
281
282 switch (phy) {
283 case PHY_1M:
284 if (switch_spacing == RADIO_DFECTRL1_TSWITCHSPACING_2us) {
285 sample_offset = CONFIG_BT_CTLR_DF_SAMPLE_OFFSET_PHY_1M_SAMPLING_1US;
286 } else if (switch_spacing == RADIO_DFECTRL1_TSWITCHSPACING_4us) {
287 sample_offset = CONFIG_BT_CTLR_DF_SAMPLE_OFFSET_PHY_1M_SAMPLING_2US;
288 } else {
289 sample_offset = 0;
290 }
291 break;
292 case PHY_2M:
293 if (switch_spacing == RADIO_DFECTRL1_TSWITCHSPACING_2us) {
294 sample_offset = CONFIG_BT_CTLR_DF_SAMPLE_OFFSET_PHY_2M_SAMPLING_1US;
295 } else if (switch_spacing == RADIO_DFECTRL1_TSWITCHSPACING_4us) {
296 sample_offset = CONFIG_BT_CTLR_DF_SAMPLE_OFFSET_PHY_2M_SAMPLING_2US;
297 } else {
298 sample_offset = 0;
299 }
300 break;
301 case PHY_LEGACY:
302 default:
303 /* If phy is set to legacy, the function is called in TX context and actual value
304 * does not matter, hence it is set to default zero.
305 */
306 sample_offset = 0;
307 }
308
309 conf = ((((uint32_t)sample_offset << RADIO_DFECTRL2_TSAMPLEOFFSET_Pos) &
310 RADIO_DFECTRL2_TSAMPLEOFFSET_Msk) |
311 (((uint32_t)CONFIG_BT_CTLR_DF_SWITCH_OFFSET << RADIO_DFECTRL2_TSWITCHOFFSET_Pos) &
312 RADIO_DFECTRL2_TSWITCHOFFSET_Msk));
313
314 NRF_RADIO->DFECTRL2 = conf;
315 }
316
radio_df_cte_tx_aod_2us_set(uint8_t cte_len)317 void radio_df_cte_tx_aod_2us_set(uint8_t cte_len)
318 {
319 /* Sample spacing does not matter for AoD Tx. It is set to value
320 * that is in DFECTRL1 register after reset. That is done instead of
321 * adding conditions on the value and masking of the field before
322 * storing configuration in the register. Also values in DFECTRL2,
323 * that depend on PHY, are irrelevant for AoD Tx, hence use of
324 * PHY_LEGACY here.
325 */
326 radio_df_ctrl_set(cte_len, RADIO_DFECTRL1_TSWITCHSPACING_2us,
327 RADIO_DFECTRL1_TSAMPLESPACING_2us, PHY_LEGACY);
328 }
329
radio_df_cte_tx_aod_4us_set(uint8_t cte_len)330 void radio_df_cte_tx_aod_4us_set(uint8_t cte_len)
331 {
332 /* Sample spacing does not matter for AoD Tx. It is set to value
333 * that is in DFECTRL1 register after reset. That is done instead of
334 * adding conditions on the value and masking of the field before
335 * storing configuration in the register. Also values in DFECTRL2,
336 * that depend on PHY, are irrelevant for AoD Tx, hence use of
337 * PHY_LEGACY here.
338 */
339 radio_df_ctrl_set(cte_len, RADIO_DFECTRL1_TSWITCHSPACING_4us,
340 RADIO_DFECTRL1_TSAMPLESPACING_2us, PHY_LEGACY);
341 }
342
radio_df_cte_tx_aoa_set(uint8_t cte_len)343 void radio_df_cte_tx_aoa_set(uint8_t cte_len)
344 {
345 /* Switch and sample spacing does not matter for AoA Tx. It is set to
346 * value that is in DFECTRL1 register after reset. That is done instead
347 * of adding conditions on the value and masking of the field before
348 * storing configuration in the register. Also values in DFECTRL2,
349 * that depend on PHY, are irrelevant for AoA Tx, hence use of
350 * PHY_LEGACY here.
351 */
352 radio_df_ctrl_set(cte_len, RADIO_DFECTRL1_TSWITCHSPACING_4us,
353 RADIO_DFECTRL1_TSAMPLESPACING_2us, PHY_LEGACY);
354 }
355
radio_df_cte_rx_2us_switching(bool cte_info_in_s1,uint8_t phy)356 void radio_df_cte_rx_2us_switching(bool cte_info_in_s1, uint8_t phy)
357 {
358 /* BT spec requires single sample for a single switching slot, so
359 * spacing for slot and samples is the same.
360 * CTE duration is used only when CTEINLINE config is disabled.
361 */
362 radio_df_ctrl_set(0, RADIO_DFECTRL1_TSWITCHSPACING_2us,
363 RADIO_DFECTRL1_TSAMPLESPACING_2us, phy);
364 radio_df_cte_inline_set_enabled(cte_info_in_s1);
365 }
366
radio_df_cte_rx_4us_switching(bool cte_info_in_s1,uint8_t phy)367 void radio_df_cte_rx_4us_switching(bool cte_info_in_s1, uint8_t phy)
368 {
369 /* BT spec requires single sample for a single switching slot, so
370 * spacing for slot and samples is the same.
371 * CTE duration is used only when CTEINLINE config is disabled.
372 */
373 radio_df_ctrl_set(0, RADIO_DFECTRL1_TSWITCHSPACING_4us,
374 RADIO_DFECTRL1_TSAMPLESPACING_4us, phy);
375 radio_df_cte_inline_set_enabled(cte_info_in_s1);
376 }
377
radio_df_ant_switch_pattern_clear(void)378 void radio_df_ant_switch_pattern_clear(void)
379 {
380 NRF_RADIO->CLEARPATTERN = (HAL_RADIO_CLEARPATTERN_CLEARPATTERN_Clear <<
381 RADIO_CLEARPATTERN_CLEARPATTERN_Pos) &
382 RADIO_CLEARPATTERN_CLEARPATTERN_Msk;
383 }
384
radio_df_reset(void)385 void radio_df_reset(void)
386 {
387 /* Initialize to NRF_RADIO reset values
388 * Note: Only registers that turn off the DF feature and those
389 * registers whose bits are partially modified across functions
390 * are assigned back the power-on reset values.
391 */
392 NRF_RADIO->DFEMODE = HAL_RADIO_RESET_VALUE_DFEMODE;
393 NRF_RADIO->CTEINLINECONF = HAL_RADIO_RESET_VALUE_CTEINLINECONF;
394
395 radio_df_ant_switch_pattern_clear();
396 }
397
radio_switch_complete_and_phy_end_b2b_tx(uint8_t phy_curr,uint8_t flags_curr,uint8_t phy_next,uint8_t flags_next)398 void radio_switch_complete_and_phy_end_b2b_tx(uint8_t phy_curr, uint8_t flags_curr,
399 uint8_t phy_next, uint8_t flags_next)
400 {
401 #if defined(CONFIG_BT_CTLR_TIFS_HW)
402 NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_END_DISABLE_Msk |
403 RADIO_SHORTS_DISABLED_TXEN_Msk;
404 #else /* !CONFIG_BT_CTLR_TIFS_HW */
405 NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk | NRF_RADIO_SHORTS_TRX_END_DISABLE_Msk;
406 sw_switch(SW_SWITCH_TX, SW_SWITCH_TX, phy_curr, flags_curr, phy_next, flags_next,
407 END_EVT_DELAY_DISABLED);
408 #endif /* !CONFIG_BT_CTLR_TIFS_HW */
409 }
410
radio_df_iq_data_packet_set(uint8_t * buffer,size_t len)411 void radio_df_iq_data_packet_set(uint8_t *buffer, size_t len)
412 {
413 nrf_radio_dfe_buffer_set(NRF_RADIO, (uint32_t *)buffer, len);
414 }
415
radio_df_iq_samples_amount_get(void)416 uint32_t radio_df_iq_samples_amount_get(void)
417 {
418 return nrf_radio_dfe_amount_get(NRF_RADIO);
419 }
420
radio_df_cte_status_get(void)421 uint8_t radio_df_cte_status_get(void)
422 {
423 return NRF_RADIO->CTESTATUS;
424 }
425
radio_df_cte_ready(void)426 bool radio_df_cte_ready(void)
427 {
428 return (NRF_RADIO->EVENTS_CTEPRESENT != 0);
429 }
430