|
@@ -0,0 +1,717 @@
|
|
|
+/*
|
|
|
+* Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved.
|
|
|
+*/
|
|
|
+#include <rtthread.h>
|
|
|
+
|
|
|
+#include "dw_eth_mac.h"
|
|
|
+#include "cache.h"
|
|
|
+
|
|
|
+#define roundup(x, y) ( \
|
|
|
+{ \
|
|
|
+ const typeof(y) __y = y; \
|
|
|
+ (((x) + (__y - 1)) / __y) * __y; \
|
|
|
+} \
|
|
|
+)
|
|
|
+
|
|
|
+#define CONFIG_GMAC_NUM 2
|
|
|
+
|
|
|
+static gmac_dev_t gmac_instance[CONFIG_GMAC_NUM];
|
|
|
+
|
|
|
+static int32_t designware_read_hwaddr(eth_mac_handle_t handle)
|
|
|
+{
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
|
|
|
+ struct dw_gmac_mac_regs *mac_reg = mac_dev->priv->mac_regs_p;
|
|
|
+ uint32_t macid_lo, macid_hi;
|
|
|
+ uint8_t mac_id[6] = {0};
|
|
|
+
|
|
|
+ macid_hi = mac_reg->macaddr0hi;
|
|
|
+ macid_lo = mac_reg->macaddr0lo;
|
|
|
+
|
|
|
+ mac_id[0] = macid_lo & 0xff;
|
|
|
+ mac_id[1] = (macid_lo >> 8) & 0xff;
|
|
|
+ mac_id[2] = (macid_lo >> 16) & 0xff;
|
|
|
+ mac_id[3] = (macid_lo >> 24) & 0xff;
|
|
|
+ mac_id[4] = macid_hi & 0xff;
|
|
|
+ mac_id[5] = (macid_hi >> 8) & 0xff;
|
|
|
+
|
|
|
+ memcpy(mac_dev->mac_addr, mac_id, sizeof(mac_id));
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int32_t designware_write_hwaddr(eth_mac_handle_t handle)
|
|
|
+{
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
|
|
|
+ struct dw_gmac_mac_regs *mac_reg = mac_dev->priv->mac_regs_p;
|
|
|
+
|
|
|
+ uint32_t macid_lo, macid_hi;
|
|
|
+ uint8_t *mac_id = mac_dev->mac_addr;
|
|
|
+
|
|
|
+ macid_lo = mac_id[0] + (mac_id[1] << 8) + (mac_id[2] << 16) +
|
|
|
+ (mac_id[3] << 24);
|
|
|
+ macid_hi = mac_id[4] + (mac_id[5] << 8);
|
|
|
+
|
|
|
+ mac_reg->macaddr0hi = macid_hi;
|
|
|
+ mac_reg->macaddr0lo = macid_lo;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void tx_descs_init(eth_mac_handle_t handle)
|
|
|
+{
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
|
|
|
+ struct dw_gmac_priv *priv = mac_dev->priv;
|
|
|
+ struct dw_gmac_dma_regs *dma_reg = priv->dma_regs_p;
|
|
|
+ struct dmamacdescr *desc_table_p = &priv->tx_mac_descrtable[0];
|
|
|
+ char *txbuffs = &priv->txbuffs[0];
|
|
|
+ struct dmamacdescr *desc_p;
|
|
|
+ uint32_t idx;
|
|
|
+
|
|
|
+ for (idx = 0; idx < CVI_CONFIG_TX_DESCR_NUM; idx++) {
|
|
|
+ desc_p = &desc_table_p[idx];
|
|
|
+ desc_p->dmamac_addr = (unsigned long)&txbuffs[idx * CVI_CONFIG_ETH_BUFSIZE];
|
|
|
+ desc_p->dmamac_next = (unsigned long)&desc_table_p[idx + 1];
|
|
|
+
|
|
|
+#if defined(CONFIG_DW_ALTDESCRIPTOR)
|
|
|
+ desc_p->txrx_status &= ~(CVI_DESC_TXSTS_TXINT | CVI_DESC_TXSTS_TXLAST |
|
|
|
+ CVI_DESC_TXSTS_TXFIRST | CVI_DESC_TXSTS_TXCRCDIS |
|
|
|
+ CVI_DESC_TXSTS_TXCHECKINSCTRL |
|
|
|
+ CVI_DESC_TXSTS_TXRINGEND | CVI_DESC_TXSTS_TXPADDIS);
|
|
|
+
|
|
|
+ desc_p->txrx_status |= CVI_DESC_TXSTS_TXCHAIN;
|
|
|
+ desc_p->dmamac_cntl = 0;
|
|
|
+ desc_p->txrx_status &= ~(CVI_DESC_TXSTS_MSK | CVI_DESC_TXSTS_OWNBYDMA);
|
|
|
+#else
|
|
|
+ desc_p->dmamac_cntl = CVI_DESC_TXCTRL_TXCHAIN;
|
|
|
+ desc_p->txrx_status = 0;
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Correcting the last pointer of the chain */
|
|
|
+ desc_p->dmamac_next = (unsigned long)&desc_table_p[0];
|
|
|
+
|
|
|
+ /* Flush all Tx buffer descriptors at once */
|
|
|
+ rt_hw_cpu_dcache_clean((unsigned long)priv->tx_mac_descrtable, sizeof(priv->tx_mac_descrtable));
|
|
|
+
|
|
|
+ dma_reg->txdesclistaddr = (unsigned long)&desc_table_p[0];
|
|
|
+
|
|
|
+ priv->tx_currdescnum = 0;
|
|
|
+}
|
|
|
+
|
|
|
+static void rx_descs_init(eth_mac_handle_t handle)
|
|
|
+{
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
|
|
|
+ struct dw_gmac_priv *priv = mac_dev->priv;
|
|
|
+ struct dw_gmac_dma_regs *dma_reg = priv->dma_regs_p;
|
|
|
+ struct dmamacdescr *desc_table_p = &priv->rx_mac_descrtable[0];
|
|
|
+ char *rxbuffs = &priv->rxbuffs[0];
|
|
|
+ struct dmamacdescr *desc_p;
|
|
|
+ uint32_t idx;
|
|
|
+
|
|
|
+ /* Before passing buffers to GMAC we need to make sure zeros
|
|
|
+ * written there right after "priv" structure allocation were
|
|
|
+ * flushed into RAM.
|
|
|
+ * Otherwise there's a chance to get some of them flushed in RAM when
|
|
|
+ * GMAC is already pushing data to RAM via DMA. This way incoming from
|
|
|
+ * GMAC data will be corrupted. */
|
|
|
+ rt_hw_cpu_dcache_clean((unsigned long)rxbuffs, CVI_RX_TOTAL_BUFSIZE);
|
|
|
+
|
|
|
+ for (idx = 0; idx < CVI_CONFIG_RX_DESCR_NUM; idx++) {
|
|
|
+ desc_p = &desc_table_p[idx];
|
|
|
+ desc_p->dmamac_addr = (unsigned long)&rxbuffs[idx * CVI_CONFIG_ETH_BUFSIZE];
|
|
|
+ desc_p->dmamac_next = (unsigned long)&desc_table_p[idx + 1];
|
|
|
+
|
|
|
+ desc_p->dmamac_cntl =
|
|
|
+ (CVI_MAC_MAX_FRAME_SZ & CVI_DESC_RXCTRL_SIZE1MASK) |
|
|
|
+ CVI_DESC_RXCTRL_RXCHAIN;
|
|
|
+
|
|
|
+ desc_p->txrx_status = CVI_DESC_RXSTS_OWNBYDMA;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Correcting the last pointer of the chain */
|
|
|
+ desc_p->dmamac_next = (unsigned long)&desc_table_p[0];
|
|
|
+
|
|
|
+ /* Flush all Rx buffer descriptors at once */
|
|
|
+ rt_hw_cpu_dcache_clean((unsigned long)priv->rx_mac_descrtable, sizeof(priv->rx_mac_descrtable));
|
|
|
+
|
|
|
+ dma_reg->rxdesclistaddr = (unsigned long)&desc_table_p[0];
|
|
|
+
|
|
|
+ priv->rx_currdescnum = 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int32_t designware_adjust_link(eth_mac_handle_t handle)
|
|
|
+{
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
|
|
|
+ struct dw_gmac_priv *priv = mac_dev->priv;
|
|
|
+ struct dw_gmac_mac_regs *mac_reg = priv->mac_regs_p;
|
|
|
+ eth_link_info_t *link_info = &mac_dev->phy_dev->priv->link_info;
|
|
|
+ eth_link_state_t link_state = mac_dev->phy_dev->link_state;
|
|
|
+
|
|
|
+ uint32_t conf = mac_reg->conf | CVI_FRAMEBURSTENABLE | CVI_DISABLERXOWN;
|
|
|
+
|
|
|
+ if (!link_state) {
|
|
|
+ rt_kprintf("eth No link.\n");
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (link_info->speed != CSI_ETH_SPEED_1G)
|
|
|
+ conf |= CVI_MII_PORTSELECT;
|
|
|
+ else
|
|
|
+ conf &= ~CVI_MII_PORTSELECT;
|
|
|
+
|
|
|
+ if (link_info->speed == CSI_ETH_SPEED_100M)
|
|
|
+ conf |= CVI_FES_100;
|
|
|
+
|
|
|
+ if (link_info->duplex)
|
|
|
+ conf |= CVI_FULLDPLXMODE;
|
|
|
+
|
|
|
+ mac_reg->conf = conf;
|
|
|
+
|
|
|
+ rt_kprintf("Speed: %s, duplex: %s\n",
|
|
|
+ (link_info->speed) ? "100M" : "10M",
|
|
|
+ (link_info->duplex) ? "full" : "half");
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int32_t designware_eth_init(eth_mac_handle_t handle)
|
|
|
+{
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
|
|
|
+ struct dw_gmac_mac_regs *mac_reg = mac_dev->priv->mac_regs_p;
|
|
|
+ struct dw_gmac_dma_regs *dma_reg = mac_dev->priv->dma_regs_p;
|
|
|
+
|
|
|
+ uint32_t start;
|
|
|
+
|
|
|
+ dma_reg->busmode |= CVI_DMAMAC_SRST;
|
|
|
+
|
|
|
+ start = rt_tick_get_millisecond();
|
|
|
+ while (dma_reg->busmode & CVI_DMAMAC_SRST) {
|
|
|
+ if ((rt_tick_get_millisecond() - start) >= CVI_CONFIG_MACRESET_TIMEOUT) {
|
|
|
+ rt_kprintf("DMA reset timeout\n");
|
|
|
+ return -ETIMEDOUT;
|
|
|
+ }
|
|
|
+
|
|
|
+ rt_thread_mdelay(100);
|
|
|
+ };
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Soft reset above clears HW address registers.
|
|
|
+ * So we have to set it here once again.
|
|
|
+ */
|
|
|
+ // designware_read_hwaddr(handle);
|
|
|
+ // designware_write_hwaddr(handle);
|
|
|
+
|
|
|
+ rx_descs_init(handle);
|
|
|
+ tx_descs_init(handle);
|
|
|
+
|
|
|
+ dma_reg->busmode = (CVI_FIXEDBURST | CVI_PRIORXTX_41 | CVI_DMA_PBL);
|
|
|
+
|
|
|
+ // mac_reg->framefilt = 0x10;
|
|
|
+ // mac_reg->flowcontrol = 0x8;
|
|
|
+ // dma_reg->wdtforri = 0xff;
|
|
|
+ // dma_reg->axibus = 0x0012100F;
|
|
|
+
|
|
|
+#ifndef CONFIG_DW_MAC_FORCE_THRESHOLD_MODE
|
|
|
+ dma_reg->opmode |= (CVI_FLUSHTXFIFO | CVI_STOREFORWARD);
|
|
|
+#else
|
|
|
+ dma_reg->opmode |= CVI_FLUSHTXFIFO;
|
|
|
+#endif
|
|
|
+
|
|
|
+ dma_reg->opmode |= (CVI_RXSTART | CVI_TXSTART);
|
|
|
+ dma_reg->opmode = 0x2202906;
|
|
|
+ dma_reg->busmode = 0x3900800;
|
|
|
+ mac_reg->conf = 0x41cc00;
|
|
|
+ dma_reg->intenable = 0x10040;
|
|
|
+
|
|
|
+#ifdef CONFIG_DW_AXI_BURST_LEN
|
|
|
+ dma_reg->axibus = (CONFIG_DW_AXI_BURST_LEN & 0x1FF >> 1);
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Start up the PHY */
|
|
|
+ /* adjust link */
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int32_t designware_eth_enable(eth_mac_handle_t handle, int32_t control)
|
|
|
+{
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
|
|
|
+ struct dw_gmac_mac_regs *mac_reg = mac_dev->priv->mac_regs_p;
|
|
|
+ eth_link_state_t link_state = mac_dev->phy_dev->link_state;
|
|
|
+
|
|
|
+ if (link_state == ETH_LINK_DOWN)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ switch (control) {
|
|
|
+ case CSI_ETH_MAC_CONTROL_TX:
|
|
|
+ mac_reg->conf |= CVI_TXENABLE;
|
|
|
+ break;
|
|
|
+ case CSI_ETH_MAC_CONTROL_RX:
|
|
|
+ mac_reg->conf |= CVI_RXENABLE;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+static int32_t designware_eth_disable(eth_mac_handle_t handle, int32_t arg)
|
|
|
+{
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
|
|
|
+ struct dw_gmac_mac_regs *mac_reg = mac_dev->priv->mac_regs_p;
|
|
|
+
|
|
|
+ switch (arg) {
|
|
|
+ case CSI_ETH_MAC_CONTROL_TX:
|
|
|
+ mac_reg->conf &= ~CVI_TXENABLE;
|
|
|
+ break;
|
|
|
+ case CSI_ETH_MAC_CONTROL_RX:
|
|
|
+ mac_reg->conf &= ~CVI_RXENABLE;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int32_t designware_eth_start(eth_mac_handle_t handle)
|
|
|
+{
|
|
|
+ int32_t ret;
|
|
|
+
|
|
|
+ ret = designware_eth_init(handle);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+void designware_eth_stop(eth_mac_handle_t handle)
|
|
|
+{
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
|
|
|
+ struct dw_gmac_mac_regs *mac_reg = mac_dev->priv->mac_regs_p;
|
|
|
+ struct dw_gmac_dma_regs *dma_reg = mac_dev->priv->dma_regs_p;
|
|
|
+
|
|
|
+ mac_reg->conf &= ~(CVI_RXENABLE | CVI_TXENABLE);
|
|
|
+ dma_reg->opmode &= ~(CVI_RXSTART | CVI_TXSTART);
|
|
|
+
|
|
|
+ //phy_shutdown(priv->phydev);
|
|
|
+}
|
|
|
+
|
|
|
+static int32_t designware_eth_send(eth_mac_handle_t handle, const uint8_t *frame, uint32_t length)
|
|
|
+{
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
|
|
|
+ struct dw_gmac_priv *priv = mac_dev->priv;
|
|
|
+ struct dw_gmac_dma_regs *dma_reg = mac_dev->priv->dma_regs_p;
|
|
|
+ uint32_t desc_num = priv->tx_currdescnum;
|
|
|
+ struct dmamacdescr *desc_p = &priv->tx_mac_descrtable[desc_num];
|
|
|
+ uint64_t desc_start = (uint64_t)desc_p;
|
|
|
+ uint64_t desc_end = desc_start + roundup(sizeof(*desc_p), DW_GMAC_DMA_ALIGN);
|
|
|
+ uint64_t data_start = desc_p->dmamac_addr;
|
|
|
+ uint64_t data_end = data_start + roundup(length, DW_GMAC_DMA_ALIGN);
|
|
|
+ uint32_t count = 0;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Strictly we only need to invalidate the "txrx_status" field
|
|
|
+ * for the following check, but on some platforms we cannot
|
|
|
+ * invalidate only 4 bytes, so we flush the entire descriptor,
|
|
|
+ * which is 16 bytes in total. This is safe because the
|
|
|
+ * individual descriptors in the array are each aligned to
|
|
|
+ * DW_GMAC_DMA_ALIGN and padded appropriately.
|
|
|
+ */
|
|
|
+
|
|
|
+ /* Check if the descriptor is owned by CPU */
|
|
|
+ while (1) {
|
|
|
+ rt_hw_cpu_dcache_invalidate(desc_start, desc_end - desc_start);
|
|
|
+ if (!(desc_p->txrx_status & CVI_DESC_TXSTS_OWNBYDMA)) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (count > 1000) {
|
|
|
+ rt_kprintf("desc onwer is DMA\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ count ++;
|
|
|
+ rt_thread_mdelay(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ memcpy((void *)data_start, frame, length);
|
|
|
+
|
|
|
+ /* Flush data to be sent */
|
|
|
+ rt_hw_cpu_dcache_clean(data_start, data_end - data_start);
|
|
|
+
|
|
|
+#if defined(CONFIG_DW_ALTDESCRIPTOR)
|
|
|
+ desc_p->txrx_status |= CVI_DESC_TXSTS_TXFIRST | CVI_DESC_TXSTS_TXLAST;
|
|
|
+ desc_p->dmamac_cntl &= ~CVI_DESC_TXCTRL_SIZE1MASK;
|
|
|
+ desc_p->dmamac_cntl |= (length << CVI_DESC_TXCTRL_SIZE1SHFT) &
|
|
|
+ CVI_DESC_TXCTRL_SIZE1MASK;
|
|
|
+
|
|
|
+ desc_p->txrx_status &= ~(CVI_DESC_TXSTS_MSK);
|
|
|
+ desc_p->txrx_status |= CVI_DESC_TXSTS_OWNBYDMA;
|
|
|
+#else
|
|
|
+ desc_p->dmamac_cntl &= ~CVI_DESC_TXCTRL_SIZE1MASK;
|
|
|
+ desc_p->dmamac_cntl |= ((length << CVI_DESC_TXCTRL_SIZE1SHFT) &
|
|
|
+ CVI_DESC_TXCTRL_SIZE1MASK) | CVI_DESC_TXCTRL_TXLAST |
|
|
|
+ CVI_DESC_TXCTRL_TXFIRST;
|
|
|
+
|
|
|
+ desc_p->txrx_status = CVI_DESC_TXSTS_OWNBYDMA;
|
|
|
+#endif
|
|
|
+
|
|
|
+ /* Flush modified buffer descriptor */
|
|
|
+ rt_hw_cpu_dcache_clean(desc_start, desc_end - desc_start);
|
|
|
+
|
|
|
+ /* Test the wrap-around condition. */
|
|
|
+ if (++desc_num >= CVI_CONFIG_TX_DESCR_NUM)
|
|
|
+ desc_num = 0;
|
|
|
+
|
|
|
+ priv->tx_currdescnum = desc_num;
|
|
|
+
|
|
|
+ /* Start the transmission */
|
|
|
+ dma_reg->txpolldemand = CVI_POLL_DATA;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int32_t designware_eth_recv(eth_mac_handle_t handle, uint8_t **packetp)
|
|
|
+{
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
|
|
|
+ struct dw_gmac_priv *priv = mac_dev->priv;
|
|
|
+ uint32_t status, desc_num = priv->rx_currdescnum;
|
|
|
+ struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
|
|
|
+ int32_t length = -1;
|
|
|
+ uint64_t desc_start = (uint64_t)desc_p;
|
|
|
+ uint64_t desc_end = desc_start +
|
|
|
+ roundup(sizeof(*desc_p), DW_GMAC_DMA_ALIGN);
|
|
|
+ uint64_t data_start = desc_p->dmamac_addr;
|
|
|
+ uint64_t data_end;
|
|
|
+
|
|
|
+ /* Invalidate entire buffer descriptor */
|
|
|
+ rt_hw_cpu_dcache_invalidate(desc_start, desc_end - desc_start);
|
|
|
+ status = desc_p->txrx_status;
|
|
|
+ /* Check if the owner is the CPU */
|
|
|
+ if (!(status & CVI_DESC_RXSTS_OWNBYDMA)) {
|
|
|
+ length = (status & CVI_DESC_RXSTS_FRMLENMSK) >>
|
|
|
+ CVI_DESC_RXSTS_FRMLENSHFT;
|
|
|
+ /* Invalidate received data */
|
|
|
+ data_end = data_start + roundup(length, DW_GMAC_DMA_ALIGN);
|
|
|
+ rt_hw_cpu_dcache_invalidate(data_start, data_end - data_start);
|
|
|
+ *packetp = (uint8_t *)((uint64_t)desc_p->dmamac_addr);
|
|
|
+ }
|
|
|
+
|
|
|
+ return length;
|
|
|
+}
|
|
|
+
|
|
|
+static int32_t designware_free_pkt(eth_mac_handle_t handle)
|
|
|
+{
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
|
|
|
+ struct dw_gmac_priv *priv = mac_dev->priv;
|
|
|
+ uint32_t desc_num = priv->rx_currdescnum;
|
|
|
+ struct dmamacdescr *desc_p = &priv->rx_mac_descrtable[desc_num];
|
|
|
+ uint64_t desc_start = (uint64_t)desc_p;
|
|
|
+ uint64_t desc_end = desc_start +
|
|
|
+ roundup(sizeof(*desc_p), DW_GMAC_DMA_ALIGN);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Make the current descriptor valid again and go to
|
|
|
+ * the next one
|
|
|
+ */
|
|
|
+ desc_p->txrx_status |= CVI_DESC_RXSTS_OWNBYDMA;
|
|
|
+
|
|
|
+ /* Flush only status field - others weren't changed */
|
|
|
+ rt_hw_cpu_dcache_clean(desc_start, desc_end - desc_start);
|
|
|
+
|
|
|
+ /* Test the wrap-around condition. */
|
|
|
+ if (++desc_num >= CVI_CONFIG_RX_DESCR_NUM)
|
|
|
+ desc_num = 0;
|
|
|
+ priv->rx_currdescnum = desc_num;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ \brief Connect phy device to mac device.
|
|
|
+ \param[in] handle_mac mac handle
|
|
|
+ \param[in] handle_phy phy handle
|
|
|
+*/
|
|
|
+void dw_eth_mac_connect_phy(eth_mac_handle_t handle_mac, eth_phy_handle_t handle_phy)
|
|
|
+{
|
|
|
+ RT_ASSERT(handle_mac);
|
|
|
+ RT_ASSERT(handle_phy);
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle_mac;
|
|
|
+ eth_phy_dev_t *phy_dev = (eth_phy_dev_t *)handle_phy;
|
|
|
+
|
|
|
+ mac_dev->phy_dev = phy_dev;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ \brief Read Ethernet PHY Register through Management Interface.
|
|
|
+ \param[in] handle ethernet handle
|
|
|
+ \param[in] phy_addr 5-bit device address
|
|
|
+ \param[in] reg_addr 5-bit register address
|
|
|
+ \param[out] data Pointer where the result is written to
|
|
|
+ \return error code
|
|
|
+*/
|
|
|
+int32_t dw_eth_mac_phy_read(eth_mac_handle_t handle, uint8_t phy_addr, uint8_t reg_addr, uint16_t *data)
|
|
|
+{
|
|
|
+ RT_ASSERT(handle);
|
|
|
+ RT_ASSERT(data);
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
|
|
|
+ struct dw_gmac_priv *priv = mac_dev->priv;
|
|
|
+ struct dw_gmac_mac_regs *mac_reg = priv->mac_regs_p;
|
|
|
+ uint16_t miiaddr;
|
|
|
+ int32_t start;
|
|
|
+
|
|
|
+ miiaddr = ((phy_addr << CVI_MIIADDRSHIFT) & CVI_MII_ADDRMSK) |
|
|
|
+ ((reg_addr << CVI_MIIREGSHIFT) & CVI_MII_REGMSK);
|
|
|
+
|
|
|
+ mac_reg->miiaddr = (miiaddr | CVI_MII_CLKRANGE_150_250M | CVI_MII_BUSY);
|
|
|
+
|
|
|
+ start = rt_tick_get_millisecond();
|
|
|
+ while ((rt_tick_get_millisecond() - start) < CVI_CONFIG_MDIO_TIMEOUT) {
|
|
|
+ if (!(mac_reg->miiaddr & CVI_MII_BUSY)) {
|
|
|
+ *data = mac_reg->miidata;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ rt_hw_us_delay(10);
|
|
|
+ };
|
|
|
+
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ \brief Write Ethernet PHY Register through Management Interface.
|
|
|
+ \param[in] handle ethernet handle
|
|
|
+ \param[in] phy_addr 5-bit device address
|
|
|
+ \param[in] reg_addr 5-bit register address
|
|
|
+ \param[in] data 16-bit data to write
|
|
|
+ \return error code
|
|
|
+*/
|
|
|
+int32_t dw_eth_mac_phy_write(eth_mac_handle_t handle, uint8_t phy_addr, uint8_t reg_addr, uint16_t data)
|
|
|
+{
|
|
|
+ RT_ASSERT(handle);
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
|
|
|
+ struct dw_gmac_priv *priv = mac_dev->priv;
|
|
|
+ struct dw_gmac_mac_regs *mac_reg = priv->mac_regs_p;
|
|
|
+ uint16_t miiaddr;
|
|
|
+ int32_t start;
|
|
|
+
|
|
|
+ mac_reg->miidata = data;
|
|
|
+ miiaddr = ((phy_addr << CVI_MIIADDRSHIFT) & CVI_MII_ADDRMSK) |
|
|
|
+ ((reg_addr << CVI_MIIREGSHIFT) & CVI_MII_REGMSK) | CVI_MII_WRITE;
|
|
|
+
|
|
|
+ mac_reg->miiaddr = (miiaddr | CVI_MII_CLKRANGE_150_250M | CVI_MII_BUSY);
|
|
|
+
|
|
|
+ start = rt_tick_get_millisecond();
|
|
|
+ while ((rt_tick_get_millisecond() - start) < CVI_CONFIG_MDIO_TIMEOUT) {
|
|
|
+ if (!(mac_reg->miiaddr & CVI_MII_BUSY)) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ rt_hw_us_delay(10);
|
|
|
+ };
|
|
|
+
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ \brief Control Ethernet Interface.
|
|
|
+ \param[in] handle ethernet handle
|
|
|
+ \param[in] control Operation
|
|
|
+ \param[in] arg Argument of operation (optional)
|
|
|
+ \return error code
|
|
|
+*/
|
|
|
+int32_t cvi_eth_mac_control(eth_mac_handle_t handle, uint32_t control, uint32_t arg)
|
|
|
+{
|
|
|
+ RT_ASSERT(handle);
|
|
|
+
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
|
|
|
+ int32_t ret = 0;
|
|
|
+
|
|
|
+ RT_ASSERT(mac_dev->phy_dev);
|
|
|
+
|
|
|
+ switch (control) {
|
|
|
+ case CSI_ETH_MAC_CONFIGURE:
|
|
|
+ if (arg) {
|
|
|
+ /* startup mac */
|
|
|
+ ret = designware_eth_start(handle);
|
|
|
+ } else {
|
|
|
+ /* stop mac */
|
|
|
+ designware_eth_stop(handle);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case DRV_ETH_MAC_ADJUST_LINK:
|
|
|
+ ret = designware_adjust_link(handle);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case CSI_ETH_MAC_CONTROL_TX:
|
|
|
+ if (arg) {
|
|
|
+ /* enable TX */
|
|
|
+ ret = designware_eth_enable(handle, CSI_ETH_MAC_CONTROL_TX);
|
|
|
+ } else {
|
|
|
+ /* disable TX */
|
|
|
+ ret = designware_eth_disable(handle, CSI_ETH_MAC_CONTROL_TX);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case CSI_ETH_MAC_CONTROL_RX:
|
|
|
+ if (arg) {
|
|
|
+ /* enable RX */
|
|
|
+ ret = designware_eth_enable(handle, CSI_ETH_MAC_CONTROL_RX);
|
|
|
+ } else {
|
|
|
+ /* disable RX */
|
|
|
+ ret = designware_eth_disable(handle, CSI_ETH_MAC_CONTROL_RX);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case DRV_ETH_MAC_CONTROL_IRQ:
|
|
|
+ if (arg) {
|
|
|
+ /* enable interrupt */
|
|
|
+ } else {
|
|
|
+ /* disable interrupt */
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ };
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ \brief Get Ethernet MAC Address.
|
|
|
+ \param[in] handle ethernet handle
|
|
|
+ \param[in] mac Pointer to address
|
|
|
+ \return error code
|
|
|
+*/
|
|
|
+int32_t cvi_eth_mac_get_macaddr(eth_mac_handle_t handle, eth_mac_addr_t *mac)
|
|
|
+{
|
|
|
+ RT_ASSERT(handle);
|
|
|
+ RT_ASSERT(mac);
|
|
|
+
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
|
|
|
+
|
|
|
+ designware_read_hwaddr(handle);
|
|
|
+
|
|
|
+ memcpy(mac->b, mac_dev->mac_addr, sizeof(mac_dev->mac_addr));
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ \brief Set Ethernet MAC Address.
|
|
|
+ \param[in] handle ethernet handle
|
|
|
+ \param[in] mac Pointer to address
|
|
|
+ \return error code
|
|
|
+*/
|
|
|
+int32_t cvi_eth_mac_set_macaddr(eth_mac_handle_t handle, const eth_mac_addr_t *mac)
|
|
|
+{
|
|
|
+ RT_ASSERT(handle);
|
|
|
+ RT_ASSERT(mac);
|
|
|
+
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
|
|
|
+ memcpy(mac_dev->mac_addr, mac->b, sizeof(mac->b));
|
|
|
+
|
|
|
+ designware_write_hwaddr(handle);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ \brief Send Ethernet frame.
|
|
|
+ \param[in] handle ethernet handle
|
|
|
+ \param[in] frame Pointer to frame buffer with data to send
|
|
|
+ \param[in] len Frame buffer length in bytes
|
|
|
+ \param[in] flags Frame transmit flags (see CSI_ETH_MAC_TX_FRAME_...)
|
|
|
+ \return error code
|
|
|
+*/
|
|
|
+int32_t cvi_eth_mac_send_frame(eth_mac_handle_t handle, const uint8_t *frame, uint32_t len, uint32_t flags)
|
|
|
+{
|
|
|
+ RT_ASSERT(handle);
|
|
|
+ RT_ASSERT(frame);
|
|
|
+
|
|
|
+ return designware_eth_send(handle, frame, len);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ \brief Read data of received Ethernet frame.
|
|
|
+ \param[in] handle ethernet handle
|
|
|
+ \param[in] frame Pointer to frame buffer for data to read into
|
|
|
+ \param[in] len Frame buffer length in bytes
|
|
|
+ \return number of data bytes read or execution status
|
|
|
+ - value >= 0: number of data bytes read
|
|
|
+ - value < 0: error occurred, value is execution status as defined with execution_status
|
|
|
+*/
|
|
|
+int32_t cvi_eth_mac_read_frame(eth_mac_handle_t handle, uint8_t *frame, uint32_t len)
|
|
|
+{
|
|
|
+ RT_ASSERT(handle);
|
|
|
+ RT_ASSERT(frame);
|
|
|
+
|
|
|
+ uint8_t *packet = NULL;
|
|
|
+ int32_t actual_length;
|
|
|
+
|
|
|
+ actual_length = designware_eth_recv(handle, &packet);
|
|
|
+
|
|
|
+ if (actual_length < 0) {
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* process received packet */
|
|
|
+ actual_length = (actual_length > len) ? len : actual_length;
|
|
|
+
|
|
|
+ if (packet != NULL) {
|
|
|
+ memcpy(frame, packet, actual_length);
|
|
|
+ }
|
|
|
+
|
|
|
+ designware_free_pkt(handle);
|
|
|
+
|
|
|
+ return actual_length;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ \brief This function is used to initialize Ethernet device and register an event callback.
|
|
|
+ \param[in] idx device id
|
|
|
+ \param[in] cb callback to handle ethernet event
|
|
|
+ \return return ethernet handle if success
|
|
|
+ */
|
|
|
+eth_mac_handle_t cvi_eth_mac_init(unsigned int base)
|
|
|
+{
|
|
|
+ gmac_dev_t *mac_dev = &gmac_instance[0];
|
|
|
+ struct dw_gmac_priv *priv, *priv_unalign;
|
|
|
+
|
|
|
+ mac_dev->base = (unsigned long)base;
|
|
|
+ // mac_dev->irq = (uint8_t)DW_MAC_IRQ;
|
|
|
+ // mac_dev->cb_event = cb_event;
|
|
|
+
|
|
|
+ priv = memalign(DW_GMAC_DMA_ALIGN, sizeof(struct dw_gmac_priv), (void **)&priv_unalign);
|
|
|
+ if (!priv)
|
|
|
+ {
|
|
|
+ rt_kprintf("malloc fail\n");
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ memset(priv_unalign, 0, sizeof(struct dw_gmac_priv) + DW_GMAC_DMA_ALIGN);
|
|
|
+
|
|
|
+ priv->mac_regs_p = (struct dw_gmac_mac_regs *)mac_dev->base;
|
|
|
+ priv->dma_regs_p = (struct dw_gmac_dma_regs *)(mac_dev->base + CVI_DW_DMA_BASE_OFFSET);
|
|
|
+
|
|
|
+ mac_dev->priv_unalign = priv_unalign;
|
|
|
+ mac_dev->priv = priv;
|
|
|
+
|
|
|
+ return (eth_mac_handle_t)mac_dev;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ \brief This function is used to de-initialize Ethernet device.
|
|
|
+ \param[in] handle ethernet handle
|
|
|
+ \return error code
|
|
|
+ */
|
|
|
+void de_eth_gmac_deinit(eth_mac_handle_t handle)
|
|
|
+{
|
|
|
+ RT_ASSERT(handle);
|
|
|
+ gmac_dev_t *mac_dev = (gmac_dev_t *)handle;
|
|
|
+
|
|
|
+ if (mac_dev->priv_unalign)
|
|
|
+ {
|
|
|
+ rt_free(mac_dev->priv_unalign);
|
|
|
+ mac_dev->priv_unalign = RT_NULL;
|
|
|
+ }
|
|
|
+}
|