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, ð_numaker_data_inst,
789 ð_numaker_cfg_inst, CONFIG_ETH_INIT_PRIORITY,
790 ð_numaker_driver_api, NET_ETH_MTU);
791