1 /* ieee802154_mcxw.c - NXP MCXW 802.15.4 driver */
2 
3 /*
4  * Copyright 2025 NXP
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #define DT_DRV_COMPAT nxp_mcxw_ieee802154
10 
11 #define LOG_MODULE_NAME ieee802154_mcxw
12 
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
15 
16 #include <zephyr/kernel.h>
17 #include <zephyr/arch/cpu.h>
18 #include <zephyr/debug/stack.h>
19 #include <zephyr/device.h>
20 #include <zephyr/drivers/counter.h>
21 #include <zephyr/init.h>
22 #include <zephyr/net/net_if.h>
23 #include <zephyr/net/net_pkt.h>
24 
25 #if defined(CONFIG_NET_L2_OPENTHREAD)
26 #include <zephyr/net/openthread.h>
27 #include <zephyr/net/ieee802154_radio_openthread.h>
28 #endif
29 
30 #include <zephyr/sys/byteorder.h>
31 #include <zephyr/random/random.h>
32 
33 #include <zephyr/net/ieee802154_radio.h>
34 
35 #include <soc.h>
36 #include <errno.h>
37 #include <string.h>
38 
39 #include "EmbeddedTypes.h"
40 #include "Phy.h"
41 
42 #include "fwk_platform_ot.h"
43 
44 #include "ieee802154_mcxw.h"
45 #include "ieee802154_mcxw_utils.h"
46 
47 void PLATFORM_RemoteActiveReq(void);
48 void PLATFORM_RemoteActiveRel(void);
49 
50 #if CONFIG_IEEE802154_CSL_ENDPOINT
51 
52 #define CMP_OVHD (4 * IEEE802154_SYMBOL_TIME_US) /* 2 LPTRM (32 kHz) ticks */
53 
54 static bool_t csl_rx = FALSE;
55 
56 static void set_csl_sample_time(void);
57 static void start_csl_receiver(void);
58 static void stop_csl_receiver(void);
59 static uint16_t rf_compute_csl_phase(uint32_t aTimeUs);
60 
61 #else /* CONFIG_IEEE802154_CSL_ENDPOINT */
62 #define start_csl_receiver()
63 #define stop_csl_receiver()
64 #endif /* CONFIG_IEEE802154_CSL_ENDPOINT */
65 
66 static volatile uint32_t sun_rx_mode = RX_ON_IDLE_START;
67 
68 /* Private functions */
69 static void rf_abort(void);
70 static void rf_set_channel(uint8_t channel);
71 static void rf_set_tx_power(int8_t tx_power);
72 static uint64_t rf_adjust_tstamp_from_phy(uint64_t ts);
73 
74 #if CONFIG_IEEE802154_CSL_ENDPOINT || CONFIG_NET_PKT_TXTIME
75 static uint32_t rf_adjust_tstamp_from_app(uint32_t time);
76 #endif /* CONFIG_IEEE802154_CSL_ENDPOINT || CONFIG_NET_PKT_TXTIME */
77 
78 static void rf_rx_on_idle(uint32_t newValue);
79 
80 static uint8_t ot_phy_ctx = (uint8_t)(-1);
81 
82 static struct mcxw_context mcxw_ctx;
83 
84 /**
85  * Stub function used for controlling low power mode
86  */
app_allow_device_to_slepp(void)87 WEAK void app_allow_device_to_slepp(void)
88 {
89 }
90 
91 /**
92  * Stub function used for controlling low power mode
93  */
app_disallow_device_to_slepp(void)94 WEAK void app_disallow_device_to_slepp(void)
95 {
96 }
97 
mcxw_get_eui64(uint8_t * eui64)98 void mcxw_get_eui64(uint8_t *eui64)
99 {
100 	__ASSERT_NO_MSG(eui64);
101 
102 	/* PLATFORM_GetIeee802_15_4Addr(); */
103 	sys_rand_get(eui64, sizeof(mcxw_ctx.mac));
104 
105 	eui64[0] = (eui64[0] & ~0x01) | 0x02;
106 }
107 
mcxw_set_pan_id(const struct device * dev,uint16_t aPanId)108 static int mcxw_set_pan_id(const struct device *dev, uint16_t aPanId)
109 {
110 	struct mcxw_context *mcxw_radio = dev->data;
111 
112 	macToPlmeMessage_t msg;
113 
114 	msg.msgType = gPlmeSetReq_c;
115 	msg.msgData.setReq.PibAttribute = gPhyPibPanId_c;
116 	msg.msgData.setReq.PibAttributeValue = (uint64_t)aPanId;
117 
118 	(void)MAC_PLME_SapHandler(&msg, ot_phy_ctx);
119 
120 	mcxw_radio->pan_id = aPanId;
121 
122 	return 0;
123 }
124 
mcxw_set_extended_address(const struct device * dev,const uint8_t * ieee_addr)125 static int mcxw_set_extended_address(const struct device *dev, const uint8_t *ieee_addr)
126 {
127 	struct mcxw_context *mcxw_radio = dev->data;
128 
129 	macToPlmeMessage_t msg;
130 
131 	msg.msgType = gPlmeSetReq_c;
132 	msg.msgData.setReq.PibAttribute = gPhyPibLongAddress_c;
133 	msg.msgData.setReq.PibAttributeValue = *(uint64_t *)ieee_addr;
134 
135 	memcpy(mcxw_radio->mac, ieee_addr, 8);
136 
137 	(void)MAC_PLME_SapHandler(&msg, ot_phy_ctx);
138 
139 	return 0;
140 }
141 
mcxw_set_short_address(const struct device * dev,uint16_t aShortAddress)142 static int mcxw_set_short_address(const struct device *dev, uint16_t aShortAddress)
143 {
144 	ARG_UNUSED(dev);
145 
146 	macToPlmeMessage_t msg;
147 
148 	msg.msgType = gPlmeSetReq_c;
149 	msg.msgData.setReq.PibAttribute = gPhyPibShortAddress_c;
150 	msg.msgData.setReq.PibAttributeValue = (uint64_t)aShortAddress;
151 
152 	(void)MAC_PLME_SapHandler(&msg, ot_phy_ctx);
153 
154 	return 0;
155 }
156 
mcxw_filter(const struct device * dev,bool set,enum ieee802154_filter_type type,const struct ieee802154_filter * filter)157 static int mcxw_filter(const struct device *dev, bool set, enum ieee802154_filter_type type,
158 		       const struct ieee802154_filter *filter)
159 {
160 	LOG_DBG("Applying filter %u", type);
161 
162 	if (!set) {
163 		return -ENOTSUP;
164 	}
165 
166 	if (type == IEEE802154_FILTER_TYPE_IEEE_ADDR) {
167 		return mcxw_set_extended_address(dev, filter->ieee_addr);
168 	} else if (type == IEEE802154_FILTER_TYPE_SHORT_ADDR) {
169 		return mcxw_set_short_address(dev, filter->short_addr);
170 	} else if (type == IEEE802154_FILTER_TYPE_PAN_ID) {
171 		return mcxw_set_pan_id(dev, filter->pan_id);
172 	}
173 
174 	return -ENOTSUP;
175 }
176 
mcxw_radio_receive(void)177 void mcxw_radio_receive(void)
178 {
179 	macToPlmeMessage_t msg;
180 	phyStatus_t phy_status;
181 
182 	app_disallow_device_to_slepp();
183 
184 	__ASSERT(mcxw_ctx.state != RADIO_STATE_DISABLED, "Radio RX invalid state");
185 
186 	mcxw_ctx.state = RADIO_STATE_RECEIVE;
187 
188 	rf_abort();
189 	rf_set_channel(mcxw_ctx.channel);
190 
191 	if (sun_rx_mode) {
192 		start_csl_receiver();
193 
194 		/* restart Rx on idle only if it was enabled */
195 		msg.msgType = gPlmeSetReq_c;
196 		msg.msgData.setReq.PibAttribute = gPhyPibRxOnWhenIdle;
197 		msg.msgData.setReq.PibAttributeValue = (uint64_t)1;
198 
199 		phy_status = MAC_PLME_SapHandler(&msg, ot_phy_ctx);
200 		__ASSERT_NO_MSG(phy_status == gPhySuccess_c);
201 	}
202 }
203 
mcxw_get_acc(const struct device * dev)204 static uint8_t mcxw_get_acc(const struct device *dev)
205 {
206 	ARG_UNUSED(dev);
207 
208 	return CONFIG_IEEE802154_MCXW_CSL_ACCURACY;
209 }
210 
mcxw_start(const struct device * dev)211 static int mcxw_start(const struct device *dev)
212 {
213 	struct mcxw_context *mcxw_radio = dev->data;
214 
215 	__ASSERT(mcxw_radio->state == RADIO_STATE_DISABLED, "%s", __func__);
216 
217 	mcxw_radio->state = RADIO_STATE_SLEEP;
218 
219 	rf_rx_on_idle(RX_ON_IDLE_START);
220 
221 	mcxw_radio_receive();
222 
223 	return 0;
224 }
225 
mcxw_stop(const struct device * dev)226 static int mcxw_stop(const struct device *dev)
227 {
228 	struct mcxw_context *mcxw_radio = dev->data;
229 
230 	__ASSERT(mcxw_radio->state != RADIO_STATE_DISABLED, "%s", __func__);
231 
232 	stop_csl_receiver();
233 
234 	mcxw_radio->state = RADIO_STATE_DISABLED;
235 
236 	return 0;
237 }
238 
mcxw_radio_sleep(void)239 void mcxw_radio_sleep(void)
240 {
241 	__ASSERT_NO_MSG(((mcxw_ctx.state != RADIO_STATE_TRANSMIT) &&
242 			 (mcxw_ctx.state != RADIO_STATE_DISABLED)));
243 
244 	rf_abort();
245 
246 	stop_csl_receiver();
247 
248 	app_allow_device_to_slepp();
249 
250 	mcxw_ctx.state = RADIO_STATE_SLEEP;
251 }
252 
mcxw_enable_src_match(bool enable)253 static void mcxw_enable_src_match(bool enable)
254 {
255 	macToPlmeMessage_t msg;
256 
257 	msg.msgType = gPlmeSetSAMState_c;
258 	msg.msgData.SAMState = enable;
259 
260 	(void)MAC_PLME_SapHandler(&msg, ot_phy_ctx);
261 }
262 
mcxw_src_match_entry(bool extended,uint8_t * address)263 static int mcxw_src_match_entry(bool extended, uint8_t *address)
264 {
265 	macToPlmeMessage_t msg;
266 
267 	msg.msgType = gPlmeAddToSapTable_c;
268 	msg.msgData.deviceAddr.panId = mcxw_ctx.pan_id;
269 
270 	if (extended) {
271 		msg.msgData.deviceAddr.mode = 3;
272 		memcpy(msg.msgData.deviceAddr.addr, address, 8);
273 	} else {
274 		msg.msgData.deviceAddr.mode = 2;
275 		memcpy(msg.msgData.deviceAddr.addr, address, 2);
276 	}
277 
278 	if (gPhySuccess_c != MAC_PLME_SapHandler(&msg, ot_phy_ctx)) {
279 		/* the status is not returned from PHY over RPMSG */
280 		return -ENOMEM;
281 	}
282 
283 	return 0;
284 }
285 
mcxw_src_clear_entry(bool extended,uint8_t * address)286 static int mcxw_src_clear_entry(bool extended, uint8_t *address)
287 {
288 	macToPlmeMessage_t msg;
289 
290 	msg.msgType = gPlmeRemoveFromSAMTable_c;
291 	msg.msgData.deviceAddr.panId = mcxw_ctx.pan_id;
292 
293 	if (extended) {
294 		msg.msgData.deviceAddr.mode = 3;
295 		memcpy(msg.msgData.deviceAddr.addr, address, 8);
296 	} else {
297 		msg.msgData.deviceAddr.mode = 2;
298 		memcpy(msg.msgData.deviceAddr.addr, address, 2);
299 	}
300 
301 	if (gPhySuccess_c != MAC_PLME_SapHandler(&msg, ot_phy_ctx)) {
302 		/* the status is not returned from PHY over RPMSG */
303 		return -ENOENT;
304 	}
305 
306 	return 0;
307 }
308 
handle_ack(struct mcxw_context * mcxw_radio)309 static int handle_ack(struct mcxw_context *mcxw_radio)
310 {
311 	uint8_t len;
312 	struct net_pkt *pkt;
313 	int err = 0;
314 
315 	len = mcxw_radio->rx_ack_frame.length;
316 	pkt = net_pkt_rx_alloc_with_buffer(mcxw_radio->iface, len, AF_UNSPEC, 0, K_NO_WAIT);
317 	if (!pkt) {
318 		LOG_ERR("No free packet available.");
319 		err = -ENOMEM;
320 		goto exit;
321 	}
322 
323 	if (net_pkt_write(pkt, mcxw_radio->rx_ack_frame.psdu, len) < 0) {
324 		LOG_ERR("Failed to write to a packet.");
325 		err = -ENOMEM;
326 		goto free_ack;
327 	}
328 
329 	/* Use some fake values for LQI and RSSI. */
330 	net_pkt_set_ieee802154_lqi(pkt, 80);
331 	net_pkt_set_ieee802154_rssi_dbm(pkt, -40);
332 
333 	net_pkt_set_timestamp_ns(pkt, mcxw_radio->rx_ack_frame.timestamp);
334 
335 	net_pkt_cursor_init(pkt);
336 
337 	if (ieee802154_handle_ack(mcxw_radio->iface, pkt) != NET_OK) {
338 		LOG_ERR("ACK packet not handled - releasing.");
339 	}
340 
341 free_ack:
342 	net_pkt_unref(pkt);
343 
344 exit:
345 	mcxw_radio->rx_ack_frame.length = 0;
346 	return err;
347 }
348 
mcxw_tx(const struct device * dev,enum ieee802154_tx_mode mode,struct net_pkt * pkt,struct net_buf * frag)349 static int mcxw_tx(const struct device *dev, enum ieee802154_tx_mode mode, struct net_pkt *pkt,
350 		   struct net_buf *frag)
351 {
352 	struct mcxw_context *mcxw_radio = dev->data;
353 	/* tx_data buffer has reserved memory for both macToPdDataMessage_t and actual data frame
354 	 * after
355 	 */
356 	macToPdDataMessage_t *msg = (macToPdDataMessage_t *)mcxw_radio->tx_data;
357 	phyStatus_t phy_status;
358 
359 	uint8_t payload_len = frag->len;
360 	uint8_t *payload = frag->data;
361 
362 	app_disallow_device_to_slepp();
363 
364 	__ASSERT(mcxw_radio->state != RADIO_STATE_DISABLED, "%s: radio disabled", __func__);
365 
366 	if (payload_len > IEEE802154_MTU) {
367 		LOG_ERR("Payload too large: %d", payload_len);
368 		return -EMSGSIZE;
369 	}
370 
371 	mcxw_radio->tx_frame.length = payload_len + IEEE802154_FCS_LENGTH;
372 	memcpy(mcxw_radio->tx_frame.psdu, payload, payload_len);
373 
374 	mcxw_radio->tx_frame.sec_processed = net_pkt_ieee802154_frame_secured(pkt);
375 	mcxw_radio->tx_frame.hdr_updated = net_pkt_ieee802154_mac_hdr_rdy(pkt);
376 
377 	rf_set_channel(mcxw_radio->channel);
378 
379 	msg->msgType = gPdDataReq_c;
380 	msg->msgData.dataReq.slottedTx = gPhyUnslottedMode_c;
381 	msg->msgData.dataReq.psduLength = mcxw_radio->tx_frame.length;
382 	msg->msgData.dataReq.CCABeforeTx = gPhyNoCCABeforeTx_c;
383 	msg->msgData.dataReq.startTime = gPhySeqStartAsap_c;
384 
385 	/* tx_frame.psdu will point to tx_frame.tx_data data buffer after macToPdDataMessage_t
386 	 * structure
387 	 */
388 	msg->msgData.dataReq.pPsdu = mcxw_radio->tx_frame.psdu;
389 
390 	if (ieee802154_is_ar_flag_set(frag)) {
391 		msg->msgData.dataReq.ackRequired = gPhyRxAckRqd_c;
392 		/* The 3 bytes are 1 byte frame length and 2 bytes FCS */
393 		msg->msgData.dataReq.txDuration =
394 			IEEE802154_CCA_LEN_SYM + IEEE802154_PHY_SHR_LEN_SYM +
395 			(3 + mcxw_radio->tx_frame.length) * RADIO_SYMBOLS_PER_OCTET +
396 			IEEE802154_TURNAROUND_LEN_SYM;
397 
398 		if (is_frame_version_2015(frag->data, frag->len)) {
399 			/* Because enhanced ack can be of variable length we need to set the timeout
400 			 * value to account for the FCF and addressing fields only, and stop the
401 			 * timeout timer after they are received and validated as a valid ACK
402 			 */
403 			msg->msgData.dataReq.txDuration += IEEE802154_ENH_ACK_WAIT_SYM;
404 		} else {
405 			msg->msgData.dataReq.txDuration += IEEE802154_IMM_ACK_WAIT_SYM;
406 		}
407 	} else {
408 		msg->msgData.dataReq.ackRequired = gPhyNoAckRqd_c;
409 		msg->msgData.dataReq.txDuration = 0xFFFFFFFFU;
410 	}
411 
412 	switch (mode) {
413 	case IEEE802154_TX_MODE_DIRECT:
414 		msg->msgData.dataReq.CCABeforeTx = gPhyNoCCABeforeTx_c;
415 		break;
416 	case IEEE802154_TX_MODE_CCA:
417 		msg->msgData.dataReq.CCABeforeTx = gPhyCCAMode1_c;
418 		break;
419 
420 #if defined(CONFIG_NET_PKT_TXTIME)
421 	case IEEE802154_TX_MODE_TXTIME:
422 	case IEEE802154_TX_MODE_TXTIME_CCA:
423 		mcxw_radio->tx_frame.tx_delay = net_pkt_timestamp_ns(pkt);
424 		msg->msgData.dataReq.startTime =
425 			rf_adjust_tstamp_from_app(mcxw_radio->tx_frame.tx_delay);
426 		msg->msgData.dataReq.startTime /= IEEE802154_SYMBOL_TIME_US;
427 		break;
428 #endif
429 	default:
430 		break;
431 	}
432 
433 	msg->msgData.dataReq.flags = 0;
434 
435 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
436 	if (is_keyid_mode_1(mcxw_radio->tx_frame.psdu, mcxw_radio->tx_frame.length)) {
437 		if (!net_pkt_ieee802154_frame_secured(pkt)) {
438 			msg->msgData.dataReq.flags |= gPhyEncFrame;
439 
440 			if (!net_pkt_ieee802154_mac_hdr_rdy(pkt)) {
441 				msg->msgData.dataReq.flags |= gPhyUpdHDr;
442 
443 #if CONFIG_IEEE802154_CSL_ENDPOINT
444 				/* Previously aFrame->mInfo.mTxInfo.mCslPresent was used to
445 				 * determine if the radio code should update the IE header. This
446 				 * field is no longer set by the OT stack. Until the issue is fixed
447 				 * in OT stack check if CSL period is > 0 and always update CSL IE
448 				 * in that case.
449 				 */
450 				if (mcxw_radio->csl_period) {
451 					uint32_t hdr_time_us;
452 
453 					start_csl_receiver();
454 
455 					/* Add TX_ENCRYPT_DELAY_SYM symbols delay to allow
456 					 * encryption to finish
457 					 */
458 					msg->msgData.dataReq.startTime =
459 						PhyTime_ReadClock() + TX_ENCRYPT_DELAY_SYM;
460 
461 					hdr_time_us = mcxw_get_time(NULL) +
462 						    (TX_ENCRYPT_DELAY_SYM +
463 						     IEEE802154_PHY_SHR_LEN_SYM) *
464 							    IEEE802154_SYMBOL_TIME_US;
465 					set_csl_ie(mcxw_radio->tx_frame.psdu,
466 						 mcxw_radio->tx_frame.length,
467 						 mcxw_radio->csl_period,
468 						 rf_compute_csl_phase(hdr_time_us));
469 				}
470 #endif /* CONFIG_IEEE802154_CSL_ENDPOINT */
471 			}
472 		}
473 	}
474 
475 #endif
476 
477 	k_sem_reset(&mcxw_radio->tx_wait);
478 
479 	phy_status = MAC_PD_SapHandler(msg, ot_phy_ctx);
480 	if (phy_status == gPhySuccess_c) {
481 		mcxw_radio->tx_status = 0;
482 		mcxw_radio->state = RADIO_STATE_TRANSMIT;
483 	} else {
484 		return -EIO;
485 	}
486 
487 	k_sem_take(&mcxw_radio->tx_wait, K_FOREVER);
488 
489 	/* PWR_AllowDeviceToSleep(); */
490 
491 	mcxw_radio_receive();
492 
493 	switch (mcxw_radio->tx_status) {
494 	case 0:
495 		if (mcxw_radio->rx_ack_frame.length) {
496 			return handle_ack(mcxw_radio);
497 		}
498 		return 0;
499 
500 	default:
501 		return -(mcxw_radio->tx_status);
502 	}
503 }
504 
mcxw_rx_thread(void * arg1,void * arg2,void * arg3)505 void mcxw_rx_thread(void *arg1, void *arg2, void *arg3)
506 {
507 	struct mcxw_context *mcxw_radio = (struct mcxw_context *)arg1;
508 	struct net_pkt *pkt;
509 	struct mcxw_rx_frame rx_frame;
510 
511 	ARG_UNUSED(arg2);
512 	ARG_UNUSED(arg3);
513 
514 	while (true) {
515 		pkt = NULL;
516 
517 		LOG_DBG("Waiting for frame");
518 
519 		if (k_msgq_get(&mcxw_radio->rx_msgq, &rx_frame, K_FOREVER) < 0) {
520 			LOG_ERR("Failed to get RX data from message queue");
521 			continue;
522 		}
523 
524 		pkt = net_pkt_rx_alloc_with_buffer(mcxw_radio->iface, rx_frame.length, AF_UNSPEC, 0,
525 						   K_FOREVER);
526 
527 		if (net_pkt_write(pkt, rx_frame.psdu, rx_frame.length)) {
528 			goto drop;
529 		}
530 
531 		net_pkt_set_ieee802154_lqi(pkt, rx_frame.lqi);
532 		net_pkt_set_ieee802154_rssi_dbm(pkt, rx_frame.rssi);
533 		net_pkt_set_ieee802154_ack_fpb(pkt, rx_frame.ack_fpb);
534 
535 #if defined(CONFIG_NET_PKT_TIMESTAMP)
536 		net_pkt_set_timestamp_ns(pkt, rx_frame.timestamp);
537 #endif
538 
539 #if defined(CONFIG_NET_L2_OPENTHREAD)
540 		net_pkt_set_ieee802154_ack_seb(pkt, rx_frame.ack_seb);
541 #endif
542 		if (net_recv_data(mcxw_radio->iface, pkt) < 0) {
543 			LOG_ERR("Packet dropped by NET stack");
544 			goto drop;
545 		}
546 
547 		k_free(rx_frame.phy_buffer);
548 		rx_frame.phy_buffer = NULL;
549 
550 		/* restart rx on idle if enough space in message queue */
551 		if (k_msgq_num_free_get(&mcxw_radio->rx_msgq) >= 2) {
552 			rf_rx_on_idle(RX_ON_IDLE_START);
553 		}
554 
555 		continue;
556 
557 drop:
558 		/* PWR_AllowDeviceToSleep(); */
559 		net_pkt_unref(pkt);
560 	}
561 }
562 
mcxw_get_rssi(void)563 int8_t mcxw_get_rssi(void)
564 {
565 	macToPlmeMessage_t msg;
566 
567 	msg.msgType = gPlmeGetReq_c;
568 	msg.msgData.getReq.PibAttribute = gPhyGetRSSILevel_c;
569 	msg.msgData.getReq.PibAttributeValue = 127; /* RSSI is invalid*/
570 
571 	(void)MAC_PLME_SapHandler(&msg, ot_phy_ctx);
572 
573 	return (int8_t)msg.msgData.getReq.PibAttributeValue;
574 }
575 
mcxw_set_promiscuous(bool aEnable)576 void mcxw_set_promiscuous(bool aEnable)
577 {
578 	macToPlmeMessage_t msg;
579 
580 	msg.msgType = gPlmeSetReq_c;
581 	msg.msgData.setReq.PibAttribute = gPhyPibPromiscuousMode_c;
582 	msg.msgData.setReq.PibAttributeValue = (uint64_t)aEnable;
583 
584 	(void)MAC_PLME_SapHandler(&msg, ot_phy_ctx);
585 }
586 
mcxw_set_pan_coord(bool aEnable)587 void mcxw_set_pan_coord(bool aEnable)
588 {
589 	macToPlmeMessage_t msg;
590 
591 	msg.msgType = gPlmeSetReq_c;
592 	msg.msgData.setReq.PibAttribute = gPhyPibPanCoordinator_c;
593 	msg.msgData.setReq.PibAttributeValue = (uint64_t)aEnable;
594 
595 	(void)MAC_PLME_SapHandler(&msg, ot_phy_ctx);
596 }
597 
mcxw_energy_scan(const struct device * dev,uint16_t duration,energy_scan_done_cb_t done_cb)598 static int mcxw_energy_scan(const struct device *dev, uint16_t duration,
599 			    energy_scan_done_cb_t done_cb)
600 {
601 
602 	int status = 0;
603 	phyStatus_t phy_status;
604 	macToPlmeMessage_t msg;
605 
606 	app_disallow_device_to_slepp();
607 
608 	struct mcxw_context *mcxw_radio = dev->data;
609 
610 	__ASSERT_NO_MSG(((mcxw_radio->state != RADIO_STATE_TRANSMIT) &&
611 			 (mcxw_radio->state != RADIO_STATE_DISABLED)));
612 
613 	rf_abort();
614 
615 	rf_set_channel(mcxw_radio->channel);
616 
617 	mcxw_radio->energy_scan_done = done_cb;
618 
619 	msg.msgType = gPlmeEdReq_c;
620 	msg.msgData.edReq.startTime = gPhySeqStartAsap_c;
621 	msg.msgData.edReq.measureDurationSym = duration * 1000;
622 
623 	phy_status = MAC_PLME_SapHandler(&msg, ot_phy_ctx);
624 	if (phy_status != gPhySuccess_c) {
625 		mcxw_radio->energy_scan_done = NULL;
626 		status = -EIO;
627 	}
628 
629 	return status;
630 }
631 
mcxw_set_txpower(const struct device * dev,int16_t dbm)632 static int mcxw_set_txpower(const struct device *dev, int16_t dbm)
633 {
634 	struct mcxw_context *mcxw_radio = dev->data;
635 
636 	LOG_DBG("%d", dbm);
637 
638 	if (dbm != mcxw_radio->tx_pwr_lvl) {
639 		/* Set Power level for TX */
640 		rf_set_tx_power(dbm);
641 		mcxw_radio->tx_pwr_lvl = dbm;
642 	}
643 
644 	return 0;
645 }
646 
mcxw_configure_enh_ack_probing(const struct ieee802154_config * config)647 static void mcxw_configure_enh_ack_probing(const struct ieee802154_config *config)
648 {
649 	uint32_t ie_param = 0;
650 	macToPlmeMessage_t msg;
651 
652 	uint8_t *header_ie_buf = (uint8_t *)(config->ack_ie.header_ie);
653 
654 	ie_param = (header_ie_buf[6] == 0x03 ? IeData_Lqi_c : 0) |
655 		   (header_ie_buf[7] == 0x02 ? IeData_LinkMargin_c : 0) |
656 		   (header_ie_buf[8] == 0x01 ? IeData_Rssi_c : 0);
657 
658 	msg.msgType = gPlmeConfigureAckIeData_c;
659 	msg.msgData.AckIeData.param = (ie_param > 0 ? IeData_MSB_VALID_DATA : 0);
660 	msg.msgData.AckIeData.param |= ie_param;
661 	msg.msgData.AckIeData.shortAddr = config->ack_ie.short_addr;
662 	memcpy(msg.msgData.AckIeData.extAddr, config->ack_ie.ext_addr, 8);
663 	memcpy(msg.msgData.AckIeData.data, config->ack_ie.header_ie,
664 	       config->ack_ie.header_ie->length);
665 
666 	(void)MAC_PLME_SapHandler(&msg, ot_phy_ctx);
667 }
668 
mcxw_set_mac_key(struct ieee802154_key * mac_keys)669 static void mcxw_set_mac_key(struct ieee802154_key *mac_keys)
670 {
671 	macToPlmeMessage_t msg;
672 
673 	__ASSERT_NO_MSG(mac_keys);
674 	__ASSERT_NO_MSG(mac_keys[0].key_id && mac_keys[0].key_value);
675 	__ASSERT_NO_MSG(mac_keys[1].key_id && mac_keys[1].key_value);
676 	__ASSERT_NO_MSG(mac_keys[2].key_id && mac_keys[2].key_value);
677 
678 	msg.msgType = gPlmeSetMacKey_c;
679 	msg.msgData.MacKeyData.keyId = *(mac_keys[1].key_id);
680 
681 	memcpy(msg.msgData.MacKeyData.prevKey, mac_keys[0].key_value, 16);
682 	memcpy(msg.msgData.MacKeyData.currKey, mac_keys[1].key_value, 16);
683 	memcpy(msg.msgData.MacKeyData.nextKey, mac_keys[2].key_value, 16);
684 
685 	(void)MAC_PLME_SapHandler(&msg, ot_phy_ctx);
686 }
687 
mcxw_set_mac_frame_counter(uint32_t frame_counter)688 void mcxw_set_mac_frame_counter(uint32_t frame_counter)
689 {
690 	macToPlmeMessage_t msg;
691 
692 	msg.msgType = gPlmeSetMacFrameCounter_c;
693 	msg.msgData.MacFrameCounter = frame_counter;
694 
695 	(void)MAC_PLME_SapHandler(&msg, ot_phy_ctx);
696 }
697 
mcxw_set_mac_frame_counter_if_larger(uint32_t frame_counter)698 void mcxw_set_mac_frame_counter_if_larger(uint32_t frame_counter)
699 {
700 	macToPlmeMessage_t msg;
701 
702 	msg.msgType = gPlmeSetMacFrameCounterIfLarger_c;
703 	msg.msgData.MacFrameCounter = frame_counter;
704 
705 	(void)MAC_PLME_SapHandler(&msg, ot_phy_ctx);
706 }
707 
708 #if CONFIG_IEEE802154_CSL_ENDPOINT
709 
mcxw_receive_at(uint8_t channel,uint32_t start,uint32_t duration)710 static void mcxw_receive_at(uint8_t channel, uint32_t start, uint32_t duration)
711 {
712 	macToPlmeMessage_t msg;
713 
714 	__ASSERT_NO_MSG(mcxw_ctx.state == RADIO_STATE_SLEEP);
715 	mcxw_ctx.state = RADIO_STATE_RECEIVE;
716 
717 	/* checks internally if the channel needs to be changed */
718 	rf_set_channel(mcxw_ctx.channel);
719 
720 	start = rf_adjust_tstamp_from_app(start);
721 
722 	msg.msgType = gPlmeSetTRxStateReq_c;
723 	msg.msgData.setTRxStateReq.slottedMode = gPhyUnslottedMode_c;
724 	msg.msgData.setTRxStateReq.state = gPhySetRxOn_c;
725 	msg.msgData.setTRxStateReq.rxDuration = duration / IEEE802154_SYMBOL_TIME_US;
726 	msg.msgData.setTRxStateReq.startTime = start / IEEE802154_SYMBOL_TIME_US;
727 
728 	(void)MAC_PLME_SapHandler(&msg, ot_phy_ctx);
729 }
730 
mcxw_enable_csl(uint16_t period)731 static void mcxw_enable_csl(uint16_t period)
732 {
733 	mcxw_ctx.csl_period = period;
734 
735 	macToPlmeMessage_t msg;
736 
737 	msg.msgType = gPlmeCslEnable_c;
738 	msg.msgData.cslPeriod = period;
739 
740 	(void)MAC_PLME_SapHandler(&msg, ot_phy_ctx);
741 }
742 
set_csl_sample_time(void)743 static void set_csl_sample_time(void)
744 {
745 	if (!mcxw_ctx.csl_period) {
746 		return;
747 	}
748 
749 	macToPlmeMessage_t msg;
750 	uint32_t csl_period = mcxw_ctx.csl_period * 10 * IEEE802154_SYMBOL_TIME_US;
751 	uint32_t dt = mcxw_ctx.csl_sample_time - (uint32_t)mcxw_get_time(NULL);
752 
753 	/* next channel sample should be in the future */
754 	while ((dt <= CMP_OVHD) || (dt > (CMP_OVHD + 2 * csl_period))) {
755 		mcxw_ctx.csl_sample_time += csl_period;
756 		dt = mcxw_ctx.csl_sample_time - (uint32_t)mcxw_get_time(NULL);
757 	}
758 
759 	/* The CSL sample time is in microseconds and PHY function expects also microseconds */
760 	msg.msgType = gPlmeCslSetSampleTime_c;
761 	msg.msgData.cslSampleTime = rf_adjust_tstamp_from_app(mcxw_ctx.csl_sample_time);
762 
763 	(void)MAC_PLME_SapHandler(&msg, ot_phy_ctx);
764 }
765 
start_csl_receiver(void)766 static void start_csl_receiver(void)
767 {
768 	if (!mcxw_ctx.csl_period) {
769 		return;
770 	}
771 
772 	/* NBU has to be awake during CSL receiver trx  so that conversion from
773 	 * PHY timebase (NBU) to TMR timebase (host) is valid
774 	 */
775 	if (!csl_rx) {
776 		PLATFORM_RemoteActiveReq();
777 
778 		csl_rx = TRUE;
779 	}
780 
781 	/* sample time is converted to PHY time */
782 	set_csl_sample_time();
783 }
784 
stop_csl_receiver(void)785 static void stop_csl_receiver(void)
786 {
787 	if (csl_rx) {
788 		PLATFORM_RemoteActiveRel();
789 
790 		csl_rx = FALSE;
791 	}
792 }
793 
794 /*
795  * Compute the CSL Phase for the time_us - i.e. the time from the time_us to
796  * mcxw_ctx.csl_sample_time. The assumption is that mcxw_ctx.csl_sample_time > time_us. Since the
797  * time is kept with a limited timer in reality it means that sometimes mcxw_ctx.csl_sample_time <
798  * time_us, when the timer overflows. Therefore the formula should be:
799  *
800  * if (time_us <= mcxw_ctx.csl_sample_time)
801  *         csl_phase_us = mcxw_ctx.csl_sample_time - time_us;
802  * else
803  *         csl_phase_us = MAX_TIMER_VALUE - time_us + mcxw_ctx.csl_sample_time;
804  *
805  * For simplicity the formula below has been used.
806  */
rf_compute_csl_phase(uint32_t time_us)807 static uint16_t rf_compute_csl_phase(uint32_t time_us)
808 {
809 	/* convert CSL Period in microseconds - it was given in 10 symbols */
810 	uint32_t csl_period_us = mcxw_ctx.csl_period * 10 * IEEE802154_SYMBOL_TIME_US;
811 	uint32_t csl_phase_us =
812 		(csl_period_us - (time_us % csl_period_us) +
813 		(mcxw_ctx.csl_sample_time % csl_period_us)) % csl_period_us;
814 
815 	return (uint16_t)(csl_phase_us / (10 * IEEE802154_SYMBOL_TIME_US) + 1);
816 }
817 #endif /* CONFIG_IEEE802154_CSL_ENDPOINT */
818 
819 /*************************************************************************************************/
rf_abort(void)820 static void rf_abort(void)
821 {
822 	macToPlmeMessage_t msg;
823 
824 	sun_rx_mode = RX_ON_IDLE_START;
825 	msg.msgType = gPlmeSetReq_c;
826 	msg.msgData.setReq.PibAttribute = gPhyPibRxOnWhenIdle;
827 	msg.msgData.setReq.PibAttributeValue = (uint64_t)0;
828 
829 	(void)MAC_PLME_SapHandler(&msg, ot_phy_ctx);
830 
831 	msg.msgType = gPlmeSetTRxStateReq_c;
832 	msg.msgData.setTRxStateReq.state = gPhyForceTRxOff_c;
833 
834 	(void)MAC_PLME_SapHandler(&msg, ot_phy_ctx);
835 }
836 
rf_set_channel(uint8_t channel)837 static void rf_set_channel(uint8_t channel)
838 {
839 	macToPlmeMessage_t msg;
840 
841 	msg.msgType = gPlmeSetReq_c;
842 	msg.msgData.setReq.PibAttribute = gPhyPibCurrentChannel_c;
843 	msg.msgData.setReq.PibAttributeValue = (uint64_t)channel;
844 
845 	(void)MAC_PLME_SapHandler(&msg, ot_phy_ctx);
846 }
847 
mcxw_cca(const struct device * dev)848 static int mcxw_cca(const struct device *dev)
849 {
850 	macToPlmeMessage_t msg;
851 	phyStatus_t phy_status;
852 
853 	struct mcxw_context *mcxw_radio = dev->data;
854 
855 	msg.msgType = gPlmeCcaReq_c;
856 	msg.msgData.ccaReq.ccaType = gPhyCCAMode1_c;
857 	msg.msgData.ccaReq.contCcaMode = gPhyContCcaDisabled;
858 
859 	phy_status = MAC_PLME_SapHandler(&msg, ot_phy_ctx);
860 
861 	__ASSERT_NO_MSG(phy_status == gPhySuccess_c);
862 
863 	k_sem_take(&mcxw_radio->cca_wait, K_FOREVER);
864 
865 	return (mcxw_radio->tx_status == OT_ERROR_CHANNEL_ACCESS_FAILURE) ? -EBUSY : 0;
866 }
867 
mcxw_set_channel(const struct device * dev,uint16_t channel)868 static int mcxw_set_channel(const struct device *dev, uint16_t channel)
869 {
870 	struct mcxw_context *mcxw_radio = dev->data;
871 
872 	LOG_DBG("%u", channel);
873 
874 	if (channel != mcxw_radio->channel) {
875 
876 		if (channel < 11 || channel > 26) {
877 			return channel < 11 ? -ENOTSUP : -EINVAL;
878 		}
879 
880 		mcxw_radio->channel = channel;
881 	}
882 
883 	return 0;
884 }
885 
mcxw_get_time(const struct device * dev)886 static net_time_t mcxw_get_time(const struct device *dev)
887 {
888 	static uint64_t sw_timestamp;
889 	static uint64_t hw_timestamp;
890 
891 	ARG_UNUSED(dev);
892 
893 	/* Get new 32bit HW timestamp */
894 	uint32_t ticks;
895 	uint64_t hw_timestamp_new;
896 	uint64_t wrapped_val = 0;
897 	uint64_t increment;
898 	unsigned int key;
899 
900 	key = irq_lock();
901 
902 	if (counter_get_value(mcxw_ctx.counter, &ticks)) {
903 		irq_unlock(key);
904 		return -1;
905 	}
906 
907 	hw_timestamp_new = counter_ticks_to_us(mcxw_ctx.counter, ticks);
908 
909 	/* Check if the timestamp has wrapped around */
910 	if (hw_timestamp > hw_timestamp_new) {
911 		wrapped_val =
912 			COUNT_TO_USEC(((uint64_t)1 << 32), counter_get_frequency(mcxw_ctx.counter));
913 	}
914 
915 	increment = (hw_timestamp_new + wrapped_val) - hw_timestamp;
916 	sw_timestamp += increment;
917 
918 	/* Store new HW timestamp for next iteration */
919 	hw_timestamp = hw_timestamp_new;
920 
921 	irq_unlock(key);
922 
923 	return (net_time_t)sw_timestamp;
924 }
925 
rf_set_tx_power(int8_t tx_power)926 static void rf_set_tx_power(int8_t tx_power)
927 {
928 	macToPlmeMessage_t msg;
929 
930 	msg.msgType = gPlmeSetReq_c;
931 	msg.msgData.setReq.PibAttribute = gPhyPibTransmitPower_c;
932 	msg.msgData.setReq.PibAttributeValue = (uint64_t)tx_power;
933 
934 	MAC_PLME_SapHandler(&msg, ot_phy_ctx);
935 }
936 
937 /* Used to convert from phy clock timestamp (in symbols) to platform time (in us)
938  * the reception timestamp which must use a true 64bit timestamp source
939  */
rf_adjust_tstamp_from_phy(uint64_t ts)940 static uint64_t rf_adjust_tstamp_from_phy(uint64_t ts)
941 {
942 	uint64_t now = PhyTime_ReadClock();
943 	uint64_t delta;
944 
945 	delta = (now >= ts) ? (now - ts) : ((PHY_TMR_MAX_VALUE + now) - ts);
946 	delta *= IEEE802154_SYMBOL_TIME_US;
947 
948 	return mcxw_get_time(NULL) - delta;
949 }
950 
951 #if CONFIG_IEEE802154_CSL_ENDPOINT || CONFIG_NET_PKT_TXTIME
rf_adjust_tstamp_from_app(uint32_t time)952 static uint32_t rf_adjust_tstamp_from_app(uint32_t time)
953 {
954 	/* The phy timestamp is in symbols so we need to convert it to microseconds */
955 	uint64_t ts = PhyTime_ReadClock() * IEEE802154_SYMBOL_TIME_US;
956 	uint32_t delta = time - (uint32_t)mcxw_get_time(NULL);
957 
958 	return (uint32_t)(ts + delta);
959 }
960 #endif /* CONFIG_IEEE802154_CSL_ENDPOINT || CONFIG_NET_PKT_TXTIME */
961 
962 /* Phy Data Service Access Point handler
963  * Called by Phy to notify when Tx has been done or Rx data is available
964  */
pd_mac_sap_handler(void * msg,instanceId_t instance)965 phyStatus_t pd_mac_sap_handler(void *msg, instanceId_t instance)
966 {
967 	pdDataToMacMessage_t *data_msg = (pdDataToMacMessage_t *)msg;
968 
969 	__ASSERT_NO_MSG(msg != NULL);
970 
971 	/* PWR_DisallowDeviceToSleep(); */
972 
973 	switch (data_msg->msgType) {
974 	case gPdDataCnf_c:
975 		/* TX is done */
976 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
977 		if (is_keyid_mode_1(mcxw_ctx.tx_frame.psdu, mcxw_ctx.tx_frame.length) &&
978 		    !mcxw_ctx.tx_frame.sec_processed && !mcxw_ctx.tx_frame.hdr_updated) {
979 			set_frame_counter(mcxw_ctx.tx_frame.psdu, mcxw_ctx.tx_frame.length,
980 					data_msg->fc);
981 			mcxw_ctx.tx_frame.hdr_updated = true;
982 		}
983 #endif
984 
985 		mcxw_ctx.tx_frame.length = 0;
986 		mcxw_ctx.tx_status = 0;
987 		mcxw_ctx.state = RADIO_STATE_RECEIVE;
988 
989 		mcxw_ctx.rx_ack_frame.channel = mcxw_ctx.channel;
990 		mcxw_ctx.rx_ack_frame.length = data_msg->msgData.dataCnf.ackLength;
991 		mcxw_ctx.rx_ack_frame.timestamp = data_msg->msgData.dataCnf.timeStamp;
992 		memcpy(mcxw_ctx.rx_ack_frame.psdu, data_msg->msgData.dataCnf.ackData,
993 		       mcxw_ctx.rx_ack_frame.length);
994 
995 		k_sem_give(&mcxw_ctx.tx_wait);
996 
997 		k_free(msg);
998 		break;
999 
1000 	case gPdDataInd_c:
1001 		/* RX is done */
1002 		struct mcxw_rx_frame rx_frame;
1003 
1004 		/* retrieve frame information and data */
1005 		rx_frame.lqi = data_msg->msgData.dataInd.ppduLinkQuality;
1006 		rx_frame.rssi = data_msg->msgData.dataInd.ppduRssi;
1007 		rx_frame.timestamp = rf_adjust_tstamp_from_phy(data_msg->msgData.dataInd.timeStamp);
1008 		rx_frame.ack_fpb = data_msg->msgData.dataInd.rxAckFp;
1009 		rx_frame.length = data_msg->msgData.dataInd.psduLength;
1010 		rx_frame.psdu = data_msg->msgData.dataInd.pPsdu;
1011 		rx_frame.ack_seb = data_msg->msgData.dataInd.ackedWithSecEnhAck;
1012 
1013 		rx_frame.phy_buffer = (void *)msg;
1014 
1015 		/* stop rx on idle if message queue is almost full */
1016 		if (k_msgq_num_free_get(&mcxw_ctx.rx_msgq) == 1) {
1017 			rf_rx_on_idle(RX_ON_IDLE_STOP);
1018 		}
1019 
1020 		/* add the rx message in queue */
1021 		if (k_msgq_put(&mcxw_ctx.rx_msgq, &rx_frame, K_NO_WAIT) < 0) {
1022 			LOG_ERR("Failed to push RX data to message queue");
1023 		}
1024 		break;
1025 
1026 	default:
1027 		/* PWR_AllowDeviceToSleep(); */
1028 		break;
1029 	}
1030 
1031 	stop_csl_receiver();
1032 
1033 	return gPhySuccess_c;
1034 }
1035 
1036 /* Phy Layer Management Entities Service Access Point handler
1037  * Called by Phy to notify PLME event
1038  */
plme_mac_sap_handler(void * msg,instanceId_t instance)1039 phyStatus_t plme_mac_sap_handler(void *msg, instanceId_t instance)
1040 {
1041 	plmeToMacMessage_t *plme_msg = (plmeToMacMessage_t *)msg;
1042 
1043 	__ASSERT_NO_MSG(msg != NULL);
1044 
1045 	/* PWR_DisallowDeviceToSleep(); */
1046 
1047 	switch (plme_msg->msgType) {
1048 	case gPlmeCcaCnf_c:
1049 		if (plme_msg->msgData.ccaCnf.status == gPhyChannelBusy_c) {
1050 			/* Channel is busy */
1051 			mcxw_ctx.tx_status = EBUSY;
1052 		} else {
1053 			mcxw_ctx.tx_status = 0;
1054 		}
1055 		mcxw_ctx.state = RADIO_STATE_RECEIVE;
1056 
1057 		k_sem_give(&mcxw_ctx.cca_wait);
1058 		break;
1059 	case gPlmeEdCnf_c:
1060 		/* Scan done */
1061 		if (mcxw_ctx.energy_scan_done != NULL) {
1062 			energy_scan_done_cb_t callback = mcxw_ctx.energy_scan_done;
1063 
1064 			mcxw_ctx.max_ed = plme_msg->msgData.edCnf.maxEnergyLeveldB;
1065 
1066 			mcxw_ctx.energy_scan_done = NULL;
1067 			callback(net_if_get_device(mcxw_ctx.iface), mcxw_ctx.max_ed);
1068 		}
1069 		break;
1070 	case gPlmeTimeoutInd_c:
1071 		if (RADIO_STATE_TRANSMIT == mcxw_ctx.state) {
1072 			/* Ack timeout */
1073 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
1074 			if (is_keyid_mode_1(mcxw_ctx.tx_frame.psdu, mcxw_ctx.tx_frame.length) &&
1075 			    !mcxw_ctx.tx_frame.sec_processed && !mcxw_ctx.tx_frame.hdr_updated) {
1076 				set_frame_counter(mcxw_ctx.tx_frame.psdu, mcxw_ctx.tx_frame.length,
1077 						plme_msg->fc);
1078 				mcxw_ctx.tx_frame.hdr_updated = true;
1079 			}
1080 #endif
1081 
1082 			mcxw_ctx.state = RADIO_STATE_RECEIVE;
1083 			/* No ack */
1084 			mcxw_ctx.tx_status = ENOMSG;
1085 
1086 			k_sem_give(&mcxw_ctx.tx_wait);
1087 		} else if (RADIO_STATE_RECEIVE == mcxw_ctx.state) {
1088 			/* CSL Receive AT state has ended with timeout and we are returning to SLEEP
1089 			 * state
1090 			 */
1091 			mcxw_ctx.state = RADIO_STATE_SLEEP;
1092 			/* PWR_AllowDeviceToSleep(); */
1093 		}
1094 		break;
1095 	case gPlmeAbortInd_c:
1096 		/* TX Packet was loaded into TX Packet RAM but the TX/TR seq did not ended ok */
1097 #if OPENTHREAD_CONFIG_THREAD_VERSION >= OT_THREAD_VERSION_1_2
1098 		if (is_keyid_mode_1(mcxw_ctx.tx_frame.psdu, mcxw_ctx.tx_frame.length) &&
1099 		    !mcxw_ctx.tx_frame.sec_processed && !mcxw_ctx.tx_frame.hdr_updated) {
1100 			set_frame_counter(mcxw_ctx.tx_frame.psdu, mcxw_ctx.tx_frame.length,
1101 					plme_msg->fc);
1102 			mcxw_ctx.tx_frame.hdr_updated = true;
1103 		}
1104 #endif
1105 
1106 		mcxw_ctx.state = RADIO_STATE_RECEIVE;
1107 		mcxw_ctx.tx_status = EIO;
1108 
1109 		k_sem_give(&mcxw_ctx.tx_wait);
1110 		break;
1111 	default:
1112 		/* PWR_AllowDeviceToSleep(); */
1113 		break;
1114 	}
1115 	/* The message has been allocated by the Phy, we have to free it */
1116 	k_free(msg);
1117 
1118 	stop_csl_receiver();
1119 
1120 	return gPhySuccess_c;
1121 }
1122 
mcxw_configure(const struct device * dev,enum ieee802154_config_type type,const struct ieee802154_config * config)1123 static int mcxw_configure(const struct device *dev, enum ieee802154_config_type type,
1124 			  const struct ieee802154_config *config)
1125 {
1126 	ARG_UNUSED(dev);
1127 
1128 	switch (type) {
1129 
1130 	case IEEE802154_CONFIG_AUTO_ACK_FPB:
1131 		if (config->auto_ack_fpb.mode == IEEE802154_FPB_ADDR_MATCH_THREAD) {
1132 			mcxw_enable_src_match(config->auto_ack_fpb.enabled);
1133 		}
1134 		/* TODO IEEE802154_FPB_ADDR_MATCH_ZIGBEE */
1135 		break;
1136 
1137 	case IEEE802154_CONFIG_ACK_FPB:
1138 		if (config->ack_fpb.enabled) {
1139 			return mcxw_src_match_entry(config->ack_fpb.extended, config->ack_fpb.addr);
1140 		} else {
1141 			return mcxw_src_clear_entry(config->ack_fpb.extended, config->ack_fpb.addr);
1142 		}
1143 
1144 		/* TODO otPlatRadioClearSrcMatchShortEntries */
1145 		/* TODO otPlatRadioClearSrcMatchExtEntries */
1146 		break;
1147 
1148 	case IEEE802154_CONFIG_PAN_COORDINATOR:
1149 		mcxw_set_pan_coord(config->pan_coordinator);
1150 		break;
1151 
1152 	case IEEE802154_CONFIG_PROMISCUOUS:
1153 		mcxw_set_promiscuous(config->promiscuous);
1154 		break;
1155 
1156 	case IEEE802154_CONFIG_MAC_KEYS:
1157 		mcxw_set_mac_key(config->mac_keys);
1158 		break;
1159 
1160 	case IEEE802154_CONFIG_FRAME_COUNTER:
1161 		mcxw_set_mac_frame_counter(config->frame_counter);
1162 		break;
1163 
1164 	case IEEE802154_CONFIG_FRAME_COUNTER_IF_LARGER:
1165 		mcxw_set_mac_frame_counter_if_larger(config->frame_counter);
1166 		break;
1167 
1168 	case IEEE802154_CONFIG_ENH_ACK_HEADER_IE:
1169 		mcxw_configure_enh_ack_probing(config);
1170 		break;
1171 
1172 #if defined(CONFIG_IEEE802154_CSL_ENDPOINT)
1173 	case IEEE802154_CONFIG_EXPECTED_RX_TIME:
1174 		mcxw_ctx.csl_sample_time = config->expected_rx_time;
1175 		break;
1176 
1177 	case IEEE802154_CONFIG_RX_SLOT:
1178 		mcxw_receive_at(config->rx_slot.channel, config->rx_slot.start / NSEC_PER_USEC,
1179 				config->rx_slot.duration / NSEC_PER_USEC);
1180 		break;
1181 
1182 	case IEEE802154_CONFIG_CSL_PERIOD:
1183 		mcxw_enable_csl(config->csl_period);
1184 		break;
1185 #endif /* CONFIG_IEEE802154_CSL_ENDPOINT */
1186 
1187 	case IEEE802154_CONFIG_RX_ON_WHEN_IDLE:
1188 		if (config->rx_on_when_idle) {
1189 			rf_rx_on_idle(RX_ON_IDLE_START);
1190 		} else {
1191 			rf_rx_on_idle(RX_ON_IDLE_STOP);
1192 		}
1193 		break;
1194 
1195 	case IEEE802154_CONFIG_EVENT_HANDLER:
1196 		break;
1197 
1198 	case IEEE802154_OPENTHREAD_CONFIG_MAX_EXTRA_CCA_ATTEMPTS:
1199 		break;
1200 
1201 	default:
1202 		return -EINVAL;
1203 	}
1204 
1205 	return 0;
1206 }
1207 
1208 IEEE802154_DEFINE_PHY_SUPPORTED_CHANNELS(drv_attr, 11, 26);
1209 
mcxw_attr_get(const struct device * dev,enum ieee802154_attr attr,struct ieee802154_attr_value * value)1210 static int mcxw_attr_get(const struct device *dev, enum ieee802154_attr attr,
1211 			 struct ieee802154_attr_value *value)
1212 {
1213 	ARG_UNUSED(dev);
1214 
1215 	if (ieee802154_attr_get_channel_page_and_range(
1216 		    attr, IEEE802154_ATTR_PHY_CHANNEL_PAGE_ZERO_OQPSK_2450_BPSK_868_915,
1217 		    &drv_attr.phy_supported_channels, value) == 0) {
1218 		return 0;
1219 	}
1220 
1221 	return -EIO;
1222 }
1223 
mcxw_get_capabilities(const struct device * dev)1224 static enum ieee802154_hw_caps mcxw_get_capabilities(const struct device *dev)
1225 {
1226 	enum ieee802154_hw_caps caps;
1227 
1228 	caps = IEEE802154_HW_FCS | IEEE802154_HW_PROMISC | IEEE802154_HW_FILTER |
1229 	       IEEE802154_HW_TX_RX_ACK | IEEE802154_HW_RX_TX_ACK | IEEE802154_HW_ENERGY_SCAN |
1230 	       IEEE802154_HW_TXTIME | IEEE802154_HW_RXTIME | IEEE802154_HW_SLEEP_TO_TX |
1231 	       IEEE802154_RX_ON_WHEN_IDLE | IEEE802154_HW_TX_SEC |
1232 	       IEEE802154_OPENTHREAD_HW_MULTIPLE_CCA | IEEE802154_HW_SELECTIVE_TXCHANNEL |
1233 	       IEEE802154_OPENTHREAD_HW_CST;
1234 	return caps;
1235 }
1236 
mcxw_init(const struct device * dev)1237 static int mcxw_init(const struct device *dev)
1238 {
1239 	struct mcxw_context *mcxw_radio = dev->data;
1240 
1241 	macToPlmeMessage_t msg;
1242 
1243 	if (PLATFORM_InitOT() < 0) {
1244 		return -EIO;
1245 	}
1246 
1247 	Phy_Init();
1248 
1249 	ot_phy_ctx = PHY_get_ctx();
1250 
1251 	/* Register Phy Data Service Access Point and Phy Layer Management Entities Service Access
1252 	 * Point handlers
1253 	 */
1254 	Phy_RegisterSapHandlers((PD_MAC_SapHandler_t)pd_mac_sap_handler,
1255 				(PLME_MAC_SapHandler_t)plme_mac_sap_handler, ot_phy_ctx);
1256 
1257 	msg.msgType = gPlmeEnableEncryption_c;
1258 	(void)MAC_PLME_SapHandler(&msg, ot_phy_ctx);
1259 
1260 	mcxw_radio->state = RADIO_STATE_DISABLED;
1261 	mcxw_radio->energy_scan_done = NULL;
1262 
1263 	mcxw_radio->channel = DEFAULT_CHANNEL;
1264 	rf_set_channel(mcxw_radio->channel);
1265 
1266 	mcxw_radio->tx_frame.length = 0;
1267 	/* Make the psdu point to the space after macToPdDataMessage_t in the data buffer */
1268 	mcxw_radio->tx_frame.psdu = mcxw_radio->tx_data + sizeof(macToPdDataMessage_t);
1269 
1270 	/* Get and start LPTRM counter */
1271 	mcxw_radio->counter = DEVICE_DT_GET(DT_NODELABEL(lptmr0));
1272 	if (counter_start(mcxw_radio->counter)) {
1273 		return -EIO;
1274 	}
1275 
1276 	/* Init TX semaphore */
1277 	k_sem_init(&mcxw_radio->tx_wait, 0, 1);
1278 	/* Init CCA semaphore */
1279 	k_sem_init(&mcxw_radio->cca_wait, 0, 1);
1280 
1281 	/* Init RX message queue */
1282 	k_msgq_init(&mcxw_radio->rx_msgq, mcxw_radio->rx_msgq_buffer, sizeof(mcxw_rx_frame),
1283 		    NMAX_RXRING_BUFFERS);
1284 
1285 	memset(&(mcxw_radio->rx_ack_frame), 0, sizeof(mcxw_radio->rx_ack_frame));
1286 	mcxw_radio->rx_ack_frame.psdu = mcxw_radio->rx_ack_data;
1287 
1288 	k_thread_create(&mcxw_radio->rx_thread, mcxw_radio->rx_stack,
1289 			CONFIG_IEEE802154_MCXW_RX_STACK_SIZE, mcxw_rx_thread, mcxw_radio, NULL,
1290 			NULL, K_PRIO_COOP(2), 0, K_NO_WAIT);
1291 
1292 	k_thread_name_set(&mcxw_radio->rx_thread, "mcxw_rx");
1293 
1294 	return 0;
1295 }
1296 
mcxw_iface_init(struct net_if * iface)1297 static void mcxw_iface_init(struct net_if *iface)
1298 {
1299 	const struct device *dev = net_if_get_device(iface);
1300 	struct mcxw_context *mcxw_radio = dev->data;
1301 
1302 	mcxw_get_eui64(mcxw_radio->mac);
1303 
1304 	net_if_set_link_addr(iface, mcxw_radio->mac, sizeof(mcxw_radio->mac), NET_LINK_IEEE802154);
1305 	mcxw_radio->iface = iface;
1306 	ieee802154_init(iface);
1307 }
1308 
rf_rx_on_idle(uint32_t new_val)1309 static void rf_rx_on_idle(uint32_t new_val)
1310 {
1311 	macToPlmeMessage_t msg;
1312 	phyStatus_t phy_status;
1313 
1314 	new_val %= 2;
1315 	if (sun_rx_mode != new_val) {
1316 		sun_rx_mode = new_val;
1317 		msg.msgType = gPlmeSetReq_c;
1318 		msg.msgData.setReq.PibAttribute = gPhyPibRxOnWhenIdle;
1319 		msg.msgData.setReq.PibAttributeValue = (uint64_t)sun_rx_mode;
1320 
1321 		phy_status = MAC_PLME_SapHandler(&msg, ot_phy_ctx);
1322 
1323 		__ASSERT_NO_MSG(phy_status == gPhySuccess_c);
1324 	}
1325 }
1326 
1327 static const struct ieee802154_radio_api mcxw71_radio_api = {
1328 	.iface_api.init = mcxw_iface_init,
1329 
1330 	.get_capabilities = mcxw_get_capabilities,
1331 	.cca = mcxw_cca,
1332 	.set_channel = mcxw_set_channel,
1333 	.filter = mcxw_filter,
1334 	.set_txpower = mcxw_set_txpower,
1335 	.start = mcxw_start,
1336 	.stop = mcxw_stop,
1337 	.configure = mcxw_configure,
1338 	.tx = mcxw_tx,
1339 	.ed_scan = mcxw_energy_scan,
1340 	.get_time = mcxw_get_time,
1341 	.get_sch_acc = mcxw_get_acc,
1342 	.attr_get = mcxw_attr_get,
1343 };
1344 
1345 #if defined(CONFIG_NET_L2_IEEE802154)
1346 #define L2          IEEE802154_L2
1347 #define L2_CTX_TYPE NET_L2_GET_CTX_TYPE(IEEE802154_L2)
1348 #define MTU         IEEE802154_MTU
1349 #elif defined(CONFIG_NET_L2_OPENTHREAD)
1350 #define L2          OPENTHREAD_L2
1351 #define L2_CTX_TYPE NET_L2_GET_CTX_TYPE(OPENTHREAD_L2)
1352 #define MTU         1280
1353 #elif defined(CONFIG_NET_L2_CUSTOM_IEEE802154)
1354 #define L2          CUSTOM_IEEE802154_L2
1355 #define L2_CTX_TYPE NET_L2_GET_CTX_TYPE(CUSTOM_IEEE802154_L2)
1356 #define MTU         CONFIG_NET_L2_CUSTOM_IEEE802154_MTU
1357 #endif
1358 
1359 NET_DEVICE_DT_INST_DEFINE(0, mcxw_init, NULL, &mcxw_ctx, NULL, CONFIG_IEEE802154_MCXW_INIT_PRIO,
1360 			  &mcxw71_radio_api, L2, L2_CTX_TYPE, MTU);
1361