1 /*
2  * Copyright (c) 2024 DENX Software Engineering GmbH
3  *               Lukasz Majewski <lukma@denx.de>
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * IEEE 802.15.4 HDLC RCP interface - serial communication interface (UART)
10  */
11 
12 /* -------------------------------------------------------------------------- */
13 /*                                  Includes                                  */
14 /* -------------------------------------------------------------------------- */
15 #include <zephyr/drivers/uart.h>
16 #include <openthread/platform/radio.h>
17 #include <stdbool.h>
18 #include <stddef.h>
19 #include <zephyr/init.h>
20 #include <zephyr/logging/log.h>
21 #include <zephyr/net/hdlc_rcp_if/hdlc_rcp_if.h>
22 #include <zephyr/net/ieee802154_radio.h>
23 #include <zephyr/net/openthread.h>
24 #include <zephyr/sys/ring_buffer.h>
25 
26 /* -------------------------------------------------------------------------- */
27 /*                                  Definitions                               */
28 /* -------------------------------------------------------------------------- */
29 
30 #define DT_DRV_COMPAT uart_hdlc_rcp_if
31 
32 #define LOG_MODULE_NAME hdlc_rcp_if_uart
33 #define LOG_LEVEL       CONFIG_HDLC_RCP_IF_DRIVER_LOG_LEVEL
34 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
35 
36 struct openthread_uart {
37 	struct k_work work;
38 	struct ring_buf *rx_ringbuf;
39 	struct ring_buf *tx_ringbuf;
40 	const struct device *dev;
41 	atomic_t tx_busy;
42 
43 	hdlc_rx_callback_t cb;
44 	void *param;
45 };
46 
47 #define OT_UART_DEFINE(_name, _ringbuf_rx_size, _ringbuf_tx_size)  \
48 	RING_BUF_DECLARE(_name##_rx_ringbuf, _ringbuf_rx_size); \
49 	RING_BUF_DECLARE(_name##_tx_ringbuf, _ringbuf_tx_size); \
50 	static struct openthread_uart _name = { \
51 		.rx_ringbuf = &_name##_rx_ringbuf, \
52 		.tx_ringbuf = &_name##_tx_ringbuf, \
53 	}
54 OT_UART_DEFINE(ot_uart, CONFIG_OPENTHREAD_HDLC_RCP_IF_UART_RX_RING_BUFFER_SIZE,
55 	       CONFIG_OPENTHREAD_HDLC_RCP_IF_UART_TX_RING_BUFFER_SIZE);
56 
57 struct ot_hdlc_rcp_context {
58 	struct net_if *iface;
59 	struct openthread_context *ot_context;
60 };
61 
62 /* -------------------------------------------------------------------------- */
63 /*                             Private functions                              */
64 /* -------------------------------------------------------------------------- */
65 
ot_uart_rx_cb(struct k_work * item)66 static void ot_uart_rx_cb(struct k_work *item)
67 {
68 	struct openthread_uart *otuart =
69 		CONTAINER_OF(item, struct openthread_uart, work);
70 	uint8_t *data;
71 	uint32_t len;
72 
73 	len = ring_buf_get_claim(otuart->rx_ringbuf, &data,
74 				 otuart->rx_ringbuf->size);
75 	if (len > 0) {
76 		otuart->cb(data, len, otuart->param);
77 		ring_buf_get_finish(otuart->rx_ringbuf, len);
78 	}
79 }
80 
uart_tx_handle(const struct device * dev)81 static void uart_tx_handle(const struct device *dev)
82 {
83 	uint32_t tx_len = 0, len;
84 	uint8_t *data;
85 
86 	len = ring_buf_get_claim(
87 		ot_uart.tx_ringbuf, &data,
88 		ot_uart.tx_ringbuf->size);
89 	if (len > 0) {
90 		tx_len = uart_fifo_fill(dev, data, len);
91 		int err = ring_buf_get_finish(ot_uart.tx_ringbuf, tx_len);
92 		(void)err;
93 		__ASSERT_NO_MSG(err == 0);
94 	} else {
95 		uart_irq_tx_disable(dev);
96 	}
97 }
98 
uart_rx_handle(const struct device * dev)99 static void uart_rx_handle(const struct device *dev)
100 {
101 	uint32_t rd_len = 0, len;
102 	uint8_t *data;
103 
104 	len = ring_buf_put_claim(
105 		ot_uart.rx_ringbuf, &data,
106 		ot_uart.rx_ringbuf->size);
107 	if (len > 0) {
108 		rd_len = uart_fifo_read(dev, data, len);
109 
110 		int err = ring_buf_put_finish(ot_uart.rx_ringbuf, rd_len);
111 		(void)err;
112 		__ASSERT_NO_MSG(err == 0);
113 	}
114 }
115 
uart_callback(const struct device * dev,void * user_data)116 static void uart_callback(const struct device *dev, void *user_data)
117 {
118 	ARG_UNUSED(user_data);
119 
120 	while (uart_irq_update(dev) && uart_irq_is_pending(dev)) {
121 		if (uart_irq_rx_ready(dev)) {
122 			uart_rx_handle(dev);
123 		}
124 
125 		if (uart_irq_tx_ready(dev)) {
126 			uart_tx_handle(dev);
127 		}
128 	}
129 
130 	if (ring_buf_size_get(ot_uart.rx_ringbuf) > 0) {
131 		k_work_submit(&ot_uart.work);
132 	}
133 }
134 
hdlc_iface_init(struct net_if * iface)135 static void hdlc_iface_init(struct net_if *iface)
136 {
137 	struct ot_hdlc_rcp_context *ctx = net_if_get_device(iface)->data;
138 	otExtAddress eui64;
139 
140 	ot_uart.dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_ot_uart));
141 
142 	if (!device_is_ready(ot_uart.dev)) {
143 		LOG_ERR("UART device not ready");
144 	}
145 
146 	uart_irq_callback_user_data_set(ot_uart.dev,
147 					uart_callback,
148 					(void *)&ot_uart);
149 
150 	ctx->iface = iface;
151 	ieee802154_init(iface);
152 	ctx->ot_context = net_if_l2_data(iface);
153 
154 	otPlatRadioGetIeeeEui64(ctx->ot_context->instance, eui64.m8);
155 	net_if_set_link_addr(iface, eui64.m8, OT_EXT_ADDRESS_SIZE,
156 			     NET_LINK_IEEE802154);
157 }
158 
hdlc_register_rx_cb(hdlc_rx_callback_t hdlc_rx_callback,void * param)159 static int hdlc_register_rx_cb(hdlc_rx_callback_t hdlc_rx_callback, void *param)
160 {
161 	ot_uart.cb = hdlc_rx_callback;
162 	ot_uart.param = param;
163 
164 	k_work_init(&ot_uart.work, ot_uart_rx_cb);
165 	uart_irq_rx_enable(ot_uart.dev);
166 
167 	return 0;
168 }
169 
hdlc_send(const uint8_t * frame,uint16_t length)170 static int hdlc_send(const uint8_t *frame, uint16_t length)
171 {
172 	uint32_t ret;
173 
174 	if (frame == NULL) {
175 		return -EIO;
176 	}
177 
178 	ret = ring_buf_put(ot_uart.tx_ringbuf, frame, length);
179 	uart_irq_tx_enable(ot_uart.dev);
180 
181 	if (ret < length) {
182 		LOG_WRN("Cannot store full frame to RB (%d < %d)", ret, length);
183 		return -EIO;
184 	}
185 
186 	return 0;
187 }
188 
hdlc_deinit(void)189 static int hdlc_deinit(void)
190 {
191 	uart_irq_tx_disable(ot_uart.dev);
192 	uart_irq_rx_disable(ot_uart.dev);
193 
194 	ring_buf_reset(ot_uart.rx_ringbuf);
195 	ring_buf_reset(ot_uart.tx_ringbuf);
196 
197 	return 0;
198 }
199 
200 static const struct hdlc_api uart_hdlc_api = {
201 	.iface_api.init = hdlc_iface_init,
202 	.register_rx_cb = hdlc_register_rx_cb,
203 	.send = hdlc_send,
204 	.deinit = hdlc_deinit,
205 };
206 
207 #define L2_CTX_TYPE NET_L2_GET_CTX_TYPE(OPENTHREAD_L2)
208 
209 #define MTU 1280
210 
211 NET_DEVICE_DT_INST_DEFINE(0, NULL,                             /* Initialization Function */
212 			  NULL,                                /* No PM API support */
213 			  NULL,                                /* No context data */
214 			  NULL,                                /* Configuration info */
215 			  CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, /* Initial priority */
216 			  &uart_hdlc_api,                       /* API interface functions */
217 			  OPENTHREAD_L2,                       /* Openthread L2 */
218 			  NET_L2_GET_CTX_TYPE(OPENTHREAD_L2),  /* Openthread L2 context type */
219 			  MTU);                                /* MTU size */
220