123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428 |
- /*
- * Copyright (c)
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Email Notes
- * 2022-04-06 Kevin.Liu kevin.liu.mchp@gmail.com First Release
- */
- #include <rtthread.h>
- #include <rtdevice.h>
- #include <rtdbg.h>
- #include <netif/ethernetif.h>
- #include <lwipopts.h>
- #include <atmel_start.h>
- #include <peripheral_clk_config.h>
- #include <ieee8023_mii_standard_config.h>
- #include "board.h"
- #include "sam_gmac.h"
- #ifdef RT_USING_LWIP
- struct rt_sam_eth
- {
- /* inherit from ethernet device */
- struct eth_device parent;
- struct mac_async_descriptor *macif;
- struct ethernet_phy_descriptor *phyif;
- #ifdef RT_USING_TIMER_SOFT
- rt_timer_t phy_monitor_timer;
- #else
- rt_thread_t phy_monitor_tid;
- #endif
- /* ethernet MAC address */
- rt_uint8_t mac_addr[NETIF_MAX_HWADDR_LEN];
- /* GMAC Link Speed */
- gmac_speed_type link_speed;
- /* GMAC Link Mode */
- gmac_duplex_type link_mode;
- };
- static struct rt_sam_eth sam_eth_device;
- /**
- * @brief Called by GMAC RX interrupt, will notify RX task
- *
- * @note Will call eth_device_ready to notify RX task.
- *
- * @param
- *
- * @return
- */
- static void rt_sam_gmac_rxcb(void)
- {
- rt_err_t result;
- /* enter interrupt */
- rt_interrupt_enter();
- result = eth_device_ready(&sam_eth_device.parent);
- if (result != RT_EOK)
- LOG_E("rt_sam_gmac_rxcb error");
- /* leave interrupt */
- rt_interrupt_leave();
- }
- /**
- * @brief Initialize the MAC hardware
- *
- * @note Will set MAC filter by using input MAC address.
- *
- * @param gmac_dev GMAC device description.
- *
- * @return
- */
- static inline void rt_sam_gmac_init(struct rt_sam_eth *gmac_dev)
- {
- struct mac_async_filter filter;
- /* set MAC hardware address */
- rt_memcpy(filter.mac, sam_eth_device.mac_addr, NETIF_MAX_HWADDR_LEN);
- filter.tid_enable = false;
- mac_async_set_filter(gmac_dev->macif, 0, &filter);
- mac_async_register_callback(gmac_dev->macif, MAC_ASYNC_RECEIVE_CB, (FUNC_PTR)rt_sam_gmac_rxcb);
- }
- static rt_err_t rt_sam_eth_init(rt_device_t dev)
- {
- LOG_D("gmac init");
- return RT_EOK;
- }
- static rt_err_t rt_sam_eth_open(rt_device_t dev, rt_uint16_t oflag)
- {
- LOG_D("gmac open");
- return RT_EOK;
- }
- static rt_err_t rt_sam_eth_close(rt_device_t dev)
- {
- LOG_D("gmac close");
- return RT_EOK;
- }
- static rt_ssize_t rt_sam_eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
- {
- LOG_D("gmac read");
- rt_set_errno(-RT_ENOSYS);
- return 0;
- }
- static rt_ssize_t rt_sam_eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
- {
- LOG_D("gmac write");
- rt_set_errno(-RT_ENOSYS);
- return 0;
- }
- static rt_err_t rt_sam_eth_control(rt_device_t dev, int cmd, void *args)
- {
- rt_err_t ret = RT_EOK;
- switch (cmd)
- {
- case NIOCTL_GADDR:
- /* get mac address */
- if (args)
- rt_memcpy(args, sam_eth_device.mac_addr, 6);
- break;
- default :
- break;
- }
- return ret;
- }
- /**
- * @brief Transmission packet though the MAC hardware
- *
- * @note Send package to MAC.
- *
- * @param dev the RT net device input.
- *
- * @param p stored message will be sent to MAC.
- *
- * @return RT_EOK.
- */
- rt_err_t rt_sam_eth_tx(rt_device_t dev, struct pbuf *p)
- {
- struct rt_sam_eth *gmac_dev = (struct rt_sam_eth *)dev->user_data;
- struct pbuf * q;
- void * tbuf;
- uint8_t * pos;
- #if ETH_PAD_SIZE
- pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
- #endif
- if (p->tot_len == p->len)
- {
- mac_async_write(gmac_dev->macif, p->payload, p->tot_len);
- }
- else
- {
- tbuf = mem_malloc(LWIP_MEM_ALIGN_SIZE(p->tot_len));
- pos = tbuf;
- if (tbuf == NULL)
- {
- return ERR_MEM;
- }
- for (q = p; q != NULL; q = q->next)
- {
- rt_memcpy(pos, q->payload, q->len);
- pos += q->len;
- }
- mac_async_write(gmac_dev->macif, tbuf, p->tot_len);
- mem_free(tbuf);
- }
- #if ETH_PAD_SIZE
- pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
- #endif
- LINK_STATS_INC(link.xmit);
- return ERR_OK;
- }
- /**
- * @brief Receive packet from the MAC hardware
- *
- * @note Returned pbuf filled with the received packet (including MAC header)
- *
- * @param dev the RT net device input.
- *
- * @return NULL on memory error
- */
- struct pbuf *rt_sam_eth_rx(rt_device_t dev)
- {
- struct rt_sam_eth *gmac_dev = (struct rt_sam_eth *)dev->user_data;
- struct pbuf * p;
- u16_t len;
- len = mac_async_read_len(gmac_dev->macif); /* Obtain the size of the packet */
- if (len == 0)
- {
- return NULL;
- }
- #if ETH_PAD_SIZE
- len += ETH_PAD_SIZE; /* allow room for Ethernet padding */
- #endif
- /* Allocate a pbuf as one large chunk, This include protocol header */
- p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM);
- if (p != NULL)
- {
- #if ETH_PAD_SIZE
- pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
- #endif
- /* Read the entire packet into the pbuf. */
- mac_async_read(gmac_dev->macif, p->payload, p->len);
- #if ETH_PAD_SIZE
- pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
- #endif
- LINK_STATS_INC(link.recv);
- }
- else
- {
- mac_async_read(gmac_dev->macif, NULL, 0);
- LINK_STATS_INC(link.memerr);
- LINK_STATS_INC(link.drop);
- }
- return p;
- }
- /**
- * @brief PHY link status monitor task - timer task or thread
- *
- * @note Will check link status, link mode and link speed
- *
- * @param parameter input parameter passing to the function.
- *
- * @return
- */
- static void rt_sam_eth_monitor(void *parameter)
- {
- struct rt_sam_eth *sam_eth = (struct rt_sam_eth *)parameter;
- bool link_up;
- int32_t ret;
- uint16_t val;
- static rt_uint8_t link_count = 0;
- #ifndef RT_USING_TIMER_SOFT
- while (1)
- {
- #endif
- ret = ethernet_phy_get_link_status(sam_eth->phyif, &link_up);
- if (ERR_NONE == ret)
- {
- if (link_up)
- {
- /* send link up. */
- eth_device_linkchange(&sam_eth->parent, RT_TRUE);
- }
- else
- {
- /* send link down. */
- eth_device_linkchange(&sam_eth->parent, RT_FALSE);;
- }
- }
- ret = ethernet_phy_read_reg(sam_eth->phyif, MDIO_REG1_BMSR, &val);
- if (ERR_NONE == ret)
- {
- if (val & (MDIO_REG1_BIT_100BASE_TX_FD | MDIO_REG1_BIT_100BASE_TX_HD))
- {
- LOG_D("100Mbps");
- sam_eth_device.link_speed = GMAC_SPEED_100MBPS;
- }
- else
- {
- LOG_D("10Mbps");
- sam_eth_device.link_speed = GMAC_SPEED_10MBPS;
- }
- if (val & (MDIO_REG1_BIT_100BASE_TX_FD | MDIO_REG1_BIT_10BASE_T_FD))
- {
- LOG_D("100Mbps");
- sam_eth_device.link_mode = GMAC_FULL_DUPLEX;
- }
- else
- {
- LOG_D("10Mbps");
- sam_eth_device.link_mode = GMAC_HALF_DUPLEX;
- }
- }
- if (link_count >= 10)
- {
- link_count = 0;
- /* Restart an auto-negotiation */
- ethernet_phy_restart_autoneg(sam_eth->phyif);
- }
- #ifndef RT_USING_TIMER_SOFT
- rt_thread_mdelay(1000);
- }
- #endif
- }
- /**
- * @brief Register the GMAC Ethernet device.
- *
- * @note
- *
- * @param
- *
- * @return RT_OK or -RT_ERROR.
- */
- static int rt_hw_sam_eth_init(void)
- {
- rt_err_t state = RT_EOK;
- #if CONF_AT24MAC_ADDRESS != 0
- rt_uint8_t addr = 0x9A;
- #endif
- sam_eth_device.macif = &MACIF;
- sam_eth_device.phyif = &MACIF_PHY_desc;
- sam_eth_device.link_speed = GMAC_SPEED_100MBPS;
- sam_eth_device.link_mode = GMAC_FULL_DUPLEX;
- #if CONF_AT24MAC_ADDRESS != 0
- i2c_m_sync_enable(&I2C_0);
- i2c_m_sync_set_slaveaddr(&I2C_0, CONF_AT24MAC_ADDRESS, I2C_M_SEVEN);
- io_write(&(I2C_0.io), &addr, 1);
- io_read(&(I2C_0.io), sam_eth_device.mac_addr, 6);
- #else
- /* set mac to 0x11 if no EEPROM mounted */
- memset(sam_eth_device.mac_addr, 0x11, 6);
- #endif
- sam_eth_device.parent.parent.init = rt_sam_eth_init;
- sam_eth_device.parent.parent.open = rt_sam_eth_open;
- sam_eth_device.parent.parent.close = rt_sam_eth_close;
- sam_eth_device.parent.parent.read = rt_sam_eth_read;
- sam_eth_device.parent.parent.write = rt_sam_eth_write;
- sam_eth_device.parent.parent.control = rt_sam_eth_control;
- sam_eth_device.parent.parent.user_data = (void *)&sam_eth_device;
- sam_eth_device.parent.eth_rx = rt_sam_eth_rx;
- sam_eth_device.parent.eth_tx = rt_sam_eth_tx;
- rt_sam_gmac_init(&sam_eth_device);
- /* register eth device */
- state = eth_device_init(&(sam_eth_device.parent), "e0");
- if (RT_EOK == state)
- {
- LOG_D("gmac device init success");
- }
- else
- {
- LOG_E("gmac device init faild: %d", state);
- state = -RT_ERROR;
- goto outs;
- }
- /* start SAM PHY monitor */
- #ifdef RT_USING_TIMER_SOFT
- sam_eth_device.phy_monitor_timer = rt_timer_create("phylnk",
- rt_sam_eth_monitor,
- (void *)&sam_eth_device,
- 10*RT_TICK_PER_SECOND,
- RT_TIMER_FLAG_PERIODIC);
- if (RT_NULL != sam_eth_device.phy_monitor_timer)
- {
- rt_timer_start(sam_eth_device.phy_monitor_timer);
- }
- else
- {
- state = -RT_ERROR;
- LOG_E("gmac rt_timer_create faild: %d", state);
- }
- #else
- sam_eth_device.phy_monitor_tid = rt_thread_create("phy",
- rt_sam_eth_monitor,
- (void *)&sam_eth_device,
- 1024,
- RT_THREAD_PRIORITY_MAX - 2,
- 2);
- if (sam_eth_device.phy_monitor_tid != RT_NULL)
- {
- rt_thread_startup(sam_eth_device.phy_monitor_tid);
- }
- else
- {
- state = -RT_ERROR;
- LOG_E("gmac rt_thread_create faild: %d", state);
- }
- #endif
- outs:
- return state;
- }
- INIT_DEVICE_EXPORT(rt_hw_sam_eth_init);
- #endif /* BSP_USING_ETH_ARTPI */
|