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