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 /* Invoke common pipeline handling of prepare */
83 err = lll_prepare(lll_conn_peripheral_is_abort_cb, lll_conn_abort_cb,
84 prepare_cb, 0U, param);
85 LL_ASSERT(!err || err == -EINPROGRESS);
86 }
87
init_reset(void)88 static int init_reset(void)
89 {
90 return 0;
91 }
92
prepare_cb(struct lll_prepare_param * p)93 static int prepare_cb(struct lll_prepare_param *p)
94 {
95 #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX)
96 struct lll_df_conn_rx_params *df_rx_params;
97 struct lll_df_conn_rx_cfg *df_rx_cfg;
98 #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */
99 uint32_t ticks_at_event;
100 uint32_t ticks_at_start;
101 uint16_t event_counter;
102 uint32_t remainder_us;
103 uint8_t data_chan_use;
104 struct lll_conn *lll;
105 struct ull_hdr *ull;
106 uint32_t remainder;
107 uint32_t hcto;
108 uint32_t ret;
109
110 DEBUG_RADIO_START_S(1);
111
112 lll = p->param;
113
114 /* Check if stopped (on disconnection between prepare and preempt)
115 */
116 if (unlikely(lll->handle == 0xFFFF)) {
117 radio_isr_set(lll_isr_early_abort, lll);
118 radio_disable();
119
120 return 0;
121 }
122
123 /* Reset connection event global variables */
124 lll_conn_prepare_reset();
125
126 /* Calculate the current event latency */
127 lll->lazy_prepare = p->lazy;
128 lll->latency_event = lll->latency_prepare + lll->lazy_prepare;
129
130 /* Calculate the current event counter value */
131 event_counter = lll->event_counter + lll->latency_event;
132
133 /* Update event counter to next value */
134 lll->event_counter = (event_counter + 1);
135
136 /* Reset accumulated latencies */
137 lll->latency_prepare = 0;
138
139 if (lll->data_chan_sel) {
140 #if defined(CONFIG_BT_CTLR_CHAN_SEL_2)
141 data_chan_use = lll_chan_sel_2(event_counter, lll->data_chan_id,
142 &lll->data_chan_map[0],
143 lll->data_chan_count);
144 #else /* !CONFIG_BT_CTLR_CHAN_SEL_2 */
145 data_chan_use = 0;
146 LL_ASSERT(0);
147 #endif /* !CONFIG_BT_CTLR_CHAN_SEL_2 */
148 } else {
149 data_chan_use = lll_chan_sel_1(&lll->data_chan_use,
150 lll->data_chan_hop,
151 lll->latency_event,
152 &lll->data_chan_map[0],
153 lll->data_chan_count);
154 }
155
156 /* Accumulate window widening */
157 lll->periph.window_widening_prepare_us +=
158 lll->periph.window_widening_periodic_us * (lll->lazy_prepare + 1U);
159 if (lll->periph.window_widening_prepare_us >
160 lll->periph.window_widening_max_us) {
161 lll->periph.window_widening_prepare_us =
162 lll->periph.window_widening_max_us;
163 }
164
165 /* current window widening */
166 lll->periph.window_widening_event_us +=
167 lll->periph.window_widening_prepare_us;
168 lll->periph.window_widening_prepare_us = 0;
169 if (lll->periph.window_widening_event_us >
170 lll->periph.window_widening_max_us) {
171 lll->periph.window_widening_event_us =
172 lll->periph.window_widening_max_us;
173 }
174
175 /* current window size */
176 lll->periph.window_size_event_us +=
177 lll->periph.window_size_prepare_us;
178 lll->periph.window_size_prepare_us = 0;
179
180 /* Ensure that empty flag reflects the state of the Tx queue, as a
181 * peripheral if this is the first connection event and as no prior PDU
182 * is transmitted, an incorrect acknowledgment by peer should not
183 * dequeue a PDU that has not been transmitted on air.
184 */
185 if (!lll->empty) {
186 memq_link_t *link;
187
188 /* Check for any Tx PDU at the head of the queue */
189 link = memq_peek(lll->memq_tx.head, lll->memq_tx.tail, NULL);
190 if (!link) {
191 /* Update empty flag to reflect that no valid non-empty
192 * PDU was transmitted prior to this connection event.
193 */
194 lll->empty = 1U;
195 }
196 }
197
198 /* Start setting up Radio h/w */
199 radio_reset();
200 #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
201 radio_tx_power_set(lll->tx_pwr_lvl);
202 #else
203 radio_tx_power_set(RADIO_TXP_DEFAULT);
204 #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL */
205
206 radio_aa_set(lll->access_addr);
207 radio_crc_configure(PDU_CRC_POLYNOMIAL,
208 sys_get_le24(lll->crc_init));
209
210 lll_chan_set(data_chan_use);
211
212 radio_isr_set(lll_conn_isr_rx, lll);
213
214 radio_tmr_tifs_set(lll->tifs_tx_us);
215
216 #if defined(CONFIG_BT_CTLR_DF_CONN_CTE_RX)
217 #if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE)
218 enum radio_end_evt_delay_state end_evt_delay;
219 #endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */
220
221 #if defined(CONFIG_BT_CTLR_PHY)
222 if (lll->phy_rx != PHY_CODED) {
223 #else
224 if (1) {
225 #endif /* CONFIG_BT_CTLR_PHY */
226 df_rx_cfg = &lll->df_rx_cfg;
227 df_rx_params = dbuf_latest_get(&df_rx_cfg->hdr, NULL);
228
229 if (df_rx_params->is_enabled == true) {
230 (void)lll_df_conf_cte_rx_enable(df_rx_params->slot_durations,
231 df_rx_params->ant_sw_len, df_rx_params->ant_ids,
232 data_chan_use, CTE_INFO_IN_S1_BYTE, lll->phy_rx);
233 lll->df_rx_cfg.chan = data_chan_use;
234 } else {
235 lll_df_conf_cte_info_parsing_enable();
236 }
237 #if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE)
238 end_evt_delay = END_EVT_DELAY_ENABLED;
239 } else {
240 end_evt_delay = END_EVT_DELAY_DISABLED;
241 #endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */
242 }
243
244 #if defined(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE)
245 /* Use special API for SOC that requires compensation for PHYEND event delay. */
246 #if defined(CONFIG_BT_CTLR_PHY)
247 radio_switch_complete_with_delay_compensation_and_tx(lll->phy_rx, 0, lll->phy_tx,
248 lll->phy_flags, end_evt_delay);
249 #else /* !CONFIG_BT_CTLR_PHY */
250 radio_switch_complete_with_delay_compensation_and_tx(0, 0, 0, 0, end_evt_delay);
251 #endif /* !CONFIG_BT_CTLR_PHY */
252
253 #endif /* CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */
254 #endif /* CONFIG_BT_CTLR_DF_CONN_CTE_RX */
255
256 /* Use regular API for cases when:
257 * - CTE RX is not enabled,
258 * - SOC does not require compensation for PHYEND event delay.
259 */
260 if (!IS_ENABLED(CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE)) {
261 #if defined(CONFIG_BT_CTLR_PHY)
262 radio_switch_complete_and_tx(lll->phy_rx, 0, lll->phy_tx, lll->phy_flags);
263 #else /* !CONFIG_BT_CTLR_PHY && !CONFIG_BT_CTLR_DF_PHYEND_OFFSET_COMPENSATION_ENABLE */
264 radio_switch_complete_and_tx(0, 0, 0, 0);
265 #endif /* !CONFIG_BT_CTLR_PHY */
266 }
267
268 /* The call can use Radio interface that alternates NRF_RADIO->SHORTS. The register is
269 * set by radio_switch_complete_XXX functions, hence any changes done before are cleared.
270 */
271 lll_conn_rx_pkt_set(lll);
272
273 ticks_at_event = p->ticks_at_expire;
274 ull = HDR_LLL2ULL(lll);
275 ticks_at_event += lll_event_offset_get(ull);
276
277 ticks_at_start = ticks_at_event;
278 ticks_at_start += HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US);
279
280 remainder = p->remainder;
281 remainder_us = radio_tmr_start(0, ticks_at_start, remainder);
282
283 radio_tmr_aa_capture();
284 radio_tmr_aa_save(0);
285
286 hcto = remainder_us +
287 ((EVENT_JITTER_US + EVENT_TICKER_RES_MARGIN_US +
288 lll->periph.window_widening_event_us) << 1) +
289 lll->periph.window_size_event_us;
290
291 #if defined(CONFIG_BT_CTLR_PHY)
292 hcto += radio_rx_ready_delay_get(lll->phy_rx, 1);
293 hcto += addr_us_get(lll->phy_rx);
294 hcto += radio_rx_chain_delay_get(lll->phy_rx, 1);
295 #else /* !CONFIG_BT_CTLR_PHY */
296 hcto += radio_rx_ready_delay_get(0, 0);
297 hcto += addr_us_get(0);
298 hcto += radio_rx_chain_delay_get(0, 0);
299 #endif /* !CONFIG_BT_CTLR_PHY */
300
301 radio_tmr_hcto_configure(hcto);
302
303 #if defined(HAL_RADIO_GPIO_HAVE_LNA_PIN)
304 radio_gpio_lna_setup();
305
306 #if defined(CONFIG_BT_CTLR_PHY)
307 radio_gpio_pa_lna_enable(remainder_us +
308 radio_rx_ready_delay_get(lll->phy_rx, 1) -
309 HAL_RADIO_GPIO_LNA_OFFSET);
310 #else /* !CONFIG_BT_CTLR_PHY */
311 radio_gpio_pa_lna_enable(remainder_us +
312 radio_rx_ready_delay_get(0, 0) -
313 HAL_RADIO_GPIO_LNA_OFFSET);
314 #endif /* !CONFIG_BT_CTLR_PHY */
315 #endif /* HAL_RADIO_GPIO_HAVE_LNA_PIN */
316
317 #if defined(CONFIG_BT_CTLR_PROFILE_ISR) || \
318 defined(CONFIG_BT_CTLR_TX_DEFER) || \
319 defined(HAL_RADIO_GPIO_HAVE_PA_PIN)
320 radio_tmr_end_capture();
321 #endif /* CONFIG_BT_CTLR_PROFILE_ISR ||
322 * CONFIG_BT_CTLR_TX_DEFER ||
323 * HAL_RADIO_GPIO_HAVE_PA_PIN
324 */
325
326 #if defined(CONFIG_BT_CTLR_CONN_RSSI)
327 radio_rssi_measure();
328 #endif /* CONFIG_BT_CTLR_CONN_RSSI */
329
330 #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \
331 (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US)
332 uint32_t overhead;
333
334 overhead = lll_preempt_calc(ull, (TICKER_ID_CONN_BASE + lll->handle), ticks_at_event);
335 /* check if preempt to start has changed */
336 if (overhead) {
337 LL_ASSERT_OVERHEAD(overhead);
338
339 radio_isr_set(lll_isr_abort, lll);
340 radio_disable();
341
342 return -ECANCELED;
343 }
344 #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
345
346 ret = lll_prepare_done(lll);
347 LL_ASSERT(!ret);
348
349 DEBUG_RADIO_START_S(1);
350
351 return 0;
352 }
353