1 /*
2  * Copyright (c) 2023 Nuvoton Technology Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nuvoton_numaker_ethernet
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/reset.h>
11 #include <zephyr/drivers/clock_control.h>
12 #include <zephyr/drivers/clock_control/clock_control_numaker.h>
13 #include <zephyr/drivers/pinctrl.h>
14 #include <zephyr/logging/log.h>
15 #include <zephyr/net/ethernet.h>
16 #include "eth_numaker_priv.h"
17 #include "ethernet/eth_stats.h"
18 #include <soc.h>
19 #include <NuMicro.h>
20 #include <synopGMAC_network_interface.h>
21 
22 #ifdef CONFIG_SOC_M467
23 #include <m460_eth.h>
24 #endif
25 
26 LOG_MODULE_REGISTER(eth_numaker, CONFIG_ETHERNET_LOG_LEVEL);
27 
28 /* Device EMAC Interface port */
29 #define NUMAKER_GMAC_INTF  0
30 /* 2KB Data Flash at 0xFF800 */
31 #define NUMAKER_DATA_FLASH (0xFF800U)
32 #define NUMAKER_MASK_32    (0xFFFFFFFFU)
33 #define NUMAKER_MII_CONFIG (ADVERTISE_CSMA | ADVERTISE_10HALF | ADVERTISE_10FULL | \
34 							ADVERTISE_100HALF | ADVERTISE_100FULL)
35 #define NUMAKER_MII_LINKED (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)
36 
37 extern synopGMACdevice GMACdev[GMAC_CNT];
38 extern struct sk_buff tx_buf[GMAC_CNT][TRANSMIT_DESC_SIZE];
39 extern struct sk_buff rx_buf[GMAC_CNT][RECEIVE_DESC_SIZE];
40 
41 static uint32_t eth_phy_addr;
42 
43 /* Device config */
44 struct eth_numaker_config {
45 	uint32_t gmac_base;
46 	const struct reset_dt_spec reset;
47 	uint32_t phy_addr;
48 	uint32_t clk_modidx;
49 	uint32_t clk_src;
50 	uint32_t clk_div;
51 	const struct device *clk_dev;
52 	const struct pinctrl_dev_config *pincfg;
53 };
54 
55 /* Driver context/data */
56 struct eth_numaker_data {
57 	synopGMACdevice *gmacdev;
58 	struct net_if *iface;
59 	uint8_t mac_addr[NU_HWADDR_SIZE];
60 	struct k_mutex tx_frame_buf_mutex;
61 	struct k_spinlock rx_frame_buf_lock;
62 };
63 
64 /* Delay execution for given amount of ticks for SDK-HAL */
plat_delay(uint32_t delay)65 void plat_delay(uint32_t delay)
66 {
67 	uint32_t us_cnt = k_ticks_to_us_floor32((uint64_t)delay);
68 
69 	k_busy_wait(us_cnt);
70 }
71 
mdio_write(synopGMACdevice * gmacdev,uint32_t addr,uint32_t reg,int data)72 static void mdio_write(synopGMACdevice *gmacdev, uint32_t addr, uint32_t reg, int data)
73 {
74 	synopGMAC_write_phy_reg((u32 *)gmacdev->MacBase, addr, reg, data);
75 }
76 
mdio_read(synopGMACdevice * gmacdev,uint32_t addr,uint32_t reg)77 static int mdio_read(synopGMACdevice *gmacdev, uint32_t addr, uint32_t reg)
78 {
79 	uint16_t data;
80 
81 	synopGMAC_read_phy_reg((u32 *)gmacdev->MacBase, addr, reg, &data);
82 	return data;
83 }
84 
numaker_eth_link_ok(synopGMACdevice * gmacdev)85 static int numaker_eth_link_ok(synopGMACdevice *gmacdev)
86 {
87 	/* first, a dummy read to latch */
88 	mdio_read(gmacdev, eth_phy_addr, MII_BMSR);
89 	if (mdio_read(gmacdev, eth_phy_addr, MII_BMSR) & BMSR_LSTATUS) {
90 		return 1;
91 	}
92 	return 0;
93 }
94 
reset_phy(synopGMACdevice * gmacdev)95 static int reset_phy(synopGMACdevice *gmacdev)
96 {
97 	uint16_t reg;
98 	uint32_t delay_us;
99 	bool ret;
100 
101 	mdio_write(gmacdev, eth_phy_addr, MII_BMCR, BMCR_RESET);
102 
103 	delay_us = 200000U;
104 	ret = WAIT_FOR(!(mdio_read(gmacdev, eth_phy_addr, MII_BMCR) & BMCR_RESET),
105 					delay_us, k_msleep(1));
106 	if (ret == false) {
107 		LOG_DBG("Reset phy failed");
108 		return -EIO;
109 	}
110 
111 	LOG_INF("PHY ID 1:0x%x", mdio_read(gmacdev, eth_phy_addr, MII_PHYSID1));
112 	LOG_INF("PHY ID 2:0x%x", mdio_read(gmacdev, eth_phy_addr, MII_PHYSID2));
113 	delay_us = 3000000U;
114 	ret = WAIT_FOR(numaker_eth_link_ok(gmacdev), delay_us, k_msleep(1));
115 	if (ret) {
116 		gmacdev->LinkState = LINKUP;
117 		LOG_DBG("Link Up");
118 	} else {
119 		gmacdev->LinkState = LINKDOWN;
120 		LOG_DBG("Link Down");
121 		return -EIO;
122 	}
123 
124 	mdio_write(gmacdev, eth_phy_addr, MII_ADVERTISE, NUMAKER_MII_CONFIG);
125 	reg = mdio_read(gmacdev, eth_phy_addr, MII_BMCR);
126 	mdio_write(gmacdev, eth_phy_addr, MII_BMCR, reg | BMCR_ANRESTART);
127 	delay_us = 3000000U;
128 	ret = WAIT_FOR((mdio_read(gmacdev, eth_phy_addr, MII_BMSR) &
129 					NUMAKER_MII_LINKED) == NUMAKER_MII_LINKED,
130 					delay_us, k_msleep(1));
131 	if (ret == false) {
132 		LOG_DBG("AN failed. Set to 100 FULL");
133 		synopGMAC_set_full_duplex(gmacdev);
134 		synopGMAC_set_mode(NUMAKER_GMAC_INTF, 1); /* Set mode 1: 100Mbps; 2: 10Mbps */
135 		return -EIO;
136 	}
137 
138 	reg = mdio_read(gmacdev, eth_phy_addr, MII_LPA);
139 	if (reg & ADVERTISE_100FULL) {
140 		LOG_DBG("100 full");
141 		gmacdev->DuplexMode = FULLDUPLEX;
142 		gmacdev->Speed = SPEED100;
143 		synopGMAC_set_full_duplex(gmacdev);
144 		synopGMAC_set_mode(NUMAKER_GMAC_INTF, 1); /* Set mode 1: 100Mbps; 2: 10Mbps */
145 	} else if (reg & ADVERTISE_100HALF) {
146 		LOG_DBG("100 half");
147 		gmacdev->DuplexMode = HALFDUPLEX;
148 		gmacdev->Speed = SPEED100;
149 		synopGMAC_set_half_duplex(gmacdev);
150 		synopGMAC_set_mode(NUMAKER_GMAC_INTF, 1); /* Set mode 1: 100Mbps; 2: 10Mbps */
151 	} else if (reg & ADVERTISE_10FULL) {
152 		LOG_DBG("10 full");
153 		gmacdev->DuplexMode = FULLDUPLEX;
154 		gmacdev->Speed = SPEED10;
155 		synopGMAC_set_full_duplex(gmacdev);
156 		synopGMAC_set_mode(NUMAKER_GMAC_INTF, 2); /* Set mode 1: 100Mbps; 2: 10Mbps */
157 	} else {
158 		LOG_DBG("10 half");
159 		gmacdev->DuplexMode = HALFDUPLEX;
160 		gmacdev->Speed = SPEED10;
161 		synopGMAC_set_half_duplex(gmacdev);
162 		synopGMAC_set_mode(NUMAKER_GMAC_INTF, 2); /* Set mode 1: 100Mbps; 2: 10Mbps */
163 	}
164 
165 	return 0;
166 }
167 
m_numaker_read_mac_addr(char * mac)168 static void m_numaker_read_mac_addr(char *mac)
169 {
170 	uint32_t uid1;
171 	/* Fetch word 0 of data flash */
172 	uint32_t word0 = *(uint32_t *)(NUMAKER_DATA_FLASH + 0x04U);
173 	/*
174 	 * Fetch word 1 of data flash
175 	 * we only want bottom 16 bits of word1 (MAC bits 32-47)
176 	 * and bit 9 forced to 1, bit 8 forced to 0
177 	 * Locally administered MAC, reduced conflicts
178 	 * http://en.wikipedia.org/wiki/MAC_address
179 	 */
180 	uint32_t word1 = *(uint32_t *)NUMAKER_DATA_FLASH;
181 
182 	/* Not burn any mac address at the beginning of data flash */
183 	if (word0 == NUMAKER_MASK_32) {
184 		/* Generate a semi-unique MAC address from the UUID */
185 		SYS_UnlockReg();
186 		/* Enable FMC ISP function */
187 		FMC_Open();
188 		uid1 = FMC_ReadUID(1);
189 		word1 = (uid1 & 0x003FFFFF) | ((uid1 & 0x030000) << 6) >> 8;
190 		word0 = ((FMC_ReadUID(0) >> 4) << 20) | ((uid1 & 0xFF) << 12) |
191 			(FMC_ReadUID(2) & 0xFFF);
192 		/* Disable FMC ISP function */
193 		FMC_Close();
194 		/* Lock protected registers */
195 		SYS_LockReg();
196 	}
197 
198 	word1 |= 0x00000200;
199 	word1 &= 0x0000FEFF;
200 
201 	mac[0] = (word1 & 0x0000ff00) >> 8;
202 	mac[1] = (word1 & 0x000000ff);
203 	mac[2] = (word0 & 0xff000000) >> 24;
204 	mac[3] = (word0 & 0x00ff0000) >> 16;
205 	mac[4] = (word0 & 0x0000ff00) >> 8;
206 	mac[5] = (word0 & 0x000000ff);
207 
208 	LOG_INF("mac address %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3],
209 	       mac[4], mac[5]);
210 }
211 
m_numaker_gmacdev_enable(synopGMACdevice * gmacdev)212 static void m_numaker_gmacdev_enable(synopGMACdevice *gmacdev)
213 {
214 
215 	synopGMAC_clear_interrupt(gmacdev);
216 
217 	/* Enable INT & TX/RX */
218 	synopGMAC_enable_interrupt(gmacdev, DmaIntEnable);
219 	synopGMAC_enable_dma_rx(gmacdev);
220 	synopGMAC_enable_dma_tx(gmacdev);
221 
222 	synopGMAC_tx_enable(gmacdev);
223 	synopGMAC_rx_enable(gmacdev);
224 }
225 
m_numaker_gmacdev_init(synopGMACdevice * gmacdev,uint8_t * mac_addr,uint32_t gmac_base)226 static int m_numaker_gmacdev_init(synopGMACdevice *gmacdev, uint8_t *mac_addr, uint32_t gmac_base)
227 {
228 	int status;
229 	int i;
230 	uint32_t offload_needed = 0;
231 	struct sk_buff *skb;
232 
233 	LOG_DBG("");
234 
235 	/*Attach the device to MAC struct This will configure all the required base
236 	 * addresses such as Mac base, configuration base, phy base address(out of 32
237 	 * possible phys )
238 	 */
239 	synopGMAC_attach(gmacdev, gmac_base + MACBASE, gmac_base + DMABASE, DEFAULT_PHY_BASE);
240 	synopGMAC_disable_interrupt_all(gmacdev);
241 
242 	/* Reset MAC */
243 	synopGMAC_reset(gmacdev);
244 	gmacdev->Intf = NUMAKER_GMAC_INTF;
245 	synopGMAC_read_version(gmacdev);
246 
247 	/* Check for Phy initialization */
248 	synopGMAC_set_mdc_clk_div(gmacdev, GmiiCsrClk5);
249 	gmacdev->ClockDivMdc = synopGMAC_get_mdc_clk_div(gmacdev);
250 
251 	/* Reset PHY */
252 	status = reset_phy(gmacdev);
253 
254 	/* Set up the tx and rx descriptor queue/ring */
255 	synopGMAC_setup_tx_desc_queue(gmacdev, TRANSMIT_DESC_SIZE, RINGMODE);
256 	synopGMAC_init_tx_desc_base(gmacdev);
257 
258 	synopGMAC_setup_rx_desc_queue(gmacdev, RECEIVE_DESC_SIZE, RINGMODE);
259 	synopGMAC_init_rx_desc_base(gmacdev);
260 
261 	/* Initialize the dma interface */
262 	synopGMAC_dma_bus_mode_init(gmacdev,
263 				    DmaBurstLength32 | DmaDescriptorSkip0 | DmaDescriptor8Words);
264 	synopGMAC_dma_control_init(gmacdev,
265 				   DmaStoreAndForward | DmaTxSecondFrame | DmaRxThreshCtrl128);
266 
267 	/* Initialize the mac interface */
268 	synopGMAC_mac_init(gmacdev);
269 	synopGMAC_promisc_enable(gmacdev);
270 
271 	/* This enables the pause control in Full duplex mode of operation */
272 	synopGMAC_pause_control(gmacdev);
273 
274 #if defined(NU_USING_HW_CHECKSUM)
275 	/*IPC Checksum offloading is enabled for this driver. Should only be used if
276 	 * Full Ip checksumm offload engine is configured in the hardware
277 	 */
278 	offload_needed = 1;
279 
280 	/* Enable the offload engine in the receive path */
281 	synopGMAC_enable_rx_chksum_offload(gmacdev);
282 
283 	/* Default configuration, DMA drops the packets if error in encapsulated ethernet payload */
284 	synopGMAC_rx_tcpip_chksum_drop_enable(gmacdev);
285 #endif
286 
287 	for (i = 0; i < RECEIVE_DESC_SIZE; i++) {
288 		skb = &rx_buf[NUMAKER_GMAC_INTF][i];
289 		synopGMAC_set_rx_qptr(gmacdev, (u32)((u64)(skb->data) & NUMAKER_MASK_32),
290 				      sizeof(skb->data), (u32)((u64)skb & NUMAKER_MASK_32));
291 	}
292 
293 	for (i = 0; i < TRANSMIT_DESC_SIZE; i++) {
294 		skb = &tx_buf[NUMAKER_GMAC_INTF][i];
295 		synopGMAC_set_tx_qptr(gmacdev, (u32)((u64)(skb->data) & NUMAKER_MASK_32),
296 				      sizeof(skb->data), (u32)((u64)skb & NUMAKER_MASK_32),
297 				      offload_needed, 0);
298 	}
299 
300 	synopGMAC_set_mac_address(NUMAKER_GMAC_INTF, mac_addr);
301 	synopGMAC_clear_interrupt(gmacdev);
302 
303 	return status;
304 }
305 
m_numaker_gmacdev_get_rx_buf(synopGMACdevice * gmacdev,uint16_t * len,uint8_t ** buf)306 static int m_numaker_gmacdev_get_rx_buf(synopGMACdevice *gmacdev, uint16_t *len, uint8_t **buf)
307 {
308 	DmaDesc *rxdesc = gmacdev->RxBusyDesc;
309 
310 	LOG_DBG("start");
311 	if (synopGMAC_is_desc_owned_by_dma(rxdesc)) {
312 		return -EIO;
313 	}
314 	if (synopGMAC_is_desc_empty(rxdesc)) {
315 		return -EIO;
316 	}
317 
318 	*len = synop_handle_received_data(NUMAKER_GMAC_INTF, buf);
319 	if (*len <= 0) {
320 		synopGMAC_enable_interrupt(gmacdev, DmaIntEnable);
321 		return -ENOSPC; /* No available RX frame */
322 	}
323 
324 	/* length of payload should be <= 1514 */
325 	if (*len > (NU_ETH_MAX_FLEN - 4)) {
326 		LOG_DBG("unexpected long packet length=%d, buf=0x%x", *len, (uint32_t)*buf);
327 		*len = 0; /* Skip this unexpected long packet */
328 	}
329 
330 	LOG_DBG("end");
331 	return 0;
332 }
333 
m_numaker_gmacdev_rx_next(synopGMACdevice * gmacdev)334 static void m_numaker_gmacdev_rx_next(synopGMACdevice *gmacdev)
335 {
336 	LOG_DBG("RX Next");
337 	/* Already did in synop_handle_received_data
338 	 * No-op at this stage
339 	 * DmaDesc * rxdesc = (gmacdev->RxBusyDesc - 1);
340 	 * rxdesc->status = DescOwnByDma;
341 	 */
342 }
343 
m_numaker_gmacdev_trigger_rx(synopGMACdevice * gmacdev)344 static void m_numaker_gmacdev_trigger_rx(synopGMACdevice *gmacdev)
345 {
346 	LOG_DBG("start");
347 
348 	/* Enable the interrupt */
349 	synopGMAC_enable_interrupt(gmacdev, DmaIntEnable);
350 
351 	/* Trigger RX DMA */
352 	synopGMAC_enable_dma_rx(gmacdev);
353 	synopGMAC_resume_dma_rx(gmacdev);
354 	LOG_DBG("resume RX DMA");
355 	LOG_DBG("end");
356 }
357 
m_numaker_gmacdev_packet_rx(const struct device * dev)358 static void m_numaker_gmacdev_packet_rx(const struct device *dev)
359 {
360 	struct eth_numaker_data *data = dev->data;
361 	synopGMACdevice *gmacdev = data->gmacdev;
362 	uint8_t *buffer;
363 	uint16_t len;
364 	struct net_pkt *pkt;
365 	k_spinlock_key_t key;
366 	int res;
367 
368 	/* Get exclusive access, use spin-lock instead of mutex in ISR */
369 	key = k_spin_lock(&data->rx_frame_buf_lock);
370 
371 	/* Two approach: 1. recv all RX packets in one time.
372 	 *               2. recv one RX and set pending interrupt for rx-next.
373 	 */
374 	while (1) {
375 		/* get received frame */
376 		if (m_numaker_gmacdev_get_rx_buf(gmacdev, &len, &buffer) != 0) {
377 			break;
378 		}
379 
380 		if (len == 0) {
381 			LOG_WRN("No available RX frame");
382 			break;
383 		}
384 		/* Allocate a memory buffer chain from buffer pool
385 		 * Using root iface. It will be updated in net_recv_data()
386 		 */
387 		pkt = net_pkt_rx_alloc_with_buffer(data->iface, len, AF_UNSPEC, 0, K_NO_WAIT);
388 		if (!pkt) {
389 			LOG_ERR("pkt alloc frame-len=%d failed", len);
390 			goto next;
391 		}
392 
393 		LOG_DBG("length=%d, pkt=0x%x", len, (uint32_t)pkt);
394 		/* deliver RX packet to upper layer, pack as one net_pkt */
395 		if (net_pkt_write(pkt, buffer, len)) {
396 			LOG_ERR("Unable to write RX frame into the pkt");
397 			net_pkt_unref(pkt);
398 			goto error;
399 		}
400 
401 		if (pkt != NULL) {
402 			res = net_recv_data(data->iface, pkt);
403 			if (res < 0) {
404 				LOG_ERR("net_recv_data: %d", res);
405 				net_pkt_unref(pkt);
406 				goto error;
407 			}
408 		}
409 next:
410 		m_numaker_gmacdev_rx_next(gmacdev);
411 	}
412 	m_numaker_gmacdev_trigger_rx(gmacdev);
413 
414 error:
415 	k_spin_unlock(&data->rx_frame_buf_lock, key);
416 }
417 
m_numaker_gmacdev_get_tx_buf(synopGMACdevice * gmacdev)418 static uint8_t *m_numaker_gmacdev_get_tx_buf(synopGMACdevice *gmacdev)
419 {
420 	DmaDesc *txdesc = gmacdev->TxNextDesc;
421 
422 	if (!synopGMAC_is_desc_empty(txdesc)) {
423 		return NULL;
424 	}
425 
426 	if (synopGMAC_is_desc_owned_by_dma(txdesc)) {
427 		return NULL;
428 	}
429 
430 	return (uint8_t *)(txdesc->buffer1);
431 }
432 
m_numaker_gmacdev_trigger_tx(synopGMACdevice * gmacdev,uint16_t length)433 static void m_numaker_gmacdev_trigger_tx(synopGMACdevice *gmacdev, uint16_t length)
434 {
435 	DmaDesc *txdesc = gmacdev->TxNextDesc;
436 	uint32_t txnext = gmacdev->TxNext;
437 	bool offload_needed = IS_ENABLED(NU_USING_HW_CHECKSUM);
438 
439 	/* busy tx descriptor is incremented by one as it will be handed over to DMA */
440 	(gmacdev->BusyTxDesc)++;
441 
442 	txdesc->length |= ((length << DescSize1Shift) & DescSize1Mask);
443 	txdesc->status |= (DescTxFirst | DescTxLast | DescTxIntEnable);
444 	if (offload_needed) {
445 		/*
446 		 * Make sure that the OS you are running supports the IP and TCP checksum
447 		 * offloading, before calling any of the functions given below.
448 		 */
449 		synopGMAC_tx_checksum_offload_tcp_pseudo(gmacdev, txdesc);
450 	} else {
451 		synopGMAC_tx_checksum_offload_bypass(gmacdev, txdesc);
452 	}
453 	__DSB();
454 	txdesc->status |= DescOwnByDma;
455 
456 	gmacdev->TxNext = synopGMAC_is_last_tx_desc(gmacdev, txdesc) ? 0 : txnext + 1;
457 	gmacdev->TxNextDesc =
458 		synopGMAC_is_last_tx_desc(gmacdev, txdesc) ? gmacdev->TxDesc : (txdesc + 1);
459 
460 	/* Enable the interrupt */
461 	synopGMAC_enable_interrupt(gmacdev, DmaIntEnable);
462 	/* Trigger TX DMA */
463 	synopGMAC_resume_dma_tx(gmacdev);
464 }
465 
numaker_eth_tx(const struct device * dev,struct net_pkt * pkt)466 static int numaker_eth_tx(const struct device *dev, struct net_pkt *pkt)
467 {
468 	struct eth_numaker_data *data = dev->data;
469 	synopGMACdevice *gmacdev = data->gmacdev;
470 	uint16_t total_len = net_pkt_get_len(pkt);
471 	uint8_t *buffer;
472 
473 	/* Get exclusive access */
474 	k_mutex_lock(&data->tx_frame_buf_mutex, K_FOREVER);
475 	if (total_len > NET_ETH_MAX_FRAME_SIZE) {
476 		/* NuMaker SDK reserve 2048 for tx_buf */
477 		LOG_ERR("TX packet length [%d] over max [%d]", total_len, NET_ETH_MAX_FRAME_SIZE);
478 		goto error;
479 	}
480 
481 	buffer = m_numaker_gmacdev_get_tx_buf(gmacdev);
482 	LOG_DBG("buffer=0x%x", (uint32_t)buffer);
483 	if (buffer == NULL) {
484 		goto error;
485 	}
486 
487 	if (net_pkt_read(pkt, buffer, total_len)) {
488 		goto error;
489 	}
490 
491 	/* Prepare transmit descriptors to give to DMA */
492 	m_numaker_gmacdev_trigger_tx(gmacdev, total_len);
493 
494 	k_mutex_unlock(&data->tx_frame_buf_mutex);
495 
496 	return 0;
497 
498 error:
499 	LOG_ERR("Writing pkt to TX descriptor failed");
500 	k_mutex_unlock(&data->tx_frame_buf_mutex);
501 	return -EIO;
502 }
503 
numaker_eth_if_init(struct net_if * iface)504 static void numaker_eth_if_init(struct net_if *iface)
505 {
506 	const struct device *dev = net_if_get_device(iface);
507 	struct eth_numaker_data *data = dev->data;
508 
509 	synopGMACdevice *gmacdev = data->gmacdev;
510 
511 	LOG_DBG("eth_if_init");
512 
513 	/* Read mac address */
514 	m_numaker_read_mac_addr(data->mac_addr);
515 
516 	net_if_set_link_addr(iface, data->mac_addr, sizeof(data->mac_addr), NET_LINK_ETHERNET);
517 	data->iface = iface;
518 	ethernet_init(iface);
519 
520 	/* Enable GMAC device INT & TX/RX */
521 	m_numaker_gmacdev_enable(gmacdev);
522 }
523 
numaker_eth_set_config(const struct device * dev,enum ethernet_config_type type,const struct ethernet_config * config)524 static int numaker_eth_set_config(const struct device *dev, enum ethernet_config_type type,
525 				  const struct ethernet_config *config)
526 {
527 	struct eth_numaker_data *data = dev->data;
528 
529 	switch (type) {
530 	case ETHERNET_CONFIG_TYPE_MAC_ADDRESS:
531 		memcpy(data->mac_addr, config->mac_address.addr, sizeof(data->mac_addr));
532 		synopGMAC_set_mac_address(NUMAKER_GMAC_INTF, data->mac_addr);
533 		net_if_set_link_addr(data->iface, data->mac_addr, sizeof(data->mac_addr),
534 				     NET_LINK_ETHERNET);
535 		LOG_DBG("%s MAC set to %02x:%02x:%02x:%02x:%02x:%02x", dev->name, data->mac_addr[0],
536 			data->mac_addr[1], data->mac_addr[2], data->mac_addr[3], data->mac_addr[4],
537 			data->mac_addr[5]);
538 		return 0;
539 	default:
540 		return -ENOTSUP;
541 	}
542 }
543 
numaker_eth_get_cap(const struct device * dev)544 static enum ethernet_hw_caps numaker_eth_get_cap(const struct device *dev)
545 {
546 	ARG_UNUSED(dev);
547 #if defined(NU_USING_HW_CHECKSUM)
548 	return ETHERNET_LINK_10BASE_T | ETHERNET_LINK_100BASE_T | ETHERNET_HW_RX_CHKSUM_OFFLOAD;
549 #else
550 	return ETHERNET_LINK_10BASE_T | ETHERNET_LINK_100BASE_T;
551 #endif
552 }
553 
554 static const struct ethernet_api eth_numaker_driver_api = {
555 	.iface_api.init = numaker_eth_if_init,
556 	.get_capabilities = numaker_eth_get_cap,
557 	.set_config = numaker_eth_set_config,
558 	.send = numaker_eth_tx,
559 };
560 
561 /* EMAC IRQ Handler */
eth_numaker_isr(const struct device * dev)562 static void eth_numaker_isr(const struct device *dev)
563 {
564 	struct eth_numaker_data *data = dev->data;
565 	synopGMACdevice *gmacdev = data->gmacdev;
566 	uint32_t interrupt;
567 	uint32_t dma_status_reg;
568 	uint32_t mac_status_reg;
569 	int status;
570 	uint32_t dma_ie = DmaIntEnable;
571 
572 	uint32_t volatile reg;
573 
574 	/* Check GMAC interrupt */
575 	mac_status_reg = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacInterruptStatus);
576 	if (mac_status_reg & GmacTSIntSts) {
577 		gmacdev->synopGMACNetStats.ts_int = 1;
578 		status = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacTSStatus);
579 		if (!(status & BIT(1))) {
580 			LOG_WRN("TS alarm flag not set??");
581 		} else {
582 			LOG_DBG("TS alarm");
583 		}
584 	}
585 
586 	if (mac_status_reg & GmacLPIIntSts) {
587 		LOG_DBG("LPI");
588 	}
589 
590 	if (mac_status_reg & GmacRgmiiIntSts) {
591 		reg = synopGMACReadReg((u32 *)gmacdev->MacBase, GmacRgmiiCtrlSts);
592 	}
593 
594 	synopGMACWriteReg((u32 *)gmacdev->MacBase, GmacInterruptStatus, mac_status_reg);
595 	/* Read the Dma interrupt status to know whether the interrupt got generated by
596 	 * our device or not
597 	 */
598 	dma_status_reg = synopGMACReadReg((u32 *)gmacdev->DmaBase, DmaStatus);
599 	LOG_DBG("i %08x %08x", mac_status_reg, dma_status_reg);
600 
601 	if (dma_status_reg == 0) {
602 		return;
603 	}
604 
605 	synopGMAC_disable_interrupt_all(gmacdev);
606 	LOG_DBG("Dma Status Reg: 0x%08x", dma_status_reg);
607 	if (dma_status_reg & GmacPmtIntr) {
608 		LOG_DBG("Interrupt due to PMT module");
609 		synopGMAC_powerup_mac(gmacdev);
610 	}
611 
612 	if (dma_status_reg & GmacLineIntfIntr) {
613 		LOG_DBG("Interrupt due to GMAC LINE module");
614 	}
615 
616 	/* Now lets handle the DMA interrupts */
617 	interrupt = synopGMAC_get_interrupt_type(gmacdev);
618 	LOG_DBG("Interrupts to be handled: 0x%08x", interrupt);
619 	if (interrupt & synopGMACDmaError) {
620 		LOG_DBG("Fatal Bus Error Interrupt Seen");
621 		synopGMAC_disable_dma_tx(gmacdev);
622 		synopGMAC_disable_dma_rx(gmacdev);
623 
624 		synopGMAC_take_desc_ownership_tx(gmacdev);
625 		synopGMAC_take_desc_ownership_rx(gmacdev);
626 
627 		synopGMAC_init_tx_rx_desc_queue(gmacdev);
628 
629 		synopGMAC_reset(gmacdev); /* reset the DMA engine and the GMAC ip */
630 		synopGMAC_set_mac_address(NUMAKER_GMAC_INTF, data->mac_addr);
631 		synopGMAC_dma_bus_mode_init(gmacdev, DmaFixedBurstEnable | DmaBurstLength8 |
632 							     DmaDescriptorSkip0);
633 		synopGMAC_dma_control_init(gmacdev, DmaStoreAndForward);
634 		synopGMAC_init_rx_desc_base(gmacdev);
635 		synopGMAC_init_tx_desc_base(gmacdev);
636 		synopGMAC_mac_init(gmacdev);
637 		synopGMAC_enable_dma_rx(gmacdev);
638 		synopGMAC_enable_dma_tx(gmacdev);
639 	}
640 
641 	if (interrupt & synopGMACDmaRxNormal) {
642 		LOG_DBG("Rx Normal");
643 		/* disable RX interrupt */
644 		dma_ie &= ~DmaIntRxNormMask;
645 		/* to handle received data */
646 		m_numaker_gmacdev_packet_rx(dev);
647 	}
648 
649 	if (interrupt & synopGMACDmaRxAbnormal) {
650 		LOG_ERR("Abnormal Rx Interrupt Seen");
651 		/* If Mac is not in powerdown */
652 		if (gmacdev->GMAC_Power_down == 0) {
653 			gmacdev->synopGMACNetStats.rx_over_errors++;
654 			dma_ie &= ~DmaIntRxAbnMask;
655 			/* To handle GBPS with 12 descriptors. */
656 			synopGMAC_resume_dma_rx(gmacdev);
657 		}
658 	}
659 
660 	/* Receiver gone in to stopped state */
661 	if (interrupt & synopGMACDmaRxStopped) {
662 		LOG_ERR("Receiver stopped seeing Rx interrupts");
663 		if (gmacdev->GMAC_Power_down == 0) {
664 			gmacdev->synopGMACNetStats.rx_over_errors++;
665 			synopGMAC_enable_dma_rx(gmacdev);
666 		}
667 	}
668 
669 	if (interrupt & synopGMACDmaTxNormal) {
670 		LOG_DBG("Finished Normal Transmission");
671 		synop_handle_transmit_over(0);
672 		/* No-op at this stage for TX INT */
673 	}
674 
675 	if (interrupt & synopGMACDmaTxAbnormal) {
676 		LOG_ERR("Abnormal Tx Interrupt Seen");
677 		if (gmacdev->GMAC_Power_down == 0) {
678 			synop_handle_transmit_over(0);
679 			/* No-op at this stage for TX INT */
680 		}
681 	}
682 
683 	if (interrupt & synopGMACDmaTxStopped) {
684 		LOG_ERR("Transmitter stopped sending the packets");
685 		if (gmacdev->GMAC_Power_down == 0) {
686 			synopGMAC_disable_dma_tx(gmacdev);
687 			synopGMAC_take_desc_ownership_tx(gmacdev);
688 			synopGMAC_enable_dma_tx(gmacdev);
689 			LOG_ERR("Transmission Resumed");
690 		}
691 	}
692 
693 	/* Enable the interrupt before returning from ISR*/
694 	synopGMAC_enable_interrupt(gmacdev, dma_ie);
695 }
696 
697 /* Declare pin-ctrl __pinctrl_dev_config__device_dts_ord_xx before
698  * PINCTRL_DT_INST_DEV_CONFIG_GET()
699  */
700 PINCTRL_DT_INST_DEFINE(0);
701 
eth_numaker_init(const struct device * dev)702 static int eth_numaker_init(const struct device *dev)
703 {
704 	const struct eth_numaker_config *cfg = dev->config;
705 	struct eth_numaker_data *data = dev->data;
706 	synopGMACdevice *gmacdev;
707 
708 	/* Init MAC Address based on UUID*/
709 	uint8_t mac_addr[NU_HWADDR_SIZE];
710 	int ret = 0;
711 	struct numaker_scc_subsys scc_subsys;
712 
713 	gmacdev = &GMACdev[NUMAKER_GMAC_INTF];
714 	data->gmacdev = gmacdev;
715 
716 	k_mutex_init(&data->tx_frame_buf_mutex);
717 
718 	eth_phy_addr = cfg->phy_addr;
719 
720 	/* CLK controller */
721 	memset(&scc_subsys, 0x00, sizeof(scc_subsys));
722 	scc_subsys.subsys_id = NUMAKER_SCC_SUBSYS_ID_PCC;
723 	scc_subsys.pcc.clk_modidx = cfg->clk_modidx;
724 	scc_subsys.pcc.clk_src = cfg->clk_src;
725 	scc_subsys.pcc.clk_div = cfg->clk_div;
726 
727 	/* Equivalent to CLK_EnableModuleClock() */
728 	ret = clock_control_on(cfg->clk_dev, (clock_control_subsys_t)&scc_subsys);
729 	if (ret != 0) {
730 		goto done;
731 	}
732 
733 	/* For EMAC, not need CLK_SetModuleClock()
734 	 * Validate this module's reset object
735 	 */
736 	if (!device_is_ready(cfg->reset.dev)) {
737 		LOG_ERR("reset controller not ready");
738 		return -ENODEV;
739 	}
740 
741 	SYS_UnlockReg();
742 
743 	irq_disable(DT_INST_IRQN(0));
744 	ret = pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_DEFAULT);
745 	if (ret != 0) {
746 		LOG_ERR("Failed to apply pinctrl state");
747 		goto done;
748 	}
749 
750 	/* Reset EMAC to default state, same as BSP's SYS_ResetModule(id_rst) */
751 	reset_line_toggle_dt(&cfg->reset);
752 
753 	/* Read mac address */
754 	m_numaker_read_mac_addr(mac_addr);
755 
756 	/* Configure GMAC device */
757 	ret = m_numaker_gmacdev_init(gmacdev, mac_addr, cfg->gmac_base);
758 	if (ret != 0) {
759 		LOG_ERR("GMAC failed to initialize");
760 		goto done;
761 	}
762 
763 	IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), eth_numaker_isr,
764 		    DEVICE_DT_INST_GET(0), 0);
765 
766 	irq_enable(DT_INST_IRQN(0));
767 
768 done:
769 	SYS_LockReg();
770 	return ret;
771 }
772 
773 static struct eth_numaker_data eth_numaker_data_inst;
774 
775 /* Set config based on DTS */
776 static struct eth_numaker_config eth_numaker_cfg_inst = {
777 	.gmac_base = (uint32_t)DT_INST_REG_ADDR(0),
778 	.reset = RESET_DT_SPEC_INST_GET(0),
779 	.phy_addr = DT_INST_PROP(0, phy_addr),
780 	.clk_modidx = DT_INST_CLOCKS_CELL(0, clock_module_index),
781 	.clk_src = DT_INST_CLOCKS_CELL(0, clock_source),
782 	.clk_div = DT_INST_CLOCKS_CELL(0, clock_divider),
783 	.clk_dev = DEVICE_DT_GET(DT_PARENT(DT_INST_CLOCKS_CTLR(0))),
784 	.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
785 	.reset = RESET_DT_SPEC_INST_GET(0),
786 };
787 
788 ETH_NET_DEVICE_DT_INST_DEFINE(0, eth_numaker_init, NULL, &eth_numaker_data_inst,
789 			      &eth_numaker_cfg_inst, CONFIG_ETH_INIT_PRIORITY,
790 			      &eth_numaker_driver_api, NET_ETH_MTU);
791