1 /*
2 * Copyright (c) 2016 - 2019 Nordic Semiconductor ASA
3 * Copyright (c) 2016 Vinayak Kariappa Chettimada
4 * Copyright 2019 - 2020 NXP
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <string.h>
10 #include <zephyr/sys/printk.h>
11 #include <zephyr/sys/byteorder.h>
12 #include <zephyr/bluetooth/addr.h>
13 #include <zephyr/toolchain.h>
14 #include <zephyr/irq.h>
15 #include <errno.h>
16
17 #include "util/mem.h"
18
19 #include "hal/ccm.h"
20 #include "hal/radio.h"
21
22 #include "lll/pdu_vendor.h"
23 #include "ll_sw/pdu.h"
24
25 #include "fsl_xcvr.h"
26 #include "hal/cntr.h"
27 #include "hal/ticker.h"
28 #include "hal/swi.h"
29 #include "fsl_cau3_ble.h" /* must be after irq.h */
30
31 #include "common/assert.h"
32
33 #include <soc.h>
34 #include "hal/debug.h"
35
36 #define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL
37 #include <zephyr/logging/log.h>
38 LOG_MODULE_REGISTER(bt_openisa_radio);
39
40 static radio_isr_cb_t isr_cb;
41 static void *isr_cb_param;
42
43 #define RADIO_AESCCM_HDR_MASK 0xE3 /* AES-CCM: NESN, SN, MD bits masked to 0 */
44 #define RADIO_PDU_LEN_MAX (BIT(8) - 1)
45 #define BYTES_TO_USEC(bytes, bits_per_usec) \
46 ((bytes) * 8 >> (__builtin_ffs(bits_per_usec) - 1))
47
48 /* us values */
49 #define MIN_CMD_TIME 10 /* Minimum interval for a delayed radio cmd */
50 #define RX_MARGIN 8
51 #define TX_MARGIN 0
52 #define RX_WTMRK 5 /* (AA + PDU header) - 1 */
53 #define AA_OVHD_1MBPS 27 /* AA playback overhead for 1 Mbps PHY */
54 #define AA_OVHD_2MBPS 10 /* AA playback overhead for 2 Mbps PHY */
55 #define RX_OVHD 32 /* Rx overhead */
56
57 #define PB_RX 544 /* half of PB (packet buffer) */
58
59 /* The PDU in packet buffer starts after the Access Address which is 4 octets */
60 #define PB_RX_PDU (PB_RX + 2) /* Rx PDU offset (in halfwords) in PB */
61 #define PB_TX_PDU 2 /* Tx PDU offset (in halfwords) in packet
62 * buffer
63 */
64
65 #define RADIO_ACTIVE_MASK 0x1fff
66 #define RADIO_DISABLE_TMR 4 /* us */
67
68 /* Delay needed in order to enter Manual DSM.
69 * Must be at least 4 ticks ahead of DSM_TIMER (from RM).
70 */
71 #define DSM_ENTER_DELAY_TICKS 6
72
73 /* Delay needed in order to exit Manual DSM.
74 * Should be after radio_tmr_start() (2 ticks after lll_clk_on()).
75 * But less that 1.5ms (EVENT_OVERHEAD_XTAL_US) (ULL to LLL time offset).
76 * Must be at least 4 ticks ahead of DSM_TIMER (from RM).
77 */
78 #define DSM_EXIT_DELAY_TICKS 30
79
80 /* Mask to determine the state of DSM machine */
81 #define MAN_DSM_ON (RSIM_DSM_CONTROL_MAN_DEEP_SLEEP_STATUS_MASK \
82 | RSIM_DSM_CONTROL_DSM_MAN_READY_MASK \
83 | RSIM_DSM_CONTROL_MAN_SLEEP_REQUEST_MASK) \
84
85 static uint32_t dsm_ref; /* DSM reference counter */
86
87 static uint8_t delayed_radio_start;
88 static uint8_t delayed_trx;
89 static uint32_t delayed_ticks_start;
90 static uint32_t delayed_remainder;
91 static uint8_t delayed_radio_stop;
92 static uint32_t delayed_hcto;
93
94 static uint32_t rtc_start;
95 static uint32_t rtc_diff_start_us;
96
97 static uint32_t tmr_aa; /* AA (Access Address) timestamp saved value */
98 static uint32_t tmr_aa_save; /* save AA timestamp */
99 static uint32_t tmr_ready; /* radio ready for Tx/Rx timestamp */
100 static uint32_t tmr_end; /* Tx/Rx end timestamp saved value */
101 static uint32_t tmr_end_save; /* save Tx/Rx end timestamp */
102 static uint32_t tmr_tifs;
103
104 static uint32_t rx_wu;
105 static uint32_t tx_wu;
106
107 static uint8_t phy_mode; /* Current PHY mode (DR_1MBPS or DR_2MBPS) */
108 static uint8_t bits_per_usec; /* This saves the # of bits per usec,
109 * depending on the PHY mode
110 */
111 static uint8_t phy_aa_ovhd; /* This saves the AA overhead, depending on the
112 * PHY mode
113 */
114
115 static uint32_t isr_tmr_aa;
116 static uint32_t isr_tmr_end;
117 static uint32_t isr_latency;
118 static uint32_t next_wu;
119 static uint32_t next_radio_cmd;
120
121 static uint32_t radio_trx;
122 static uint32_t force_bad_crc;
123 static uint32_t skip_hcto;
124
125 static uint8_t *rx_pkt_ptr;
126 static uint32_t payload_max_size;
127
128 static uint8_t MALIGN(4) _pkt_empty[PDU_EM_LL_SIZE_MAX];
129 static uint8_t MALIGN(4) _pkt_scratch[
130 ((RADIO_PDU_LEN_MAX + 3) > PDU_AC_LL_SIZE_MAX) ?
131 (RADIO_PDU_LEN_MAX + 3) : PDU_AC_LL_SIZE_MAX];
132
133 static int8_t rssi;
134
135 static struct {
136 union {
137 uint64_t counter;
138 uint8_t bytes[CAU3_AES_BLOCK_SIZE - 1 - 2];
139 } nonce; /* used by the B0 format but not in-situ */
140 struct pdu_data *rx_pkt_out;
141 struct pdu_data *rx_pkt_in;
142 uint8_t auth_mic_valid;
143 uint8_t empty_pdu_rxed;
144 } ctx_ccm;
145
146 #if defined(CONFIG_BT_CTLR_PRIVACY)
147 #define RPA_NO_IRK_MATCH 0xFF /* No IRK match in AR table */
148
149 static struct {
150 uint8_t ar_enable;
151 uint32_t irk_idx;
152 } radio_ar_ctx = {0U, RPA_NO_IRK_MATCH};
153 #endif /* CONFIG_BT_CTLR_PRIVACY */
154
tmp_cb(void * param)155 static void tmp_cb(void *param)
156 {
157 uint32_t tmr = GENFSK->EVENT_TMR & GENFSK_EVENT_TMR_EVENT_TMR_MASK;
158 uint32_t t2 = GENFSK->T2_CMP & GENFSK_T2_CMP_T2_CMP_MASK;
159
160 isr_latency = (tmr - t2) & GENFSK_EVENT_TMR_EVENT_TMR_MASK; /* 24bit */
161 /* Mark as done */
162 *(uint32_t *)param = 1;
163 }
164
get_isr_latency(void)165 static void get_isr_latency(void)
166 {
167 volatile uint32_t tmp = 0;
168
169 radio_isr_set(tmp_cb, (void *)&tmp);
170
171 /* Reset TMR to zero */
172 GENFSK->EVENT_TMR = 0x1000000;
173
174 radio_disable();
175 while (!tmp) {
176 }
177 irq_disable(LL_RADIO_IRQn_2nd_lvl);
178 }
179
180 static uint32_t radio_tmr_start_hlp(uint8_t trx, uint32_t ticks_start, uint32_t remainder);
181 static void radio_tmr_hcto_configure_hlp(uint32_t hcto);
radio_config_after_wake(void)182 static void radio_config_after_wake(void)
183 {
184 if (!delayed_radio_start) {
185 delayed_radio_stop = 0;
186 return;
187 }
188
189 delayed_radio_start = 0;
190 radio_tmr_start_hlp(delayed_trx, delayed_ticks_start,
191 delayed_remainder);
192
193 if (delayed_radio_stop) {
194 delayed_radio_stop = 0;
195
196 /* Adjust time out as remainder was in radio_tmr_start_hlp() */
197 delayed_hcto += rtc_diff_start_us;
198 radio_tmr_hcto_configure_hlp(delayed_hcto);
199 }
200 }
201
202 #if defined(CONFIG_BT_CTLR_PRIVACY)
ar_execute(void * pkt)203 static void ar_execute(void *pkt)
204 {
205 struct pdu_adv *pdu_adv = (struct pdu_adv *)pkt;
206 bt_addr_t *rpa = (bt_addr_t *)&pdu_adv->payload[0];
207
208 /* Perform address resolution when TxAdd=1 and address is resolvable */
209 if (pdu_adv->tx_addr && BT_ADDR_IS_RPA(rpa)) {
210 uint32_t *hash, *prand;
211 status_t status;
212
213 /* Use pointers to avoid breaking strict aliasing */
214 hash = (uint32_t *)(&rpa->val[0]);
215 prand = (uint32_t *)(&rpa->val[3]);
216
217 /* CAUv3 needs hash & prand in le format, right-justified */
218 status = CAU3_RPAtableSearch(CAU3, (*prand & 0xFFFFFF),
219 (*hash & 0xFFFFFF),
220 &radio_ar_ctx.irk_idx,
221 kCAU3_TaskDoneEvent);
222 if (status != kStatus_Success) {
223 radio_ar_ctx.irk_idx = RPA_NO_IRK_MATCH;
224 LOG_ERR("CAUv3 RPA table search failed %d", status);
225 return;
226 }
227 }
228
229 radio_ar_ctx.ar_enable = 0U;
230 }
231 #endif /* CONFIG_BT_CTLR_PRIVACY */
232
pkt_rx(void)233 static void pkt_rx(void)
234 {
235 uint32_t len, idx;
236 uint16_t *rxb = (uint16_t *)rx_pkt_ptr, tmp;
237 volatile uint16_t *pb = &GENFSK->PACKET_BUFFER[PB_RX_PDU];
238 volatile const uint32_t *sts = &GENFSK->XCVR_STS;
239
240 /* payload length */
241 len = (GENFSK->XCVR_CTRL & GENFSK_XCVR_CTRL_LENGTH_EXT_MASK) >>
242 GENFSK_XCVR_CTRL_LENGTH_EXT_SHIFT;
243
244 if (len > payload_max_size) {
245 /* Unexpected size */
246 force_bad_crc = 1;
247 next_radio_cmd = 0;
248 while (*sts & GENFSK_XCVR_STS_RX_IN_PROGRESS_MASK) {
249 }
250 return;
251 }
252
253 /* For Data Physical Channel PDU,
254 * assume no CTEInfo field, CP=0 => 2 bytes header
255 */
256 /* Add PDU header size */
257 len += 2;
258
259 /* Add to AA time, PDU + CRC time */
260 isr_tmr_end = isr_tmr_aa + BYTES_TO_USEC(len + 3, bits_per_usec);
261
262 /* If not enough time for warmup after we copy the PDU from
263 * packet buffer, send delayed command now
264 */
265 if (next_radio_cmd) {
266 /* Start Rx/Tx in TIFS */
267 idx = isr_tmr_end + tmr_tifs - next_wu;
268 GENFSK->XCVR_CTRL = next_radio_cmd;
269 GENFSK->T1_CMP = GENFSK_T1_CMP_T1_CMP(idx) |
270 GENFSK_T1_CMP_T1_CMP_EN(1);
271 next_radio_cmd = 0;
272 }
273
274 /* Can't rely on data read from packet buffer while in Rx */
275 /* Wait for Rx to finish */
276 while (*sts & GENFSK_XCVR_STS_RX_IN_PROGRESS_MASK) {
277 }
278
279 if (ctx_ccm.rx_pkt_out) {
280 *(uint16_t *)ctx_ccm.rx_pkt_out = pb[0];
281 if (len < CAU3_BLE_MIC_SIZE) {
282 ctx_ccm.rx_pkt_out = 0;
283 ctx_ccm.rx_pkt_in = 0;
284 ctx_ccm.empty_pdu_rxed = 1;
285 }
286 }
287
288 /* Copy the PDU */
289 for (idx = 0; idx < len / 2; idx++) {
290 rxb[idx] = pb[idx];
291 }
292
293 /* Copy last byte */
294 if (len & 0x1) {
295 tmp = pb[len / 2];
296 rx_pkt_ptr[len - 1] = ((uint8_t *)&tmp)[0];
297 }
298
299 #if defined(CONFIG_BT_CTLR_PRIVACY)
300 /* Perform address resolution on this Rx */
301 if (radio_ar_ctx.ar_enable) {
302 ar_execute(rxb);
303 }
304 #endif /* CONFIG_BT_CTLR_PRIVACY */
305
306 force_bad_crc = 0;
307 }
308
309 #define IRQ_MASK ~(GENFSK_IRQ_CTRL_T2_IRQ_MASK | \
310 GENFSK_IRQ_CTRL_RX_WATERMARK_IRQ_MASK | \
311 GENFSK_IRQ_CTRL_TX_IRQ_MASK | \
312 GENFSK_IRQ_CTRL_WAKE_IRQ_MASK)
isr_radio(void * arg)313 void isr_radio(void *arg)
314 {
315 ARG_UNUSED(arg);
316
317 uint32_t tmr = GENFSK->EVENT_TMR & GENFSK_EVENT_TMR_EVENT_TMR_MASK;
318 uint32_t irq = GENFSK->IRQ_CTRL;
319 uint32_t valid = 0;
320 /* We need to check for a valid IRQ source.
321 * In theory, we could get to this ISR after the IRQ source was cleared.
322 * This could happen due to the way LLL interacts with IRQs
323 * (radio_isr_set(), radio_disable()) and their propagation path:
324 * GENFSK -> INTMUX(does not latch pending source interrupts)
325 * INTMUX -> EVENT_UNIT
326 */
327
328 if (irq & GENFSK_IRQ_CTRL_WAKE_IRQ_MASK) {
329 /* Clear pending interrupts */
330 GENFSK->IRQ_CTRL &= 0xffffffff;
331
332 /* Disable DSM_TIMER */
333 RSIM->DSM_CONTROL &= ~RSIM_DSM_CONTROL_DSM_TIMER_EN(1);
334
335 radio_config_after_wake();
336 return;
337 }
338
339 if (irq & GENFSK_IRQ_CTRL_TX_IRQ_MASK) {
340 valid = 1;
341 GENFSK->IRQ_CTRL &= (IRQ_MASK | GENFSK_IRQ_CTRL_TX_IRQ_MASK);
342 GENFSK->T1_CMP &= ~GENFSK_T1_CMP_T1_CMP_EN_MASK;
343
344 isr_tmr_end = tmr - isr_latency;
345 if (tmr_end_save) {
346 tmr_end = isr_tmr_end;
347 }
348 radio_trx = 1;
349 }
350
351 if (irq & GENFSK_IRQ_CTRL_RX_WATERMARK_IRQ_MASK) {
352 valid = 1;
353 /* Disable Rx timeout */
354 /* 0b1010..RX Cancel -- Cancels pending RX events but do not
355 * abort a RX-in-progress
356 */
357 GENFSK->XCVR_CTRL = GENFSK_XCVR_CTRL_SEQCMD(0xa);
358 GENFSK->T2_CMP &= ~GENFSK_T2_CMP_T2_CMP_EN_MASK;
359
360 GENFSK->IRQ_CTRL &= (IRQ_MASK |
361 GENFSK_IRQ_CTRL_RX_WATERMARK_IRQ_MASK);
362 GENFSK->T1_CMP &= ~GENFSK_T1_CMP_T1_CMP_EN_MASK;
363
364 /* Fix reported AA time */
365 isr_tmr_aa = GENFSK->TIMESTAMP - phy_aa_ovhd;
366
367 if (tmr_aa_save) {
368 tmr_aa = isr_tmr_aa;
369 }
370 /* Copy the PDU as it arrives, calculates Rx end */
371 pkt_rx();
372 if (tmr_end_save) {
373 tmr_end = isr_tmr_end; /* from pkt_rx() */
374 }
375 radio_trx = 1;
376 rssi = (GENFSK->XCVR_STS & GENFSK_XCVR_STS_RSSI_MASK) >>
377 GENFSK_XCVR_STS_RSSI_SHIFT;
378 }
379
380 if (irq & GENFSK_IRQ_CTRL_T2_IRQ_MASK) {
381 valid = 1;
382 GENFSK->IRQ_CTRL &= (IRQ_MASK | GENFSK_IRQ_CTRL_T2_IRQ_MASK);
383 /* Disable both comparators */
384 GENFSK->T1_CMP &= ~GENFSK_T1_CMP_T1_CMP_EN_MASK;
385 GENFSK->T2_CMP &= ~GENFSK_T2_CMP_T2_CMP_EN_MASK;
386 }
387
388 if (radio_trx && next_radio_cmd) {
389 /* Start Rx/Tx in TIFS */
390 tmr = isr_tmr_end + tmr_tifs - next_wu;
391 GENFSK->XCVR_CTRL = next_radio_cmd;
392 GENFSK->T1_CMP = GENFSK_T1_CMP_T1_CMP(tmr) |
393 GENFSK_T1_CMP_T1_CMP_EN(1);
394 next_radio_cmd = 0;
395 }
396
397 if (valid) {
398 isr_cb(isr_cb_param);
399 }
400 }
401
radio_isr_set(radio_isr_cb_t cb,void * param)402 void radio_isr_set(radio_isr_cb_t cb, void *param)
403 {
404 irq_disable(LL_RADIO_IRQn_2nd_lvl);
405 irq_disable(LL_RADIO_IRQn);
406
407 isr_cb_param = param;
408 isr_cb = cb;
409
410 /* Clear pending interrupts */
411 GENFSK->IRQ_CTRL &= 0xffffffff;
412 EVENT_UNIT->INTPTPENDCLEAR = (uint32_t)(1U << LL_RADIO_IRQn);
413
414 irq_enable(LL_RADIO_IRQn);
415 irq_enable(LL_RADIO_IRQn_2nd_lvl);
416 }
417
418 #define DISABLE_HPMCAL
419
420 #ifdef DISABLE_HPMCAL
421 #define WU_OPTIM 26 /* 34: quite ok, 36 few ok */
422 #define USE_FIXED_HPMCAL 563
423
hpmcal_disable(void)424 static void hpmcal_disable(void)
425 {
426 #ifdef USE_FIXED_HPMCAL
427 uint32_t hpmcal = USE_FIXED_HPMCAL;
428 #else
429 uint32_t hpmcal_vals[40];
430 uint32_t hpmcal;
431 int i;
432
433 GENFSK->TX_POWER = GENFSK_TX_POWER_TX_POWER(1);
434
435 /* TX warm-up at Channel Frequency = 2.44GHz */
436 for (i = 0; i < ARRAY_SIZE(hpmcal_vals); i++) {
437 GENFSK->CHANNEL_NUM = 2402 - 2360 + 2 * i;
438
439 /* Reset TMR to zero */
440 GENFSK->EVENT_TMR = 0x1000000;
441
442 /* TX Start Now */
443 GENFSK->XCVR_CTRL = GENFSK_XCVR_CTRL_SEQCMD(0x1);
444
445 while ((GENFSK->EVENT_TMR & 0xffffff) < 1000)
446 ;
447
448 /* Abort All */
449 GENFSK->XCVR_CTRL = GENFSK_XCVR_CTRL_SEQCMD(0xb);
450
451 /* Wait for XCVR to become idle. */
452 while (GENFSK->XCVR_CTRL & GENFSK_XCVR_CTRL_XCVR_BUSY_MASK)
453 ;
454
455 hpmcal_vals[i] = (XCVR_PLL_DIG->HPMCAL_CTRL &
456 XCVR_PLL_DIG_HPMCAL_CTRL_HPM_CAL_FACTOR_MASK) >>
457 XCVR_PLL_DIG_HPMCAL_CTRL_HPM_CAL_FACTOR_SHIFT;
458 }
459
460 hpmcal = hpmcal_vals[20];
461 #endif
462
463 XCVR_PLL_DIG->HPMCAL_CTRL = (XCVR_PLL_DIG->HPMCAL_CTRL &
464 ~XCVR_PLL_DIG_HPMCAL_CTRL_HPM_CAL_FACTOR_MANUAL_MASK) +
465 XCVR_PLL_DIG_HPMCAL_CTRL_HPM_CAL_FACTOR_MANUAL(hpmcal) +
466 XCVR_PLL_DIG_HPMCAL_CTRL_HP_CAL_DISABLE_MASK +
467 0x00000000;
468
469 /* Move the sigma_delta_en signal to be 1us after pll_dig_en */
470 int pll_dig_en = (XCVR_TSM->TIMING34 &
471 XCVR_TSM_TIMING34_PLL_DIG_EN_TX_HI_MASK) >>
472 XCVR_TSM_TIMING34_PLL_DIG_EN_TX_HI_SHIFT;
473
474 XCVR_TSM->TIMING38 = (XCVR_TSM->TIMING38 &
475 ~XCVR_TSM_TIMING38_SIGMA_DELTA_EN_TX_HI_MASK) +
476 XCVR_TSM_TIMING38_SIGMA_DELTA_EN_TX_HI(pll_dig_en+1);
477 /* sigma_delta_en */
478
479 XCVR_TSM->TIMING19 -= B1(WU_OPTIM); /* sy_pd_filter_charge_en */
480 XCVR_TSM->TIMING24 -= B1(WU_OPTIM); /* sy_divn_cal_en */
481 XCVR_TSM->TIMING13 -= B1(WU_OPTIM); /* sy_vco_autotune_en */
482 XCVR_TSM->TIMING17 -= B0(WU_OPTIM); /* sy_lo_tx_buf_en */
483 XCVR_TSM->TIMING26 -= B0(WU_OPTIM); /* tx_pa_en */
484 XCVR_TSM->TIMING35 -= B0(WU_OPTIM); /* tx_dig_en */
485 XCVR_TSM->TIMING14 -= B0(WU_OPTIM); /* sy_pd_cycle_slip_ld_ft_en */
486
487 XCVR_TSM->END_OF_SEQ -= B1(WU_OPTIM) + B0(WU_OPTIM);
488 }
489 #endif
490
radio_setup(void)491 void radio_setup(void)
492 {
493 XCVR_Reset();
494
495 #if defined(CONFIG_BT_CTLR_PRIVACY) || defined(CONFIG_BT_CTLR_LE_ENC)
496 CAU3_Init(CAU3);
497 #endif /* CONFIG_BT_CTLR_PRIVACY || CONFIG_BT_CTLR_LE_ENC */
498
499 XCVR_Init(GFSK_BT_0p5_h_0p5, DR_1MBPS);
500 XCVR_SetXtalTrim(41);
501
502 #ifdef DISABLE_HPMCAL
503 hpmcal_disable();
504 #endif
505
506 /* Enable Deep Sleep Mode for GENFSK */
507 XCVR_MISC->XCVR_CTRL |= XCVR_CTRL_XCVR_CTRL_MAN_DSM_SEL(2);
508
509 /* Enable the CRC as it is disabled by default after reset */
510 XCVR_MISC->CRCW_CFG |= XCVR_CTRL_CRCW_CFG_CRCW_EN(1);
511
512 /* Assign Radio #0 Interrupt to GENERIC_FSK */
513 XCVR_MISC->XCVR_CTRL |= XCVR_CTRL_XCVR_CTRL_RADIO0_IRQ_SEL(3);
514
515 phy_mode = GENFSK->BITRATE = DR_1MBPS;
516 bits_per_usec = 1;
517 phy_aa_ovhd = AA_OVHD_1MBPS;
518
519 /*
520 * Split the buffer in equal parts: first half for Tx,
521 * second half for Rx
522 */
523 GENFSK->PB_PARTITION = GENFSK_PB_PARTITION_PB_PARTITION(PB_RX);
524
525 /* Get warmup times. They are used in TIFS calculations */
526 rx_wu = (XCVR_TSM->END_OF_SEQ & XCVR_TSM_END_OF_SEQ_END_OF_RX_WU_MASK)
527 >> XCVR_TSM_END_OF_SEQ_END_OF_RX_WU_SHIFT;
528 tx_wu = (XCVR_TSM->END_OF_SEQ & XCVR_TSM_END_OF_SEQ_END_OF_TX_WU_MASK)
529 >> XCVR_TSM_END_OF_SEQ_END_OF_TX_WU_SHIFT;
530
531 /* IRQ config, clear pending interrupts */
532 irq_disable(LL_RADIO_IRQn_2nd_lvl);
533 GENFSK->IRQ_CTRL = 0xffffffff;
534 GENFSK->IRQ_CTRL = GENFSK_IRQ_CTRL_GENERIC_FSK_IRQ_EN(1) |
535 GENFSK_IRQ_CTRL_RX_WATERMARK_IRQ_EN(1) |
536 GENFSK_IRQ_CTRL_TX_IRQ_EN(1) |
537 GENFSK_IRQ_CTRL_T2_IRQ_EN(1) |
538 GENFSK_IRQ_CTRL_WAKE_IRQ_EN(1);
539
540 /* Disable Rx recycle */
541 GENFSK->IRQ_CTRL |= GENFSK_IRQ_CTRL_CRC_IGNORE(1);
542 GENFSK->WHITEN_SZ_THR |= GENFSK_WHITEN_SZ_THR_REC_BAD_PKT(1);
543
544 /* Turn radio on to measure ISR latency */
545 if (radio_is_off()) {
546 dsm_ref = 0;
547 radio_wake();
548 while (radio_is_off()) {
549 }
550 } else {
551 dsm_ref = 1;
552 }
553
554 get_isr_latency();
555
556 /* Turn radio off */
557 radio_sleep();
558 }
559
radio_reset(void)560 void radio_reset(void)
561 {
562 irq_disable(LL_RADIO_IRQn_2nd_lvl);
563 /* Vega radio is never disabled therefore doesn't require resetting */
564 }
565
radio_phy_set(uint8_t phy,uint8_t flags)566 void radio_phy_set(uint8_t phy, uint8_t flags)
567 {
568 int err = 0;
569 ARG_UNUSED(flags);
570
571 /* This function sets one of two modes:
572 * - BLE 1 Mbps
573 * - BLE 2 Mbps
574 * Coded BLE is not supported by VEGA
575 */
576 switch (phy) {
577 case BIT(0):
578 default:
579 if (phy_mode == DR_1MBPS) {
580 break;
581 }
582
583 err = XCVR_ChangeMode(GFSK_BT_0p5_h_0p5, DR_1MBPS);
584 if (err) {
585 LOG_ERR("Failed to change PHY to 1 Mbps");
586 BT_ASSERT(0);
587 }
588
589 phy_mode = GENFSK->BITRATE = DR_1MBPS;
590 bits_per_usec = 1;
591 phy_aa_ovhd = AA_OVHD_1MBPS;
592
593 break;
594
595 case BIT(1):
596 if (phy_mode == DR_2MBPS) {
597 break;
598 }
599
600 err = XCVR_ChangeMode(GFSK_BT_0p5_h_0p5, DR_2MBPS);
601 if (err) {
602 LOG_ERR("Failed to change PHY to 2 Mbps");
603 BT_ASSERT(0);
604 }
605
606 phy_mode = GENFSK->BITRATE = DR_2MBPS;
607 bits_per_usec = 2;
608 phy_aa_ovhd = AA_OVHD_2MBPS;
609
610 break;
611 }
612 }
613
radio_tx_power_set(uint32_t power)614 void radio_tx_power_set(uint32_t power)
615 {
616 ARG_UNUSED(power);
617
618 /* tx_power_level should only have the values 1, 2, 4, 6, ... , 62.
619 * Any value odd value (1, 3, ...) is not permitted and will result in
620 * undefined behavior.
621 * Those value have an associated db level that was not found in the
622 * documentation.
623 * Because of these inconsistencies for the moment this
624 * function sets the power level to a known value.
625 */
626 uint32_t tx_power_level = 62;
627
628 GENFSK->TX_POWER = GENFSK_TX_POWER_TX_POWER(tx_power_level);
629 }
630
radio_tx_power_max_set(void)631 void radio_tx_power_max_set(void)
632 {
633 printk("%s\n", __func__);
634 }
635
radio_freq_chan_set(uint32_t chan)636 void radio_freq_chan_set(uint32_t chan)
637 {
638 /*
639 * The channel number for vega radio is computed
640 * as 2360 + ch_num [in MHz]
641 * The LLL expects the channel number to be computed as 2400 + ch_num.
642 * Therefore a compensation of 40 MHz has been provided.
643 */
644 GENFSK->CHANNEL_NUM = GENFSK_CHANNEL_NUM_CHANNEL_NUM(40 + chan);
645 }
646
647 #define GENFSK_BLE_WHITEN_START 1 /* after H0 */
648 #define GENFSK_BLE_WHITEN_END 1 /* at the end of CRC */
649 #define GENFSK_BLE_WHITEN_POLY_TYPE 0 /* Galois poly type */
650 #define GENFSK_BLE_WHITEN_SIZE 7 /* poly order */
651 #define GENFSK_BLE_WHITEN_POLY 0x04
652
radio_whiten_iv_set(uint32_t iv)653 void radio_whiten_iv_set(uint32_t iv)
654 {
655 GENFSK->WHITEN_CFG &= ~(GENFSK_WHITEN_CFG_WHITEN_START_MASK |
656 GENFSK_WHITEN_CFG_WHITEN_END_MASK |
657 GENFSK_WHITEN_CFG_WHITEN_B4_CRC_MASK |
658 GENFSK_WHITEN_CFG_WHITEN_POLY_TYPE_MASK |
659 GENFSK_WHITEN_CFG_WHITEN_REF_IN_MASK |
660 GENFSK_WHITEN_CFG_WHITEN_PAYLOAD_REINIT_MASK |
661 GENFSK_WHITEN_CFG_WHITEN_SIZE_MASK |
662 GENFSK_WHITEN_CFG_MANCHESTER_EN_MASK |
663 GENFSK_WHITEN_CFG_MANCHESTER_INV_MASK |
664 GENFSK_WHITEN_CFG_MANCHESTER_START_MASK |
665 GENFSK_WHITEN_CFG_WHITEN_INIT_MASK);
666
667 GENFSK->WHITEN_CFG |=
668 GENFSK_WHITEN_CFG_WHITEN_START(GENFSK_BLE_WHITEN_START) |
669 GENFSK_WHITEN_CFG_WHITEN_END(GENFSK_BLE_WHITEN_END) |
670 GENFSK_WHITEN_CFG_WHITEN_B4_CRC(0) |
671 GENFSK_WHITEN_CFG_WHITEN_POLY_TYPE(GENFSK_BLE_WHITEN_POLY_TYPE) |
672 GENFSK_WHITEN_CFG_WHITEN_REF_IN(0) |
673 GENFSK_WHITEN_CFG_WHITEN_PAYLOAD_REINIT(0) |
674 GENFSK_WHITEN_CFG_WHITEN_SIZE(GENFSK_BLE_WHITEN_SIZE) |
675 GENFSK_WHITEN_CFG_MANCHESTER_EN(0) |
676 GENFSK_WHITEN_CFG_MANCHESTER_INV(0) |
677 GENFSK_WHITEN_CFG_MANCHESTER_START(0) |
678 GENFSK_WHITEN_CFG_WHITEN_INIT(iv | 0x40);
679
680 GENFSK->WHITEN_POLY =
681 GENFSK_WHITEN_POLY_WHITEN_POLY(GENFSK_BLE_WHITEN_POLY);
682
683 GENFSK->WHITEN_SZ_THR &= ~GENFSK_WHITEN_SZ_THR_WHITEN_SZ_THR_MASK;
684 GENFSK->WHITEN_SZ_THR |= GENFSK_WHITEN_SZ_THR_WHITEN_SZ_THR(0);
685 }
686
radio_aa_set(const uint8_t * aa)687 void radio_aa_set(const uint8_t *aa)
688 {
689 /* Configure Access Address detection using NETWORK ADDRESS 0 */
690 GENFSK->NTW_ADR_0 = *((uint32_t *)aa);
691 GENFSK->NTW_ADR_CTRL &= ~(GENFSK_NTW_ADR_CTRL_NTW_ADR0_SZ_MASK |
692 GENFSK_NTW_ADR_CTRL_NTW_ADR_THR0_MASK);
693 GENFSK->NTW_ADR_CTRL |= GENFSK_NTW_ADR_CTRL_NTW_ADR0_SZ(3) |
694 GENFSK_NTW_ADR_CTRL_NTW_ADR_THR0(0);
695
696 GENFSK->NTW_ADR_CTRL |= (uint32_t) ((1 << 0) <<
697 GENFSK_NTW_ADR_CTRL_NTW_ADR_EN_SHIFT);
698
699 /*
700 * The Access Address must be written in the packet buffer
701 * in front of the PDU
702 */
703 GENFSK->PACKET_BUFFER[0] = (aa[1] << 8) + aa[0];
704 GENFSK->PACKET_BUFFER[1] = (aa[3] << 8) + aa[2];
705 }
706
707 #define GENFSK_BLE_CRC_SZ 3 /* 3 bytes */
708 #define GENFSK_BLE_PREAMBLE_SZ 0 /* 1 byte of preamble, depends on PHY type */
709 #define GENFSK_BLE_LEN_BIT_ORD 0 /* LSB */
710 #define GENFSK_BLE_SYNC_ADDR_SZ 3 /* 4 bytes, Access Address */
711 #define GENFSK_BLE_LEN_ADJ_SZ GENFSK_BLE_CRC_SZ /* adjust length with CRC
712 * size
713 */
714 #define GENFSK_BLE_H0_SZ 8 /* 8 bits */
715
radio_pkt_configure(uint8_t bits_len,uint8_t max_len,uint8_t flags)716 void radio_pkt_configure(uint8_t bits_len, uint8_t max_len, uint8_t flags)
717 {
718 ARG_UNUSED(flags);
719
720 payload_max_size = max_len;
721
722 GENFSK->XCVR_CFG &= ~GENFSK_XCVR_CFG_PREAMBLE_SZ_MASK;
723 GENFSK->XCVR_CFG |=
724 GENFSK_XCVR_CFG_PREAMBLE_SZ(GENFSK_BLE_PREAMBLE_SZ);
725
726 GENFSK->PACKET_CFG &= ~(GENFSK_PACKET_CFG_LENGTH_SZ_MASK |
727 GENFSK_PACKET_CFG_LENGTH_BIT_ORD_MASK |
728 GENFSK_PACKET_CFG_SYNC_ADDR_SZ_MASK |
729 GENFSK_PACKET_CFG_LENGTH_ADJ_MASK |
730 GENFSK_PACKET_CFG_H0_SZ_MASK |
731 GENFSK_PACKET_CFG_H1_SZ_MASK);
732
733 GENFSK->PACKET_CFG |= GENFSK_PACKET_CFG_LENGTH_SZ(bits_len) |
734 GENFSK_PACKET_CFG_LENGTH_BIT_ORD(GENFSK_BLE_LEN_BIT_ORD) |
735 GENFSK_PACKET_CFG_SYNC_ADDR_SZ(GENFSK_BLE_SYNC_ADDR_SZ) |
736 GENFSK_PACKET_CFG_LENGTH_ADJ(GENFSK_BLE_LEN_ADJ_SZ) |
737 GENFSK_PACKET_CFG_H0_SZ(GENFSK_BLE_H0_SZ) |
738 GENFSK_PACKET_CFG_H1_SZ((8 - bits_len));
739
740 GENFSK->H0_CFG &= ~(GENFSK_H0_CFG_H0_MASK_MASK |
741 GENFSK_H0_CFG_H0_MATCH_MASK);
742 GENFSK->H0_CFG |= GENFSK_H0_CFG_H0_MASK(0) |
743 GENFSK_H0_CFG_H0_MATCH(0);
744
745 GENFSK->H1_CFG &= ~(GENFSK_H1_CFG_H1_MASK_MASK |
746 GENFSK_H1_CFG_H1_MATCH_MASK);
747 GENFSK->H1_CFG |= GENFSK_H1_CFG_H1_MASK(0) |
748 GENFSK_H1_CFG_H1_MATCH(0);
749
750 /* set Rx watermark to AA + PDU header */
751 GENFSK->RX_WATERMARK = GENFSK_RX_WATERMARK_RX_WATERMARK(RX_WTMRK);
752 }
753
radio_pkt_rx_set(void * rx_packet)754 void radio_pkt_rx_set(void *rx_packet)
755 {
756 rx_pkt_ptr = rx_packet;
757 }
758
radio_pkt_tx_set(void * tx_packet)759 void radio_pkt_tx_set(void *tx_packet)
760 {
761 /*
762 * The GENERIC_FSK software must program the TX buffer
763 * before commanding a TX operation, and must not access the RAM during
764 * the transmission.
765 */
766 uint16_t *pkt = tx_packet;
767 uint32_t cnt = 0, pkt_len = (((uint8_t *)tx_packet)[1] + 1) / 2 + 1;
768 volatile uint16_t *pkt_buffer = &GENFSK->PACKET_BUFFER[PB_TX_PDU];
769
770 for (; cnt < pkt_len; cnt++) {
771 pkt_buffer[cnt] = pkt[cnt];
772 }
773 }
774
radio_tx_ready_delay_get(uint8_t phy,uint8_t flags)775 uint32_t radio_tx_ready_delay_get(uint8_t phy, uint8_t flags)
776 {
777 return tx_wu;
778 }
779
radio_tx_chain_delay_get(uint8_t phy,uint8_t flags)780 uint32_t radio_tx_chain_delay_get(uint8_t phy, uint8_t flags)
781 {
782 return 0;
783 }
784
radio_rx_ready_delay_get(uint8_t phy,uint8_t flags)785 uint32_t radio_rx_ready_delay_get(uint8_t phy, uint8_t flags)
786 {
787 return rx_wu;
788 }
789
radio_rx_chain_delay_get(uint8_t phy,uint8_t flags)790 uint32_t radio_rx_chain_delay_get(uint8_t phy, uint8_t flags)
791 {
792 /* RX_WTMRK = AA + PDU header, but AA time is already accounted for */
793 /* PDU header (assume 2 bytes) => 16us, depends on PHY type */
794 /* 2 * RX_OVHD = RX_WATERMARK_IRQ time - TIMESTAMP - isr_latency */
795 /* The rest is Rx margin that for now isn't well defined */
796 return BYTES_TO_USEC(2, bits_per_usec) + 2 * RX_OVHD +
797 RX_MARGIN + isr_latency +
798 RX_OVHD;
799 }
800
radio_rx_enable(void)801 void radio_rx_enable(void)
802 {
803 /* Wait for idle state */
804 while (GENFSK->XCVR_STS & RADIO_ACTIVE_MASK) {
805 }
806
807 /* 0b0101..RX Start Now */
808 GENFSK->XCVR_CTRL = GENFSK_XCVR_CTRL_SEQCMD(0x5);
809 }
810
radio_tx_enable(void)811 void radio_tx_enable(void)
812 {
813 /* Wait for idle state */
814 while (GENFSK->XCVR_STS & RADIO_ACTIVE_MASK) {
815 }
816
817 /* 0b0001..TX Start Now */
818 GENFSK->XCVR_CTRL = GENFSK_XCVR_CTRL_SEQCMD(0x1);
819 }
820
radio_disable(void)821 void radio_disable(void)
822 {
823 /* Disable both comparators */
824 GENFSK->T1_CMP = 0;
825 GENFSK->T2_CMP = 0;
826
827 /*
828 * 0b1011..Abort All - Cancels all pending events and abort any
829 * sequence-in-progress
830 */
831 GENFSK->XCVR_CTRL = GENFSK_XCVR_CTRL_SEQCMD(0xb);
832
833 /* Wait for idle state */
834 while (GENFSK->XCVR_STS & RADIO_ACTIVE_MASK) {
835 }
836
837 /* Clear pending interrupts */
838 GENFSK->IRQ_CTRL &= 0xffffffff;
839 EVENT_UNIT->INTPTPENDCLEAR = (uint32_t)(1U << LL_RADIO_IRQn);
840
841 next_radio_cmd = 0;
842 radio_trx = 0;
843
844 /* generate T2 interrupt to get into isr_radio() */
845 uint32_t tmr = GENFSK->EVENT_TMR + RADIO_DISABLE_TMR;
846
847 GENFSK->T2_CMP = GENFSK_T2_CMP_T2_CMP(tmr) | GENFSK_T2_CMP_T2_CMP_EN(1);
848 }
849
radio_status_reset(void)850 void radio_status_reset(void)
851 {
852 radio_trx = 0;
853 }
854
radio_is_ready(void)855 uint32_t radio_is_ready(void)
856 {
857 /* Always false. LLL expects the radio not to be in idle/Tx/Rx state */
858 return 0;
859 }
860
radio_is_done(void)861 uint32_t radio_is_done(void)
862 {
863 return radio_trx;
864 }
865
radio_has_disabled(void)866 uint32_t radio_has_disabled(void)
867 {
868 /* Not used */
869 return 0;
870 }
871
radio_is_idle(void)872 uint32_t radio_is_idle(void)
873 {
874 /* Vega radio is never disabled */
875 return 1;
876 }
877
878 #define GENFSK_BLE_CRC_START_BYTE 4 /* After Access Address */
879 #define GENFSK_BLE_CRC_BYTE_ORD 0 /* LSB */
880
radio_crc_configure(uint32_t polynomial,uint32_t iv)881 void radio_crc_configure(uint32_t polynomial, uint32_t iv)
882 {
883 /* printk("%s poly: %08x, iv: %08x\n", __func__, polynomial, iv); */
884
885 GENFSK->CRC_CFG &= ~(GENFSK_CRC_CFG_CRC_SZ_MASK |
886 GENFSK_CRC_CFG_CRC_START_BYTE_MASK |
887 GENFSK_CRC_CFG_CRC_REF_IN_MASK |
888 GENFSK_CRC_CFG_CRC_REF_OUT_MASK |
889 GENFSK_CRC_CFG_CRC_BYTE_ORD_MASK);
890 GENFSK->CRC_CFG |= GENFSK_CRC_CFG_CRC_SZ(GENFSK_BLE_CRC_SZ) |
891 GENFSK_CRC_CFG_CRC_START_BYTE(GENFSK_BLE_CRC_START_BYTE) |
892 GENFSK_CRC_CFG_CRC_REF_IN(0) |
893 GENFSK_CRC_CFG_CRC_REF_OUT(0) |
894 GENFSK_CRC_CFG_CRC_BYTE_ORD(GENFSK_BLE_CRC_BYTE_ORD);
895
896 GENFSK->CRC_INIT = (iv << ((4U - GENFSK_BLE_CRC_SZ) << 3));
897 GENFSK->CRC_POLY = (polynomial << ((4U - GENFSK_BLE_CRC_SZ) << 3));
898 GENFSK->CRC_XOR_OUT = 0;
899
900 /*
901 * Enable CRC in hardware; this is already done at startup but we do it
902 * here anyways just to be sure.
903 */
904 GENFSK->XCVR_CFG &= ~GENFSK_XCVR_CFG_SW_CRC_EN_MASK;
905 }
906
radio_crc_is_valid(void)907 uint32_t radio_crc_is_valid(void)
908 {
909 if (force_bad_crc) {
910 return 0;
911 }
912
913 uint32_t radio_crc = (GENFSK->XCVR_STS & GENFSK_XCVR_STS_CRC_VALID_MASK) >>
914 GENFSK_XCVR_STS_CRC_VALID_SHIFT;
915 return radio_crc;
916 }
917
radio_pkt_empty_get(void)918 void *radio_pkt_empty_get(void)
919 {
920 return _pkt_empty;
921 }
922
radio_pkt_scratch_get(void)923 void *radio_pkt_scratch_get(void)
924 {
925 return _pkt_scratch;
926 }
927
radio_switch_complete_and_rx(uint8_t phy_rx)928 void radio_switch_complete_and_rx(uint8_t phy_rx)
929 {
930 /* 0b0110..RX Start @ T1 Timer Compare Match (EVENT_TMR = T1_CMP) */
931 next_radio_cmd = GENFSK_XCVR_CTRL_SEQCMD(0x6);
932
933 /* the margin is used to account for any overhead in radio switching */
934 next_wu = rx_wu + RX_MARGIN;
935 }
936
radio_switch_complete_and_tx(uint8_t phy_rx,uint8_t flags_rx,uint8_t phy_tx,uint8_t flags_tx)937 void radio_switch_complete_and_tx(uint8_t phy_rx, uint8_t flags_rx, uint8_t phy_tx,
938 uint8_t flags_tx)
939 {
940 /* 0b0010..TX Start @ T1 Timer Compare Match (EVENT_TMR = T1_CMP) */
941 next_radio_cmd = GENFSK_XCVR_CTRL_SEQCMD(0x2);
942
943 /* the margin is used to account for any overhead in radio switching */
944 next_wu = tx_wu + TX_MARGIN;
945 }
946
radio_switch_complete_and_disable(void)947 void radio_switch_complete_and_disable(void)
948 {
949 next_radio_cmd = 0;
950 }
951
radio_rssi_measure(void)952 void radio_rssi_measure(void)
953 {
954 rssi = 0;
955 }
956
radio_rssi_get(void)957 uint32_t radio_rssi_get(void)
958 {
959 return (uint32_t)-rssi;
960 }
961
radio_rssi_status_reset(void)962 void radio_rssi_status_reset(void)
963 {
964 }
965
radio_rssi_is_ready(void)966 uint32_t radio_rssi_is_ready(void)
967 {
968 return (rssi != 0);
969 }
970
radio_filter_configure(uint8_t bitmask_enable,uint8_t bitmask_addr_type,uint8_t * bdaddr)971 void radio_filter_configure(uint8_t bitmask_enable, uint8_t bitmask_addr_type,
972 uint8_t *bdaddr)
973 {
974 /* printk("%s\n", __func__); */
975 }
976
radio_filter_disable(void)977 void radio_filter_disable(void)
978 {
979 /* Nothing to do here */
980 }
981
radio_filter_status_reset(void)982 void radio_filter_status_reset(void)
983 {
984 /* printk("%s\n", __func__); */
985 }
986
radio_filter_has_match(void)987 uint32_t radio_filter_has_match(void)
988 {
989 /* printk("%s\n", __func__); */
990 return 0;
991 }
992
radio_filter_match_get(void)993 uint32_t radio_filter_match_get(void)
994 {
995 /* printk("%s\n", __func__); */
996 return 0;
997 }
998
radio_bc_configure(uint32_t n)999 void radio_bc_configure(uint32_t n)
1000 {
1001 printk("%s\n", __func__);
1002 }
1003
radio_bc_status_reset(void)1004 void radio_bc_status_reset(void)
1005 {
1006 printk("%s\n", __func__);
1007 }
1008
radio_bc_has_match(void)1009 uint32_t radio_bc_has_match(void)
1010 {
1011 printk("%s\n", __func__);
1012 return 0;
1013 }
1014
radio_tmr_status_reset(void)1015 void radio_tmr_status_reset(void)
1016 {
1017 tmr_aa_save = 0;
1018 tmr_end_save = 0;
1019 }
1020
radio_tmr_tifs_set(uint32_t tifs)1021 void radio_tmr_tifs_set(uint32_t tifs)
1022 {
1023 tmr_tifs = tifs;
1024 }
1025
1026 /* Start the radio after ticks_start (ticks) + remainder (us) time */
radio_tmr_start_hlp(uint8_t trx,uint32_t ticks_start,uint32_t remainder)1027 static uint32_t radio_tmr_start_hlp(uint8_t trx, uint32_t ticks_start, uint32_t remainder)
1028 {
1029 uint32_t radio_start_now_cmd = 0;
1030
1031 /* Disable both comparators */
1032 GENFSK->T1_CMP = 0;
1033 GENFSK->T2_CMP = 0;
1034
1035 /* Save it for later */
1036 rtc_start = ticks_start;
1037
1038 /* Convert ticks to us and use just EVENT_TMR */
1039 rtc_diff_start_us = HAL_TICKER_TICKS_TO_US(rtc_start - cntr_cnt_get());
1040
1041 skip_hcto = 0;
1042 if (rtc_diff_start_us > GENFSK_T1_CMP_T1_CMP_MASK) {
1043 /* ticks_start already passed. Don't start the radio */
1044 rtc_diff_start_us = 0;
1045
1046 /* Ignore time out as well */
1047 skip_hcto = 1;
1048 return remainder;
1049 }
1050 remainder += rtc_diff_start_us;
1051
1052 if (trx) {
1053 if (remainder <= MIN_CMD_TIME) {
1054 /* 0b0001..TX Start Now */
1055 radio_start_now_cmd = GENFSK_XCVR_CTRL_SEQCMD(0x1);
1056 remainder = 0;
1057 } else {
1058 /*
1059 * 0b0010..TX Start @ T1 Timer Compare Match
1060 * (EVENT_TMR = T1_CMP)
1061 */
1062 GENFSK->XCVR_CTRL = GENFSK_XCVR_CTRL_SEQCMD(0x2);
1063 GENFSK->T1_CMP = GENFSK_T1_CMP_T1_CMP(remainder);
1064 }
1065 tmr_ready = remainder + tx_wu;
1066 } else {
1067 if (remainder <= MIN_CMD_TIME) {
1068 /* 0b0101..RX Start Now */
1069 radio_start_now_cmd = GENFSK_XCVR_CTRL_SEQCMD(0x5);
1070 remainder = 0;
1071 } else {
1072 /*
1073 * 0b0110..RX Start @ T1 Timer Compare Match
1074 * (EVENT_TMR = T1_CMP)
1075 */
1076 GENFSK->XCVR_CTRL = GENFSK_XCVR_CTRL_SEQCMD(0x6);
1077 GENFSK->T1_CMP = GENFSK_T1_CMP_T1_CMP(remainder);
1078 }
1079 tmr_ready = remainder + rx_wu;
1080 }
1081
1082 /*
1083 * reset EVENT_TMR should be done after ticks_start.
1084 * We converted ticks to us, so we reset it now.
1085 * All tmr_* times are relative to EVENT_TMR reset.
1086 * rtc_diff_start_us is used to adjust them
1087 */
1088 GENFSK->EVENT_TMR = GENFSK_EVENT_TMR_EVENT_TMR_LD(1);
1089
1090 if (radio_start_now_cmd) {
1091 /* trigger Rx/Tx Start Now */
1092 GENFSK->XCVR_CTRL = radio_start_now_cmd;
1093 } else {
1094 /* enable T1_CMP to trigger the SEQCMD */
1095 GENFSK->T1_CMP |= GENFSK_T1_CMP_T1_CMP_EN(1);
1096 }
1097
1098 return remainder;
1099 }
1100
radio_tmr_start(uint8_t trx,uint32_t ticks_start,uint32_t remainder)1101 uint32_t radio_tmr_start(uint8_t trx, uint32_t ticks_start, uint32_t remainder)
1102 {
1103 if ((!(remainder / 1000000UL)) || (remainder & 0x80000000)) {
1104 ticks_start--;
1105 remainder += 30517578UL;
1106 }
1107 remainder /= 1000000UL;
1108
1109 if (radio_is_off()) {
1110 delayed_radio_start = 1;
1111 delayed_trx = trx;
1112 delayed_ticks_start = ticks_start;
1113 delayed_remainder = remainder;
1114 return remainder;
1115 }
1116
1117 delayed_radio_start = 0;
1118 return radio_tmr_start_hlp(trx, ticks_start, remainder);
1119 }
1120
radio_tmr_start_tick(uint8_t trx,uint32_t tick)1121 uint32_t radio_tmr_start_tick(uint8_t trx, uint32_t tick)
1122 {
1123 /* Setup compare event with min. 1 us offset */
1124 uint32_t remainder_us = 1;
1125
1126 return radio_tmr_start_hlp(trx, tick, remainder_us);
1127 }
1128
radio_tmr_start_us(uint8_t trx,uint32_t us)1129 void radio_tmr_start_us(uint8_t trx, uint32_t us)
1130 {
1131 printk("%s\n", __func__);
1132 }
1133
radio_tmr_start_now(uint8_t trx)1134 uint32_t radio_tmr_start_now(uint8_t trx)
1135 {
1136 printk("%s\n", __func__);
1137 return 0;
1138 }
1139
radio_tmr_start_get(void)1140 uint32_t radio_tmr_start_get(void)
1141 {
1142 return rtc_start;
1143 }
1144
radio_tmr_stop(void)1145 void radio_tmr_stop(void)
1146 {
1147 }
1148
radio_tmr_hcto_configure_hlp(uint32_t hcto)1149 static void radio_tmr_hcto_configure_hlp(uint32_t hcto)
1150 {
1151 if (skip_hcto) {
1152 skip_hcto = 0;
1153 return;
1154 }
1155
1156 /* 0b1001..RX Stop @ T2 Timer Compare Match (EVENT_TMR = T2_CMP) */
1157 GENFSK->XCVR_CTRL = GENFSK_XCVR_CTRL_SEQCMD(0x9);
1158 GENFSK->T2_CMP = GENFSK_T2_CMP_T2_CMP(hcto) |
1159 GENFSK_T2_CMP_T2_CMP_EN(1);
1160
1161 }
1162
1163 /* Header completion time out */
radio_tmr_hcto_configure(uint32_t hcto)1164 void radio_tmr_hcto_configure(uint32_t hcto)
1165 {
1166 if (delayed_radio_start) {
1167 delayed_radio_stop = 1;
1168 delayed_hcto = hcto;
1169 return;
1170 }
1171
1172 delayed_radio_stop = 0;
1173 radio_tmr_hcto_configure_hlp(hcto);
1174 }
1175
radio_tmr_aa_capture(void)1176 void radio_tmr_aa_capture(void)
1177 {
1178 tmr_aa_save = 1;
1179 }
1180
radio_tmr_aa_get(void)1181 uint32_t radio_tmr_aa_get(void)
1182 {
1183 return tmr_aa - rtc_diff_start_us;
1184 }
1185
1186 static uint32_t radio_tmr_aa;
1187
radio_tmr_aa_save(uint32_t aa)1188 void radio_tmr_aa_save(uint32_t aa)
1189 {
1190 radio_tmr_aa = aa;
1191 }
1192
radio_tmr_aa_restore(void)1193 uint32_t radio_tmr_aa_restore(void)
1194 {
1195 return radio_tmr_aa;
1196 }
1197
radio_tmr_ready_get(void)1198 uint32_t radio_tmr_ready_get(void)
1199 {
1200 return tmr_ready - rtc_diff_start_us;
1201 }
1202
radio_tmr_end_capture(void)1203 void radio_tmr_end_capture(void)
1204 {
1205 tmr_end_save = 1;
1206 }
1207
radio_tmr_end_get(void)1208 uint32_t radio_tmr_end_get(void)
1209 {
1210 return tmr_end - rtc_diff_start_us;
1211 }
1212
radio_tmr_tifs_base_get(void)1213 uint32_t radio_tmr_tifs_base_get(void)
1214 {
1215 return radio_tmr_end_get() + rtc_diff_start_us;
1216 }
1217
radio_tmr_sample(void)1218 void radio_tmr_sample(void)
1219 {
1220 printk("%s\n", __func__);
1221 }
1222
radio_tmr_sample_get(void)1223 uint32_t radio_tmr_sample_get(void)
1224 {
1225 printk("%s\n", __func__);
1226 return 0;
1227 }
1228
radio_ccm_rx_pkt_set_ut(struct ccm * ccm,uint8_t phy,void * pkt)1229 void *radio_ccm_rx_pkt_set_ut(struct ccm *ccm, uint8_t phy, void *pkt)
1230 {
1231 /* Saved by LL as MSO to LSO in the ccm->key
1232 * SK (LSO to MSO)
1233 * :0x66:0xC6:0xC2:0x27:0x8E:0x3B:0x8E:0x05
1234 * :0x3E:0x7E:0xA3:0x26:0x52:0x1B:0xAD:0x99
1235 */
1236 uint8_t key_local[16] __aligned(4) = {
1237 0x99, 0xad, 0x1b, 0x52, 0x26, 0xa3, 0x7e, 0x3e,
1238 0x05, 0x8e, 0x3b, 0x8e, 0x27, 0xc2, 0xc6, 0x66
1239 };
1240 void *result;
1241
1242 /* ccm.key[16] is stored in MSO format, as retrieved from e function */
1243 memcpy(ccm->key, key_local, sizeof(key_local));
1244
1245 /* Input std sample data, vol 6, part C, ch 1 */
1246 _pkt_scratch[0] = 0x0f;
1247 _pkt_scratch[1] = 0x05;
1248 _pkt_scratch[2] = 0x9f; /* cleartext = 0x06*/
1249 _pkt_scratch[3] = 0xcd;
1250 _pkt_scratch[4] = 0xa7;
1251 _pkt_scratch[5] = 0xf4;
1252 _pkt_scratch[6] = 0x48;
1253
1254 /* IV std sample data, vol 6, part C, ch 1, stored in LL in LSO format
1255 * IV (LSO to MSO) :0x24:0xAB:0xDC:0xBA:0xBE:0xBA:0xAF:0xDE
1256 */
1257 ccm->iv[0] = 0x24;
1258 ccm->iv[1] = 0xAB;
1259 ccm->iv[2] = 0xDC;
1260 ccm->iv[3] = 0xBA;
1261 ccm->iv[4] = 0xBE;
1262 ccm->iv[5] = 0xBA;
1263 ccm->iv[6] = 0xAF;
1264 ccm->iv[7] = 0xDE;
1265
1266 result = radio_ccm_rx_pkt_set(ccm, phy, pkt);
1267 radio_ccm_is_done();
1268
1269 if (ctx_ccm.auth_mic_valid == 1 && ((uint8_t *)pkt)[2] == 0x06) {
1270 LOG_INF("Passed decrypt\n");
1271 } else {
1272 LOG_INF("Failed decrypt\n");
1273 }
1274
1275 return result;
1276 }
1277
radio_ccm_rx_pkt_set(struct ccm * ccm,uint8_t phy,void * pkt)1278 void *radio_ccm_rx_pkt_set(struct ccm *ccm, uint8_t phy, void *pkt)
1279 {
1280 uint8_t key_local[16] __aligned(4);
1281 status_t status;
1282 cau3_handle_t handle = {
1283 .keySlot = kCAU3_KeySlot2,
1284 .taskDone = kCAU3_TaskDonePoll
1285 };
1286 ARG_UNUSED(phy);
1287
1288 /* ccm.key[16] is stored in MSO format, as retrieved from e function */
1289 memcpy(key_local, ccm->key, sizeof(key_local));
1290 ctx_ccm.auth_mic_valid = 0;
1291 ctx_ccm.empty_pdu_rxed = 0;
1292 ctx_ccm.rx_pkt_in = (struct pdu_data *)_pkt_scratch;
1293 ctx_ccm.rx_pkt_out = (struct pdu_data *)pkt;
1294 ctx_ccm.nonce.counter = ccm->counter; /* LSO to MSO, counter is LE */
1295 /* The directionBit set to 1 for Data Physical Chan PDUs sent by
1296 * the central and set to 0 for Data Physical Chan PDUs sent by the
1297 * peripheral
1298 */
1299 ctx_ccm.nonce.bytes[4] |= ccm->direction << 7;
1300 memcpy(&ctx_ccm.nonce.bytes[5], ccm->iv, 8); /* LSO to MSO */
1301
1302 /* Loads the key into CAU3's DMEM and expands the AES key schedule. */
1303 status = CAU3_AES_SetKey(CAU3, &handle, key_local, 16);
1304 if (status != kStatus_Success) {
1305 LOG_ERR("CAUv3 AES key set failed %d", status);
1306 return NULL;
1307 }
1308
1309 return _pkt_scratch;
1310 }
1311
radio_ccm_tx_pkt_set_ut(struct ccm * ccm,void * pkt)1312 void *radio_ccm_tx_pkt_set_ut(struct ccm *ccm, void *pkt)
1313 {
1314 /* Clear:
1315 * 06 1b 17 00 37 36 35 34 33 32 31 30 41 42 43
1316 * 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51
1317 */
1318 uint8_t data_in[29] = {
1319 0x06, 0x1b, 0x17, 0x00, 0x37, 0x36, 0x35, 0x34,
1320 0x33, 0x32, 0x31, 0x30, 0x41, 0x42, 0x43, 0x44,
1321 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c,
1322 0x4d, 0x4e, 0x4f, 0x50, 0x51
1323 };
1324 /* LL_DATA2:
1325 * 06 1f f3 88 81 e7 bd 94 c9 c3 69 b9 a6 68 46
1326 * dd 47 86 aa 8c 39 ce 54 0d 0d ae 3a dc df 89 b9 60 88
1327 */
1328 uint8_t data_ref_out[33] = {
1329 0x06, 0x1f, 0xf3, 0x88, 0x81, 0xe7, 0xbd, 0x94,
1330 0xc9, 0xc3, 0x69, 0xb9, 0xa6, 0x68, 0x46, 0xdd,
1331 0x47, 0x86, 0xaa, 0x8c, 0x39, 0xce, 0x54, 0x0d,
1332 0x0d, 0xae, 0x3a, 0xdc, 0xdf,
1333 0x89, 0xb9, 0x60, 0x88
1334 };
1335 /* Saved by LL as MSO to LSO in the ccm->key
1336 * SK (LSO to MSO)
1337 * :0x66:0xC6:0xC2:0x27:0x8E:0x3B:0x8E:0x05
1338 * :0x3E:0x7E:0xA3:0x26:0x52:0x1B:0xAD:0x99
1339 */
1340 uint8_t key_local[16] __aligned(4) = {
1341 0x99, 0xad, 0x1b, 0x52, 0x26, 0xa3, 0x7e, 0x3e,
1342 0x05, 0x8e, 0x3b, 0x8e, 0x27, 0xc2, 0xc6, 0x66
1343 };
1344 void *result;
1345
1346 /* ccm.key[16] is stored in MSO format, as retrieved from e function */
1347 memcpy(ccm->key, key_local, sizeof(key_local));
1348 memcpy(pkt, data_in, sizeof(data_in));
1349 /* IV std sample data, vol 6, part C, ch 1, stored in LL in LSO format
1350 * IV (LSO to MSO) :0x24:0xAB:0xDC:0xBA:0xBE:0xBA:0xAF:0xDE
1351 */
1352 ccm->iv[0] = 0x24;
1353 ccm->iv[1] = 0xAB;
1354 ccm->iv[2] = 0xDC;
1355 ccm->iv[3] = 0xBA;
1356 ccm->iv[4] = 0xBE;
1357 ccm->iv[5] = 0xBA;
1358 ccm->iv[6] = 0xAF;
1359 ccm->iv[7] = 0xDE;
1360 /* 4. Data packet2 (packet 1, S --> M) */
1361 ccm->counter = 1;
1362 ccm->direction = 0;
1363
1364 result = radio_ccm_tx_pkt_set(ccm, pkt);
1365
1366 if (memcmp(result, data_ref_out, sizeof(data_ref_out))) {
1367 LOG_INF("Failed encrypt\n");
1368 } else {
1369 LOG_INF("Passed encrypt\n");
1370 }
1371
1372 return result;
1373 }
1374
radio_ccm_tx_pkt_set(struct ccm * ccm,void * pkt)1375 void *radio_ccm_tx_pkt_set(struct ccm *ccm, void *pkt)
1376 {
1377 uint8_t key_local[16] __aligned(4);
1378 uint8_t aad;
1379 uint8_t *auth_mic;
1380 status_t status;
1381 cau3_handle_t handle = {
1382 .keySlot = kCAU3_KeySlot2,
1383 .taskDone = kCAU3_TaskDonePoll
1384 };
1385
1386 /* Test for Empty PDU and bypass encryption */
1387 if (((struct pdu_data *)pkt)->len == 0) {
1388 return pkt;
1389 }
1390
1391 /* ccm.key[16] is stored in MSO format, as retrieved from e function */
1392 memcpy(key_local, ccm->key, sizeof(key_local));
1393 ctx_ccm.nonce.counter = ccm->counter; /* LSO to MSO, counter is LE */
1394 /* The directionBit set to 1 for Data Physical Chan PDUs sent by
1395 * the central and set to 0 for Data Physical Chan PDUs sent by the
1396 * peripheral
1397 */
1398 ctx_ccm.nonce.bytes[4] |= ccm->direction << 7;
1399 memcpy(&ctx_ccm.nonce.bytes[5], ccm->iv, 8); /* LSO to MSO */
1400
1401 /* Loads the key into CAU3's DMEM and expands the AES key schedule. */
1402 status = CAU3_AES_SetKey(CAU3, &handle, key_local, 16);
1403 if (status != kStatus_Success) {
1404 LOG_ERR("CAUv3 AES key set failed %d", status);
1405 return NULL;
1406 }
1407
1408 auth_mic = _pkt_scratch + 2 + ((struct pdu_data *)pkt)->len;
1409 aad = *(uint8_t *)pkt & RADIO_AESCCM_HDR_MASK;
1410
1411 status = CAU3_AES_CCM_EncryptTag(CAU3, &handle,
1412 (uint8_t *)pkt + 2, ((struct pdu_data *)pkt)->len,
1413 _pkt_scratch + 2,
1414 ctx_ccm.nonce.bytes, 13,
1415 &aad, 1, auth_mic, CAU3_BLE_MIC_SIZE);
1416 if (status != kStatus_Success) {
1417 LOG_ERR("CAUv3 AES CCM decrypt failed %d", status);
1418 return 0;
1419 }
1420
1421 _pkt_scratch[0] = *(uint8_t *)pkt;
1422 _pkt_scratch[1] = ((struct pdu_data *)pkt)->len + CAU3_BLE_MIC_SIZE;
1423
1424 return _pkt_scratch;
1425 }
1426
radio_ccm_is_done(void)1427 uint32_t radio_ccm_is_done(void)
1428 {
1429 status_t status;
1430 uint8_t *auth_mic;
1431 uint8_t aad;
1432 cau3_handle_t handle = {
1433 .keySlot = kCAU3_KeySlot2,
1434 .taskDone = kCAU3_TaskDonePoll
1435 };
1436
1437 if (ctx_ccm.rx_pkt_in->len > CAU3_BLE_MIC_SIZE) {
1438 auth_mic = (uint8_t *)ctx_ccm.rx_pkt_in + 2 +
1439 ctx_ccm.rx_pkt_in->len - CAU3_BLE_MIC_SIZE;
1440 aad = *(uint8_t *)ctx_ccm.rx_pkt_in & RADIO_AESCCM_HDR_MASK;
1441 status = CAU3_AES_CCM_DecryptTag(CAU3, &handle,
1442 (uint8_t *)ctx_ccm.rx_pkt_in + 2,
1443 (uint8_t *)ctx_ccm.rx_pkt_out + 2,
1444 ctx_ccm.rx_pkt_in->len - CAU3_BLE_MIC_SIZE,
1445 ctx_ccm.nonce.bytes, 13,
1446 &aad, 1, auth_mic, CAU3_BLE_MIC_SIZE);
1447 if (status != kStatus_Success) {
1448 LOG_ERR("CAUv3 AES CCM decrypt failed %d", status);
1449 return 0;
1450 }
1451
1452 ctx_ccm.auth_mic_valid = handle.micPassed;
1453 ctx_ccm.rx_pkt_out->len -= 4;
1454
1455 } else if (ctx_ccm.rx_pkt_in->len == 0) {
1456 /* Just copy input into output */
1457 *ctx_ccm.rx_pkt_out = *ctx_ccm.rx_pkt_in;
1458 ctx_ccm.auth_mic_valid = 1;
1459 ctx_ccm.empty_pdu_rxed = 1;
1460 } else {
1461 return 0; /* length only allowed 0, not 1,2,3,4 */
1462 }
1463
1464 return 1;
1465 }
1466
radio_ccm_mic_is_valid(void)1467 uint32_t radio_ccm_mic_is_valid(void)
1468 {
1469 return ctx_ccm.auth_mic_valid;
1470 }
1471
radio_ccm_is_available(void)1472 uint32_t radio_ccm_is_available(void)
1473 {
1474 return ctx_ccm.empty_pdu_rxed;
1475 }
1476
1477 #if defined(CONFIG_BT_CTLR_PRIVACY)
radio_ar_configure(uint32_t nirk,void * irk)1478 void radio_ar_configure(uint32_t nirk, void *irk)
1479 {
1480 status_t status;
1481 uint8_t pirk[16];
1482
1483 /* Initialize CAUv3 RPA table */
1484 status = CAU3_RPAtableInit(CAU3, kCAU3_TaskDoneEvent);
1485 if (kStatus_Success != status) {
1486 LOG_ERR("CAUv3 RPA table init failed");
1487 return;
1488 }
1489
1490 /* CAUv3 RPA table is limited to CONFIG_BT_CTLR_RL_SIZE entries */
1491 if (nirk > CONFIG_BT_CTLR_RL_SIZE) {
1492 LOG_WRN("Max CAUv3 RPA table size is %d", CONFIG_BT_CTLR_RL_SIZE);
1493 nirk = CONFIG_BT_CTLR_RL_SIZE;
1494 }
1495
1496 /* Insert RPA keys(IRK) in table */
1497 for (int i = 0; i < nirk; i++) {
1498 /* CAUv3 needs IRK in le format */
1499 sys_memcpy_swap(pirk, (uint8_t *)irk + i * 16, 16);
1500 status = CAU3_RPAtableInsertKey(CAU3, (uint32_t *)&pirk,
1501 kCAU3_TaskDoneEvent);
1502 if (kStatus_Success != status) {
1503 LOG_ERR("CAUv3 RPA table insert failed");
1504 return;
1505 }
1506 }
1507
1508 /* RPA Table was configured, it can be used for next Rx */
1509 radio_ar_ctx.ar_enable = 1U;
1510 }
1511
radio_ar_match_get(void)1512 uint32_t radio_ar_match_get(void)
1513 {
1514 return radio_ar_ctx.irk_idx;
1515 }
1516
radio_ar_status_reset(void)1517 void radio_ar_status_reset(void)
1518 {
1519 radio_ar_ctx.ar_enable = 0U;
1520 radio_ar_ctx.irk_idx = RPA_NO_IRK_MATCH;
1521 }
1522
radio_ar_has_match(void)1523 uint32_t radio_ar_has_match(void)
1524 {
1525 return (radio_ar_ctx.irk_idx != RPA_NO_IRK_MATCH);
1526 }
1527 #endif /* CONFIG_BT_CTLR_PRIVACY */
1528
radio_sleep(void)1529 uint32_t radio_sleep(void)
1530 {
1531
1532 if (dsm_ref == 0) {
1533 return -EALREADY;
1534 }
1535
1536 uint32_t localref = --dsm_ref;
1537 #if (CONFIG_BT_CTLR_LLL_PRIO == CONFIG_BT_CTLR_ULL_HIGH_PRIO) && \
1538 (CONFIG_BT_CTLR_LLL_PRIO == CONFIG_BT_CTLR_ULL_LOW_PRIO)
1539 /* TODO:
1540 * These operations (decrement, check) should be atomic/critical section
1541 * since we turn radio on/off from different contexts/ISRs (LLL, radio).
1542 * It's fine for now as all the contexts have the same priority and
1543 * don't preempt each other.
1544 */
1545 #else
1546 #error "Missing atomic operation in radio_sleep()"
1547 #endif
1548 if (localref == 0) {
1549
1550 uint32_t status = (RSIM->DSM_CONTROL & MAN_DSM_ON);
1551
1552 if (status) {
1553 /* Already in sleep mode */
1554 return 0;
1555 }
1556
1557 /* Disable DSM_TIMER */
1558 RSIM->DSM_CONTROL &= ~RSIM_DSM_CONTROL_DSM_TIMER_EN(1);
1559
1560 /* Get current DSM_TIMER value */
1561 uint32_t dsm_timer = RSIM->DSM_TIMER;
1562
1563 /* Set Sleep time after DSM_ENTER_DELAY */
1564 RSIM->MAN_SLEEP = RSIM_MAN_SLEEP_MAN_SLEEP_TIME(dsm_timer +
1565 DSM_ENTER_DELAY_TICKS);
1566
1567 /* Set Wake time to max, we use DSM early exit */
1568 RSIM->MAN_WAKE = RSIM_MAN_WAKE_MAN_WAKE_TIME(dsm_timer - 1);
1569
1570 /* MAN wakeup request enable */
1571 RSIM->DSM_CONTROL |= RSIM_DSM_CONTROL_MAN_WAKEUP_REQUEST_EN(1);
1572
1573 /* Enable DSM, sending a sleep request */
1574 GENFSK->DSM_CTRL |= GENFSK_DSM_CTRL_GEN_SLEEP_REQUEST(1);
1575
1576 /* Enable DSM_TIMER */
1577 RSIM->DSM_CONTROL |= RSIM_DSM_CONTROL_DSM_TIMER_EN(1);
1578 }
1579
1580 return 0;
1581 }
1582
radio_wake(void)1583 uint32_t radio_wake(void)
1584 {
1585 uint32_t localref = ++dsm_ref;
1586 #if (CONFIG_BT_CTLR_LLL_PRIO == CONFIG_BT_CTLR_ULL_HIGH_PRIO) && \
1587 (CONFIG_BT_CTLR_LLL_PRIO == CONFIG_BT_CTLR_ULL_LOW_PRIO)
1588 /* TODO:
1589 * These operations (increment, check) should be atomic/critical section
1590 * since we turn radio on/off from different contexts/ISRs (LLL, radio).
1591 * It's fine for now as all the contexts have the same priority and
1592 * don't preempt each other.
1593 */
1594 #else
1595 #error "Missing atomic operation in radio_wake()"
1596 #endif
1597 if (localref == 1) {
1598
1599 uint32_t status = (RSIM->DSM_CONTROL & MAN_DSM_ON);
1600
1601 if (!status) {
1602 /* Not in sleep mode */
1603 return 0;
1604 }
1605
1606 /* Get current DSM_TIMER value */
1607 uint32_t dsm_timer = RSIM->DSM_TIMER;
1608
1609 /* Set Wake time after DSM_ENTER_DELAY */
1610 RSIM->MAN_WAKE = RSIM_MAN_WAKE_MAN_WAKE_TIME(dsm_timer +
1611 DSM_EXIT_DELAY_TICKS);
1612 }
1613
1614 return 0;
1615 }
1616
radio_is_off(void)1617 uint32_t radio_is_off(void)
1618 {
1619 uint32_t status = (RSIM->DSM_CONTROL & MAN_DSM_ON);
1620
1621 return status;
1622 }
1623