1 /*
2 * Copyright (c) 2018-2020 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdint.h>
8
9 #include <zephyr/toolchain.h>
10
11 #include <zephyr/sys/util.h>
12 #include <zephyr/sys/byteorder.h>
13
14 #include "hal/ccm.h"
15 #include "hal/radio.h"
16 #include "hal/ticker.h"
17
18 #include "util/util.h"
19 #include "util/memq.h"
20 #include "util/dbuf.h"
21 #include "util/util.h"
22
23 #include "pdu_df.h"
24 #include "pdu_vendor.h"
25 #include "pdu.h"
26
27 #include "lll.h"
28 #include "lll_vendor.h"
29 #include "lll_clock.h"
30 #include "lll_df_types.h"
31 #include "lll_conn.h"
32 #include "lll_peripheral.h"
33 #include "lll_chan.h"
34
35 #include "lll_internal.h"
36 #include "lll_df_internal.h"
37 #include "lll_tim_internal.h"
38
39 #include <soc.h>
40 #include "hal/debug.h"
41
42 static int init_reset(void);
43 static int prepare_cb(struct lll_prepare_param *p);
44
lll_periph_init(void)45 int lll_periph_init(void)
46 {
47 int err;
48
49 err = init_reset();
50 if (err) {
51 return err;
52 }
53
54 return 0;
55 }
56
lll_periph_reset(void)57 int lll_periph_reset(void)
58 {
59 int err;
60
61 err = init_reset();
62 if (err) {
63 return err;
64 }
65
66 return 0;
67 }
68
lll_periph_prepare(void * param)69 void lll_periph_prepare(void *param)
70 {
71 struct lll_prepare_param *p;
72 struct lll_conn *lll;
73 int err;
74
75 err = lll_hfclock_on();
76 LL_ASSERT(err >= 0);
77
78 p = param;
79
80 lll = p->param;
81
82 /* Accumulate window widening */
83 lll->periph.window_widening_prepare_us +=
84 lll->periph.window_widening_periodic_us * (p->lazy + 1);
85 if (lll->periph.window_widening_prepare_us >
86 lll->periph.window_widening_max_us) {
87 lll->periph.window_widening_prepare_us =
88 lll->periph.window_widening_max_us;
89 }
90
91 /* Invoke common pipeline handling of prepare */
92 err = lll_prepare(lll_is_abort_cb, lll_conn_abort_cb, prepare_cb, 0, p);
93 LL_ASSERT(!err || err == -EINPROGRESS);
94 }
95
init_reset(void)96 static int init_reset(void)
97 {
98 return 0;
99 }
100
prepare_cb(struct lll_prepare_param * p)101 static int prepare_cb(struct lll_prepare_param *p)
102 {
103 #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX)
104 struct lll_df_conn_rx_params *df_rx_params;
105 struct lll_df_conn_rx_cfg *df_rx_cfg;
106 #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */
107 uint32_t ticks_at_event;
108 uint32_t ticks_at_start;
109 uint16_t event_counter;
110 uint32_t remainder_us;
111 uint8_t data_chan_use;
112 struct lll_conn *lll;
113 struct ull_hdr *ull;
114 uint32_t remainder;
115 uint32_t hcto;
116 uint32_t ret;
117
118 DEBUG_RADIO_START_S(1);
119
120 lll = p->param;
121
122 /* Check if stopped (on disconnection between prepare and pre-empt)
123 */
124 if (unlikely(lll->handle == 0xFFFF)) {
125 radio_isr_set(lll_isr_early_abort, lll);
126 radio_disable();
127
128 return 0;
129 }
130
131 /* Reset connection event global variables */
132 lll_conn_prepare_reset();
133
134 /* Calculate the current event latency */
135 lll->latency_event = lll->latency_prepare + p->lazy;
136
137 /* Calculate the current event counter value */
138 event_counter = lll->event_counter + lll->latency_event;
139
140 /* Update event counter to next value */
141 lll->event_counter = (event_counter + 1);
142
143 /* Reset accumulated latencies */
144 lll->latency_prepare = 0;
145
146 if (lll->data_chan_sel) {
147 #if defined(CONFIG_BT_CTLR_CHAN_SEL_2)
148 data_chan_use = lll_chan_sel_2(event_counter, lll->data_chan_id,
149 &lll->data_chan_map[0],
150 lll->data_chan_count);
151 #else /* !CONFIG_BT_CTLR_CHAN_SEL_2 */
152 data_chan_use = 0;
153 LL_ASSERT(0);
154 #endif /* !CONFIG_BT_CTLR_CHAN_SEL_2 */
155 } else {
156 data_chan_use = lll_chan_sel_1(&lll->data_chan_use,
157 lll->data_chan_hop,
158 lll->latency_event,
159 &lll->data_chan_map[0],
160 lll->data_chan_count);
161 }
162
163 /* current window widening */
164 lll->periph.window_widening_event_us +=
165 lll->periph.window_widening_prepare_us;
166 lll->periph.window_widening_prepare_us = 0;
167 if (lll->periph.window_widening_event_us >
168 lll->periph.window_widening_max_us) {
169 lll->periph.window_widening_event_us =
170 lll->periph.window_widening_max_us;
171 }
172
173 /* current window size */
174 lll->periph.window_size_event_us +=
175 lll->periph.window_size_prepare_us;
176 lll->periph.window_size_prepare_us = 0;
177
178 /* Ensure that empty flag reflects the state of the Tx queue, as a
179 * peripheral if this is the first connection event and as no prior PDU
180 * is transmitted, an incorrect acknowledgment by peer should not
181 * dequeue a PDU that has not been transmitted on air.
182 */
183 if (!lll->empty) {
184 memq_link_t *link;
185
186 /* Check for any Tx PDU at the head of the queue */
187 link = memq_peek(lll->memq_tx.head, lll->memq_tx.tail, NULL);
188 if (!link) {
189 /* Update empty flag to reflect that no valid non-empty
190 * PDU was transmitted prior to this connection event.
191 */
192 lll->empty = 1U;
193 }
194 }
195
196 /* Start setting up Radio h/w */
197 radio_reset();
198 #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
199 radio_tx_power_set(lll->tx_pwr_lvl);
200 #else
201 radio_tx_power_set(RADIO_TXP_DEFAULT);
202 #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
203
204 radio_aa_set(lll->access_addr);
205 radio_crc_configure(PDU_CRC_POLYNOMIAL,
206 sys_get_le24(lll->crc_init));
207
208 lll_chan_set(data_chan_use);
209
210 radio_isr_set(lll_conn_isr_rx, lll);
211
212 radio_tmr_tifs_set(EVENT_IFS_US);
213
214 #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX)
215 #if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE)
216 enum radio_end_evt_delay_state end_evt_delay;
217 #endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */
218
219 #if defined(CONFIG_BT_CTLR_PHY)
220 if (lll->phy_rx != PHY_CODED) {
221 #else
222 if (1) {
223 #endif /* CONFIG_BT_CTLR_PHY */
224 df_rx_cfg = &lll->df_rx_cfg;
225 df_rx_params = dbuf_latest_get(&df_rx_cfg->hdr, NULL);
226
227 if (df_rx_params->is_enabled == true) {
228 (void)lll_df_conf_cte_rx_enable(df_rx_params->slot_durations,
229 df_rx_params->ant_sw_len, df_rx_params->ant_ids,
230 data_chan_use, CTE_INFO_IN_S1_BYTE, lll->phy_rx);
231 lll->df_rx_cfg.chan = data_chan_use;
232 } else {
233 lll_df_conf_cte_info_parsing_enable();
234 }
235 #if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE)
236 end_evt_delay = END_EVT_DELAY_ENABLED;
237 } else {
238 end_evt_delay = END_EVT_DELAY_DISABLED;
239 #endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */
240 }
241
242 #if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE)
243 /* Use special API for SOC that requires compensation for PHYEND event delay. */
244 #if defined(CONFIG_BT_CTLR_PHY)
245 radio_switch_complete_with_delay_compensation_and_tx(lll->phy_rx, 0, lll->phy_tx,
246 lll->phy_flags, end_evt_delay);
247 #else /* !CONFIG_BT_CTLR_PHY */
248 radio_switch_complete_with_delay_compensation_and_tx(0, 0, 0, 0, end_evt_delay);
249 #endif /* !CONFIG_BT_CTLR_PHY */
250
251 #endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */
252 #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */
253
254 /* Use regular API for cases when:
255 * - CTE RX is not enabled,
256 * - SOC does not require compensation for PHYEND event delay.
257 */
258 if (!IS_ENABLED(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE)) {
259 #if defined(CONFIG_BT_CTLR_PHY)
260 radio_switch_complete_and_tx(lll->phy_rx, 0, lll->phy_tx, lll->phy_flags);
261 #else /* !CONFIG_BT_CTLR_PHY && !CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */
262 radio_switch_complete_and_tx(0, 0, 0, 0);
263 #endif /* !CONFIG_BT_CTLR_PHY */
264 }
265
266 /* The call can use Radio interface that alternates NRF_RADIO->SHORTS. The register is
267 * set by radio_switch_complete_XXX functions, hence any changes done before are cleared.
268 */
269 lll_conn_rx_pkt_set(lll);
270
271 ticks_at_event = p->ticks_at_expire;
272 ull = HDR_LLL2ULL(lll);
273 ticks_at_event += lll_event_offset_get(ull);
274
275 ticks_at_start = ticks_at_event;
276 ticks_at_start += HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US);
277
278 remainder = p->remainder;
279 remainder_us = radio_tmr_start(0, ticks_at_start, remainder);
280
281 radio_tmr_aa_capture();
282 radio_tmr_aa_save(0);
283
284 hcto = remainder_us +
285 ((EVENT_JITTER_US + EVENT_TICKER_RES_MARGIN_US +
286 lll->periph.window_widening_event_us) << 1) +
287 lll->periph.window_size_event_us;
288
289 #if defined(CONFIG_BT_CTLR_PHY)
290 hcto += radio_rx_ready_delay_get(lll->phy_rx, 1);
291 hcto += addr_us_get(lll->phy_rx);
292 hcto += radio_rx_chain_delay_get(lll->phy_rx, 1);
293 #else /* !CONFIG_BT_CTLR_PHY */
294 hcto += radio_rx_ready_delay_get(0, 0);
295 hcto += addr_us_get(0);
296 hcto += radio_rx_chain_delay_get(0, 0);
297 #endif /* !CONFIG_BT_CTLR_PHY */
298
299 radio_tmr_hcto_configure(hcto);
300
301 #if defined(HAL_RADIO_GPIO_HAVE_LNA_PIN)
302 radio_gpio_lna_setup();
303
304 #if defined(CONFIG_BT_CTLR_PHY)
305 radio_gpio_pa_lna_enable(remainder_us +
306 radio_rx_ready_delay_get(lll->phy_rx, 1) -
307 HAL_RADIO_GPIO_LNA_OFFSET);
308 #else /* !CONFIG_BT_CTLR_PHY */
309 radio_gpio_pa_lna_enable(remainder_us +
310 radio_rx_ready_delay_get(0, 0) -
311 HAL_RADIO_GPIO_LNA_OFFSET);
312 #endif /* !CONFIG_BT_CTLR_PHY */
313 #endif /* HAL_RADIO_GPIO_HAVE_LNA_PIN */
314
315 #if defined(CONFIG_BT_CTLR_PROFILE_ISR) || \
316 defined(HAL_RADIO_GPIO_HAVE_PA_PIN)
317 radio_tmr_end_capture();
318 #endif /* CONFIG_BT_CTLR_PROFILE_ISR */
319
320 #if defined(CONFIG_BT_CTLR_CONN_RSSI)
321 radio_rssi_measure();
322 #endif /* CONFIG_BT_CTLR_CONN_RSSI */
323
324 #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \
325 (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US)
326 uint32_t overhead;
327
328 overhead = lll_preempt_calc(ull, (TICKER_ID_CONN_BASE + lll->handle), ticks_at_event);
329 /* check if preempt to start has changed */
330 if (overhead) {
331 LL_ASSERT_OVERHEAD(overhead);
332
333 radio_isr_set(lll_isr_abort, lll);
334 radio_disable();
335
336 return -ECANCELED;
337 }
338 #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
339
340 ret = lll_prepare_done(lll);
341 LL_ASSERT(!ret);
342
343 DEBUG_RADIO_START_S(1);
344
345 return 0;
346 }
347