1 /* ieee802154_cc2520.c - TI CC2520 driver */
2
3 #define DT_DRV_COMPAT ti_cc2520
4
5 /*
6 * Copyright (c) 2016 Intel Corporation.
7 *
8 * SPDX-License-Identifier: Apache-2.0
9 */
10
11 #define LOG_MODULE_NAME ieee802154_cc2520
12 #define LOG_LEVEL CONFIG_IEEE802154_DRIVER_LOG_LEVEL
13
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
16
17 #include <errno.h>
18
19 #include <zephyr/kernel.h>
20 #include <zephyr/arch/cpu.h>
21 #include <zephyr/debug/stack.h>
22
23 #include <zephyr/device.h>
24 #include <zephyr/init.h>
25 #include <zephyr/net/net_if.h>
26 #include <zephyr/net/net_pkt.h>
27
28 #include <zephyr/sys/byteorder.h>
29 #include <string.h>
30 #include <zephyr/random/random.h>
31
32 #include <zephyr/drivers/gpio.h>
33
34 #ifdef CONFIG_IEEE802154_CC2520_CRYPTO
35
36 #include <zephyr/crypto/crypto.h>
37 #include <zephyr/crypto/cipher.h>
38
39 #endif /* CONFIG_IEEE802154_CC2520_CRYPTO */
40
41 #include <zephyr/net/ieee802154_radio.h>
42
43 #include "ieee802154_cc2520.h"
44
45 /**
46 * Content is split as follows:
47 * 1 - Debug related functions
48 * 2 - Generic helper functions (for any parts)
49 * 3 - GPIO related functions
50 * 4 - TX related helper functions
51 * 5 - RX related helper functions
52 * 6 - Radio device API functions
53 * 7 - Legacy radio device API functions
54 * 8 - Initialization
55 */
56
57
58 #define CC2520_AUTOMATISM (FRMCTRL0_AUTOCRC | FRMCTRL0_AUTOACK)
59 #define CC2520_TX_THRESHOLD (0x7F)
60 #define CC2520_FCS_LENGTH (2)
61
62 /*********
63 * DEBUG *
64 ********/
65 #if LOG_LEVEL == LOG_LEVEL_DBG
cc2520_print_gpio_config(const struct device * dev)66 static inline void cc2520_print_gpio_config(const struct device *dev)
67 {
68 struct cc2520_context *cc2520 = dev->data;
69
70 LOG_DBG("GPIOCTRL0/1/2/3/4/5 = 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x",
71 read_reg_gpioctrl0(cc2520),
72 read_reg_gpioctrl1(cc2520),
73 read_reg_gpioctrl2(cc2520),
74 read_reg_gpioctrl3(cc2520),
75 read_reg_gpioctrl4(cc2520),
76 read_reg_gpioctrl5(cc2520));
77 LOG_DBG("GPIOPOLARITY: 0x%x",
78 read_reg_gpiopolarity(cc2520));
79 LOG_DBG("GPIOCTRL: 0x%x",
80 read_reg_gpioctrl(cc2520));
81 }
82
cc2520_print_exceptions(struct cc2520_context * cc2520)83 static inline void cc2520_print_exceptions(struct cc2520_context *cc2520)
84 {
85 uint8_t flag = read_reg_excflag0(cc2520);
86
87 LOG_DBG("EXCFLAG0:");
88
89 if (flag & EXCFLAG0_RF_IDLE) {
90 LOG_DBG(" RF_IDLE");
91 }
92
93 if (flag & EXCFLAG0_TX_FRM_DONE) {
94 LOG_DBG(" TX_FRM_DONE");
95 }
96
97 if (flag & EXCFLAG0_TX_ACK_DONE) {
98 LOG_DBG(" TX_ACK_DONE");
99 }
100
101 if (flag & EXCFLAG0_TX_UNDERFLOW) {
102 LOG_DBG(" TX_UNDERFLOW");
103 }
104
105 if (flag & EXCFLAG0_TX_OVERFLOW) {
106 LOG_DBG(" TX_OVERFLOW");
107 }
108
109 if (flag & EXCFLAG0_RX_UNDERFLOW) {
110 LOG_DBG(" RX_UNDERFLOW");
111 }
112
113 if (flag & EXCFLAG0_RX_OVERFLOW) {
114 LOG_DBG(" RX_OVERFLOW");
115 }
116
117 if (flag & EXCFLAG0_RXENABLE_ZERO) {
118 LOG_DBG(" RXENABLE_ZERO");
119 }
120
121 flag = read_reg_excflag1(cc2520);
122
123 LOG_DBG("EXCFLAG1:");
124
125 if (flag & EXCFLAG1_RX_FRM_DONE) {
126 LOG_DBG(" RX_FRM_DONE");
127 }
128
129 if (flag & EXCFLAG1_RX_FRM_ACCEPTED) {
130 LOG_DBG(" RX_FRM_ACCEPTED");
131 }
132
133 if (flag & EXCFLAG1_SRC_MATCH_DONE) {
134 LOG_DBG(" SRC_MATCH_DONE");
135 }
136
137 if (flag & EXCFLAG1_SRC_MATCH_FOUND) {
138 LOG_DBG(" SRC_MATCH_FOUND");
139 }
140
141 if (flag & EXCFLAG1_FIFOP) {
142 LOG_DBG(" FIFOP");
143 }
144
145 if (flag & EXCFLAG1_SFD) {
146 LOG_DBG(" SFD");
147 }
148
149 if (flag & EXCFLAG1_DPU_DONE_L) {
150 LOG_DBG(" DPU_DONE_L");
151 }
152
153 if (flag & EXCFLAG1_DPU_DONE_H) {
154 LOG_DBG(" DPU_DONE_H");
155 }
156 }
157
cc2520_print_errors(struct cc2520_context * cc2520)158 static inline void cc2520_print_errors(struct cc2520_context *cc2520)
159 {
160 uint8_t flag = read_reg_excflag2(cc2520);
161
162 LOG_DBG("EXCFLAG2:");
163
164 if (flag & EXCFLAG2_MEMADDR_ERROR) {
165 LOG_DBG(" MEMADDR_ERROR");
166 }
167
168 if (flag & EXCFLAG2_USAGE_ERROR) {
169 LOG_DBG(" USAGE_ERROR");
170 }
171
172 if (flag & EXCFLAG2_OPERAND_ERROR) {
173 LOG_DBG(" OPERAND_ERROR");
174 }
175
176 if (flag & EXCFLAG2_SPI_ERROR) {
177 LOG_DBG(" SPI_ERROR");
178 }
179
180 if (flag & EXCFLAG2_RF_NO_LOCK) {
181 LOG_DBG(" RF_NO_LOCK");
182 }
183
184 if (flag & EXCFLAG2_RX_FRM_ABORTED) {
185 LOG_DBG(" RX_FRM_ABORTED");
186 }
187
188 if (flag & EXCFLAG2_RFBUFMOV_TIMEOUT) {
189 LOG_DBG(" RFBUFMOV_TIMEOUT");
190 }
191 }
192 #else
193 #define cc2520_print_gpio_config(...)
194 #define cc2520_print_exceptions(...)
195 #define cc2520_print_errors(...)
196 #endif /* LOG_LEVEL == LOG_LEVEL_DBG */
197
198
199 /*********************
200 * Generic functions *
201 ********************/
202 #define z_usleep(usec) k_busy_wait(usec)
203
z_cc2520_access(const struct device * dev,bool read,uint8_t ins,uint16_t addr,void * data,size_t length)204 bool z_cc2520_access(const struct device *dev, bool read, uint8_t ins,
205 uint16_t addr, void *data, size_t length)
206 {
207 const struct cc2520_config *cfg = dev->config;
208 uint8_t cmd_buf[2];
209 struct spi_buf buf[2] = {
210 {
211 .buf = cmd_buf,
212 .len = 1,
213 },
214 {
215 .buf = data,
216 .len = length,
217
218 }
219 };
220 struct spi_buf_set tx = {
221 .buffers = buf,
222 };
223
224
225 cmd_buf[0] = ins;
226
227 if (ins == CC2520_INS_MEMRD || ins == CC2520_INS_MEMWR) {
228 buf[0].len = 2;
229 cmd_buf[0] |= (uint8_t)(addr >> 8);
230 cmd_buf[1] = (uint8_t)(addr & 0xff);
231 } else if (ins == CC2520_INS_REGRD || ins == CC2520_INS_REGWR) {
232 cmd_buf[0] |= (uint8_t)(addr & 0xff);
233 }
234
235 if (read) {
236 const struct spi_buf_set rx = {
237 .buffers = buf,
238 .count = 2
239 };
240
241 tx.count = 1;
242
243 return (spi_transceive_dt(&cfg->bus, &tx, &rx) == 0);
244 }
245
246 tx.count = data ? 2 : 1;
247
248 return (spi_write_dt(&cfg->bus, &tx) == 0);
249 }
250
cc2520_status(const struct device * dev)251 static inline uint8_t cc2520_status(const struct device *dev)
252 {
253 uint8_t status;
254
255 if (z_cc2520_access(dev, true, CC2520_INS_SNOP, 0, &status, 1)) {
256 return status;
257 }
258
259 return 0;
260 }
261
verify_osc_stabilization(const struct device * dev)262 static bool verify_osc_stabilization(const struct device *dev)
263 {
264 uint8_t timeout = 100U;
265 uint8_t status;
266
267 do {
268 status = cc2520_status(dev);
269 z_usleep(1);
270 timeout--;
271 } while (!(status & CC2520_STATUS_XOSC_STABLE_N_RUNNING) && timeout);
272
273 return !!(status & CC2520_STATUS_XOSC_STABLE_N_RUNNING);
274 }
275
276
get_mac(const struct device * dev)277 static inline uint8_t *get_mac(const struct device *dev)
278 {
279 struct cc2520_context *cc2520 = dev->data;
280
281 #if defined(CONFIG_IEEE802154_CC2520_RANDOM_MAC)
282 uint32_t *ptr = (uint32_t *)(cc2520->mac_addr + 4);
283
284 UNALIGNED_PUT(sys_rand32_get(), ptr);
285
286 cc2520->mac_addr[7] = (cc2520->mac_addr[7] & ~0x01) | 0x02;
287 #else
288 cc2520->mac_addr[4] = CONFIG_IEEE802154_CC2520_MAC4;
289 cc2520->mac_addr[5] = CONFIG_IEEE802154_CC2520_MAC5;
290 cc2520->mac_addr[6] = CONFIG_IEEE802154_CC2520_MAC6;
291 cc2520->mac_addr[7] = CONFIG_IEEE802154_CC2520_MAC7;
292 #endif
293
294 cc2520->mac_addr[0] = 0x00;
295 cc2520->mac_addr[1] = 0x12;
296 cc2520->mac_addr[2] = 0x4b;
297 cc2520->mac_addr[3] = 0x00;
298
299 return cc2520->mac_addr;
300 }
301
cc2520_set_pan_id(const struct device * dev,uint16_t pan_id)302 static int cc2520_set_pan_id(const struct device *dev, uint16_t pan_id)
303 {
304 LOG_DBG("0x%x", pan_id);
305
306 pan_id = sys_le16_to_cpu(pan_id);
307
308 if (!write_mem_pan_id(dev, (uint8_t *) &pan_id)) {
309 LOG_ERR("Failed");
310 return -EIO;
311 }
312
313 return 0;
314 }
315
cc2520_set_short_addr(const struct device * dev,uint16_t short_addr)316 static int cc2520_set_short_addr(const struct device *dev,
317 uint16_t short_addr)
318 {
319 LOG_DBG("0x%x", short_addr);
320
321 short_addr = sys_le16_to_cpu(short_addr);
322
323 if (!write_mem_short_addr(dev, (uint8_t *) &short_addr)) {
324 LOG_ERR("Failed");
325 return -EIO;
326 }
327
328 return 0;
329 }
330
cc2520_set_ieee_addr(const struct device * dev,const uint8_t * ieee_addr)331 static int cc2520_set_ieee_addr(const struct device *dev,
332 const uint8_t *ieee_addr)
333 {
334 if (!write_mem_ext_addr(dev, (void *)ieee_addr)) {
335 LOG_ERR("Failed");
336 return -EIO;
337 }
338
339 LOG_DBG("IEEE address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
340 ieee_addr[7], ieee_addr[6], ieee_addr[5], ieee_addr[4],
341 ieee_addr[3], ieee_addr[2], ieee_addr[1], ieee_addr[0]);
342
343 return 0;
344 }
345
346 /******************
347 * GPIO functions *
348 *****************/
set_reset(const struct device * dev,uint32_t value)349 static inline void set_reset(const struct device *dev, uint32_t value)
350 {
351 const struct cc2520_config *cfg = dev->config;
352
353 gpio_pin_set_raw(cfg->reset.port, cfg->reset.pin, value);
354 }
355
set_vreg_en(const struct device * dev,uint32_t value)356 static inline void set_vreg_en(const struct device *dev, uint32_t value)
357 {
358 const struct cc2520_config *cfg = dev->config;
359
360 gpio_pin_set_raw(cfg->vreg_en.port, cfg->vreg_en.pin, value);
361 }
362
get_fifo(const struct device * dev)363 static inline uint32_t get_fifo(const struct device *dev)
364 {
365 const struct cc2520_config *cfg = dev->config;
366
367 return gpio_pin_get_raw(cfg->fifo.port, cfg->fifo.pin);
368 }
369
get_fifop(const struct device * dev)370 static inline uint32_t get_fifop(const struct device *dev)
371 {
372 const struct cc2520_config *cfg = dev->config;
373
374 return gpio_pin_get_raw(cfg->fifop.port, cfg->fifop.pin);
375 }
376
get_cca(const struct device * dev)377 static inline uint32_t get_cca(const struct device *dev)
378 {
379 const struct cc2520_config *cfg = dev->config;
380
381 return gpio_pin_get_raw(cfg->cca.port, cfg->cca.pin);
382 }
383
sfd_int_handler(const struct device * port,struct gpio_callback * cb,uint32_t pins)384 static inline void sfd_int_handler(const struct device *port,
385 struct gpio_callback *cb, uint32_t pins)
386 {
387 struct cc2520_context *cc2520 =
388 CONTAINER_OF(cb, struct cc2520_context, sfd_cb);
389
390 if (atomic_get(&cc2520->tx) == 1) {
391 atomic_set(&cc2520->tx, 0);
392 k_sem_give(&cc2520->tx_sync);
393 }
394 }
395
fifop_int_handler(const struct device * port,struct gpio_callback * cb,uint32_t pins)396 static inline void fifop_int_handler(const struct device *port,
397 struct gpio_callback *cb, uint32_t pins)
398 {
399 struct cc2520_context *cc2520 =
400 CONTAINER_OF(cb, struct cc2520_context, fifop_cb);
401
402 /* Note: Errata document - 1.2 */
403 if (!get_fifop(cc2520->dev) && !get_fifop(cc2520->dev)) {
404 return;
405 }
406
407 if (!get_fifo(cc2520->dev)) {
408 cc2520->overflow = true;
409 }
410
411 k_sem_give(&cc2520->rx_lock);
412 }
413
enable_fifop_interrupt(const struct device * dev,bool enable)414 static void enable_fifop_interrupt(const struct device *dev,
415 bool enable)
416 {
417 const struct cc2520_config *cfg = dev->config;
418 gpio_flags_t mode = enable ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE;
419
420 gpio_pin_interrupt_configure_dt(&cfg->fifop, mode);
421 }
422
enable_sfd_interrupt(const struct device * dev,bool enable)423 static void enable_sfd_interrupt(const struct device *dev,
424 bool enable)
425 {
426 const struct cc2520_config *cfg = dev->config;
427 gpio_flags_t mode = enable ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE;
428
429 gpio_pin_interrupt_configure_dt(&cfg->sfd, mode);
430 }
431
setup_gpio_callbacks(const struct device * dev)432 static inline int setup_gpio_callbacks(const struct device *dev)
433 {
434 const struct cc2520_config *cfg = dev->config;
435 struct cc2520_context *cc2520 = dev->data;
436
437 gpio_init_callback(&cc2520->sfd_cb, sfd_int_handler, BIT(cfg->sfd.pin));
438 if (gpio_add_callback(cfg->sfd.port, &cc2520->sfd_cb) != 0) {
439 return -EIO;
440 }
441
442
443 gpio_init_callback(&cc2520->fifop_cb, fifop_int_handler, BIT(cfg->fifop.pin));
444 if (gpio_add_callback(cfg->fifop.port, &cc2520->fifop_cb) != 0) {
445 return -EIO;
446 }
447
448 return 0;
449 }
450
451
452 /****************
453 * TX functions *
454 ***************/
write_txfifo_length(const struct device * dev,uint8_t len)455 static inline bool write_txfifo_length(const struct device *dev, uint8_t len)
456 {
457 uint8_t length = len + CC2520_FCS_LENGTH;
458
459 return z_cc2520_access(dev, false, CC2520_INS_TXBUF, 0, &length, 1);
460 }
461
write_txfifo_content(const struct device * dev,uint8_t * frame,uint8_t len)462 static inline bool write_txfifo_content(const struct device *dev,
463 uint8_t *frame, uint8_t len)
464 {
465 return z_cc2520_access(dev, false, CC2520_INS_TXBUF, 0, frame, len);
466 }
467
verify_txfifo_status(const struct device * dev,uint8_t len)468 static inline bool verify_txfifo_status(const struct device *dev,
469 uint8_t len)
470 {
471 if (read_reg_txfifocnt(dev) < len ||
472 (read_reg_excflag0(dev) & EXCFLAG0_TX_UNDERFLOW)) {
473 return false;
474 }
475
476 return true;
477 }
478
verify_tx_done(const struct device * dev)479 static inline bool verify_tx_done(const struct device *dev)
480 {
481 uint8_t timeout = 10U;
482 uint8_t status;
483
484 do {
485 z_usleep(1);
486 timeout--;
487 status = read_reg_excflag0(dev);
488 } while (!(status & EXCFLAG0_TX_FRM_DONE) && timeout);
489
490 return !!(status & EXCFLAG0_TX_FRM_DONE);
491 }
492
493 /****************
494 * RX functions *
495 ***************/
496
flush_rxfifo(const struct device * dev)497 static inline void flush_rxfifo(const struct device *dev)
498 {
499 /* Note: Errata document - 1.1 */
500 enable_fifop_interrupt(dev, false);
501
502 instruct_sflushrx(dev);
503 instruct_sflushrx(dev);
504
505 enable_fifop_interrupt(dev, true);
506
507 write_reg_excflag0(dev, EXCFLAG0_RESET_RX_FLAGS);
508 }
509
read_rxfifo_length(const struct device * dev)510 static inline uint8_t read_rxfifo_length(const struct device *dev)
511 {
512 uint8_t len;
513
514
515 if (z_cc2520_access(dev, true, CC2520_INS_RXBUF, 0, &len, 1)) {
516 return len;
517 }
518
519 return 0;
520 }
521
read_rxfifo_content(const struct device * dev,struct net_buf * buf,uint8_t len)522 static inline bool read_rxfifo_content(const struct device *dev,
523 struct net_buf *buf, uint8_t len)
524 {
525 if (!z_cc2520_access(dev, true, CC2520_INS_RXBUF, 0, buf->data, len)) {
526 return false;
527 }
528
529 if (read_reg_excflag0(dev) & EXCFLAG0_RX_UNDERFLOW) {
530 LOG_ERR("RX underflow!");
531 return false;
532 }
533
534 net_buf_add(buf, len);
535
536 return true;
537 }
538
insert_radio_noise_details(struct net_pkt * pkt,uint8_t * status)539 static inline void insert_radio_noise_details(struct net_pkt *pkt, uint8_t *status)
540 {
541 uint8_t lqi;
542
543 net_pkt_set_ieee802154_rssi_dbm(pkt, (int8_t) status[0]);
544
545 /**
546 * CC2520 does not provide an LQI but a correlation factor.
547 * See Section 20.6
548 * Such calculation can be loosely used to transform it to lqi:
549 * corr <= 50 ? lqi = 0
550 * or:
551 * corr >= 110 ? lqi = 255
552 * else:
553 * lqi = (lqi - 50) * 4
554 */
555 lqi = status[1] & CC2520_FCS_CORRELATION;
556 if (lqi <= 50U) {
557 lqi = 0U;
558 } else if (lqi >= 110U) {
559 lqi = 255U;
560 } else {
561 lqi = (lqi - 50U) << 2;
562 }
563
564 net_pkt_set_ieee802154_lqi(pkt, lqi);
565 }
566
verify_crc(const struct device * dev,struct net_pkt * pkt)567 static inline bool verify_crc(const struct device *dev, struct net_pkt *pkt)
568 {
569 uint8_t status[2];
570
571 if (!z_cc2520_access(dev, true, CC2520_INS_RXBUF, 0, &status, 2)) {
572 return false;
573 }
574
575 if (!(status[1] & CC2520_FCS_CRC_OK)) {
576 return false;
577 }
578
579 insert_radio_noise_details(pkt, status);
580
581 return true;
582 }
583
verify_rxfifo_validity(const struct device * dev,uint8_t pkt_len)584 static inline bool verify_rxfifo_validity(const struct device *dev,
585 uint8_t pkt_len)
586 {
587 if (pkt_len < 2 || read_reg_rxfifocnt(dev) != pkt_len) {
588 return false;
589 }
590
591 return true;
592 }
593
cc2520_rx(void * arg)594 static void cc2520_rx(void *arg)
595 {
596 const struct device *dev = arg;
597 struct cc2520_context *cc2520 = dev->data;
598 struct net_pkt *pkt;
599 uint8_t pkt_len;
600
601 while (1) {
602 pkt = NULL;
603
604 k_sem_take(&cc2520->rx_lock, K_FOREVER);
605
606 if (cc2520->overflow) {
607 LOG_ERR("RX overflow!");
608 cc2520->overflow = false;
609
610 goto flush;
611 }
612
613 pkt_len = read_rxfifo_length(dev) & 0x7f;
614 if (!verify_rxfifo_validity(dev, pkt_len)) {
615 LOG_ERR("Invalid content");
616 goto flush;
617 }
618
619 pkt = net_pkt_rx_alloc_with_buffer(cc2520->iface, pkt_len,
620 AF_UNSPEC, 0, K_NO_WAIT);
621 if (!pkt) {
622 LOG_ERR("No pkt available");
623 goto flush;
624 }
625
626 if (!IS_ENABLED(CONFIG_IEEE802154_RAW_MODE)) {
627 pkt_len -= 2U;
628 }
629
630 if (!read_rxfifo_content(dev, pkt->buffer, pkt_len)) {
631 LOG_ERR("No content read");
632 goto flush;
633 }
634
635 if (!verify_crc(dev, pkt)) {
636 LOG_ERR("Bad packet CRC");
637 goto out;
638 }
639
640 if (ieee802154_handle_ack(cc2520->iface, pkt) == NET_OK) {
641 LOG_DBG("ACK packet handled");
642 goto out;
643 }
644
645 LOG_DBG("Caught a packet (%u)", pkt_len);
646
647 if (net_recv_data(cc2520->iface, pkt) < 0) {
648 LOG_DBG("Packet dropped by NET stack");
649 goto out;
650 }
651
652 log_stack_usage(&cc2520->cc2520_rx_thread);
653 continue;
654 flush:
655 cc2520_print_exceptions(cc2520);
656 cc2520_print_errors(cc2520);
657 flush_rxfifo(dev);
658 out:
659 if (pkt) {
660 net_pkt_unref(pkt);
661 }
662 }
663 }
664
665 /********************
666 * Radio device API *
667 *******************/
cc2520_get_capabilities(const struct device * dev)668 static enum ieee802154_hw_caps cc2520_get_capabilities(const struct device *dev)
669 {
670 /* TODO: Add support for IEEE802154_HW_PROMISC */
671 return IEEE802154_HW_FCS | IEEE802154_HW_FILTER |
672 IEEE802154_HW_RX_TX_ACK;
673 }
674
cc2520_cca(const struct device * dev)675 static int cc2520_cca(const struct device *dev)
676 {
677 if (!get_cca(dev)) {
678 LOG_WRN("Busy");
679 return -EBUSY;
680 }
681
682 return 0;
683 }
684
cc2520_set_channel(const struct device * dev,uint16_t channel)685 static int cc2520_set_channel(const struct device *dev, uint16_t channel)
686 {
687 LOG_DBG("%u", channel);
688
689 if (channel > 26) {
690 return -EINVAL;
691 }
692
693 if (channel < 11) {
694 return -ENOTSUP;
695 }
696
697 /* See chapter 16 */
698 channel = 11 + (channel - 11) * 5U;
699
700 if (!write_reg_freqctrl(dev, FREQCTRL_FREQ(channel))) {
701 LOG_ERR("Failed");
702 return -EIO;
703 }
704
705 return 0;
706 }
707
cc2520_filter(const struct device * dev,bool set,enum ieee802154_filter_type type,const struct ieee802154_filter * filter)708 static int cc2520_filter(const struct device *dev,
709 bool set,
710 enum ieee802154_filter_type type,
711 const struct ieee802154_filter *filter)
712 {
713 LOG_DBG("Applying filter %u", type);
714
715 if (!set) {
716 return -ENOTSUP;
717 }
718
719 if (type == IEEE802154_FILTER_TYPE_IEEE_ADDR) {
720 return cc2520_set_ieee_addr(dev, filter->ieee_addr);
721 } else if (type == IEEE802154_FILTER_TYPE_SHORT_ADDR) {
722 return cc2520_set_short_addr(dev, filter->short_addr);
723 } else if (type == IEEE802154_FILTER_TYPE_PAN_ID) {
724 return cc2520_set_pan_id(dev, filter->pan_id);
725 }
726
727 return -ENOTSUP;
728 }
729
cc2520_set_txpower(const struct device * dev,int16_t dbm)730 static int cc2520_set_txpower(const struct device *dev, int16_t dbm)
731 {
732 uint8_t pwr;
733
734 LOG_DBG("%d", dbm);
735
736 /* See chapter 19 part 8 */
737 switch (dbm) {
738 case 5:
739 pwr = 0xF7;
740 break;
741 case 3:
742 pwr = 0xF2;
743 break;
744 case 2:
745 pwr = 0xAB;
746 break;
747 case 1:
748 pwr = 0x13;
749 break;
750 case 0:
751 pwr = 0x32;
752 break;
753 case -2:
754 pwr = 0x81;
755 break;
756 case -4:
757 pwr = 0x88;
758 break;
759 case -7:
760 pwr = 0x2C;
761 break;
762 case -18:
763 pwr = 0x03;
764 break;
765 default:
766 goto error;
767 }
768
769 if (!write_reg_txpower(dev, pwr)) {
770 goto error;
771 }
772
773 return 0;
774 error:
775 LOG_ERR("Failed");
776 return -EIO;
777 }
778
cc2520_tx(const struct device * dev,enum ieee802154_tx_mode mode,struct net_pkt * pkt,struct net_buf * frag)779 static int cc2520_tx(const struct device *dev,
780 enum ieee802154_tx_mode mode,
781 struct net_pkt *pkt,
782 struct net_buf *frag)
783 {
784 uint8_t *frame = frag->data;
785 uint8_t len = frag->len;
786 struct cc2520_context *cc2520 = dev->data;
787 uint8_t retry = 2U;
788 bool status;
789
790 if (mode != IEEE802154_TX_MODE_DIRECT) {
791 NET_ERR("TX mode %d not supported", mode);
792 return -ENOTSUP;
793 }
794
795 LOG_DBG("%p (%u)", frag, len);
796
797 if (!write_reg_excflag0(dev, EXCFLAG0_RESET_TX_FLAGS) ||
798 !write_txfifo_length(dev, len) ||
799 !write_txfifo_content(dev, frame, len)) {
800 LOG_ERR("Cannot feed in TX fifo");
801 goto error;
802 }
803
804 if (!verify_txfifo_status(dev, len)) {
805 LOG_ERR("Did not write properly into TX FIFO");
806 goto error;
807 }
808
809 #ifdef CONFIG_IEEE802154_CC2520_CRYPTO
810 k_sem_take(&cc2520->access_lock, K_FOREVER);
811 #endif
812
813 /* 1 retry is allowed here */
814 do {
815 atomic_set(&cc2520->tx, 1);
816 k_sem_init(&cc2520->tx_sync, 0, K_SEM_MAX_LIMIT);
817
818 if (!instruct_stxoncca(dev)) {
819 LOG_ERR("Cannot start transmission");
820 goto error;
821 }
822
823 /* TODO: Implement standard conforming CSMA/CA or use the soft MAC's default. */
824 k_sem_take(&cc2520->tx_sync, K_MSEC(10));
825
826 retry--;
827 status = verify_tx_done(dev);
828 } while (!status && retry);
829
830 #ifdef CONFIG_IEEE802154_CC2520_CRYPTO
831 k_sem_give(&cc2520->access_lock);
832 #endif
833
834 if (status) {
835 return 0;
836 }
837
838 error:
839 #ifdef CONFIG_IEEE802154_CC2520_CRYPTO
840 k_sem_give(&cc2520->access_lock);
841 #endif
842 LOG_ERR("No TX_FRM_DONE");
843 cc2520_print_exceptions(cc2520);
844 cc2520_print_errors(cc2520);
845
846 atomic_set(&cc2520->tx, 0);
847 instruct_sflushtx(dev);
848
849 return -EIO;
850 }
851
cc2520_start(const struct device * dev)852 static int cc2520_start(const struct device *dev)
853 {
854 if (!instruct_sxoscon(dev) ||
855 !instruct_srxon(dev) ||
856 !verify_osc_stabilization(dev)) {
857 LOG_ERR("Error starting CC2520");
858 return -EIO;
859 }
860
861 flush_rxfifo(dev);
862
863 enable_fifop_interrupt(dev, true);
864 enable_sfd_interrupt(dev, true);
865
866 return 0;
867 }
868
cc2520_stop(const struct device * dev)869 static int cc2520_stop(const struct device *dev)
870 {
871 flush_rxfifo(dev);
872
873 enable_fifop_interrupt(dev, false);
874 enable_sfd_interrupt(dev, false);
875
876 if (!instruct_srfoff(dev) ||
877 !instruct_sxoscoff(dev)) {
878 LOG_ERR("Error stopping CC2520");
879 return -EIO;
880 }
881
882 return 0;
883 }
884
885 /* driver-allocated attribute memory - constant across all driver instances */
886 IEEE802154_DEFINE_PHY_SUPPORTED_CHANNELS(drv_attr, 11, 26);
887
cc2520_attr_get(const struct device * dev,enum ieee802154_attr attr,struct ieee802154_attr_value * value)888 static int cc2520_attr_get(const struct device *dev, enum ieee802154_attr attr,
889 struct ieee802154_attr_value *value)
890 {
891 ARG_UNUSED(dev);
892
893 return ieee802154_attr_get_channel_page_and_range(
894 attr, IEEE802154_ATTR_PHY_CHANNEL_PAGE_ZERO_OQPSK_2450_BPSK_868_915,
895 &drv_attr.phy_supported_channels, value);
896 }
897
898 /******************
899 * Initialization *
900 *****************/
power_on_and_setup(const struct device * dev)901 static int power_on_and_setup(const struct device *dev)
902 {
903 /* Switching to LPM2 mode */
904 set_reset(dev, 0);
905 z_usleep(150);
906
907 set_vreg_en(dev, 0);
908 z_usleep(250);
909
910 /* Then to ACTIVE mode */
911 set_vreg_en(dev, 1);
912 z_usleep(250);
913
914 set_reset(dev, 1);
915 z_usleep(150);
916
917 if (!verify_osc_stabilization(dev)) {
918 return -EIO;
919 }
920
921 /* Default settings to always write (see chapter 28 part 1) */
922 if (!write_reg_txpower(dev, CC2520_TXPOWER_DEFAULT) ||
923 !write_reg_ccactrl0(dev, CC2520_CCACTRL0_DEFAULT) ||
924 !write_reg_mdmctrl0(dev, CC2520_MDMCTRL0_DEFAULT) ||
925 !write_reg_mdmctrl1(dev, CC2520_MDMCTRL1_DEFAULT) ||
926 !write_reg_rxctrl(dev, CC2520_RXCTRL_DEFAULT) ||
927 !write_reg_fsctrl(dev, CC2520_FSCTRL_DEFAULT) ||
928 !write_reg_fscal1(dev, CC2520_FSCAL1_DEFAULT) ||
929 !write_reg_agcctrl1(dev, CC2520_AGCCTRL1_DEFAULT) ||
930 !write_reg_adctest0(dev, CC2520_ADCTEST0_DEFAULT) ||
931 !write_reg_adctest1(dev, CC2520_ADCTEST1_DEFAULT) ||
932 !write_reg_adctest2(dev, CC2520_ADCTEST2_DEFAULT)) {
933 return -EIO;
934 }
935
936 /* EXTCLOCK0: Disabling external clock
937 * FRMCTRL0: AUTOACK and AUTOCRC enabled
938 * FRMCTRL1: SET_RXENMASK_ON_TX and IGNORE_TX_UNDERF
939 * FRMFILT0: Frame filtering (setting CC2520_FRAME_FILTERING)
940 * FIFOPCTRL: Set TX threshold (setting CC2520_TX_THRESHOLD)
941 */
942 if (!write_reg_extclock(dev, 0) ||
943 !write_reg_frmctrl0(dev, CC2520_AUTOMATISM) ||
944 !write_reg_frmctrl1(dev, FRMCTRL1_IGNORE_TX_UNDERF |
945 FRMCTRL1_SET_RXENMASK_ON_TX) ||
946 !write_reg_frmfilt0(dev, FRMFILT0_FRAME_FILTER_EN |
947 FRMFILT0_MAX_FRAME_VERSION(3)) ||
948 !write_reg_frmfilt1(dev, FRMFILT1_ACCEPT_ALL) ||
949 !write_reg_srcmatch(dev, SRCMATCH_DEFAULTS) ||
950 !write_reg_fifopctrl(dev,
951 FIFOPCTRL_FIFOP_THR(CC2520_TX_THRESHOLD))) {
952 return -EIO;
953 }
954
955 /* Cleaning up TX fifo */
956 instruct_sflushtx(dev);
957
958 if (setup_gpio_callbacks(dev) != 0) {
959 return -EIO;
960 }
961
962 cc2520_print_gpio_config(dev);
963
964 return 0;
965 }
966
configure_gpios(const struct device * dev)967 static int configure_gpios(const struct device *dev)
968 {
969 const struct cc2520_config *cfg = dev->config;
970
971 if (!gpio_is_ready_dt(&cfg->vreg_en) ||
972 !gpio_is_ready_dt(&cfg->reset) ||
973 !gpio_is_ready_dt(&cfg->fifo) ||
974 !gpio_is_ready_dt(&cfg->cca) ||
975 !gpio_is_ready_dt(&cfg->sfd) ||
976 !gpio_is_ready_dt(&cfg->fifop)) {
977 return -ENODEV;
978 }
979
980 gpio_pin_configure_dt(&cfg->vreg_en, GPIO_OUTPUT_LOW);
981 gpio_pin_configure_dt(&cfg->reset, GPIO_OUTPUT_LOW);
982 gpio_pin_configure_dt(&cfg->fifo, GPIO_INPUT);
983 gpio_pin_configure_dt(&cfg->cca, GPIO_INPUT);
984 gpio_pin_configure_dt(&cfg->sfd, GPIO_INPUT);
985 gpio_pin_configure_dt(&cfg->fifop, GPIO_INPUT);
986
987 return 0;
988 }
989
cc2520_init(const struct device * dev)990 static int cc2520_init(const struct device *dev)
991 {
992 const struct cc2520_config *cfg = dev->config;
993 struct cc2520_context *cc2520 = dev->data;
994
995 cc2520->dev = dev;
996
997 atomic_set(&cc2520->tx, 0);
998 k_sem_init(&cc2520->rx_lock, 0, K_SEM_MAX_LIMIT);
999
1000 #ifdef CONFIG_IEEE802154_CC2520_CRYPTO
1001 k_sem_init(&cc2520->access_lock, 1, 1);
1002 #endif
1003
1004 if (configure_gpios(dev) != 0) {
1005 LOG_ERR("Configuring GPIOS failed");
1006 return -EIO;
1007 }
1008
1009 if (!spi_is_ready_dt(&cfg->bus)) {
1010 LOG_ERR("SPI bus %s not ready", cfg->bus.bus->name);
1011 return -EIO;
1012 }
1013
1014 LOG_DBG("GPIO and SPI configured");
1015
1016 if (power_on_and_setup(dev) != 0) {
1017 LOG_ERR("Configuring CC2520 failed");
1018 return -EIO;
1019 }
1020
1021 k_thread_create(&cc2520->cc2520_rx_thread, cc2520->cc2520_rx_stack,
1022 CONFIG_IEEE802154_CC2520_RX_STACK_SIZE,
1023 (k_thread_entry_t)cc2520_rx,
1024 (void *)dev, NULL, NULL, K_PRIO_COOP(2), 0, K_NO_WAIT);
1025 k_thread_name_set(&cc2520->cc2520_rx_thread, "cc2520_rx");
1026
1027 LOG_INF("CC2520 initialized");
1028
1029 return 0;
1030 }
1031
cc2520_iface_init(struct net_if * iface)1032 static void cc2520_iface_init(struct net_if *iface)
1033 {
1034 const struct device *dev = net_if_get_device(iface);
1035 struct cc2520_context *cc2520 = dev->data;
1036 uint8_t *mac = get_mac(dev);
1037
1038 net_if_set_link_addr(iface, mac, 8, NET_LINK_IEEE802154);
1039
1040 cc2520->iface = iface;
1041
1042 ieee802154_init(iface);
1043 }
1044
1045 static const struct cc2520_config cc2520_config = {
1046 .bus = SPI_DT_SPEC_INST_GET(0, SPI_WORD_SET(8), 0),
1047 .vreg_en = GPIO_DT_SPEC_INST_GET(0, vreg_en_gpios),
1048 .reset = GPIO_DT_SPEC_INST_GET(0, reset_gpios),
1049 .fifo = GPIO_DT_SPEC_INST_GET(0, fifo_gpios),
1050 .cca = GPIO_DT_SPEC_INST_GET(0, cca_gpios),
1051 .sfd = GPIO_DT_SPEC_INST_GET(0, sfd_gpios),
1052 .fifop = GPIO_DT_SPEC_INST_GET(0, fifop_gpios)
1053 };
1054
1055 static struct cc2520_context cc2520_context_data;
1056
1057 static struct ieee802154_radio_api cc2520_radio_api = {
1058 .iface_api.init = cc2520_iface_init,
1059
1060 .get_capabilities = cc2520_get_capabilities,
1061 .cca = cc2520_cca,
1062 .set_channel = cc2520_set_channel,
1063 .filter = cc2520_filter,
1064 .set_txpower = cc2520_set_txpower,
1065 .start = cc2520_start,
1066 .stop = cc2520_stop,
1067 .tx = cc2520_tx,
1068 .attr_get = cc2520_attr_get,
1069 };
1070
1071 #if defined(CONFIG_IEEE802154_RAW_MODE)
1072 DEVICE_DT_INST_DEFINE(0, cc2520_init, NULL, &cc2520_context_data, NULL,
1073 POST_KERNEL, CONFIG_IEEE802154_CC2520_INIT_PRIO,
1074 &cc2520_radio_api);
1075 #else
1076 NET_DEVICE_DT_INST_DEFINE(0, cc2520_init, NULL, &cc2520_context_data,
1077 &cc2520_config, CONFIG_IEEE802154_CC2520_INIT_PRIO,
1078 &cc2520_radio_api, IEEE802154_L2,
1079 NET_L2_GET_CTX_TYPE(IEEE802154_L2), 125);
1080 #endif
1081
1082
1083 #ifdef CONFIG_IEEE802154_CC2520_CRYPTO
1084
cc2520_read_ram(const struct device * dev,uint16_t addr,uint8_t * data_buf,uint8_t len)1085 static inline bool cc2520_read_ram(const struct device *dev, uint16_t addr,
1086 uint8_t *data_buf, uint8_t len)
1087 {
1088 return z_cc2520_access(dev, true, CC2520_INS_MEMRD,
1089 addr, data_buf, len);
1090 }
1091
cc2520_write_ram(const struct device * dev,uint16_t addr,uint8_t * data_buf,uint8_t len)1092 static inline bool cc2520_write_ram(const struct device *dev, uint16_t addr,
1093 uint8_t *data_buf, uint8_t len)
1094 {
1095 return z_cc2520_access(dev, false, CC2520_INS_MEMWR,
1096 addr, data_buf, len);
1097 }
1098
instruct_uccm_ccm(const struct device * dev,bool uccm,uint8_t key_addr,uint8_t auth_crypt,uint8_t nonce_addr,uint16_t input_addr,uint16_t output_addr,uint8_t in_len,uint8_t m)1099 static inline bool instruct_uccm_ccm(const struct device *dev,
1100 bool uccm,
1101 uint8_t key_addr,
1102 uint8_t auth_crypt,
1103 uint8_t nonce_addr,
1104 uint16_t input_addr,
1105 uint16_t output_addr,
1106 uint8_t in_len,
1107 uint8_t m)
1108 {
1109 const struct cc2520_config *cfg = dev->config;
1110 struct cc2520_context *ctx = dev->data;
1111 uint8_t cmd[9];
1112 const struct spi_buf buf[1] = {
1113 {
1114 .buf = cmd,
1115 .len = 9,
1116 },
1117 };
1118 const struct spi_buf_set tx = {
1119 .buffers = buf,
1120 .count = 1
1121 };
1122
1123 int ret;
1124
1125 LOG_DBG("%sCCM(P={01} K={%02x} C={%02x} N={%02x}"
1126 " A={%03x} E={%03x} F{%02x} M={%02x})",
1127 uccm ? "U" : "", key_addr, auth_crypt, nonce_addr,
1128 input_addr, output_addr, in_len, m);
1129
1130 cmd[0] = uccm ? CC2520_INS_UCCM | 1 : CC2520_INS_CCM | 1;
1131 cmd[1] = key_addr;
1132 cmd[2] = (auth_crypt & 0x7f);
1133 cmd[3] = nonce_addr;
1134 cmd[4] = (uint8_t)(((input_addr & 0x0f00) >> 4) |
1135 ((output_addr & 0x0f00) >> 8));
1136 cmd[5] = (uint8_t)(input_addr & 0x00ff);
1137 cmd[6] = (uint8_t)(output_addr & 0x00ff);
1138 cmd[7] = (in_len & 0x7f);
1139 cmd[8] = (m & 0x03);
1140
1141 k_sem_take(&ctx->access_lock, K_FOREVER);
1142
1143 ret = spi_write_dt(&cfg->bus, &tx);
1144
1145 k_sem_give(&ctx->access_lock);
1146
1147 if (ret) {
1148 LOG_ERR("%sCCM Failed", uccm ? "U" : "");
1149 return false;
1150 }
1151
1152 return true;
1153 }
1154
generate_nonce(uint8_t * ccm_nonce,uint8_t * nonce,struct cipher_aead_pkt * apkt,uint8_t m)1155 static inline void generate_nonce(uint8_t *ccm_nonce, uint8_t *nonce,
1156 struct cipher_aead_pkt *apkt, uint8_t m)
1157 {
1158 nonce[0] = 0 | (apkt->ad_len ? 0x40 : 0) | (m << 3) | 1;
1159
1160 memcpy(&nonce[1], ccm_nonce, 13);
1161
1162 nonce[14] = (uint8_t)(apkt->pkt->in_len >> 8);
1163 nonce[15] = (uint8_t)(apkt->pkt->in_len);
1164
1165 /* See section 26.8.1 */
1166 sys_mem_swap(nonce, 16);
1167 }
1168
insert_crypto_parameters(struct cipher_ctx * ctx,struct cipher_aead_pkt * apkt,uint8_t * ccm_nonce,uint8_t * auth_crypt)1169 static int insert_crypto_parameters(struct cipher_ctx *ctx,
1170 struct cipher_aead_pkt *apkt,
1171 uint8_t *ccm_nonce, uint8_t *auth_crypt)
1172 {
1173 const struct device *cc2520 = ctx->device;
1174 uint8_t data[128];
1175 uint8_t *in_buf;
1176 uint8_t in_len;
1177 uint8_t m = 0U;
1178
1179 if (!apkt->pkt->out_buf || !apkt->pkt->out_buf_max) {
1180 LOG_ERR("Out buffer needs to be set");
1181 return -EINVAL;
1182 }
1183
1184 if (!ctx->key.bit_stream || !ctx->keylen) {
1185 LOG_ERR("No key installed");
1186 return -EINVAL;
1187 }
1188
1189 if (!(ctx->flags & CAP_INPLACE_OPS)) {
1190 LOG_ERR("It supports only in-place operation");
1191 return -EINVAL;
1192 }
1193
1194 if (!apkt->ad || !apkt->ad_len) {
1195 LOG_ERR("CCM needs associated data");
1196 return -EINVAL;
1197 }
1198
1199 if (apkt->pkt->in_buf && apkt->pkt->in_buf - apkt->ad_len != apkt->ad) {
1200 LOG_ERR("In-place needs ad and input in same memory");
1201 return -EINVAL;
1202 }
1203
1204 if (!apkt->pkt->in_buf) {
1205 if (!ctx->mode_params.ccm_info.tag_len) {
1206 LOG_ERR("Auth only needs a tag length");
1207 return -EINVAL;
1208 }
1209
1210 in_buf = apkt->ad;
1211 in_len = apkt->ad_len;
1212
1213 *auth_crypt = 0U;
1214 } else {
1215 in_buf = data;
1216
1217 memcpy(in_buf, apkt->ad, apkt->ad_len);
1218 memcpy(in_buf + apkt->ad_len,
1219 apkt->pkt->in_buf, apkt->pkt->in_len);
1220 in_len = apkt->ad_len + apkt->pkt->in_len;
1221
1222 *auth_crypt = !apkt->tag ? apkt->pkt->in_len :
1223 apkt->pkt->in_len - ctx->mode_params.ccm_info.tag_len;
1224 }
1225
1226 if (ctx->mode_params.ccm_info.tag_len) {
1227 if ((ctx->mode_params.ccm_info.tag_len >> 2) > 3) {
1228 m = 3U;
1229 } else {
1230 m = ctx->mode_params.ccm_info.tag_len >> 2;
1231 }
1232 }
1233
1234 /* Writing the frame in RAM */
1235 if (!cc2520_write_ram(cc2520, CC2520_MEM_DATA, in_buf, in_len)) {
1236 LOG_ERR("Cannot write the frame in RAM");
1237 return -EIO;
1238 }
1239
1240 /* See section 26.8.1 */
1241 sys_memcpy_swap(data, ctx->key.bit_stream, ctx->keylen);
1242
1243 /* Writing the key in RAM */
1244 if (!cc2520_write_ram(cc2520, CC2520_MEM_KEY, data, 16)) {
1245 LOG_ERR("Cannot write the key in RAM");
1246 return -EIO;
1247 }
1248
1249 generate_nonce(ccm_nonce, data, apkt, m);
1250
1251 /* Writing the nonce in RAM */
1252 if (!cc2520_write_ram(cc2520, CC2520_MEM_NONCE, data, 16)) {
1253 LOG_ERR("Cannot write the nonce in RAM");
1254 return -EIO;
1255 }
1256
1257 return m;
1258 }
1259
cc2520_crypto_ccm(struct cipher_ctx * ctx,struct cipher_aead_pkt * apkt,uint8_t * ccm_nonce)1260 static int cc2520_crypto_ccm(struct cipher_ctx *ctx,
1261 struct cipher_aead_pkt *apkt,
1262 uint8_t *ccm_nonce)
1263 {
1264 const struct device *cc2520 = ctx->device;
1265 uint8_t auth_crypt;
1266 int m;
1267
1268 if (!apkt || !apkt->pkt) {
1269 LOG_ERR("Invalid crypto packet to operate with");
1270 return -EINVAL;
1271 }
1272
1273 m = insert_crypto_parameters(ctx, apkt, ccm_nonce, &auth_crypt);
1274 if (m < 0) {
1275 LOG_ERR("Inserting crypto parameters failed");
1276 return m;
1277 }
1278
1279 apkt->pkt->out_len = apkt->pkt->in_len + apkt->ad_len +
1280 (m ? ctx->mode_params.ccm_info.tag_len : 0);
1281
1282 if (apkt->pkt->out_len > apkt->pkt->out_buf_max) {
1283 LOG_ERR("Result will not fit into out buffer %u vs %u",
1284 apkt->pkt->out_len, apkt->pkt->out_buf_max);
1285 return -ENOBUFS;
1286 }
1287
1288 if (!instruct_uccm_ccm(cc2520, false, CC2520_MEM_KEY >> 4, auth_crypt,
1289 CC2520_MEM_NONCE >> 4, CC2520_MEM_DATA,
1290 0x000, apkt->ad_len, m) ||
1291 !cc2520_read_ram(cc2520, CC2520_MEM_DATA,
1292 apkt->pkt->out_buf, apkt->pkt->out_len)) {
1293 LOG_ERR("CCM or reading result from RAM failed");
1294 return -EIO;
1295 }
1296
1297 if (apkt->tag) {
1298 memcpy(apkt->tag, apkt->pkt->out_buf + apkt->pkt->in_len,
1299 ctx->mode_params.ccm_info.tag_len);
1300 }
1301
1302 return 0;
1303 }
1304
cc2520_crypto_uccm(struct cipher_ctx * ctx,struct cipher_aead_pkt * apkt,uint8_t * ccm_nonce)1305 static int cc2520_crypto_uccm(struct cipher_ctx *ctx,
1306 struct cipher_aead_pkt *apkt,
1307 uint8_t *ccm_nonce)
1308 {
1309 const struct device *cc2520 = ctx->device;
1310 uint8_t auth_crypt;
1311 int m;
1312
1313 if (!apkt || !apkt->pkt) {
1314 LOG_ERR("Invalid crypto packet to operate with");
1315 return -EINVAL;
1316 }
1317
1318 if (ctx->mode_params.ccm_info.tag_len && !apkt->tag) {
1319 LOG_ERR("In case of MIC you need to provide a tag");
1320 return -EINVAL;
1321 }
1322
1323 m = insert_crypto_parameters(ctx, apkt, ccm_nonce, &auth_crypt);
1324 if (m < 0) {
1325 return m;
1326 }
1327
1328 apkt->pkt->out_len = apkt->pkt->in_len + apkt->ad_len;
1329
1330 if (!instruct_uccm_ccm(cc2520, true, CC2520_MEM_KEY >> 4, auth_crypt,
1331 CC2520_MEM_NONCE >> 4, CC2520_MEM_DATA,
1332 0x000, apkt->ad_len, m) ||
1333 !cc2520_read_ram(cc2520, CC2520_MEM_DATA,
1334 apkt->pkt->out_buf, apkt->pkt->out_len)) {
1335 LOG_ERR("UCCM or reading result from RAM failed");
1336 return -EIO;
1337 }
1338
1339 if (m && (!(read_reg_dpustat(cc2520) & DPUSTAT_AUTHSTAT_H))) {
1340 LOG_ERR("Authentication of the frame failed");
1341 return -EBADMSG;
1342 }
1343
1344 return 0;
1345 }
1346
cc2520_crypto_hw_caps(const struct device * dev)1347 static int cc2520_crypto_hw_caps(const struct device *dev)
1348 {
1349 return CAP_RAW_KEY | CAP_INPLACE_OPS | CAP_SYNC_OPS;
1350 }
1351
cc2520_crypto_begin_session(const struct device * dev,struct cipher_ctx * ctx,enum cipher_algo algo,enum cipher_mode mode,enum cipher_op op_type)1352 static int cc2520_crypto_begin_session(const struct device *dev,
1353 struct cipher_ctx *ctx,
1354 enum cipher_algo algo,
1355 enum cipher_mode mode,
1356 enum cipher_op op_type)
1357 {
1358 if (algo != CRYPTO_CIPHER_ALGO_AES || mode != CRYPTO_CIPHER_MODE_CCM) {
1359 LOG_ERR("Wrong algo (%u) or mode (%u)", algo, mode);
1360 return -EINVAL;
1361 }
1362
1363 if (ctx->mode_params.ccm_info.nonce_len != 13U) {
1364 LOG_ERR("Nonce length erroneous (%u)",
1365 ctx->mode_params.ccm_info.nonce_len);
1366 return -EINVAL;
1367 }
1368
1369 if (op_type == CRYPTO_CIPHER_OP_ENCRYPT) {
1370 ctx->ops.ccm_crypt_hndlr = cc2520_crypto_ccm;
1371 } else {
1372 ctx->ops.ccm_crypt_hndlr = cc2520_crypto_uccm;
1373 }
1374
1375 ctx->ops.cipher_mode = mode;
1376 ctx->device = dev;
1377
1378 return 0;
1379 }
1380
cc2520_crypto_free_session(const struct device * dev,struct cipher_ctx * ctx)1381 static int cc2520_crypto_free_session(const struct device *dev,
1382 struct cipher_ctx *ctx)
1383 {
1384 ARG_UNUSED(dev);
1385
1386 ctx->ops.ccm_crypt_hndlr = NULL;
1387 ctx->device = NULL;
1388
1389 return 0;
1390 }
1391
cc2520_crypto_init(const struct device * dev)1392 static int cc2520_crypto_init(const struct device *dev)
1393 {
1394 LOG_INF("CC2520 crypto part initialized");
1395
1396 return 0;
1397 }
1398
1399 struct crypto_driver_api cc2520_crypto_api = {
1400 .query_hw_caps = cc2520_crypto_hw_caps,
1401 .cipher_begin_session = cc2520_crypto_begin_session,
1402 .cipher_free_session = cc2520_crypto_free_session,
1403 .cipher_async_callback_set = NULL
1404 };
1405
1406 DEVICE_DEFINE(cc2520_crypto, "cc2520_crypto",
1407 cc2520_crypto_init, NULL,
1408 &cc2520_context_data, NULL, POST_KERNEL,
1409 CONFIG_IEEE802154_CC2520_CRYPTO_INIT_PRIO, &cc2520_crypto_api);
1410
1411 #endif /* CONFIG_IEEE802154_CC2520_CRYPTO */
1412