1 /*
2  * Copyright (c) 2025 sensry.io
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT sensry_sy1xx_mac
8 
9 #include <zephyr/logging/log.h>
10 LOG_MODULE_REGISTER(sy1xx_mac, CONFIG_ETHERNET_LOG_LEVEL);
11 
12 #include <sys/types.h>
13 #include <zephyr/kernel.h>
14 #include <zephyr/net/ethernet.h>
15 #include <zephyr/sys/barrier.h>
16 #include <zephyr/drivers/pinctrl.h>
17 #include <zephyr/net/phy.h>
18 #include <udma.h>
19 #include "eth.h"
20 
21 /* MAC register offsets */
22 #define SY1XX_MAC_VERSION_REG      0x0000
23 #define SY1XX_MAC_ADDRESS_LOW_REG  0x0004
24 #define SY1XX_MAC_ADDRESS_HIGH_REG 0x0008
25 #define SY1XX_MAC_CTRL_REG         0x000c
26 
27 /* MAC control register bit offsets */
28 #define SY1XX_MAC_CTRL_RESET_OFFS   (0)
29 #define SY1XX_MAC_CTRL_RX_EN_OFFS   (1)
30 #define SY1XX_MAC_CTRL_TX_EN_OFFS   (2)
31 #define SY1XX_MAC_CTRL_GMII_OFFS    (3)
32 #define SY1XX_MAC_CTRL_CLK_DIV_OFFS (8)
33 #define SY1XX_MAC_CTRL_CLK_SEL_OFFS (10)
34 
35 /* MAC clock sources */
36 #define SY1XX_MAC_CTRL_CLK_SEL_REF_CLK 0
37 #define SY1XX_MAC_CTRL_CLK_SEL_MII_CLK 1
38 
39 /* Clock divider options */
40 #define SY1XX_MAC_CTRL_CLK_DIV_1  0x0
41 #define SY1XX_MAC_CTRL_CLK_DIV_5  0x1
42 #define SY1XX_MAC_CTRL_CLK_DIV_10 0x2
43 #define SY1XX_MAC_CTRL_CLK_DIV_50 0x3
44 
45 /* Clock divider mask */
46 #define SY1XX_MAC_CTRL_CLK_DIV_MASK (0x3)
47 
48 #define MAX_MAC_PACKET_LEN      1600
49 #define MAX_TX_RETRIES          5
50 #define RECEIVE_GRACE_TIME_MSEC 1
51 
52 #define SY1XX_ETH_STACK_SIZE      4096
53 #define SY1XX_ETH_THREAD_PRIORITY K_PRIO_PREEMPT(0)
54 
55 struct sy1xx_mac_dev_config {
56 	/* address of controller configuration registers */
57 	uint32_t ctrl_addr;
58 	/* address of udma for data transfers */
59 	uint32_t base_addr;
60 	/* optional - enable promiscuous mode */
61 	bool promiscuous_mode;
62 	/* optional - device tree mac */
63 	bool use_local_mac_address;
64 	uint8_t local_mac_address[6];
65 	/* optional - random mac */
66 	bool use_zephyr_random_mac;
67 
68 	/* phy config */
69 	const struct device *phy_dev;
70 
71 	/* pinctrl for rgmii pins */
72 	const struct pinctrl_dev_config *pcfg;
73 };
74 
75 struct sy1xx_mac_dma_buffers {
76 	uint8_t tx[MAX_MAC_PACKET_LEN];
77 	uint8_t rx[MAX_MAC_PACKET_LEN];
78 };
79 
80 struct sy1xx_mac_dev_data {
81 	struct k_mutex mutex;
82 
83 	/* current state of link and mac address */
84 	bool link_is_up;
85 	enum phy_link_speed link_speed;
86 
87 	uint8_t mac_addr[6];
88 
89 	/* intermediate, linear buffers that can hold a received or transmit msg */
90 	struct {
91 		uint8_t tx[MAX_MAC_PACKET_LEN];
92 		uint16_t tx_len;
93 
94 		uint8_t rx[MAX_MAC_PACKET_LEN];
95 		uint16_t rx_len;
96 	} temp;
97 
98 	/* buffers used for dma transfer, cannot be accessed while transfer active */
99 	struct sy1xx_mac_dma_buffers *dma_buffers;
100 
101 	struct k_thread rx_data_thread;
102 
103 	K_KERNEL_STACK_MEMBER(rx_data_thread_stack, SY1XX_ETH_STACK_SIZE);
104 
105 	struct net_if *iface;
106 };
107 
108 /* prototypes */
109 static int sy1xx_mac_set_mac_addr(const struct device *dev, uint8_t *mac_addr);
110 static int sy1xx_mac_set_promiscuous_mode(const struct device *dev, bool promiscuous_mode);
111 static int sy1xx_mac_set_config(const struct device *dev, enum ethernet_config_type type,
112 				const struct ethernet_config *config);
113 static void sy1xx_mac_rx_thread_entry(void *p1, void *p2, void *p3);
114 
sy1xx_mac_initialize(const struct device * dev)115 static int sy1xx_mac_initialize(const struct device *dev)
116 {
117 	struct sy1xx_mac_dev_config *cfg = (struct sy1xx_mac_dev_config *)dev->config;
118 	struct sy1xx_mac_dev_data *data = (struct sy1xx_mac_dev_data *)dev->data;
119 	int ret;
120 
121 	data->link_is_up = false;
122 	data->link_speed = -1;
123 
124 	k_mutex_init(&data->mutex);
125 
126 	/* PAD config */
127 	ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
128 	if (ret) {
129 		LOG_ERR("failed to configure pins");
130 		return ret;
131 	}
132 
133 	/* create the receiver thread */
134 	k_thread_create(&data->rx_data_thread, (k_thread_stack_t *)data->rx_data_thread_stack,
135 			SY1XX_ETH_STACK_SIZE, sy1xx_mac_rx_thread_entry, (void *)dev, NULL, NULL,
136 			SY1XX_ETH_THREAD_PRIORITY, 0, K_NO_WAIT);
137 
138 	/* start suspended and resume once we have link */
139 	k_thread_suspend(&data->rx_data_thread);
140 
141 	k_thread_name_set(&data->rx_data_thread, "mac-rx-thread");
142 
143 	return 0;
144 }
145 
sy1xx_mac_set_promiscuous_mode(const struct device * dev,bool promiscuous_mode)146 static int sy1xx_mac_set_promiscuous_mode(const struct device *dev, bool promiscuous_mode)
147 {
148 	struct sy1xx_mac_dev_config *cfg = (struct sy1xx_mac_dev_config *)dev->config;
149 	uint32_t prom;
150 
151 	/* set promiscuous mode */
152 	prom = sys_read32(cfg->ctrl_addr + SY1XX_MAC_ADDRESS_HIGH_REG);
153 	if (promiscuous_mode) {
154 		prom &= ~BIT(16);
155 	} else {
156 		prom |= BIT(16);
157 	}
158 	sys_write32(prom, cfg->ctrl_addr + SY1XX_MAC_ADDRESS_HIGH_REG);
159 
160 	return 0;
161 }
162 
sy1xx_mac_set_mac_addr(const struct device * dev,uint8_t * mac_addr)163 static int sy1xx_mac_set_mac_addr(const struct device *dev, uint8_t *mac_addr)
164 {
165 	struct sy1xx_mac_dev_config *cfg = (struct sy1xx_mac_dev_config *)dev->config;
166 	struct sy1xx_mac_dev_data *data = (struct sy1xx_mac_dev_data *)dev->data;
167 	int ret;
168 	uint32_t v_low, v_high;
169 
170 	LOG_INF("%s set link address %02x:%02x:%02x:%02x:%02x:%02x", dev->name, mac_addr[0],
171 		mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
172 
173 	/* update mac in controller */
174 	v_low = sys_get_le32(&mac_addr[0]);
175 	sys_write32(v_low, cfg->ctrl_addr + SY1XX_MAC_ADDRESS_LOW_REG);
176 
177 	v_high = sys_read32(cfg->ctrl_addr + SY1XX_MAC_ADDRESS_HIGH_REG);
178 	v_high |= (v_high & 0xffff0000) | sys_get_le16(&mac_addr[4]);
179 	sys_write32(v_high, cfg->ctrl_addr + SY1XX_MAC_ADDRESS_HIGH_REG);
180 
181 	memcpy(data->mac_addr, mac_addr, 6);
182 
183 	/* Register Ethernet MAC Address with the upper layer */
184 	ret = net_if_set_link_addr(data->iface, data->mac_addr, sizeof(data->mac_addr),
185 				   NET_LINK_ETHERNET);
186 	if (ret) {
187 		LOG_ERR("%s failed to set link address", dev->name);
188 		return ret;
189 	}
190 
191 	return 0;
192 }
193 
sy1xx_mac_start(const struct device * dev)194 static int sy1xx_mac_start(const struct device *dev)
195 {
196 	struct sy1xx_mac_dev_config *cfg = (struct sy1xx_mac_dev_config *)dev->config;
197 	struct sy1xx_mac_dev_data *data = (struct sy1xx_mac_dev_data *)dev->data;
198 	uint8_t rand_mac_addr[6];
199 
200 	extern void sy1xx_udma_disable_clock(sy1xx_udma_module_t module, uint32_t instance);
201 
202 	/* UDMA clock reset and enable */
203 	sy1xx_udma_enable_clock(SY1XX_UDMA_MODULE_MAC, 0);
204 	sy1xx_udma_disable_clock(SY1XX_UDMA_MODULE_MAC, 0);
205 	sy1xx_udma_enable_clock(SY1XX_UDMA_MODULE_MAC, 0);
206 
207 	/* reset mac controller */
208 	sys_write32(0x0001, cfg->ctrl_addr + SY1XX_MAC_CTRL_REG);
209 	sys_write32(0x0000, cfg->ctrl_addr + SY1XX_MAC_CTRL_REG);
210 
211 	/* preset mac addr */
212 	if (cfg->use_local_mac_address) {
213 		/* prio 0 -- from device tree */
214 		sy1xx_mac_set_mac_addr(dev, cfg->local_mac_address);
215 	} else if (cfg->use_zephyr_random_mac) {
216 		/* prio 1 -- generate random, if set in device tree */
217 		sys_rand_get(&rand_mac_addr, 6);
218 		/* Set MAC address locally administered, unicast (LAA) */
219 		rand_mac_addr[0] |= 0x02;
220 		sy1xx_mac_set_mac_addr(dev, rand_mac_addr);
221 	} else {
222 		/* no preset mac address available */
223 	}
224 
225 	sy1xx_mac_set_promiscuous_mode(dev, cfg->promiscuous_mode);
226 
227 	k_thread_resume(&data->rx_data_thread);
228 
229 	return 0;
230 }
231 
sy1xx_mac_stop(const struct device * dev)232 static int sy1xx_mac_stop(const struct device *dev)
233 {
234 	struct sy1xx_mac_dev_data *data = (struct sy1xx_mac_dev_data *)dev->data;
235 
236 	k_thread_suspend(&data->rx_data_thread);
237 	return 0;
238 }
239 
phy_link_state_changed(const struct device * pdev,struct phy_link_state * state,void * user_data)240 static void phy_link_state_changed(const struct device *pdev, struct phy_link_state *state,
241 				   void *user_data)
242 {
243 	const struct device *dev = (const struct device *)user_data;
244 	struct sy1xx_mac_dev_data *const data = dev->data;
245 	const struct sy1xx_mac_dev_config *const cfg = dev->config;
246 	bool is_up;
247 	enum phy_link_speed speed;
248 	uint32_t v, en;
249 
250 	is_up = state->is_up;
251 	speed = state->speed;
252 
253 	if (speed != data->link_speed) {
254 		data->link_speed = speed;
255 
256 		/* configure mac, based on provided link information 1Gbs/100MBit/... */
257 		v = sys_read32(cfg->ctrl_addr + SY1XX_MAC_CTRL_REG);
258 
259 		/* mask out relevant bits */
260 		v &= ~(BIT(SY1XX_MAC_CTRL_GMII_OFFS) | BIT(SY1XX_MAC_CTRL_CLK_SEL_OFFS) |
261 		       (SY1XX_MAC_CTRL_CLK_DIV_MASK << SY1XX_MAC_CTRL_CLK_DIV_OFFS));
262 
263 		switch (speed) {
264 		case LINK_FULL_10BASE_T:
265 			LOG_INF("link speed FULL_10BASE_T");
266 			/* 2.5MHz, MAC is clock source */
267 			v |= (SY1XX_MAC_CTRL_CLK_SEL_MII_CLK << SY1XX_MAC_CTRL_CLK_SEL_OFFS) |
268 			     (SY1XX_MAC_CTRL_CLK_DIV_10 << SY1XX_MAC_CTRL_CLK_DIV_OFFS);
269 			break;
270 		case LINK_FULL_100BASE_T:
271 			LOG_INF("link speed FULL_100BASE_T");
272 			/* 25MHz, MAC is clock source */
273 			v |= (SY1XX_MAC_CTRL_CLK_SEL_MII_CLK << SY1XX_MAC_CTRL_CLK_SEL_OFFS) |
274 			     (SY1XX_MAC_CTRL_CLK_DIV_1 << SY1XX_MAC_CTRL_CLK_DIV_OFFS);
275 			break;
276 		case LINK_FULL_1000BASE_T:
277 			LOG_INF("link speed FULL_1000BASE_T");
278 			/* 125MHz, Phy is clock source */
279 			v |= BIT(SY1XX_MAC_CTRL_GMII_OFFS) |
280 			     (SY1XX_MAC_CTRL_CLK_SEL_REF_CLK << SY1XX_MAC_CTRL_CLK_SEL_OFFS) |
281 			     (SY1XX_MAC_CTRL_CLK_DIV_1 << SY1XX_MAC_CTRL_CLK_DIV_OFFS);
282 			break;
283 		default:
284 			LOG_ERR("invalid link speed");
285 			return;
286 		}
287 		sys_write32(v, cfg->ctrl_addr + SY1XX_MAC_CTRL_REG);
288 	}
289 
290 	if (is_up != data->link_is_up) {
291 		data->link_is_up = is_up;
292 
293 		if (is_up) {
294 			LOG_DBG("Link up");
295 
296 			/* enable mac controller */
297 			en = sys_read32(cfg->ctrl_addr + SY1XX_MAC_CTRL_REG);
298 			en |= BIT(SY1XX_MAC_CTRL_TX_EN_OFFS) | BIT(SY1XX_MAC_CTRL_RX_EN_OFFS);
299 			sys_write32(en, cfg->ctrl_addr + SY1XX_MAC_CTRL_REG);
300 
301 			/* Announce link up status */
302 			net_eth_carrier_on(data->iface);
303 
304 		} else {
305 			LOG_DBG("Link down");
306 
307 			/* disable mac controller */
308 			en = sys_read32(cfg->ctrl_addr + SY1XX_MAC_CTRL_REG);
309 			en &= ~(BIT(SY1XX_MAC_CTRL_TX_EN_OFFS) | BIT(SY1XX_MAC_CTRL_RX_EN_OFFS));
310 			sys_write32(en, cfg->ctrl_addr + SY1XX_MAC_CTRL_REG);
311 
312 			/* Announce link down status */
313 			net_eth_carrier_off(data->iface);
314 		}
315 	}
316 }
317 
sy1xx_mac_iface_init(struct net_if * iface)318 static void sy1xx_mac_iface_init(struct net_if *iface)
319 {
320 	const struct device *dev = net_if_get_device(iface);
321 	struct sy1xx_mac_dev_config *cfg = (struct sy1xx_mac_dev_config *)dev->config;
322 	struct sy1xx_mac_dev_data *const data = dev->data;
323 
324 	LOG_INF("Interface init %s (%.8x)", net_if_get_device(iface)->name, iface);
325 
326 	data->iface = iface;
327 
328 	ethernet_init(iface);
329 
330 	if (device_is_ready(cfg->phy_dev)) {
331 		phy_link_callback_set(cfg->phy_dev, &phy_link_state_changed, (void *)dev);
332 	} else {
333 		LOG_ERR("PHY device not ready");
334 	}
335 
336 	/* Do not start the interface until PHY link is up */
337 	if (!(data->link_is_up)) {
338 		LOG_INF("found PHY link down");
339 		net_if_carrier_off(iface);
340 	}
341 }
342 
sy1xx_mac_get_caps(const struct device * dev)343 static enum ethernet_hw_caps sy1xx_mac_get_caps(const struct device *dev)
344 {
345 	enum ethernet_hw_caps supported = 0;
346 
347 	/* basic implemented features */
348 	supported |= ETHERNET_PROMISC_MODE;
349 	supported |= ETHERNET_LINK_1000BASE_T;
350 	supported |= ETHERNET_PROMISC_MODE;
351 
352 	return supported;
353 }
354 
sy1xx_mac_get_config(const struct device * dev,enum ethernet_config_type type,struct ethernet_config * config)355 static int sy1xx_mac_get_config(const struct device *dev, enum ethernet_config_type type,
356 				struct ethernet_config *config)
357 {
358 	struct sy1xx_mac_dev_data *data = (struct sy1xx_mac_dev_data *)dev->data;
359 
360 	/* we currently support only 1000mbit/s full duplex */
361 	switch (type) {
362 	case ETHERNET_CONFIG_TYPE_LINK:
363 		config->l.link_1000bt = true;
364 		break;
365 
366 	case ETHERNET_CONFIG_TYPE_DUPLEX:
367 		config->full_duplex = true;
368 		break;
369 
370 	case ETHERNET_CONFIG_TYPE_MAC_ADDRESS:
371 		memcpy(config->mac_address.addr, data->mac_addr, 6);
372 		break;
373 	default:
374 		return -ENOTSUP;
375 	}
376 	return 0;
377 }
378 
sy1xx_mac_set_config(const struct device * dev,enum ethernet_config_type type,const struct ethernet_config * config)379 static int sy1xx_mac_set_config(const struct device *dev, enum ethernet_config_type type,
380 				const struct ethernet_config *config)
381 {
382 	int ret = 0;
383 
384 	switch (type) {
385 
386 	case ETHERNET_CONFIG_TYPE_PROMISC_MODE:
387 		ret = sy1xx_mac_set_promiscuous_mode(dev, config->promisc_mode);
388 		break;
389 
390 	case ETHERNET_CONFIG_TYPE_MAC_ADDRESS:
391 		ret = sy1xx_mac_set_mac_addr(dev, (uint8_t *)&(config->mac_address.addr));
392 		break;
393 	default:
394 		return -ENOTSUP;
395 	}
396 	return ret;
397 }
398 
sy1xx_mac_get_phy(const struct device * dev)399 static const struct device *sy1xx_mac_get_phy(const struct device *dev)
400 {
401 	const struct sy1xx_mac_dev_config *const cfg = dev->config;
402 
403 	return cfg->phy_dev;
404 }
405 
406 /*
407  * rx ready status of eth is different to any other rx udma,
408  * so we implement here
409  */
sy1xx_mac_udma_is_finished_rx(uint32_t base)410 static int32_t sy1xx_mac_udma_is_finished_rx(uint32_t base)
411 {
412 	uint32_t isBusy = SY1XX_UDMA_READ_REG(base, SY1XX_UDMA_CFG_REG + 0x00) & (BIT(17));
413 
414 	return isBusy ? 0 : 1;
415 }
416 
sy1xx_mac_low_level_send(const struct device * dev,uint8_t * tx,uint16_t len)417 static int sy1xx_mac_low_level_send(const struct device *dev, uint8_t *tx, uint16_t len)
418 {
419 	struct sy1xx_mac_dev_config *cfg = (struct sy1xx_mac_dev_config *)dev->config;
420 	struct sy1xx_mac_dev_data *const data = dev->data;
421 
422 	if (len == 0) {
423 		return -EINVAL;
424 	}
425 
426 	if (len > MAX_MAC_PACKET_LEN) {
427 		return -EINVAL;
428 	}
429 
430 	if (!SY1XX_UDMA_IS_FINISHED_TX(cfg->base_addr)) {
431 		return -EBUSY;
432 	}
433 
434 	/* udma is ready, double check if last transmission was successful */
435 	if (SY1XX_UDMA_GET_REMAINING_TX(cfg->base_addr)) {
436 		SY1XX_UDMA_CANCEL_TX(cfg->base_addr);
437 		LOG_ERR("tx - last transmission failed");
438 		return -EINVAL;
439 	}
440 
441 	/* copy data to dma buffer */
442 	for (uint32_t i = 0; i < len; i++) {
443 		data->dma_buffers->tx[i] = tx[i];
444 	}
445 
446 	/* start dma transfer */
447 	SY1XX_UDMA_START_TX(cfg->base_addr, (uint32_t)data->dma_buffers->tx, len, 0);
448 
449 	return 0;
450 }
451 
sy1xx_mac_low_level_receive(const struct device * dev,uint8_t * rx,uint16_t * len)452 static int sy1xx_mac_low_level_receive(const struct device *dev, uint8_t *rx, uint16_t *len)
453 {
454 	struct sy1xx_mac_dev_config *cfg = (struct sy1xx_mac_dev_config *)dev->config;
455 	struct sy1xx_mac_dev_data *const data = dev->data;
456 	int ret;
457 	uint32_t bytes_transferred;
458 
459 	*len = 0;
460 
461 	/* rx udma still busy */
462 	if (0 == sy1xx_mac_udma_is_finished_rx(cfg->base_addr)) {
463 		return -EBUSY;
464 	}
465 
466 	/* rx udma is ready */
467 	bytes_transferred = SY1XX_UDMA_READ_REG(cfg->base_addr, SY1XX_UDMA_CFG_REG) & 0x0000ffff;
468 	if (bytes_transferred) {
469 		/* message received, copy data */
470 		memcpy(rx, data->dma_buffers->rx, bytes_transferred);
471 		*len = bytes_transferred;
472 		ret = 0;
473 	} else {
474 		/* no data, should never happen */
475 		SY1XX_UDMA_CANCEL_RX(cfg->base_addr);
476 		ret = -EINVAL;
477 	}
478 
479 	/* start new reception */
480 	SY1XX_UDMA_START_RX(cfg->base_addr, (uint32_t)data->dma_buffers->rx, MAX_MAC_PACKET_LEN, 0);
481 
482 	return ret;
483 }
484 
sy1xx_mac_send(const struct device * dev,struct net_pkt * pkt)485 static int sy1xx_mac_send(const struct device *dev, struct net_pkt *pkt)
486 {
487 	struct sy1xx_mac_dev_data *const data = dev->data;
488 	int ret;
489 	uint32_t retries_left;
490 	struct net_buf *frag;
491 
492 	k_mutex_lock(&data->mutex, K_FOREVER);
493 
494 	/* push all fragments of the packet into one linear buffer */
495 	frag = pkt->buffer;
496 	data->temp.tx_len = 0;
497 	do {
498 		/* copy fragment to buffer */
499 		for (uint32_t i = 0; i < frag->len; i++) {
500 			if (data->temp.tx_len < MAX_MAC_PACKET_LEN) {
501 				data->temp.tx[data->temp.tx_len++] = frag->data[i];
502 			} else {
503 				LOG_ERR("tx buffer overflow");
504 				k_mutex_unlock(&data->mutex);
505 				return -ENOMEM;
506 			}
507 		}
508 
509 		frag = frag->frags;
510 	} while (frag);
511 
512 	/* hand over linear tx frame to udma */
513 	retries_left = MAX_TX_RETRIES;
514 	while (retries_left) {
515 		ret = sy1xx_mac_low_level_send(dev, data->temp.tx, data->temp.tx_len);
516 		if (ret == 0) {
517 			break;
518 		}
519 		if (ret != -EBUSY) {
520 			LOG_ERR("tx error");
521 			k_mutex_unlock(&data->mutex);
522 			return ret;
523 		}
524 		k_sleep(K_MSEC(1));
525 		retries_left--;
526 	};
527 
528 	k_mutex_unlock(&data->mutex);
529 	return ret;
530 }
531 
sy1xx_mac_receive_data(const struct device * dev,uint8_t * rx,uint16_t len)532 static int sy1xx_mac_receive_data(const struct device *dev, uint8_t *rx, uint16_t len)
533 {
534 	struct sy1xx_mac_dev_data *const data = dev->data;
535 	struct net_pkt *rx_pkt;
536 	int ret;
537 
538 	rx_pkt = net_pkt_alloc_with_buffer(data->iface, len, AF_UNSPEC, 0, K_FOREVER);
539 	if (rx_pkt == NULL) {
540 		LOG_ERR("rx packet allocation failed");
541 		return -EINVAL;
542 	}
543 
544 	/* add data to the net_pkt */
545 	if (net_pkt_write(rx_pkt, rx, len)) {
546 		LOG_ERR("failed to write data to net_pkt");
547 		net_pkt_unref(rx_pkt);
548 		return -EINVAL;
549 	}
550 
551 	/* register new packet in stack */
552 	ret = net_recv_data(data->iface, rx_pkt);
553 	if (ret) {
554 		LOG_ERR("rx packet registration failed");
555 		return ret;
556 	}
557 
558 	return 0;
559 }
560 
sy1xx_mac_rx_thread_entry(void * p1,void * p2,void * p3)561 static void sy1xx_mac_rx_thread_entry(void *p1, void *p2, void *p3)
562 {
563 	const struct device *dev = p1;
564 	struct sy1xx_mac_dev_data *const data = dev->data;
565 	int ret;
566 
567 	while (true) {
568 		ret = sy1xx_mac_low_level_receive(dev, data->temp.rx, &data->temp.rx_len);
569 		if (ret == 0) {
570 			/* register a new received frame */
571 			if (data->temp.rx_len) {
572 				sy1xx_mac_receive_data(dev, data->temp.rx, data->temp.rx_len);
573 			}
574 		} else {
575 			/*
576 			 * rx thread is running at higher prio, in case of error or busy,
577 			 * we could lock up the system partially.
578 			 */
579 
580 			/* we wait and try again */
581 			k_sleep(K_MSEC(RECEIVE_GRACE_TIME_MSEC));
582 		}
583 	}
584 }
585 
586 const struct ethernet_api sy1xx_mac_driver_api = {
587 	.start = sy1xx_mac_start,
588 	.stop = sy1xx_mac_stop,
589 	.iface_api.init = sy1xx_mac_iface_init,
590 	.get_capabilities = sy1xx_mac_get_caps,
591 	.get_config = sy1xx_mac_get_config,
592 	.set_config = sy1xx_mac_set_config,
593 	.send = sy1xx_mac_send,
594 	.get_phy = sy1xx_mac_get_phy,
595 };
596 
597 #define SY1XX_MAC_INIT(n)                                                                          \
598                                                                                                    \
599 	PINCTRL_DT_INST_DEFINE(n);                                                                 \
600                                                                                                    \
601 	static const struct sy1xx_mac_dev_config sy1xx_mac_dev_config_##n = {                      \
602 		.ctrl_addr = DT_INST_REG_ADDR_BY_NAME(n, ctrl),                                    \
603 		.base_addr = DT_INST_REG_ADDR_BY_NAME(n, data),                                    \
604 		.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n),                                         \
605 		.promiscuous_mode = DT_INST_PROP_OR(n, promiscuous_mode, false),                   \
606 		.local_mac_address = DT_INST_PROP_OR(n, local_mac_address, {0}),                   \
607 		.use_local_mac_address = DT_INST_NODE_HAS_PROP(n, local_mac_address),              \
608 		.use_zephyr_random_mac = DT_INST_NODE_HAS_PROP(n, zephyr_random_mac_address),      \
609 		.phy_dev = DEVICE_DT_GET(DT_INST_PHANDLE(0, phy_handle))};                         \
610                                                                                                    \
611 	static struct sy1xx_mac_dma_buffers __attribute__((section(".udma_access")))               \
612 	__aligned(4) sy1xx_mac_dma_buffers_##n;                                                    \
613                                                                                                    \
614 	static struct sy1xx_mac_dev_data sy1xx_mac_dev_data##n = {                                 \
615 		.dma_buffers = &sy1xx_mac_dma_buffers_##n,                                         \
616 	};                                                                                         \
617                                                                                                    \
618 	ETH_NET_DEVICE_DT_INST_DEFINE(n, &sy1xx_mac_initialize, NULL, &sy1xx_mac_dev_data##n,      \
619 				      &sy1xx_mac_dev_config_##n, CONFIG_ETH_INIT_PRIORITY,         \
620 				      &sy1xx_mac_driver_api, NET_ETH_MTU);
621 
622 DT_INST_FOREACH_STATUS_OKAY(SY1XX_MAC_INIT)
623