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