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