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