1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2020/12/31     Bernard      Add license info
9  */
10 
11 #include <board.h>
12 #include <rtthread.h>
13 #include <rtdevice.h>
14 #include <automac.h>
15 #include <netif/ethernetif.h>
16 #include <lwipopts.h>
17 #include "delay.h"
18 #include "mmu.h"
19 #include "drv_smc911x.h"
20 
21 #define MAX_ADDR_LEN                6
22 #define SMC911X_EMAC_DEVICE(eth)    (struct eth_device_smc911x*)(eth)
23 
24 #define DRIVERNAME "EMAC"
25 
26 #define DBG_LVL DBG_LOG
27 #define DBG_TAG "EMAC"
28 #include <rtdbg.h>
29 
30 struct eth_device_smc911x
31 {
32     /* inherit from Ethernet device */
33     struct eth_device parent;
34     /* interface address info. */
35     rt_uint8_t enetaddr[MAX_ADDR_LEN];         /* MAC address  */
36 
37     uint32_t iobase;
38     uint32_t irqno;
39 };
40 static struct eth_device_smc911x _emac;
41 
42 
43 #if defined (CONFIG_SMC911X_32_BIT)
smc911x_reg_read(struct eth_device_smc911x * dev,uint32_t offset)44 rt_inline uint32_t smc911x_reg_read(struct eth_device_smc911x *dev, uint32_t offset)
45 {
46     return *(volatile uint32_t *)(dev->iobase + offset);
47 }
48 
smc911x_reg_write(struct eth_device_smc911x * dev,uint32_t offset,uint32_t val)49 rt_inline void smc911x_reg_write(struct eth_device_smc911x *dev, uint32_t offset, uint32_t val)
50 {
51     *(volatile uint32_t *)(dev->iobase + offset) = val;
52 }
53 
54 #elif defined (CONFIG_SMC911X_16_BIT)
smc911x_reg_read(struct eth_device_smc911x * dev,uint32_t offset)55 rt_inline uint32_t smc911x_reg_read(struct eth_device_smc911x *dev, uint32_t offset)
56 {
57     volatile uint16_t *addr_16 = (uint16_t *)(dev->iobase + offset);
58     return ((*addr_16 & 0x0000ffff) | (*(addr_16 + 1) << 16));
59 }
60 
smc911x_reg_write(struct eth_device_smc911x * dev,uint32_t offset,uint32_t val)61 rt_inline void smc911x_reg_write(struct eth_device_smc911x *dev, uint32_t offset, uint32_t val)
62 {
63     *(volatile uint16_t *)(dev->iobase + offset) = (uint16_t)val;
64     *(volatile uint16_t *)(dev->iobase + offset + 2) = (uint16_t)(val >> 16);
65 }
66 #else
67 #error "SMC911X: undefined bus width"
68 #endif /* CONFIG_SMC911X_16_BIT */
69 
70 struct chip_id
71 {
72     uint16_t id;
73     char *name;
74 };
75 
76 static const struct chip_id chip_ids[] =
77 {
78     { LAN9118_ID_89218, "LAN89218" },
79     { LAN9118_ID_9115, "LAN9115" },
80     { LAN9118_ID_9116, "LAN9116" },
81     { LAN9118_ID_9117, "LAN9117" },
82     { LAN9118_ID_9118, "LAN9118" },
83     { LAN9210_ID_9211, "LAN9211" },
84     { LAN9218_ID_9215, "LAN9215" },
85     { LAN9218_ID_9216, "LAN9216" },
86     { LAN9218_ID_9217, "LAN9217" },
87     { LAN9218_ID_9218, "LAN9218" },
88     { LAN9220_ID_9220, "LAN9220" },
89     { LAN9220_ID_9221, "LAN9221" },
90     { 0, RT_NULL },
91 };
92 
smc911x_get_mac_csr(struct eth_device_smc911x * dev,uint8_t reg)93 static uint32_t smc911x_get_mac_csr(struct eth_device_smc911x *dev, uint8_t reg)
94 {
95     while (smc911x_reg_read(dev, LAN9118_MAC_CSR_CMD) & LAN9118_MAC_CSR_CMD_BUSY) ;
96 
97     smc911x_reg_write(dev, LAN9118_MAC_CSR_CMD, LAN9118_MAC_CSR_CMD_BUSY | LAN9118_MAC_CSR_CMD_R | reg);
98 
99     while (smc911x_reg_read(dev, LAN9118_MAC_CSR_CMD) & LAN9118_MAC_CSR_CMD_BUSY) ;
100 
101     return smc911x_reg_read(dev, LAN9118_MAC_CSR_DATA);
102 }
103 
smc911x_set_mac_csr(struct eth_device_smc911x * dev,uint8_t reg,uint32_t data)104 static void smc911x_set_mac_csr(struct eth_device_smc911x *dev, uint8_t reg, uint32_t data)
105 {
106     while (smc911x_reg_read(dev, LAN9118_MAC_CSR_CMD) & LAN9118_MAC_CSR_CMD_BUSY) ;
107 
108     smc911x_reg_write(dev, LAN9118_MAC_CSR_DATA, data);
109     smc911x_reg_write(dev, LAN9118_MAC_CSR_CMD, LAN9118_MAC_CSR_CMD_BUSY | reg);
110 
111     while (smc911x_reg_read(dev, LAN9118_MAC_CSR_CMD) & LAN9118_MAC_CSR_CMD_BUSY) ;
112 }
113 
smc911x_detect_chip(struct eth_device_smc911x * dev)114 static int smc911x_detect_chip(struct eth_device_smc911x *dev)
115 {
116     unsigned long val, i;
117 
118     val = smc911x_reg_read(dev, LAN9118_BYTE_TEST);
119     if (val == 0xffffffff)
120     {
121         /* Special case -- no chip present */
122         return -1;
123     }
124     else if (val != 0x87654321)
125     {
126         LOG_E("Invalid chip endian 0x%08lx\n", val);
127         return -1;
128     }
129 
130     val = smc911x_reg_read(dev, LAN9118_ID_REV) >> 16;
131     for (i = 0; chip_ids[i].id != 0; i++)
132     {
133         if (chip_ids[i].id == val) break;
134     }
135 
136     if (!chip_ids[i].id)
137     {
138         rt_kprintf(DRIVERNAME ": Unknown chip ID %04lx\n", val);
139         return -1;
140     }
141 
142     return 0;
143 }
144 
smc911x_reset(struct eth_device_smc911x * dev)145 static void smc911x_reset(struct eth_device_smc911x *dev)
146 {
147     int timeout;
148 
149     /*
150     *  Take out of PM setting first
151     *  Device is already wake up if LAN9118_PMT_CTRL_READY bit is set
152     */
153     if ((smc911x_reg_read(dev, LAN9118_PMT_CTRL) & LAN9118_PMT_CTRL_READY) == 0)
154     {
155         /* Write to the bytetest will take out of powerdown */
156         smc911x_reg_write(dev, LAN9118_BYTE_TEST, 0x0);
157 
158         timeout = 10;
159 
160         while (timeout-- && !(smc911x_reg_read(dev, LAN9118_PMT_CTRL) & LAN9118_PMT_CTRL_READY))
161             udelay(10);
162 
163         if (timeout < 0)
164         {
165             rt_kprintf(DRIVERNAME
166                        ": timeout waiting for PM restore\n");
167             return;
168         }
169     }
170 
171     /* Disable interrupts */
172     smc911x_reg_write(dev, LAN9118_INT_EN, 0);
173     smc911x_reg_write(dev, LAN9118_HW_CFG, LAN9118_HW_CFG_SRST);
174 
175     timeout = 1000;
176     while (timeout-- && smc911x_reg_read(dev, LAN9118_E2P_CMD) & LAN9118_E2P_CMD)
177         udelay(10);
178 
179     if (timeout < 0)
180     {
181         rt_kprintf(DRIVERNAME ": reset timeout\n");
182         return;
183     }
184 
185     /* Reset the FIFO level and flow control settings */
186     smc911x_set_mac_csr(dev, LAN9118_FLOW, LAN9118_FLOW_FCPT(0xffff) | LAN9118_FLOW_FCEN);
187     smc911x_reg_write(dev, LAN9118_AFC_CFG, 0x0050287F);
188 
189     /* Set to LED outputs */
190     smc911x_reg_write(dev, LAN9118_GPIO_CFG, 0x70070000);
191 }
192 
smc911x_handle_mac_address(struct eth_device_smc911x * dev)193 static void smc911x_handle_mac_address(struct eth_device_smc911x *dev)
194 {
195     unsigned long addrh, addrl;
196     uint8_t *m = dev->enetaddr;
197 
198     addrl = m[0] | (m[1] << 8) | (m[2] << 16) | (m[3] << 24);
199     addrh = m[4] | (m[5] << 8);
200 
201     smc911x_set_mac_csr(dev, LAN9118_ADDRL, addrl);
202     smc911x_set_mac_csr(dev, LAN9118_ADDRH, addrh);
203 }
204 
smc911x_eth_phy_read(struct eth_device_smc911x * dev,uint8_t phy,uint8_t reg,uint16_t * val)205 static int smc911x_eth_phy_read(struct eth_device_smc911x *dev,
206                                 uint8_t phy, uint8_t reg, uint16_t *val)
207 {
208     while (smc911x_get_mac_csr(dev, LAN9118_MII_ACC) & LAN9118_MII_ACC_MIIBZY) ;
209 
210     smc911x_set_mac_csr(dev, LAN9118_MII_ACC, phy << 11 | reg << 6 | LAN9118_MII_ACC_MIIBZY);
211 
212     while (smc911x_get_mac_csr(dev, LAN9118_MII_ACC) & LAN9118_MII_ACC_MIIBZY) ;
213 
214     *val = smc911x_get_mac_csr(dev, LAN9118_MII_DATA);
215 
216     return 0;
217 }
218 
smc911x_eth_phy_write(struct eth_device_smc911x * dev,uint8_t phy,uint8_t reg,uint16_t val)219 static int smc911x_eth_phy_write(struct eth_device_smc911x *dev,
220                                  uint8_t phy, uint8_t reg, uint16_t  val)
221 {
222     while (smc911x_get_mac_csr(dev, LAN9118_MII_ACC) & LAN9118_MII_ACC_MIIBZY)
223         ;
224 
225     smc911x_set_mac_csr(dev, LAN9118_MII_DATA, val);
226     smc911x_set_mac_csr(dev, LAN9118_MII_ACC,
227                         phy << 11 | reg << 6 | LAN9118_MII_ACC_MIIBZY | LAN9118_MII_ACC_MIIWNR);
228 
229     while (smc911x_get_mac_csr(dev, LAN9118_MII_ACC) & LAN9118_MII_ACC_MIIBZY)
230         ;
231     return 0;
232 }
233 
smc911x_phy_reset(struct eth_device_smc911x * dev)234 static int smc911x_phy_reset(struct eth_device_smc911x *dev)
235 {
236     uint32_t reg;
237 
238     reg = smc911x_reg_read(dev, LAN9118_PMT_CTRL);
239     reg &= ~0xfffff030;
240     reg |= LAN9118_PMT_CTRL_PHY_RST;
241     smc911x_reg_write(dev, LAN9118_PMT_CTRL, reg);
242 
243     mdelay(100);
244 
245     return 0;
246 }
247 
smc911x_phy_configure(struct eth_device_smc911x * dev)248 static void smc911x_phy_configure(struct eth_device_smc911x *dev)
249 {
250     int timeout;
251     uint16_t status;
252 
253     smc911x_phy_reset(dev);
254 
255     smc911x_eth_phy_write(dev, 1, LAN9118_MII_BMCR, LAN9118_BMCR_RESET);
256     mdelay(1);
257     smc911x_eth_phy_write(dev, 1, LAN9118_MII_ADVERTISE, 0x01e1);
258     smc911x_eth_phy_write(dev, 1, LAN9118_MII_BMCR, LAN9118_BMCR_ANENABLE | LAN9118_BMCR_ANRESTART);
259 
260     timeout = 5000;
261     do
262     {
263         mdelay(1);
264         if ((timeout--) == 0)
265             goto err_out;
266 
267         if (smc911x_eth_phy_read(dev, 1, LAN9118_MII_BMSR, &status) != 0)
268             goto err_out;
269     }
270     while (!(status & LAN9118_BMSR_LSTATUS));
271 
272     return;
273 
274 err_out:
275     rt_kprintf(DRIVERNAME ": autonegotiation timed out\n");
276 }
277 
smc911x_enable(struct eth_device_smc911x * dev)278 static void smc911x_enable(struct eth_device_smc911x *dev)
279 {
280     /* Enable TX */
281     smc911x_reg_write(dev, LAN9118_HW_CFG, 8 << 16 | LAN9118_HW_CFG_SF);
282 
283     smc911x_reg_write(dev, LAN9118_GPT_CFG, LAN9118_GPT_CFG_TIMER_EN | 10000);
284 
285     smc911x_reg_write(dev, LAN9118_TX_CFG, LAN9118_TX_CFG_TX_ON);
286 
287     /* no padding to start of packets */
288     smc911x_reg_write(dev, LAN9118_RX_CFG, 0);
289 
290     smc911x_set_mac_csr(dev, LAN9118_MAC_CR, LAN9118_MAC_CR_TXEN | LAN9118_MAC_CR_RXEN |
291                         LAN9118_MAC_CR_HBDIS);
292 }
293 
294 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
295 /* wrapper for smc911x_eth_phy_read */
smc911x_miiphy_read(struct mii_dev * bus,int phy,int devad,int reg)296 static int smc911x_miiphy_read(struct mii_dev *bus, int phy, int devad,
297                                int reg)
298 {
299     uint16_t val = 0;
300     struct eth_device_smc911x *dev = eth_get_dev_by_name(bus->name);
301     if (dev)
302     {
303         int retval = smc911x_eth_phy_read(dev, phy, reg, &val);
304         if (retval < 0)
305             return retval;
306         return val;
307     }
308     return -ENODEV;
309 }
310 
311 /* wrapper for smc911x_eth_phy_write */
smc911x_miiphy_write(struct mii_dev * bus,int phy,int devad,int reg,uint16_t val)312 static int smc911x_miiphy_write(struct mii_dev *bus, int phy, int devad,
313                                 int reg, uint16_t val)
314 {
315     struct eth_device_smc911x *dev = eth_get_dev_by_name(bus->name);
316     if (dev)
317         return smc911x_eth_phy_write(dev, phy, reg, val);
318     return -ENODEV;
319 }
320 #endif
321 
smc911x_isr(int vector,void * param)322 static void smc911x_isr(int vector, void *param)
323 {
324     uint32_t status;
325     struct eth_device_smc911x *emac;
326 
327     emac = SMC911X_EMAC_DEVICE(param);
328 
329     status = smc911x_reg_read(emac, LAN9118_INT_STS);
330 
331     if (status & LAN9118_INT_STS_RSFL)
332     {
333         eth_device_ready(&emac->parent);
334     }
335     smc911x_reg_write(emac, LAN9118_INT_STS, status);
336 
337     return ;
338 }
339 
smc911x_emac_init(rt_device_t dev)340 static rt_err_t smc911x_emac_init(rt_device_t dev)
341 {
342     // uint32_t value;
343     struct eth_device_smc911x *emac;
344 
345     emac = SMC911X_EMAC_DEVICE(dev);
346     RT_ASSERT(emac != RT_NULL);
347 
348     smc911x_reset(emac);
349 
350     /* Configure the PHY, initialize the link state */
351     smc911x_phy_configure(emac);
352     smc911x_handle_mac_address(emac);
353 
354     /* Turn on Tx + Rx */
355     smc911x_enable(emac);
356 
357     /* Interrupt on every received packet */
358     smc911x_reg_write(emac, LAN9118_FIFO_INT, 0x01 << 8);
359     smc911x_reg_write(emac, LAN9118_INT_EN, LAN9118_INT_EN_RDFL_EN | LAN9118_INT_RSFL);
360 
361     /* enable interrupt */
362     smc911x_reg_write(emac, LAN9118_IRQ_CFG, LAN9118_IRQ_CFG_IRQ_EN | LAN9118_IRQ_CFG_IRQ_POL | LAN9118_IRQ_CFG_IRQ_TYPE);
363 
364     rt_hw_interrupt_install(emac->irqno, smc911x_isr, emac, "smc911x");
365     rt_hw_interrupt_umask(emac->irqno);
366 
367     return RT_EOK;
368 }
369 
smc911x_emac_control(rt_device_t dev,int cmd,void * args)370 static rt_err_t smc911x_emac_control(rt_device_t dev, int cmd, void *args)
371 {
372     struct eth_device_smc911x *emac;
373 
374     emac = SMC911X_EMAC_DEVICE(dev);
375     RT_ASSERT(emac != RT_NULL);
376 
377     switch (cmd)
378     {
379     case NIOCTL_GADDR:
380         /* get MAC address */
381         if (args) rt_memcpy(args, emac->enetaddr, 6);
382         else return -RT_ERROR;
383         break;
384     default :
385         break;
386     }
387     return RT_EOK;
388 }
389 
390 /* Ethernet device interface */
391 /* transmit packet. */
392 static uint8_t tx_buf[2048];
smc911x_emac_tx(rt_device_t dev,struct pbuf * p)393 rt_err_t smc911x_emac_tx(rt_device_t dev, struct pbuf *p)
394 {
395     struct eth_device_smc911x *emac;
396 
397     uint32_t *data;
398     uint32_t tmplen;
399     uint32_t status;
400     uint32_t length;
401 
402     emac = SMC911X_EMAC_DEVICE(dev);
403     RT_ASSERT(emac != RT_NULL);
404 
405     /* copy pbuf to a whole ETH frame */
406     pbuf_copy_partial(p, tx_buf, p->tot_len, 0);
407 
408     /* send it out */
409     data = (uint32_t *)tx_buf;
410     length = p->tot_len;
411 
412     smc911x_reg_write(emac, LAN9118_TXDFIFOP, LAN9118_TXC_A_FS | LAN9118_TXC_A_LS | length);
413     smc911x_reg_write(emac, LAN9118_TXDFIFOP, length);
414 
415     tmplen = (length + 3) / 4;
416     while (tmplen--)
417     {
418         smc911x_reg_write(emac, LAN9118_TXDFIFOP, *data++);
419     }
420 
421     /* wait for transmission */
422     while (!(LAN9118_TX_FIFO_INF_TXSUSED(smc911x_reg_read(emac, LAN9118_TX_FIFO_INF))));
423 
424     /* get status. Ignore 'no carrier' error, it has no meaning for
425      * full duplex operation
426      */
427     status = smc911x_reg_read(emac, LAN9118_TXSFIFOP) &
428              (LAN9118_TXS_LOC | LAN9118_TXS_LCOL | LAN9118_TXS_ECOL |
429               LAN9118_TXS_ED | LAN9118_TX_STS_UNDERRUN);
430 
431     if (!status) return 0;
432 
433     LOG_E(DRIVERNAME ": failed to send packet: %s%s%s%s%s\n",
434                status & LAN9118_TXS_LOC ? "LAN9118_TXS_LOC " : "",
435                status & LAN9118_TXS_LCOL ? "LAN9118_TXS_LCOL " : "",
436                status & LAN9118_TXS_ECOL ? "LAN9118_TXS_ECOL " : "",
437                status & LAN9118_TXS_ED ? "LAN9118_TXS_ED " : "",
438                status & LAN9118_TX_STS_UNDERRUN ? "LAN9118_TX_STS_UNDERRUN" : "");
439 
440     return -RT_EIO;
441 }
442 
443 /* reception packet. */
smc911x_emac_rx(rt_device_t dev)444 struct pbuf *smc911x_emac_rx(rt_device_t dev)
445 {
446     struct pbuf *p = RT_NULL;
447     struct eth_device_smc911x *emac;
448 
449     emac = SMC911X_EMAC_DEVICE(dev);
450     RT_ASSERT(emac != RT_NULL);
451 
452     /* take the emac buffer to the pbuf */
453     if (LAN9118_RX_FIFO_INF_RXSUSED(smc911x_reg_read(emac, LAN9118_RX_FIFO_INF)))
454     {
455         uint32_t status;
456         uint32_t pktlen, tmplen;
457 
458         status = smc911x_reg_read(emac, LAN9118_RXSFIFOP);
459 
460         /* get frame length */
461         pktlen = (status & LAN9118_RX_STS_PKT_LEN) >> 16;
462 
463         smc911x_reg_write(emac, LAN9118_RX_CFG, 0);
464 
465         tmplen = (pktlen + 3) / 4;
466 
467         /* allocate pbuf */
468         p = pbuf_alloc(PBUF_RAW, tmplen * 4, PBUF_RAM);
469         if (p)
470         {
471             uint32_t *data = (uint32_t *)p->payload;
472             while (tmplen--)
473             {
474                 *data++ = smc911x_reg_read(emac, LAN9118_RXDFIFOP);
475             }
476         }
477 
478         if (status & LAN9118_RXS_ES)
479         {
480             rt_kprintf(DRIVERNAME ": dropped bad packet. Status: 0x%08x\n", status);
481         }
482     }
483 
484     return p;
485 }
486 
487 #ifdef RT_USING_DEVICE_OPS
488 const static struct rt_device_ops smc911x_emac_ops =
489 {
490     smc911x_emac_init,
491     RT_NULL,
492     RT_NULL,
493     RT_NULL,
494     RT_NULL,
495     smc911x_emac_control
496 };
497 #endif
498 
smc911x_emac_hw_init(void)499 int smc911x_emac_hw_init(void)
500 {
501     rt_memset(&_emac, 0x0, sizeof(_emac));
502 
503     _emac.iobase = VEXPRESS_ETH_BASE;
504 #ifdef RT_USING_SMART
505     _emac.iobase = (uint32_t)rt_ioremap((void*)VEXPRESS_ETH_BASE, 0x1000);
506 #endif
507     _emac.irqno  = IRQ_VEXPRESS_A9_ETH;
508 
509     if (smc911x_detect_chip(&_emac))
510     {
511         rt_kprintf("no smc911x network interface found!\n");
512         return -1;
513     }
514 
515     /* set INT CFG */
516     smc911x_reg_write(&_emac, LAN9118_IRQ_CFG, LAN9118_IRQ_CFG_IRQ_POL | LAN9118_IRQ_CFG_IRQ_TYPE);
517 
518     /* test MAC address */
519     _emac.enetaddr[0] = AUTOMAC0;
520     _emac.enetaddr[1] = AUTOMAC1;
521     _emac.enetaddr[2] = AUTOMAC2;
522     _emac.enetaddr[3] = AUTOMAC3;
523     _emac.enetaddr[4] = AUTOMAC4;
524     _emac.enetaddr[5] = AUTOMAC5;
525 
526 #ifdef RT_USING_DEVICE_OPS
527     _emac.parent.parent.ops        = &smc911x_emac_ops;
528 #else
529     _emac.parent.parent.init       = smc911x_emac_init;
530     _emac.parent.parent.open       = RT_NULL;
531     _emac.parent.parent.close      = RT_NULL;
532     _emac.parent.parent.read       = RT_NULL;
533     _emac.parent.parent.write      = RT_NULL;
534     _emac.parent.parent.control    = smc911x_emac_control;
535 #endif
536     _emac.parent.parent.user_data  = RT_NULL;
537     _emac.parent.eth_rx     = smc911x_emac_rx;
538     _emac.parent.eth_tx     = smc911x_emac_tx;
539 
540     /* register ETH device */
541     eth_device_init(&(_emac.parent), "e0");
542 
543 #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
544     {
545         int retval;
546         struct mii_dev *mdiodev = mdio_alloc();
547         if (!mdiodev)
548             return -ENOMEM;
549         strncpy(mdiodev->name, dev->name, MDIO_NAME_LEN);
550         mdiodev->read = smc911x_miiphy_read;
551         mdiodev->write = smc911x_miiphy_write;
552 
553         retval = mdio_register(mdiodev);
554         if (retval < 0)
555             return retval;
556     }
557 #endif
558 
559     eth_device_linkchange(&_emac.parent, RT_TRUE);
560     return 0;
561 }
562 INIT_APP_EXPORT(smc911x_emac_hw_init);
563