[bsp/cvitek]add eth driver
This commit is contained in:
parent
b586889216
commit
7890e2cb14
|
@ -64,6 +64,7 @@ $ scons
|
|||
| timer | 支持 | |
|
||||
| wdt | 支持 | |
|
||||
| sdio | 支持 | |
|
||||
| eth | 支持 | |
|
||||
|
||||
## 支持开发板
|
||||
- milk-v duo: [https://milkv.io/duo](https://milkv.io/duo)
|
||||
|
|
|
@ -108,7 +108,7 @@ CONFIG_RT_USING_FINSH=y
|
|||
CONFIG_FINSH_USING_MSH=y
|
||||
CONFIG_FINSH_THREAD_NAME="tshell"
|
||||
CONFIG_FINSH_THREAD_PRIORITY=20
|
||||
CONFIG_FINSH_THREAD_STACK_SIZE=4096
|
||||
CONFIG_FINSH_THREAD_STACK_SIZE=8192
|
||||
CONFIG_FINSH_USING_HISTORY=y
|
||||
CONFIG_FINSH_HISTORY_LINES=5
|
||||
CONFIG_FINSH_USING_SYMTAB=y
|
||||
|
@ -196,9 +196,9 @@ CONFIG_RT_USING_RTC=y
|
|||
# CONFIG_RT_USING_ALARM is not set
|
||||
# CONFIG_RT_USING_SOFT_RTC is not set
|
||||
CONFIG_RT_USING_SDIO=y
|
||||
CONFIG_RT_SDIO_STACK_SIZE=4096
|
||||
CONFIG_RT_SDIO_STACK_SIZE=8192
|
||||
CONFIG_RT_SDIO_THREAD_PRIORITY=15
|
||||
CONFIG_RT_MMCSD_STACK_SIZE=4096
|
||||
CONFIG_RT_MMCSD_STACK_SIZE=8192
|
||||
CONFIG_RT_MMCSD_THREAD_PREORITY=22
|
||||
CONFIG_RT_MMCSD_MAX_PARTITION=16
|
||||
# CONFIG_RT_SDIO_DEBUG is not set
|
||||
|
@ -252,10 +252,10 @@ CONFIG_RT_USING_POSIX_FS=y
|
|||
CONFIG_RT_USING_POSIX_DEVIO=y
|
||||
CONFIG_RT_USING_POSIX_STDIO=y
|
||||
CONFIG_RT_USING_POSIX_POLL=y
|
||||
# CONFIG_RT_USING_POSIX_SELECT is not set
|
||||
CONFIG_RT_USING_POSIX_SELECT=y
|
||||
# CONFIG_RT_USING_POSIX_EVENTFD is not set
|
||||
# CONFIG_RT_USING_POSIX_TIMERFD is not set
|
||||
# CONFIG_RT_USING_POSIX_SOCKET is not set
|
||||
CONFIG_RT_USING_POSIX_SOCKET=y
|
||||
CONFIG_RT_USING_POSIX_TERMIOS=y
|
||||
# CONFIG_RT_USING_POSIX_AIO is not set
|
||||
# CONFIG_RT_USING_POSIX_MMAN is not set
|
||||
|
@ -284,9 +284,87 @@ CONFIG_RT_USING_POSIX_TIMER=y
|
|||
#
|
||||
# Network
|
||||
#
|
||||
# CONFIG_RT_USING_SAL is not set
|
||||
# CONFIG_RT_USING_NETDEV is not set
|
||||
# CONFIG_RT_USING_LWIP is not set
|
||||
CONFIG_RT_USING_SAL=y
|
||||
CONFIG_SAL_INTERNET_CHECK=y
|
||||
|
||||
#
|
||||
# Docking with protocol stacks
|
||||
#
|
||||
CONFIG_SAL_USING_LWIP=y
|
||||
# CONFIG_SAL_USING_AT is not set
|
||||
# CONFIG_SAL_USING_TLS is not set
|
||||
# end of Docking with protocol stacks
|
||||
|
||||
CONFIG_SAL_USING_POSIX=y
|
||||
CONFIG_RT_USING_NETDEV=y
|
||||
CONFIG_NETDEV_USING_IFCONFIG=y
|
||||
CONFIG_NETDEV_USING_PING=y
|
||||
CONFIG_NETDEV_USING_NETSTAT=y
|
||||
CONFIG_NETDEV_USING_AUTO_DEFAULT=y
|
||||
# CONFIG_NETDEV_USING_IPV6 is not set
|
||||
CONFIG_NETDEV_IPV4=1
|
||||
CONFIG_NETDEV_IPV6=0
|
||||
CONFIG_RT_USING_LWIP=y
|
||||
# CONFIG_RT_USING_LWIP_LOCAL_VERSION is not set
|
||||
# CONFIG_RT_USING_LWIP141 is not set
|
||||
# CONFIG_RT_USING_LWIP203 is not set
|
||||
CONFIG_RT_USING_LWIP212=y
|
||||
# CONFIG_RT_USING_LWIP_LATEST is not set
|
||||
CONFIG_RT_USING_LWIP_VER_NUM=0x20102
|
||||
# CONFIG_RT_USING_LWIP_IPV6 is not set
|
||||
CONFIG_RT_LWIP_MEM_ALIGNMENT=8
|
||||
CONFIG_RT_LWIP_IGMP=y
|
||||
CONFIG_RT_LWIP_ICMP=y
|
||||
# CONFIG_RT_LWIP_SNMP is not set
|
||||
CONFIG_RT_LWIP_DNS=y
|
||||
CONFIG_RT_LWIP_DHCP=y
|
||||
CONFIG_IP_SOF_BROADCAST=1
|
||||
CONFIG_IP_SOF_BROADCAST_RECV=1
|
||||
|
||||
#
|
||||
# Static IPv4 Address
|
||||
#
|
||||
CONFIG_RT_LWIP_IPADDR="192.168.1.30"
|
||||
CONFIG_RT_LWIP_GWADDR="192.168.1.1"
|
||||
CONFIG_RT_LWIP_MSKADDR="255.255.255.0"
|
||||
# end of Static IPv4 Address
|
||||
|
||||
CONFIG_RT_LWIP_UDP=y
|
||||
CONFIG_RT_LWIP_TCP=y
|
||||
CONFIG_RT_LWIP_RAW=y
|
||||
# CONFIG_RT_LWIP_PPP is not set
|
||||
CONFIG_RT_MEMP_NUM_NETCONN=8
|
||||
CONFIG_RT_LWIP_PBUF_NUM=16
|
||||
CONFIG_RT_LWIP_RAW_PCB_NUM=4
|
||||
CONFIG_RT_LWIP_UDP_PCB_NUM=4
|
||||
CONFIG_RT_LWIP_TCP_PCB_NUM=4
|
||||
CONFIG_RT_LWIP_TCP_SEG_NUM=40
|
||||
CONFIG_RT_LWIP_TCP_SND_BUF=8196
|
||||
CONFIG_RT_LWIP_TCP_WND=8196
|
||||
CONFIG_RT_LWIP_TCPTHREAD_PRIORITY=10
|
||||
CONFIG_RT_LWIP_TCPTHREAD_MBOX_SIZE=8
|
||||
CONFIG_RT_LWIP_TCPTHREAD_STACKSIZE=8192
|
||||
# CONFIG_LWIP_NO_RX_THREAD is not set
|
||||
# CONFIG_LWIP_NO_TX_THREAD is not set
|
||||
CONFIG_RT_LWIP_ETHTHREAD_PRIORITY=12
|
||||
CONFIG_RT_LWIP_ETHTHREAD_STACKSIZE=8192
|
||||
CONFIG_RT_LWIP_ETHTHREAD_MBOX_SIZE=8
|
||||
# CONFIG_RT_LWIP_REASSEMBLY_FRAG is not set
|
||||
CONFIG_LWIP_NETIF_STATUS_CALLBACK=1
|
||||
CONFIG_LWIP_NETIF_LINK_CALLBACK=1
|
||||
CONFIG_RT_LWIP_NETIF_NAMESIZE=6
|
||||
CONFIG_SO_REUSE=1
|
||||
CONFIG_LWIP_SO_RCVTIMEO=1
|
||||
CONFIG_LWIP_SO_SNDTIMEO=1
|
||||
CONFIG_LWIP_SO_RCVBUF=1
|
||||
CONFIG_LWIP_SO_LINGER=0
|
||||
# CONFIG_RT_LWIP_NETIF_LOOPBACK is not set
|
||||
CONFIG_LWIP_NETIF_LOOPBACK=0
|
||||
# CONFIG_RT_LWIP_STATS is not set
|
||||
# CONFIG_RT_LWIP_USING_HW_CHECKSUM is not set
|
||||
CONFIG_RT_LWIP_USING_PING=y
|
||||
# CONFIG_LWIP_USING_DHCPD is not set
|
||||
# CONFIG_RT_LWIP_DEBUG is not set
|
||||
# CONFIG_RT_USING_AT is not set
|
||||
# end of Network
|
||||
|
||||
|
@ -1205,6 +1283,7 @@ CONFIG_UART_IRQ_BASE=44
|
|||
# CONFIG_BSP_USING_SPI is not set
|
||||
# CONFIG_BSP_USING_PWM is not set
|
||||
# CONFIG_BSP_USING_SDH is not set
|
||||
# CONFIG_BSP_USING_ETH is not set
|
||||
# end of General Drivers Configuration
|
||||
|
||||
CONFIG_BSP_USING_CV18XX=y
|
||||
|
|
|
@ -73,5 +73,11 @@ menu "General Drivers Configuration"
|
|||
select RT_USING_DFS_ROMFS
|
||||
bool "Enable Secure Digital Host Controller"
|
||||
default n
|
||||
|
||||
|
||||
config BSP_USING_ETH
|
||||
bool "Enable Ethernet"
|
||||
default n
|
||||
select RT_USING_LWIP
|
||||
select RT_USING_POSIX_FS
|
||||
select RT_USING_POSIX_SOCKET
|
||||
endmenu
|
||||
|
|
|
@ -74,7 +74,7 @@
|
|||
#define FINSH_USING_MSH
|
||||
#define FINSH_THREAD_NAME "tshell"
|
||||
#define FINSH_THREAD_PRIORITY 20
|
||||
#define FINSH_THREAD_STACK_SIZE 4096
|
||||
#define FINSH_THREAD_STACK_SIZE 8192
|
||||
#define FINSH_USING_HISTORY
|
||||
#define FINSH_HISTORY_LINES 5
|
||||
#define FINSH_USING_SYMTAB
|
||||
|
@ -127,9 +127,9 @@
|
|||
#define RT_USING_RANDOM
|
||||
#define RT_USING_RTC
|
||||
#define RT_USING_SDIO
|
||||
#define RT_SDIO_STACK_SIZE 4096
|
||||
#define RT_SDIO_STACK_SIZE 8192
|
||||
#define RT_SDIO_THREAD_PRIORITY 15
|
||||
#define RT_MMCSD_STACK_SIZE 4096
|
||||
#define RT_MMCSD_STACK_SIZE 8192
|
||||
#define RT_MMCSD_THREAD_PREORITY 22
|
||||
#define RT_MMCSD_MAX_PARTITION 16
|
||||
#define RT_USING_PIN
|
||||
|
@ -159,6 +159,8 @@
|
|||
#define RT_USING_POSIX_DEVIO
|
||||
#define RT_USING_POSIX_STDIO
|
||||
#define RT_USING_POSIX_POLL
|
||||
#define RT_USING_POSIX_SELECT
|
||||
#define RT_USING_POSIX_SOCKET
|
||||
#define RT_USING_POSIX_TERMIOS
|
||||
#define RT_USING_POSIX_DELAY
|
||||
#define RT_USING_POSIX_CLOCK
|
||||
|
@ -175,6 +177,65 @@
|
|||
|
||||
/* Network */
|
||||
|
||||
#define RT_USING_SAL
|
||||
#define SAL_INTERNET_CHECK
|
||||
|
||||
/* Docking with protocol stacks */
|
||||
|
||||
#define SAL_USING_LWIP
|
||||
/* end of Docking with protocol stacks */
|
||||
#define SAL_USING_POSIX
|
||||
#define RT_USING_NETDEV
|
||||
#define NETDEV_USING_IFCONFIG
|
||||
#define NETDEV_USING_PING
|
||||
#define NETDEV_USING_NETSTAT
|
||||
#define NETDEV_USING_AUTO_DEFAULT
|
||||
#define NETDEV_IPV4 1
|
||||
#define NETDEV_IPV6 0
|
||||
#define RT_USING_LWIP
|
||||
#define RT_USING_LWIP212
|
||||
#define RT_USING_LWIP_VER_NUM 0x20102
|
||||
#define RT_LWIP_MEM_ALIGNMENT 8
|
||||
#define RT_LWIP_IGMP
|
||||
#define RT_LWIP_ICMP
|
||||
#define RT_LWIP_DNS
|
||||
#define RT_LWIP_DHCP
|
||||
#define IP_SOF_BROADCAST 1
|
||||
#define IP_SOF_BROADCAST_RECV 1
|
||||
|
||||
/* Static IPv4 Address */
|
||||
|
||||
#define RT_LWIP_IPADDR "192.168.1.30"
|
||||
#define RT_LWIP_GWADDR "192.168.1.1"
|
||||
#define RT_LWIP_MSKADDR "255.255.255.0"
|
||||
/* end of Static IPv4 Address */
|
||||
#define RT_LWIP_UDP
|
||||
#define RT_LWIP_TCP
|
||||
#define RT_LWIP_RAW
|
||||
#define RT_MEMP_NUM_NETCONN 8
|
||||
#define RT_LWIP_PBUF_NUM 16
|
||||
#define RT_LWIP_RAW_PCB_NUM 4
|
||||
#define RT_LWIP_UDP_PCB_NUM 4
|
||||
#define RT_LWIP_TCP_PCB_NUM 4
|
||||
#define RT_LWIP_TCP_SEG_NUM 40
|
||||
#define RT_LWIP_TCP_SND_BUF 8196
|
||||
#define RT_LWIP_TCP_WND 8196
|
||||
#define RT_LWIP_TCPTHREAD_PRIORITY 10
|
||||
#define RT_LWIP_TCPTHREAD_MBOX_SIZE 8
|
||||
#define RT_LWIP_TCPTHREAD_STACKSIZE 8192
|
||||
#define RT_LWIP_ETHTHREAD_PRIORITY 12
|
||||
#define RT_LWIP_ETHTHREAD_STACKSIZE 8192
|
||||
#define RT_LWIP_ETHTHREAD_MBOX_SIZE 8
|
||||
#define LWIP_NETIF_STATUS_CALLBACK 1
|
||||
#define LWIP_NETIF_LINK_CALLBACK 1
|
||||
#define RT_LWIP_NETIF_NAMESIZE 6
|
||||
#define SO_REUSE 1
|
||||
#define LWIP_SO_RCVTIMEO 1
|
||||
#define LWIP_SO_SNDTIMEO 1
|
||||
#define LWIP_SO_RCVBUF 1
|
||||
#define LWIP_SO_LINGER 0
|
||||
#define LWIP_NETIF_LOOPBACK 0
|
||||
#define RT_LWIP_USING_PING
|
||||
/* end of Network */
|
||||
|
||||
/* Memory protection */
|
||||
|
|
|
@ -41,6 +41,16 @@ if GetDepend('BSP_USING_SDH'):
|
|||
src += ['drv_sdhci.c', 'port/mnt.c']
|
||||
CPPPATH += [cwd + r'/libraries/sdif']
|
||||
|
||||
|
||||
if GetDepend('BSP_USING_ETH'):
|
||||
src += Split('''
|
||||
drv_eth.c
|
||||
libraries/eth/dw_eth_mac.c
|
||||
libraries/eth/cvi_eth_phy.c
|
||||
libraries/eth/eth_phy_cvitek.c
|
||||
''')
|
||||
CPPPATH += [cwd + r'/libraries/eth']
|
||||
|
||||
CPPDEFINES += ['-DCONFIG_64BIT']
|
||||
|
||||
if GetDepend('BSP_USING_RTC'):
|
||||
|
|
|
@ -0,0 +1,411 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024/04/25 flyingcys first version
|
||||
*/
|
||||
#include <rthw.h>
|
||||
#include <rtthread.h>
|
||||
#include <rtdevice.h>
|
||||
|
||||
#include "board.h"
|
||||
|
||||
#define DBG_TAG "drv.eth"
|
||||
#define DBG_LEVEL DBG_INFO
|
||||
#include <rtdbg.h>
|
||||
|
||||
#include <lwip/sys.h>
|
||||
#include <netif/ethernetif.h>
|
||||
|
||||
#include "drv_eth.h"
|
||||
|
||||
|
||||
// #define ETH_TX_DUMP
|
||||
// #define ETH_RX_DUMP
|
||||
|
||||
#define MAX_ADDR_LEN 6
|
||||
|
||||
struct _dw_eth
|
||||
{
|
||||
rt_uint32_t *base;
|
||||
rt_uint32_t irq;
|
||||
|
||||
struct eth_device parent; /* inherit from ethernet device */
|
||||
|
||||
rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* interface address info, hw address */
|
||||
|
||||
struct rt_semaphore rx_sem;
|
||||
};
|
||||
static struct _dw_eth dw_eth_device = {0};
|
||||
|
||||
#define GMAC_BUF_LEN (1500 + 20)
|
||||
static uint8_t g_mac_addr[6] = {0xf2, 0x42, 0x9f, 0xa5, 0x0a, 0x72};
|
||||
static uint8_t g_mac_phy_init_finish = 0;
|
||||
static eth_mac_handle_t g_mac_handle;
|
||||
static eth_phy_handle_t g_phy_handle;
|
||||
|
||||
static uint8_t SendDataBuf[GMAC_BUF_LEN];
|
||||
static uint8_t RecvDataBuf[GMAC_BUF_LEN];
|
||||
|
||||
static void cvi_ephy_id_init(void)
|
||||
{
|
||||
// set rg_ephy_apb_rw_sel 0x0804@[0]=1/APB by using APB interface
|
||||
mmio_write_32(0x03009804, 0x0001);
|
||||
|
||||
// Release 0x0800[0]=0/shutdown
|
||||
mmio_write_32(0x03009800, 0x0900);
|
||||
|
||||
// Release 0x0800[2]=1/dig_rst_n, Let mii_reg can be accessabile
|
||||
mmio_write_32(0x03009800, 0x0904);
|
||||
|
||||
// PHY_ID
|
||||
mmio_write_32(0x03009008, 0x0043);
|
||||
mmio_write_32(0x0300900c, 0x5649);
|
||||
|
||||
// switch to MDIO control by ETH_MAC
|
||||
mmio_write_32(0x03009804, 0x0000);
|
||||
}
|
||||
|
||||
static int cvi_eth_mac_phy_enable(uint32_t enable)
|
||||
{
|
||||
eth_mac_addr_t addr;
|
||||
int32_t ret;
|
||||
|
||||
if ((g_mac_phy_init_finish == 0) && enable)
|
||||
{
|
||||
/* startup mac */
|
||||
ret = cvi_eth_mac_control(g_mac_handle, CSI_ETH_MAC_CONFIGURE, 1);
|
||||
if (ret != 0)
|
||||
{
|
||||
LOG_E("Failed to control mac");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Start up the PHY */
|
||||
ret = cvi_eth_phy_power_control(g_phy_handle, CSI_ETH_POWER_FULL);
|
||||
if (ret != 0)
|
||||
{
|
||||
LOG_E("Failed to control phy, ret:0x%d", ret);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* enable mac TX/RX */
|
||||
ret = cvi_eth_mac_control(g_mac_handle, CSI_ETH_MAC_CONTROL_TX, enable ? 1 : 0);
|
||||
if (ret != 0)
|
||||
{
|
||||
LOG_E("Failed to enable mac TX");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = cvi_eth_mac_control(g_mac_handle, CSI_ETH_MAC_CONTROL_RX, enable ? 1 : 0);
|
||||
if (ret != 0)
|
||||
{
|
||||
LOG_E("Failed to enable mac RX");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* set mac address */
|
||||
memcpy(addr.b, g_mac_addr, sizeof(g_mac_addr));
|
||||
ret = cvi_eth_mac_set_macaddr(g_mac_handle, &addr);
|
||||
if (ret != 0)
|
||||
{
|
||||
LOG_E("Failed to set mac address");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* adjust mac link parameter */
|
||||
ret = cvi_eth_mac_control(g_mac_handle, DRV_ETH_MAC_ADJUST_LINK, 1);
|
||||
if (ret != 0)
|
||||
{
|
||||
LOG_E("Failed to adjust link");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t fn_phy_read(uint8_t phy_addr, uint8_t reg_addr, uint16_t *data)
|
||||
{
|
||||
return dw_eth_mac_phy_read(g_mac_handle, phy_addr, reg_addr, data);
|
||||
}
|
||||
|
||||
static int32_t fn_phy_write(uint8_t phy_addr, uint8_t reg_addr, uint16_t data)
|
||||
{
|
||||
return dw_eth_mac_phy_write(g_mac_handle, phy_addr, reg_addr, data);
|
||||
}
|
||||
|
||||
static void dw_gmac_handler_irq(int vector, void *param)
|
||||
{
|
||||
gmac_dev_t *mac_dev = (gmac_dev_t *)param;
|
||||
struct dw_gmac_dma_regs *dma_reg = mac_dev->priv->dma_regs_p;
|
||||
uint32_t dma_status;
|
||||
uint32_t event = 0;
|
||||
|
||||
/* no ephy or ephy link down */
|
||||
if (!mac_dev->phy_dev || !mac_dev->phy_dev->link_state)
|
||||
return;
|
||||
|
||||
/* read and clear dma interrupt */
|
||||
dma_status = dma_reg->status;
|
||||
|
||||
/* Clear the interrupt by writing a logic 1 to the CSR5[15-0] */
|
||||
dma_reg->status = dma_status & 0x1ffff;
|
||||
|
||||
if (dma_status & CVI_DMA_STATUS_RI)
|
||||
{
|
||||
LOG_D("CVI_DMA_STATUS_RI");
|
||||
|
||||
/* a frame has been received */
|
||||
eth_device_ready(&(dw_eth_device.parent));
|
||||
}
|
||||
|
||||
if (dma_status & CVI_DMA_STATUS_TI)
|
||||
{
|
||||
LOG_D("CVI_DMA_STATUS_TI");
|
||||
}
|
||||
|
||||
if (dma_status & CVI_DMA_STATUS_ERI)
|
||||
{
|
||||
LOG_D("CVI_DMA_STATUS_TI");
|
||||
}
|
||||
}
|
||||
|
||||
static rt_err_t rt_dw_eth_init(rt_device_t dev)
|
||||
{
|
||||
struct _dw_eth *dw_eth;
|
||||
struct eth_device *eth_dev;
|
||||
|
||||
RT_ASSERT(dev != RT_NULL);
|
||||
eth_dev = rt_container_of(dev, struct eth_device, parent);
|
||||
if (eth_dev == RT_NULL)
|
||||
return -RT_ERROR;
|
||||
|
||||
dw_eth = rt_container_of(eth_dev, struct _dw_eth, parent);
|
||||
if (dw_eth == RT_NULL)
|
||||
return -RT_ERROR;
|
||||
|
||||
/* init phy id */
|
||||
cvi_ephy_id_init();
|
||||
|
||||
/* initialize MAC & PHY */
|
||||
g_mac_handle = cvi_eth_mac_init(dw_eth->base);
|
||||
if (g_mac_handle == NULL)
|
||||
return -RT_ERROR;
|
||||
|
||||
g_phy_handle = cvi_eth_phy_init(fn_phy_read, fn_phy_write);
|
||||
|
||||
dw_eth_mac_connect_phy(g_mac_handle, g_phy_handle);
|
||||
|
||||
if (cvi_eth_mac_phy_enable(1))
|
||||
{
|
||||
LOG_E("PHY MAC init fail");
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
rt_hw_interrupt_install(dw_eth->irq, dw_gmac_handler_irq, g_mac_handle, "e0");
|
||||
rt_hw_interrupt_umask(dw_eth->irq);
|
||||
|
||||
/* change device link status */
|
||||
eth_device_linkchange(&(dw_eth_device.parent), RT_TRUE);
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static rt_err_t rt_dw_eth_control(rt_device_t dev, int cmd, void *args)
|
||||
{
|
||||
switch (cmd)
|
||||
{
|
||||
case NIOCTL_GADDR:
|
||||
if (args)
|
||||
rt_memcpy(args, g_mac_addr, MAX_ADDR_LEN);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
#if defined(ETH_RX_DUMP) || defined(ETH_TX_DUMP)
|
||||
static void packet_dump(const char *msg, const struct pbuf *p)
|
||||
{
|
||||
const struct pbuf *q;
|
||||
rt_uint32_t i, j;
|
||||
rt_uint8_t *ptr;
|
||||
|
||||
rt_kprintf("%s %d byte\n", msg, p->tot_len);
|
||||
|
||||
i = 0;
|
||||
for (q = p; q != RT_NULL; q = q->next)
|
||||
{
|
||||
ptr = q->payload;
|
||||
|
||||
for (j = 0; j < q->len; j++)
|
||||
{
|
||||
if ((i % 8) == 0)
|
||||
{
|
||||
rt_kprintf(" ");
|
||||
}
|
||||
|
||||
if ((i % 16) == 0)
|
||||
{
|
||||
rt_kprintf("\r\n");
|
||||
}
|
||||
rt_kprintf("%02x ", *ptr);
|
||||
|
||||
i ++;
|
||||
ptr ++;
|
||||
}
|
||||
}
|
||||
|
||||
rt_kprintf("\n\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
struct pbuf* rt_dw_eth_rx(rt_device_t dev)
|
||||
{
|
||||
struct pbuf *p = NULL;
|
||||
struct pbuf *q = NULL;
|
||||
uint32_t i = 0;
|
||||
|
||||
int32_t len = cvi_eth_mac_read_frame(g_mac_handle, RecvDataBuf, GMAC_BUF_LEN);
|
||||
if((len <= 0) || (len > GMAC_BUF_LEN))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if RT_LWIP_ETH_PAD_SIZE
|
||||
len += RT_LWIP_ETH_PAD_SIZE; /* allow room for Ethernet padding */
|
||||
#endif
|
||||
|
||||
p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);
|
||||
if (p == NULL)
|
||||
{
|
||||
LOG_E("eth_rx: pbuf_alloc failed");
|
||||
len = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if RT_LWIP_ETH_PAD_SIZE
|
||||
pbuf_header(p, -RT_LWIP_ETH_PAD_SIZE); /* drop the padding word */
|
||||
#endif
|
||||
|
||||
/* We iterate over the pbuf chain until we have read the entire
|
||||
* packet into the pbuf. */
|
||||
for (q = p; q != NULL; q = q->next)
|
||||
{
|
||||
/* Read enough bytes to fill this pbuf in the chain. The
|
||||
* available data in the pbuf is given by the q->len
|
||||
* variable.
|
||||
* This does not necessarily have to be a memcpy, you can also preallocate
|
||||
* pbufs for a DMA-enabled MAC and after receiving truncate it to the
|
||||
* actually received size. In this case, ensure the tot_len member of the
|
||||
* pbuf is the sum of the chained pbuf len members.
|
||||
*/
|
||||
memcpy((u8_t*)q->payload, (u8_t*)&RecvDataBuf[i], q->len);
|
||||
i = i + q->len;
|
||||
}
|
||||
|
||||
if((i != p->tot_len) || (i > len))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef ETH_RX_DUMP
|
||||
packet_dump("RX dump", p);
|
||||
#endif /* ETH_RX_DUMP */
|
||||
|
||||
return p;
|
||||
|
||||
}
|
||||
|
||||
rt_err_t rt_dw_eth_tx(rt_device_t dev, struct pbuf* p)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
|
||||
#ifdef ETH_TX_DUMP
|
||||
packet_dump("send", p);
|
||||
#endif
|
||||
|
||||
struct pbuf *q;
|
||||
uint32_t len = 0;
|
||||
|
||||
|
||||
#if RT_LWIP_ETH_PAD_SIZE
|
||||
pbuf_header(p, -RT_LWIP_ETH_PAD_SIZE); /* drop the padding word */
|
||||
#endif
|
||||
|
||||
for (q = p; q != NULL; q = q->next)
|
||||
{
|
||||
/* Send the data from the pbuf to the interface, one pbuf at a
|
||||
time. The size of the data in each pbuf is kept in the ->len
|
||||
variable. */
|
||||
MEMCPY((uint8_t *)&SendDataBuf[len], (uint8_t *)q->payload, q->len);
|
||||
len = len + q->len;
|
||||
if((len > GMAC_BUF_LEN) || (len > p->tot_len))
|
||||
{
|
||||
LOG_E("rt_dw_eth_tx: error, len=%d, tot_len=%d", len, p->tot_len);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if(len == p->tot_len)
|
||||
{
|
||||
if (cvi_eth_mac_send_frame(g_mac_handle, SendDataBuf, len) < 0)
|
||||
ret = -RT_ERROR;
|
||||
}
|
||||
else
|
||||
ret = -RT_ERROR;
|
||||
|
||||
#if RT_LWIP_ETH_PAD_SIZE
|
||||
pbuf_header(p, RT_LWIP_ETH_PAD_SIZE); /* reclaim the padding word */
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const static struct rt_device_ops dw_eth_ops =
|
||||
{
|
||||
rt_dw_eth_init,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
RT_NULL,
|
||||
rt_dw_eth_control
|
||||
};
|
||||
|
||||
static int rthw_eth_init(void)
|
||||
{
|
||||
rt_err_t ret = RT_EOK;
|
||||
|
||||
dw_eth_device.base = (rt_uint32_t *)DW_MAC_BASE;
|
||||
dw_eth_device.irq = DW_MAC_IRQ;
|
||||
|
||||
dw_eth_device.parent.parent.ops = &dw_eth_ops;
|
||||
|
||||
dw_eth_device.parent.eth_rx = rt_dw_eth_rx;
|
||||
dw_eth_device.parent.eth_tx = rt_dw_eth_tx;
|
||||
|
||||
ret = rt_sem_init(&dw_eth_device.rx_sem, "rx_sem", 0, RT_IPC_FLAG_FIFO);
|
||||
if (ret != RT_EOK)
|
||||
{
|
||||
LOG_E("rt_sem_init failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = eth_device_init(&dw_eth_device.parent, "e0");
|
||||
if (ret != RT_EOK)
|
||||
{
|
||||
LOG_E("eth_device_init failed: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
INIT_DEVICE_EXPORT(rthw_eth_init);
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2024, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2024/04/25 flyingcys first version
|
||||
*/
|
||||
#ifndef __DRV_ETH_H__
|
||||
#define __DRV_ETH_H__
|
||||
|
||||
#include "mmio.h"
|
||||
#include "dw_eth_mac.h"
|
||||
#include "cvi_eth_phy.h"
|
||||
|
||||
#define DW_MAC_BASE 0x04070000UL
|
||||
#define DW_MAC_IRQ 31
|
||||
|
||||
#endif /* __DRV_ETH_H__ */
|
|
@ -0,0 +1,606 @@
|
|||
/*
|
||||
* Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved.
|
||||
*/
|
||||
#include <rtthread.h>
|
||||
|
||||
#include "cvi_eth_phy.h"
|
||||
|
||||
#define CSI_ETH_AUTONEG_DISABLE (0) ///< Disable auto-negotiation
|
||||
#define CSI_ETH_AUTONEG_ENABLE (1) ///< Enable auto-negotiation
|
||||
|
||||
#define CONFIG_ETH_PHY_NUM 2
|
||||
|
||||
eth_phy_priv_t phy_priv_list[CONFIG_ETH_PHY_NUM];
|
||||
|
||||
extern eth_phy_dev_t cv181x_device;
|
||||
|
||||
/* registered phy devices */
|
||||
static eth_phy_dev_t *const eth_phy_devices[] = {
|
||||
&cv181x_device,
|
||||
NULL /* Must be the last item */
|
||||
};
|
||||
|
||||
int32_t eth_phy_read(eth_phy_priv_t *priv, uint8_t phy_addr, uint8_t reg_addr, uint16_t *data)
|
||||
{
|
||||
RT_ASSERT(priv);
|
||||
RT_ASSERT(priv->phy_read);
|
||||
return priv->phy_read(phy_addr, reg_addr, data);
|
||||
}
|
||||
|
||||
int32_t eth_phy_write(eth_phy_priv_t *priv, uint8_t phy_addr, uint8_t reg_addr, uint16_t data)
|
||||
{
|
||||
RT_ASSERT(priv);
|
||||
RT_ASSERT(priv->phy_write);
|
||||
return priv->phy_write(phy_addr, reg_addr, data);
|
||||
}
|
||||
|
||||
static eth_phy_dev_t *eth_get_phy_device(eth_phy_priv_t *priv, uint8_t phy_addr, uint32_t phy_id)
|
||||
{
|
||||
eth_phy_dev_t *p = eth_phy_devices[0];
|
||||
int32_t i = 0;
|
||||
|
||||
while (p != NULL)
|
||||
{
|
||||
if ((p->phy_id & p->mask) == (phy_id & p->mask))
|
||||
{
|
||||
p->phy_addr = phy_addr;
|
||||
p->advertising = p->supported = p->features;
|
||||
return p;
|
||||
}
|
||||
|
||||
i ++;
|
||||
p = eth_phy_devices[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int32_t eth_read_phy_id(eth_phy_priv_t *priv, uint8_t phy_addr, uint32_t *phy_id)
|
||||
{
|
||||
int32_t ret;
|
||||
uint16_t data;
|
||||
uint32_t id;
|
||||
|
||||
ret = eth_phy_read(priv, phy_addr, CVI_MII_PHYSID1, &data);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
id = data;
|
||||
id = (id & 0xffff) << 16;
|
||||
|
||||
ret = eth_phy_read(priv, phy_addr, CVI_MII_PHYSID2, &data);
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
id |= (data & 0xffff);
|
||||
|
||||
if (phy_id != NULL)
|
||||
{
|
||||
*phy_id = id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static eth_phy_dev_t * eth_get_phy_by_mask(eth_phy_priv_t *priv, uint32_t phy_mask, phy_if_mode_t interface)
|
||||
{
|
||||
uint32_t phy_id = 0xffffffff;
|
||||
|
||||
while (phy_mask)
|
||||
{
|
||||
int32_t addr = ffs(phy_mask) - 1;
|
||||
int32_t r = eth_read_phy_id(priv, addr, &phy_id);
|
||||
|
||||
/* If the PHY ID is mostly f's, we didn't find anything */
|
||||
if (r == 0 && (phy_id & 0x1fffffff) != 0x1fffffff)
|
||||
return eth_get_phy_device(priv, addr, phy_id);
|
||||
|
||||
phy_mask &= ~(1 << addr);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void eth_config(void)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
val = mmio_read_32(ETH_PHY_BASE) & ETH_PHY_INIT_MASK;
|
||||
mmio_write_32(ETH_PHY_BASE, (val | ETH_PHY_SHUTDOWN) & ETH_PHY_RESET);
|
||||
rt_thread_mdelay(1);
|
||||
mmio_write_32(ETH_PHY_BASE, val & ETH_PHY_POWERUP & ETH_PHY_RESET);
|
||||
rt_thread_mdelay(20);
|
||||
mmio_write_32(ETH_PHY_BASE, (val & ETH_PHY_POWERUP) | ETH_PHY_RESET_N);
|
||||
rt_thread_mdelay(1);
|
||||
}
|
||||
|
||||
static eth_phy_dev_t *eth_connect_phy(eth_phy_priv_t *priv, uint32_t phy_mask, phy_if_mode_t interface)
|
||||
{
|
||||
int32_t i;
|
||||
eth_phy_dev_t *phydev = NULL;
|
||||
|
||||
/* config eth internal phy on ASIC board */
|
||||
eth_config();
|
||||
|
||||
#ifdef CONFIG_PHY_ADDR
|
||||
phy_mask = 1 << CONFIG_PHY_ADDR;
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
phydev = eth_get_phy_by_mask(priv, phy_mask, interface);
|
||||
if (phydev)
|
||||
return phydev;
|
||||
}
|
||||
|
||||
rt_kprintf("\n PHY: ");
|
||||
while (phy_mask)
|
||||
{
|
||||
int32_t addr = ffs(phy_mask) - 1;
|
||||
rt_kprintf("%d ", addr);
|
||||
phy_mask &= ~(1 << addr);
|
||||
}
|
||||
rt_kprintf("not found\n");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int32_t eth_phy_reset(eth_phy_handle_t handle)
|
||||
{
|
||||
RT_ASSERT(handle);
|
||||
eth_phy_dev_t *dev = (eth_phy_dev_t *)handle;
|
||||
RT_ASSERT(dev->priv);
|
||||
|
||||
uint16_t data;
|
||||
int32_t ret;
|
||||
int32_t timeout = 600; /* in ms */
|
||||
eth_phy_priv_t *priv = dev->priv;
|
||||
uint32_t phy_addr = dev->phy_addr;
|
||||
|
||||
/* Soft reset */
|
||||
ret = eth_phy_read(priv, phy_addr, CVI_MII_BMCR, &data);
|
||||
if (ret != 0)
|
||||
{
|
||||
rt_kprintf("eth phy read failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = eth_phy_write(priv, phy_addr, CVI_MII_BMCR, data | CVI_BMCR_RESET);
|
||||
if (ret != 0)
|
||||
{
|
||||
rt_kprintf("eth phy write failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PHY_RESET_DELAY
|
||||
rt_hw_us_delay(CONFIG_PHY_RESET_DELAY); /* Intel LXT971A needs this */
|
||||
#endif
|
||||
/*
|
||||
* Wait up to 0.6s for the reset sequence to finish. According to
|
||||
* IEEE 802.3, Section 2, Subsection 22.2.4.1.1 a PHY reset may take
|
||||
* up to 0.5 s.
|
||||
*/
|
||||
ret = eth_phy_read(priv, phy_addr, CVI_MII_BMCR, &data);
|
||||
while ((data & CVI_BMCR_RESET) && timeout--)
|
||||
{
|
||||
ret = eth_phy_read(priv, phy_addr, CVI_MII_BMCR, &data);
|
||||
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
rt_thread_mdelay(1);
|
||||
}
|
||||
|
||||
if (data & CVI_BMCR_RESET)
|
||||
{
|
||||
rt_kprintf("eth phy reset timed out\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t eth_phy_config(eth_phy_handle_t handle)
|
||||
{
|
||||
RT_ASSERT(handle);
|
||||
eth_phy_dev_t *dev = (eth_phy_dev_t *)handle;
|
||||
|
||||
if (dev->config)
|
||||
{
|
||||
return dev->config(handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t eth_phy_start(eth_phy_handle_t handle)
|
||||
{
|
||||
RT_ASSERT(handle);
|
||||
eth_phy_dev_t *dev = (eth_phy_dev_t *)handle;
|
||||
|
||||
if (dev->start)
|
||||
{
|
||||
return dev->start(handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t eth_phy_stop(eth_phy_handle_t handle)
|
||||
{
|
||||
RT_ASSERT(handle);
|
||||
eth_phy_dev_t *dev = (eth_phy_dev_t *)handle;
|
||||
|
||||
if (dev->start) {
|
||||
return dev->stop(handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t cvi_eth_phy_power_control(eth_phy_handle_t handle, eth_power_state_t state)
|
||||
{
|
||||
if (state == CSI_ETH_POWER_FULL)
|
||||
{
|
||||
return eth_phy_start(handle);
|
||||
}
|
||||
else if (state == CSI_ETH_POWER_OFF)
|
||||
{
|
||||
return eth_phy_stop(handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t genphy_update_link(eth_phy_dev_t *phy_dev)
|
||||
{
|
||||
uint8_t phy_addr = phy_dev->phy_addr;
|
||||
uint16_t mii_reg;
|
||||
int32_t ret;
|
||||
|
||||
/*
|
||||
* Wait if the link is up, and autonegotiation is in progress
|
||||
* (ie - we're capable and it's not done)
|
||||
*/
|
||||
ret = eth_phy_read(phy_dev->priv, phy_addr, CVI_MII_BMSR, &mii_reg);
|
||||
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we already saw the link up, and it hasn't gone down, then
|
||||
* we don't need to wait for autoneg again
|
||||
*/
|
||||
if (phy_dev->link_state && mii_reg & CVI_BMSR_LSTATUS)
|
||||
return 0;
|
||||
|
||||
if ((phy_dev->priv->link_info.autoneg == CSI_ETH_AUTONEG_ENABLE) &&
|
||||
!(mii_reg & CVI_BMSR_ANEGCOMPLETE)) {
|
||||
int i = 0;
|
||||
|
||||
rt_kprintf("%s waiting for PHY auto negotiation to complete...\n",
|
||||
phy_dev->name);
|
||||
while (!(mii_reg & CVI_BMSR_ANEGCOMPLETE)) {
|
||||
/*
|
||||
* Timeout reached ?
|
||||
*/
|
||||
if (i > CVI_PHY_ANEG_TIMEOUT) {
|
||||
rt_kprintf("TIMEOUT!\n");
|
||||
phy_dev->link_state = ETH_LINK_DOWN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if ((i++ % 1000) == 0)
|
||||
// rt_kprintf(".");
|
||||
i ++;
|
||||
|
||||
rt_hw_us_delay(1000); /* 1 ms */
|
||||
|
||||
ret = eth_phy_read(phy_dev->priv, phy_addr, CVI_MII_BMSR, &mii_reg);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
rt_kprintf("auto negotiation Done!\n");
|
||||
phy_dev->link_state = ETH_LINK_UP;
|
||||
} else {
|
||||
|
||||
/* Read the link a second time to clear the latched state */
|
||||
ret = eth_phy_read(phy_dev->priv, phy_addr, CVI_MII_BMSR, &mii_reg);
|
||||
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (mii_reg & CVI_BMSR_LSTATUS)
|
||||
phy_dev->link_state = ETH_LINK_UP;
|
||||
else
|
||||
phy_dev->link_state = ETH_LINK_DOWN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t eth_phy_update_link(eth_phy_handle_t handle)
|
||||
{
|
||||
RT_ASSERT(handle);
|
||||
eth_phy_dev_t *dev = (eth_phy_dev_t *)handle;
|
||||
|
||||
if (dev->update_link) {
|
||||
return dev->update_link(handle);
|
||||
} else {
|
||||
return genphy_update_link(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t genphy_config_advert(eth_phy_dev_t *phy_dev)
|
||||
{
|
||||
RT_ASSERT(phy_dev->priv);
|
||||
|
||||
eth_phy_priv_t *priv = phy_dev->priv;
|
||||
uint8_t phy_addr = phy_dev->phy_addr;
|
||||
uint32_t advertise;
|
||||
uint16_t oldadv, adv, bmsr;
|
||||
int32_t changed = 0;
|
||||
int32_t ret;
|
||||
|
||||
/* Only allow advertising what this PHY supports */
|
||||
phy_dev->advertising &= phy_dev->supported;
|
||||
advertise = phy_dev->advertising;
|
||||
|
||||
/* Setup standard advertisement */
|
||||
ret = eth_phy_read(priv, phy_addr, CVI_MII_ADVERTISE, &adv);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
oldadv = adv;
|
||||
|
||||
if (adv < 0)
|
||||
return adv;
|
||||
|
||||
adv &= ~(CVI_ADVERTISE_ALL | CVI_ADVERTISE_100BASE4 | CVI_ADVERTISE_PAUSE_CAP |
|
||||
CVI_ADVERTISE_PAUSE_ASYM);
|
||||
if (advertise & CVI_ADVERTISED_10baseT_Half)
|
||||
adv |= CVI_ADVERTISE_10HALF;
|
||||
if (advertise & CVI_ADVERTISED_10baseT_Full)
|
||||
adv |= CVI_ADVERTISE_10FULL;
|
||||
if (advertise & CVI_ADVERTISED_100baseT_Half)
|
||||
adv |= CVI_ADVERTISE_100HALF;
|
||||
if (advertise & CVI_ADVERTISED_100baseT_Full)
|
||||
adv |= CVI_ADVERTISE_100FULL;
|
||||
if (advertise & CVI_ADVERTISED_Pause)
|
||||
adv |= CVI_ADVERTISE_PAUSE_CAP;
|
||||
if (advertise & CVI_ADVERTISED_Asym_Pause)
|
||||
adv |= CVI_ADVERTISE_PAUSE_ASYM;
|
||||
if (advertise & CVI_ADVERTISED_1000baseX_Half)
|
||||
adv |= CVI_ADVERTISE_1000XHALF;
|
||||
if (advertise & CVI_ADVERTISED_1000baseX_Full)
|
||||
adv |= CVI_ADVERTISE_1000XFULL;
|
||||
|
||||
if (adv != oldadv) {
|
||||
ret = eth_phy_write(priv, phy_addr, CVI_MII_ADVERTISE, adv);
|
||||
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
ret = eth_phy_read(priv, phy_addr, CVI_MII_BMSR, &bmsr);
|
||||
|
||||
if (ret != 0 || bmsr < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
|
||||
* 1000Mbits/sec capable PHYs shall have the CVI_BMSR_ESTATEN bit set to a
|
||||
* logical 1.
|
||||
*/
|
||||
if (!(bmsr & CVI_BMSR_ESTATEN))
|
||||
return changed;
|
||||
|
||||
/* Configure gigabit if it's supported */
|
||||
ret = eth_phy_read(priv, phy_addr, CVI_MII_CTRL1000, &adv);
|
||||
|
||||
if (ret != 0 || adv < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
oldadv = adv;
|
||||
|
||||
adv &= ~(CVI_ADVERTISE_1000FULL | CVI_ADVERTISE_1000HALF);
|
||||
|
||||
if (phy_dev->supported & (CVI_SUPPORTED_1000baseT_Half |
|
||||
CVI_SUPPORTED_1000baseT_Full)) {
|
||||
if (advertise & CVI_SUPPORTED_1000baseT_Half)
|
||||
adv |= CVI_ADVERTISE_1000HALF;
|
||||
if (advertise & CVI_SUPPORTED_1000baseT_Full)
|
||||
adv |= CVI_ADVERTISE_1000FULL;
|
||||
}
|
||||
|
||||
if (adv != oldadv)
|
||||
changed = 1;
|
||||
|
||||
ret = eth_phy_write(priv, phy_addr, CVI_MII_CTRL1000, adv);
|
||||
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static int32_t genphy_setup_forced(eth_phy_dev_t *phy_dev)
|
||||
{
|
||||
RT_ASSERT(phy_dev->priv);
|
||||
|
||||
eth_phy_priv_t *priv = phy_dev->priv;
|
||||
uint8_t phy_addr = phy_dev->phy_addr;
|
||||
int32_t ctl = CVI_BMCR_ANRESTART;
|
||||
int32_t ret;
|
||||
|
||||
if (CSI_ETH_SPEED_1G == priv->link_info.speed)
|
||||
ctl |= CVI_BMCR_SPEED1000;
|
||||
else if (CSI_ETH_SPEED_100M == priv->link_info.speed)
|
||||
ctl |= CVI_BMCR_SPEED100;
|
||||
else//CSI_ETH_SPEED_10M == priv->link_info.speed
|
||||
ctl |= CVI_BMCR_SPEED100;
|
||||
|
||||
if (CSI_ETH_DUPLEX_FULL == priv->link_info.duplex)
|
||||
ctl |= CVI_BMCR_FULLDPLX;
|
||||
|
||||
ret = eth_phy_write(priv, phy_addr, CVI_MII_BMCR, ctl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int genphy_restart_aneg(eth_phy_dev_t *phy_dev)
|
||||
{
|
||||
int32_t ret;
|
||||
uint16_t ctl;
|
||||
ret = eth_phy_read(phy_dev->priv, phy_dev->phy_addr, CVI_MII_BMCR, &ctl);
|
||||
|
||||
if (ret != 0 || ctl < 0)
|
||||
return ret;
|
||||
|
||||
ctl |= (CVI_BMCR_ANENABLE | CVI_BMCR_ANRESTART);
|
||||
|
||||
/* Don't isolate the PHY if we're negotiating */
|
||||
ctl &= ~(CVI_BMCR_ISOLATE);
|
||||
|
||||
ret = eth_phy_write(phy_dev->priv, phy_dev->phy_addr, CVI_MII_BMCR, ctl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32_t genphy_config_aneg(eth_phy_dev_t *phy_dev)
|
||||
{
|
||||
RT_ASSERT(phy_dev->priv);
|
||||
|
||||
eth_phy_priv_t *priv = phy_dev->priv;
|
||||
uint8_t phy_addr = phy_dev->phy_addr;
|
||||
int32_t result;
|
||||
uint16_t ctl;
|
||||
int32_t ret;
|
||||
|
||||
if (CSI_ETH_AUTONEG_ENABLE != priv->link_info.autoneg)
|
||||
return genphy_setup_forced(phy_dev);
|
||||
|
||||
result = genphy_config_advert(phy_dev);
|
||||
|
||||
if (result < 0) /* error */
|
||||
return result;
|
||||
|
||||
if (result == 0) {
|
||||
/* Advertisment hasn't changed, but maybe aneg was never on to
|
||||
* begin with? Or maybe phy was isolated? */
|
||||
ret = eth_phy_read(priv, phy_addr, CVI_MII_BMCR, &ctl);
|
||||
if (ret != 0 || ctl < 0)
|
||||
return ret;
|
||||
|
||||
if (!(ctl & CVI_BMCR_ANENABLE) || (ctl & CVI_BMCR_ISOLATE))
|
||||
result = 1; /* do restart aneg */
|
||||
}
|
||||
|
||||
/* Only restart aneg if we are advertising something different
|
||||
* than we were before. */
|
||||
if (result > 0)
|
||||
result = genphy_restart_aneg(phy_dev);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t genphy_config(eth_phy_dev_t *phy_dev)
|
||||
{
|
||||
RT_ASSERT(phy_dev->priv);
|
||||
|
||||
eth_phy_priv_t *priv = phy_dev->priv;
|
||||
uint8_t phy_addr = phy_dev->phy_addr;
|
||||
int32_t ret;
|
||||
uint16_t val;
|
||||
uint32_t features;
|
||||
|
||||
features = (CVI_SUPPORTED_TP | CVI_SUPPORTED_MII
|
||||
| CVI_SUPPORTED_AUI | CVI_SUPPORTED_FIBRE |
|
||||
CVI_SUPPORTED_BNC);
|
||||
|
||||
/* Do we support autonegotiation? */
|
||||
ret = eth_phy_read(priv, phy_addr, CVI_MII_BMSR, &val);
|
||||
if (ret != 0 || val < 0)
|
||||
return ret;
|
||||
|
||||
if (val & CVI_BMSR_ANEGCAPABLE)
|
||||
features |= CVI_SUPPORTED_Autoneg;
|
||||
|
||||
if (val & CVI_BMSR_100FULL)
|
||||
features |= CVI_SUPPORTED_100baseT_Full;
|
||||
if (val & CVI_BMSR_100HALF)
|
||||
features |= CVI_SUPPORTED_100baseT_Half;
|
||||
if (val & CVI_BMSR_10FULL)
|
||||
features |= CVI_SUPPORTED_10baseT_Full;
|
||||
if (val & CVI_BMSR_10HALF)
|
||||
features |= CVI_SUPPORTED_10baseT_Half;
|
||||
|
||||
if (val & CVI_BMSR_ESTATEN) {
|
||||
ret = eth_phy_read(priv, phy_addr, CVI_MII_ESTATUS, &val);
|
||||
if (ret != 0 || val < 0)
|
||||
return val;
|
||||
|
||||
if (val & CVI_ESTATUS_1000_TFULL)
|
||||
features |= CVI_SUPPORTED_1000baseT_Full;
|
||||
if (val & CVI_ESTATUS_1000_THALF)
|
||||
features |= CVI_SUPPORTED_1000baseT_Half;
|
||||
if (val & CVI_ESTATUS_1000_XFULL)
|
||||
features |= CVI_SUPPORTED_1000baseX_Full;
|
||||
if (val & CVI_ESTATUS_1000_XHALF)
|
||||
features |= CVI_SUPPORTED_1000baseX_Half;
|
||||
}
|
||||
|
||||
phy_dev->supported &= features;
|
||||
phy_dev->advertising &= features;
|
||||
|
||||
genphy_config_aneg(phy_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
eth_phy_handle_t cvi_eth_phy_init(csi_eth_phy_read_t fn_read, csi_eth_phy_write_t fn_write)
|
||||
{
|
||||
eth_phy_dev_t *phy_dev;
|
||||
eth_phy_priv_t *priv;
|
||||
uint32_t phy_mask = 0xffffffff;
|
||||
phy_if_mode_t interface = 0;
|
||||
|
||||
RT_ASSERT(fn_read != RT_NULL);
|
||||
RT_ASSERT(fn_write != RT_NULL);
|
||||
|
||||
priv = &phy_priv_list[0];
|
||||
|
||||
priv->phy_read = fn_read;
|
||||
priv->phy_write = fn_write;
|
||||
priv->link_info.autoneg = CSI_ETH_AUTONEG_ENABLE;
|
||||
|
||||
phy_dev = eth_connect_phy(priv, phy_mask, interface);
|
||||
if (phy_dev == NULL) {
|
||||
rt_kprintf("No phy device found!\n");
|
||||
return;
|
||||
}
|
||||
rt_kprintf("connect phy id: 0x%X\n", phy_dev->phy_id);
|
||||
|
||||
phy_dev->priv = priv;
|
||||
|
||||
/* Reset PHY */
|
||||
eth_phy_reset(phy_dev);
|
||||
|
||||
/* Config PHY */
|
||||
eth_phy_config(phy_dev);
|
||||
|
||||
return phy_dev;
|
||||
}
|
|
@ -0,0 +1,401 @@
|
|||
/*
|
||||
* Copyright (C) 2019-2020 AlibabaGroup Holding Limited
|
||||
*/
|
||||
/******************************************************************************
|
||||
* @file phy.h
|
||||
* @brief header file for generic PHY Driver
|
||||
* @version V1.0
|
||||
* @date 21 March 2019
|
||||
******************************************************************************/
|
||||
#ifndef _ETH_PHY_H_
|
||||
#define _ETH_PHY_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include "mmio.h"
|
||||
|
||||
/**
|
||||
\brief Ethernet link speed
|
||||
*/
|
||||
#define CSI_ETH_SPEED_10M (0) ///< 10 Mbps link speed
|
||||
#define CSI_ETH_SPEED_100M (1) ///< 100 Mbps link speed
|
||||
#define CSI_ETH_SPEED_1G (2) ///< 1 Gpbs link speed
|
||||
|
||||
/**
|
||||
\brief Ethernet duplex mode
|
||||
*/
|
||||
#define CSI_ETH_DUPLEX_HALF (0) ///< Half duplex link
|
||||
#define CSI_ETH_DUPLEX_FULL (1) ///< Full duplex link
|
||||
|
||||
typedef void *eth_phy_handle_t;
|
||||
|
||||
typedef enum eth_power_state
|
||||
{
|
||||
CSI_ETH_POWER_OFF, ///< Power off: no operation possible
|
||||
CSI_ETH_POWER_LOW, ///< Low Power mode: retain state, detect and signal wake-up events
|
||||
CSI_ETH_POWER_FULL ///< Power on: full operation at maximum performance
|
||||
} eth_power_state_t;
|
||||
|
||||
typedef int32_t (*csi_eth_phy_read_t)(uint8_t phy_addr, uint8_t reg_addr, uint16_t *data); ///< Read Ethernet PHY Register.
|
||||
typedef int32_t (*csi_eth_phy_write_t)(uint8_t phy_addr, uint8_t reg_addr, uint16_t data); ///< Write Ethernet PHY Register.
|
||||
|
||||
typedef volatile struct eth_link_info
|
||||
{
|
||||
uint32_t speed : 2; ///< Link speed: 0= 10 MBit, 1= 100 MBit, 2= 1 GBit
|
||||
uint32_t duplex : 1; ///< Duplex mode: 0= Half, 1= Full
|
||||
uint32_t autoneg : 1; ///< Set the interface to Auto Negotiation mode of transmission parameters
|
||||
uint32_t loopback : 1; ///< Set the interface into a Loop-back test mode
|
||||
uint32_t isolation : 1; ///< Set to indicate electrical isolation of PHY interface from MII/RMII interface
|
||||
uint32_t reserved : 26;
|
||||
} eth_link_info_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
csi_eth_phy_read_t phy_read;
|
||||
csi_eth_phy_write_t phy_write;
|
||||
eth_link_info_t link_info;
|
||||
} eth_phy_priv_t;
|
||||
|
||||
typedef enum eth_link_state
|
||||
{
|
||||
ETH_LINK_DOWN, ///< Link is down
|
||||
ETH_LINK_UP ///< Link is up
|
||||
} eth_link_state_t;
|
||||
|
||||
/* Basic mode control register */
|
||||
#define CVI_BMCR_RESV (0x003f)
|
||||
#define CVI_BMCR_SPEED1000 (0x0040)
|
||||
#define CVI_BMCR_CTST (0x0080)
|
||||
#define CVI_BMCR_FULLDPLX (0x0100)
|
||||
#define CVI_BMCR_ANRESTART (0x0200)
|
||||
#define CVI_BMCR_ISOLATE (0x0400)
|
||||
#define CVI_BMCR_PDOWN (0x0800)
|
||||
#define CVI_BMCR_ANENABLE (0x1000)
|
||||
#define CVI_BMCR_SPEED100 (0x2000)
|
||||
#define CVI_BMCR_LOOPBACK (0x4000)
|
||||
#define CVI_BMCR_RESET (0x8000)
|
||||
#define BMCR_SPEED10 (0x0000)
|
||||
|
||||
|
||||
/* Generic MII registers */
|
||||
#define CVI_MII_BMCR (0x00)
|
||||
#define CVI_MII_BMSR (0x01)
|
||||
#define CVI_MII_PHYSID1 (0x02)
|
||||
#define CVI_MII_PHYSID2 (0x03)
|
||||
#define CVI_MII_ADVERTISE (0x04)
|
||||
#define CVI_MII_LPA (0x05)
|
||||
#define CVI_MII_EXPANSION (0x06)
|
||||
#define CVI_MII_CTRL1000 (0x09)
|
||||
#define CVI_MII_STAT1000 (0x0a)
|
||||
#define MII_MMD_CTRL (0x0d)
|
||||
#define MII_MMD_DATA (0x0e)
|
||||
#define CVI_MII_ESTATUS (0x0f)
|
||||
#define CVI_MII_DCOUNTER (0x12)
|
||||
#define CVI_MII_FCSCOUNTER (0x13)
|
||||
#define CVI_MII_NWAYTEST (0x14)
|
||||
#define CVI_MII_RERRCOUNTER (0x15)
|
||||
#define CVI_MII_SREVISION (0x16)
|
||||
#define CVI_MII_RESV1 (0x17)
|
||||
#define CVI_MII_LBRERROR (0x18)
|
||||
#define CVI_MII_PHYADDR (0x19)
|
||||
#define CVI_MII_RESV2 (0x1a)
|
||||
#define CVI_MII_TPISTATUS (0x1b)
|
||||
#define CVI_MII_NCONFIG (0x1c)
|
||||
|
||||
/* Advertisement control register. */
|
||||
#define CVI_ADVERTISE_CSMA (0x0001)
|
||||
#define CVI_ADVERTISE_SLCT (0x001f)
|
||||
#define CVI_ADVERTISE_10HALF (0x0020)
|
||||
#define CVI_ADVERTISE_1000XFULL (0x0020)
|
||||
#define CVI_ADVERTISE_10FULL (0x0040)
|
||||
#define CVI_ADVERTISE_1000XHALF (0x0040)
|
||||
#define CVI_ADVERTISE_100HALF (0x0080)
|
||||
#define CVI_ADVERTISE_1000XPAUSE (0x0080)
|
||||
#define CVI_ADVERTISE_100FULL (0x0100)
|
||||
#define CVI_ADVERTISE_1000XPSE_ASYM (0x0100)
|
||||
#define CVI_ADVERTISE_100BASE4 (0x0200)
|
||||
#define CVI_ADVERTISE_PAUSE_CAP (0x0400)
|
||||
#define CVI_ADVERTISE_PAUSE_ASYM (0x0800)
|
||||
#define CVI_ADVERTISE_RESV (0x1000)
|
||||
#define CVI_ADVERTISE_RFAULT (0x2000)
|
||||
#define CVI_ADVERTISE_LPACK (0x4000)
|
||||
#define CVI_ADVERTISE_NPAGE (0x8000)
|
||||
|
||||
/* Basic mode status register. */
|
||||
#define CVI_BMSR_ERCAP (0x0001)
|
||||
#define CVI_BMSR_JCD (0x0002)
|
||||
#define CVI_BMSR_LSTATUS (0x0004)
|
||||
#define CVI_BMSR_ANEGCAPABLE (0x0008)
|
||||
#define CVI_BMSR_RFAULT (0x0010)
|
||||
#define CVI_BMSR_ANEGCOMPLETE (0x0020)
|
||||
#define CVI_BMSR_RESV (0x00c0)
|
||||
#define CVI_BMSR_ESTATEN (0x0100)
|
||||
#define CVI_BMSR_100HALF2 (0x0200)
|
||||
#define CVI_BMSR_100FULL2 (0x0400)
|
||||
#define CVI_BMSR_10HALF (0x0800)
|
||||
#define CVI_BMSR_10FULL (0x1000)
|
||||
#define CVI_BMSR_100HALF (0x2000)
|
||||
#define CVI_BMSR_100FULL (0x4000)
|
||||
#define CVI_BMSR_100BASE4 (0x8000)
|
||||
|
||||
#define CVI_ADVERTISE_FULL (CVI_ADVERTISE_100FULL | CVI_ADVERTISE_10FULL | \
|
||||
CVI_ADVERTISE_CSMA)
|
||||
#define CVI_ADVERTISE_ALL (CVI_ADVERTISE_10HALF | CVI_ADVERTISE_10FULL | \
|
||||
CVI_ADVERTISE_100HALF | CVI_ADVERTISE_100FULL)
|
||||
|
||||
/* Link partner ability register. */
|
||||
#define CVI_LPA_SLCT (0x001f) /* Same as advertise selector */
|
||||
#define CVI_LPA_10HALF (0x0020) /* Can do 10mbps half-duplex */
|
||||
#define CVI_LPA_1000XFULL (0x0020) /* Can do 1000BASE-X full-duplex */
|
||||
#define CVI_LPA_10FULL (0x0040) /* Can do 10mbps full-duplex */
|
||||
#define CVI_LPA_1000XHALF (0x0040) /* Can do 1000BASE-X half-duplex */
|
||||
#define CVI_LPA_100HALF (0x0080) /* Can do 100mbps half-duplex */
|
||||
#define CVI_LPA_1000XPAUSE (0x0080) /* Can do 1000BASE-X pause */
|
||||
#define CVI_LPA_100FULL (0x0100) /* Can do 100mbps full-duplex */
|
||||
#define CVI_LPA_1000XPAUSE_ASYM (0x0100) /* Can do 1000BASE-X pause asym */
|
||||
#define CVI_LPA_100BASE4 (0x0200) /* Can do 100mbps 4k packets */
|
||||
#define CVI_LPA_PAUSE_CAP (0x0400) /* Can pause */
|
||||
#define CVI_LPA_PAUSE_ASYM (0x0800) /* Can pause asymetrically */
|
||||
#define CVI_LPA_RESV (0x1000) /* Unused */
|
||||
#define CVI_LPA_RFAULT (0x2000) /* Link partner faulted */
|
||||
#define CVI_LPA_LPACK (0x4000) /* Link partner acked us */
|
||||
#define CVI_LPA_NPAGE (0x8000) /* Next page bit */
|
||||
|
||||
#define CVI_LPA_DUPLEX (CVI_LPA_10FULL | CVI_LPA_100FULL)
|
||||
#define CVI_LPA_100 (CVI_LPA_100FULL | CVI_LPA_100HALF | CVI_LPA_100BASE4)
|
||||
|
||||
/* Expansion register for auto-negotiation. */
|
||||
#define CVI_EXPANSION_NWAY (0x0001) /* Can do N-way auto-nego */
|
||||
#define CVI_EXPANSION_LCWP (0x0002) /* Got new RX page code word */
|
||||
#define CVI_EXPANSION_ENABLENPAGE (0x0004) /* This enables npage words */
|
||||
#define CVI_EXPANSION_NPCAPABLE (0x0008) /* Link partner supports npage */
|
||||
#define CVI_EXPANSION_MFAULTS (0x0010) /* Multiple faults detected */
|
||||
#define CVI_EXPANSION_RESV (0xffe0) /* Unused */
|
||||
|
||||
#define CVI_ESTATUS_1000_XFULL (0x8000) /* Can do 1000BX Full */
|
||||
#define CVI_ESTATUS_1000_XHALF (0x4000) /* Can do 1000BX Half */
|
||||
#define CVI_ESTATUS_1000_TFULL (0x2000) /* Can do 1000BT Full */
|
||||
#define CVI_ESTATUS_1000_THALF (0x1000) /* Can do 1000BT Half */
|
||||
|
||||
/* N-way test register. */
|
||||
#define CVI_NWAYTEST_RESV1 (0x00ff) /* Unused */
|
||||
#define CVI_NWAYTEST_LOOPBACK (0x0100) /* Enable loopback for N-way */
|
||||
#define CVI_NWAYTEST_RESV2 (0xfe00) /* Unused */
|
||||
|
||||
/* 1000BASE-T Control register */
|
||||
#define CVI_ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */
|
||||
#define CVI_ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */
|
||||
#define CTL1000_AS_MASTER 0x0800
|
||||
#define CTL1000_ENABLE_MASTER 0x1000
|
||||
|
||||
/* 1000BASE-T Status register */
|
||||
#define CVI_LPA_1000LOCALRXOK 0x2000 /* Link partner local receiver status */
|
||||
#define CVI_LPA_1000REMRXOK 0x1000 /* Link partner remote receiver status */
|
||||
#define CVI_LPA_1000FULL 0x0800 /* Link partner 1000BASE-T full duplex */
|
||||
#define CVI_LPA_1000HALF 0x0400 /* Link partner 1000BASE-T half duplex */
|
||||
|
||||
/* Flow control flags */
|
||||
#define CVI_FLOW_CTRL_TX 0x01
|
||||
#define CVI_FLOW_CTRL_RX 0x02
|
||||
|
||||
/* MMD Access Control register fields */
|
||||
#define CVI_MII_MMD_CTRL_DEVAD_MASK 0x1f /* Mask MMD DEVAD*/
|
||||
#define CVI_MII_MMD_CTRL_ADDR 0x0000 /* Address */
|
||||
#define CVI_MII_MMD_CTRL_NOINCR 0x4000 /* no post increment */
|
||||
#define CVI_MII_MMD_CTRL_INCR_RDWT 0x8000 /* post increment on reads & writes */
|
||||
#define CVI_MII_MMD_CTRL_INCR_ON_WT 0xC000 /* post increment on writes only */
|
||||
|
||||
|
||||
/* Indicates what features are advertised by the interface. */
|
||||
#define CVI_ADVERTISED_10baseT_Half (1 << 0)
|
||||
#define CVI_ADVERTISED_10baseT_Full (1 << 1)
|
||||
#define CVI_ADVERTISED_100baseT_Half (1 << 2)
|
||||
#define CVI_ADVERTISED_100baseT_Full (1 << 3)
|
||||
#define CVI_ADVERTISED_1000baseT_Half (1 << 4)
|
||||
#define CVI_ADVERTISED_1000baseT_Full (1 << 5)
|
||||
#define CVI_ADVERTISED_Autoneg (1 << 6)
|
||||
#define CVI_ADVERTISED_TP (1 << 7)
|
||||
#define CVI_ADVERTISED_AUI (1 << 8)
|
||||
#define CVI_ADVERTISED_MII (1 << 9)
|
||||
#define CVI_ADVERTISED_FIBRE (1 << 10)
|
||||
#define CVI_ADVERTISED_BNC (1 << 11)
|
||||
#define CVI_ADVERTISED_10000baseT_Full (1 << 12)
|
||||
#define CVI_ADVERTISED_Pause (1 << 13)
|
||||
#define CVI_ADVERTISED_Asym_Pause (1 << 14)
|
||||
#define CVI_ADVERTISED_2500baseX_Full (1 << 15)
|
||||
#define CVI_ADVERTISED_Backplane (1 << 16)
|
||||
#define CVI_ADVERTISED_1000baseKX_Full (1 << 17)
|
||||
#define CVI_ADVERTISED_10000baseKX4_Full (1 << 18)
|
||||
#define CVI_ADVERTISED_10000baseKR_Full (1 << 19)
|
||||
#define CVI_ADVERTISED_10000baseR_FEC (1 << 20)
|
||||
#define CVI_ADVERTISED_1000baseX_Half (1 << 21)
|
||||
#define CVI_ADVERTISED_1000baseX_Full (1 << 22)
|
||||
|
||||
|
||||
/* Indicates what features are supported by the interface. */
|
||||
#define CVI_SUPPORTED_10baseT_Half (1 << 0)
|
||||
#define CVI_SUPPORTED_10baseT_Full (1 << 1)
|
||||
#define CVI_SUPPORTED_100baseT_Half (1 << 2)
|
||||
#define CVI_SUPPORTED_100baseT_Full (1 << 3)
|
||||
#define CVI_SUPPORTED_1000baseT_Half (1 << 4)
|
||||
#define CVI_SUPPORTED_1000baseT_Full (1 << 5)
|
||||
#define CVI_SUPPORTED_Autoneg (1 << 6)
|
||||
#define CVI_SUPPORTED_TP (1 << 7)
|
||||
#define CVI_SUPPORTED_AUI (1 << 8)
|
||||
#define CVI_SUPPORTED_MII (1 << 9)
|
||||
#define CVI_SUPPORTED_FIBRE (1 << 10)
|
||||
#define CVI_SUPPORTED_BNC (1 << 11)
|
||||
#define CVI_SUPPORTED_10000baseT_Full (1 << 12)
|
||||
#define CVI_SUPPORTED_Pause (1 << 13)
|
||||
#define CVI_SUPPORTED_Asym_Pause (1 << 14)
|
||||
#define CVI_SUPPORTED_2500baseX_Full (1 << 15)
|
||||
#define CVI_SUPPORTED_Backplane (1 << 16)
|
||||
#define CVI_SUPPORTED_1000baseKX_Full (1 << 17)
|
||||
#define CVI_SUPPORTED_10000baseKX4_Full (1 << 18)
|
||||
#define CVI_SUPPORTED_10000baseKR_Full (1 << 19)
|
||||
#define CVI_SUPPORTED_10000baseR_FEC (1 << 20)
|
||||
#define CVI_SUPPORTED_1000baseX_Half (1 << 21)
|
||||
#define CVI_SUPPORTED_1000baseX_Full (1 << 22)
|
||||
|
||||
/* PHY features */
|
||||
#define CVI_PHY_DEFAULT_FEATURES (CVI_SUPPORTED_Autoneg | \
|
||||
CVI_SUPPORTED_TP | \
|
||||
CVI_SUPPORTED_MII)
|
||||
|
||||
#define CVI_PHY_10BT_FEATURES (CVI_SUPPORTED_10baseT_Half | \
|
||||
CVI_SUPPORTED_10baseT_Full)
|
||||
|
||||
#define CVI_PHY_100BT_FEATURES (CVI_SUPPORTED_100baseT_Half | \
|
||||
CVI_SUPPORTED_100baseT_Full)
|
||||
|
||||
#define CVI_PHY_1000BT_FEATURES (CVI_SUPPORTED_1000baseT_Half | \
|
||||
CVI_SUPPORTED_1000baseT_Full)
|
||||
|
||||
#define CVI_PHY_BASIC_FEATURES (CVI_PHY_10BT_FEATURES | \
|
||||
CVI_PHY_100BT_FEATURES | \
|
||||
CVI_PHY_DEFAULT_FEATURES)
|
||||
|
||||
#define CVI_PHY_GBIT_FEATURES (CVI_PHY_BASIC_FEATURES | \
|
||||
CVI_PHY_1000BT_FEATURES)
|
||||
|
||||
#define CVI_PHY_ANEG_TIMEOUT 5000 /* in ms */
|
||||
|
||||
typedef enum {
|
||||
LOOPBACK_XMII2MAC,
|
||||
LOOPBACK_PCS2MAC,
|
||||
LOOPBACK_PMA2MAC,
|
||||
LOOPBACK_RMII2PHY,
|
||||
} phy_loopback_mode_t;
|
||||
|
||||
/* phy interface mode */
|
||||
typedef enum {
|
||||
PHY_IF_MODE_MII,
|
||||
PHY_IF_MODE_GMII,
|
||||
PHY_IF_MODE_SGMII,
|
||||
PHY_IF_MODE_TBI,
|
||||
PHY_IF_MODE_RMII,
|
||||
PHY_IF_MODE_RGMII,
|
||||
PHY_IF_MODE_RGMII_ID,
|
||||
PHY_IF_MODE_RGMII_RXID,
|
||||
PHY_IF_MODE_RGMII_TXID,
|
||||
PHY_IF_MODE_RTBI,
|
||||
|
||||
PHY_IF_MODE_NONE, /* Last One */
|
||||
PHY_IF_MODE_COUNT,
|
||||
} phy_if_mode_t;
|
||||
|
||||
typedef struct {
|
||||
eth_phy_priv_t *priv;
|
||||
eth_link_state_t link_state;
|
||||
|
||||
uint32_t supported;
|
||||
uint32_t advertising;
|
||||
|
||||
/*
|
||||
* platform specific
|
||||
*/
|
||||
uint32_t phy_addr;
|
||||
phy_if_mode_t interface;
|
||||
|
||||
/*
|
||||
* driver specific
|
||||
*/
|
||||
uint32_t phy_id;
|
||||
uint32_t mask;
|
||||
uint32_t features;
|
||||
int8_t name[20];
|
||||
/* config() should be called before calling start() */
|
||||
int32_t (*config)(eth_phy_handle_t *phy_dev);
|
||||
int32_t (*start)(eth_phy_handle_t *phy_dev);
|
||||
int32_t (*stop)(eth_phy_handle_t *phy_dev);
|
||||
int32_t (*loopback)(eth_phy_handle_t *phy_dev);
|
||||
int32_t (*update_link)(eth_phy_handle_t *phy_dev);
|
||||
} eth_phy_dev_t;
|
||||
|
||||
/* ethernet phy config */
|
||||
#define ETH_PHY_BASE 0x03009000
|
||||
#define ETH_PHY_INIT_MASK 0xFFFFFFF9
|
||||
#define ETH_PHY_SHUTDOWN (1 << 1)
|
||||
#define ETH_PHY_POWERUP 0xFFFFFFFD
|
||||
#define ETH_PHY_RESET 0xFFFFFFFB
|
||||
#define ETH_PHY_RESET_N (1 << 2)
|
||||
#define ETH_PHY_LED_LOW_ACTIVE (1 << 3)
|
||||
|
||||
int generic_phy_config_aneg(eth_phy_dev_t *dev);
|
||||
int generic_phy_restart_aneg(eth_phy_dev_t *dev);
|
||||
int generic_phy_update_link(eth_phy_dev_t *dev);
|
||||
|
||||
int32_t eth_phy_read(eth_phy_priv_t *priv, uint8_t phy_addr, uint8_t reg_addr, uint16_t *data);
|
||||
int32_t eth_phy_write(eth_phy_priv_t *priv, uint8_t phy_addr, uint8_t reg_addr, uint16_t data);
|
||||
|
||||
int32_t eth_phy_reset(eth_phy_handle_t handle);
|
||||
int32_t eth_phy_config(eth_phy_handle_t handle);
|
||||
int32_t eth_phy_start(eth_phy_handle_t handle);
|
||||
int32_t eth_phy_update_link(eth_phy_handle_t handle);
|
||||
|
||||
int32_t genphy_config(eth_phy_dev_t *phy_dev);
|
||||
int32_t genphy_update_link(eth_phy_dev_t *phy_dev);
|
||||
|
||||
/*
|
||||
* ffs: find first bit set. This is defined the same way as
|
||||
* the libc and compiler builtin ffs routines, therefore
|
||||
* differs in spirit from the above ffz (man ffs).
|
||||
*/
|
||||
|
||||
// static inline int32_t ffs(int32_t x)
|
||||
// {
|
||||
// int32_t r = 1;
|
||||
|
||||
// if (!x)
|
||||
// return 0;
|
||||
// if (!(x & 0xffff)) {
|
||||
// x >>= 16;
|
||||
// r += 16;
|
||||
// }
|
||||
// if (!(x & 0xff)) {
|
||||
// x >>= 8;
|
||||
// r += 8;
|
||||
// }
|
||||
// if (!(x & 0xf)) {
|
||||
// x >>= 4;
|
||||
// r += 4;
|
||||
// }
|
||||
// if (!(x & 3)) {
|
||||
// x >>= 2;
|
||||
// r += 2;
|
||||
// }
|
||||
// if (!(x & 1)) {
|
||||
// x >>= 1;
|
||||
// r += 1;
|
||||
// }
|
||||
// return r;
|
||||
// }
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ETH_PHY_H_ */
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
* Copyright (C) Cvitek Co., Ltd. 2019-2022. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DW_GMAC_182x_H_
|
||||
#define _DW_GMAC_182x_H_
|
||||
|
||||
#include "cvi_eth_phy.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void *eth_mac_handle_t;
|
||||
|
||||
#define CSI_ETH_MAC_CONFIGURE (0x01) ///< Configure MAC; arg = configuration
|
||||
#define CSI_ETH_MAC_CONTROL_TX (0x02) ///< Transmitter; arg: 0=disabled (default), 1=enabled
|
||||
#define CSI_ETH_MAC_CONTROL_RX (0x03) ///< Receiver; arg: 0=disabled (default), 1=enabled
|
||||
#define CSI_ETH_MAC_FLUSH (0x04) ///< Flush buffer; arg = CSI_ETH_MAC_FLUSH_...
|
||||
#define CSI_ETH_MAC_SLEEP (0x05) ///< Sleep mode; arg: 1=enter and wait for Magic packet, 0=exit
|
||||
#define CSI_ETH_MAC_VLAN_FILTER (0x06) ///< VLAN Filter for received frames; arg15..0: VLAN Tag; arg16: optional CSI_ETH_MAC_VLAN_FILTER_ID_ONLY; 0=disabled (default)
|
||||
#define DRV_ETH_MAC_ADJUST_LINK (0x07) ///< Adjust MAC link state according to phy state; arg: phy handle
|
||||
#define DRV_ETH_MAC_CONTROL_IRQ (0x08) ///< Interrupt request; arg: 0=disable, 1=enable
|
||||
|
||||
#define DW_GMAC_DMA_ALIGN 128
|
||||
|
||||
#ifndef _DW_ETH_H
|
||||
#define _DW_ETH_H
|
||||
|
||||
#define GMAC_NULL_PARAM_CHK(para) CSI_PARAM_CHK(para, -1)
|
||||
#define GMAC_NULL_PARAM_CHK_NORETVAL(para) CSI_PARAM_CHK_NORETVAL(para)
|
||||
|
||||
#define CVI_CONFIG_SYS_HZ 1000
|
||||
#define CVI_CONFIG_TX_DESCR_NUM 16
|
||||
#define CVI_CONFIG_RX_DESCR_NUM 16
|
||||
#define CVI_CONFIG_ETH_BUFSIZE 2048
|
||||
#define CVI_TX_TOTAL_BUFSIZE (CVI_CONFIG_ETH_BUFSIZE * CVI_CONFIG_TX_DESCR_NUM)
|
||||
#define CVI_RX_TOTAL_BUFSIZE (CVI_CONFIG_ETH_BUFSIZE * CVI_CONFIG_RX_DESCR_NUM)
|
||||
|
||||
#define CVI_CONFIG_MACRESET_TIMEOUT (3 * CVI_CONFIG_SYS_HZ)
|
||||
#define CVI_CONFIG_MDIO_TIMEOUT (3 * CVI_CONFIG_SYS_HZ)
|
||||
|
||||
struct dw_gmac_mac_regs {
|
||||
volatile uint32_t conf; /* 0x00 */
|
||||
volatile uint32_t framefilt; /* 0x04 */
|
||||
volatile uint32_t hashtablehigh; /* 0x08 */
|
||||
volatile uint32_t hashtablelow; /* 0x0c */
|
||||
volatile uint32_t miiaddr; /* 0x10 */
|
||||
volatile uint32_t miidata; /* 0x14 */
|
||||
volatile uint32_t flowcontrol; /* 0x18 */
|
||||
volatile uint32_t vlantag; /* 0x1c */
|
||||
volatile uint32_t version; /* 0x20 */
|
||||
volatile uint32_t reserved_1[5];
|
||||
volatile uint32_t intreg; /* 0x38 */
|
||||
volatile uint32_t intmask; /* 0x3c */
|
||||
volatile uint32_t macaddr0hi; /* 0x40 */
|
||||
volatile uint32_t macaddr0lo; /* 0x44 */
|
||||
};
|
||||
|
||||
/* MAC configuration register definitions */
|
||||
#define CVI_FRAMEBURSTENABLE (1 << 21)
|
||||
#define CVI_MII_PORTSELECT (1 << 15)
|
||||
#define CVI_FES_100 (1 << 14)
|
||||
#define CVI_DISABLERXOWN (1 << 13)
|
||||
#define CVI_FULLDPLXMODE (1 << 11)
|
||||
#define CVI_RXENABLE (1 << 2)
|
||||
#define CVI_TXENABLE (1 << 3)
|
||||
|
||||
/* MII address register definitions */
|
||||
#define CVI_MII_BUSY (1 << 0)
|
||||
#define CVI_MII_WRITE (1 << 1)
|
||||
#define CVI_MII_CLKRANGE_60_100M (0)
|
||||
#define CVI_MII_CLKRANGE_100_150M (0x4)
|
||||
#define CVI_MII_CLKRANGE_20_35M (0x8)
|
||||
#define CVI_MII_CLKRANGE_35_60M (0xC)
|
||||
#define CVI_MII_CLKRANGE_150_250M (0x10)
|
||||
#define CVI_MII_CLKRANGE_250_300M (0x14)
|
||||
|
||||
#define CVI_MIIADDRSHIFT (11)
|
||||
#define CVI_MIIREGSHIFT (6)
|
||||
#define CVI_MII_REGMSK (0x1F << 6)
|
||||
#define CVI_MII_ADDRMSK (0x1F << 11)
|
||||
|
||||
typedef uint32_t reg_type;
|
||||
struct dw_gmac_dma_regs {
|
||||
volatile reg_type busmode; /* 0x00 */
|
||||
volatile reg_type txpolldemand; /* 0x04 */
|
||||
volatile reg_type rxpolldemand; /* 0x08 */
|
||||
volatile reg_type rxdesclistaddr; /* 0x0c */
|
||||
volatile reg_type txdesclistaddr; /* 0x10 */
|
||||
volatile reg_type status; /* 0x14 */
|
||||
volatile reg_type opmode; /* 0x18 */
|
||||
volatile reg_type intenable; /* 0x1c */
|
||||
volatile reg_type discardedcount; /* 0x20 */
|
||||
volatile reg_type wdtforri; /* 0x24 */
|
||||
//volatile reg_type reserved1[2];
|
||||
volatile reg_type axibus; /* 0x28 */
|
||||
volatile reg_type reserved2[7];
|
||||
volatile reg_type currhosttxdesc; /* 0x48 */
|
||||
volatile reg_type currhostrxdesc; /* 0x4c */
|
||||
volatile reg_type currhosttxbuffaddr; /* 0x50 */
|
||||
volatile reg_type currhostrxbuffaddr; /* 0x54 */
|
||||
};
|
||||
|
||||
/* Operation mode definitions */
|
||||
#define CVI_RXSTART (1 << 1)
|
||||
#define CVI_TXSECONDFRAME (1 << 2)
|
||||
#define CVI_TXSTART (1 << 13)
|
||||
#define CVI_FLUSHTXFIFO (1 << 20)
|
||||
#define CVI_STOREFORWARD (1 << 21)
|
||||
#define CVI_DW_DMA_BASE_OFFSET (0x1000)
|
||||
|
||||
/* Default DMA Burst length */
|
||||
#ifndef CONFIG_DW_GMAC_DEFAULT_DMA_PBL
|
||||
#define CONFIG_DW_GMAC_DEFAULT_DMA_PBL 8
|
||||
#endif
|
||||
/* Status definitions */
|
||||
#define CVI_DMA_STATUS_ERI 0x00004000 /* Early Receive Interrupt */
|
||||
#define CVI_DMA_STATUS_RI 0x00000040 /* Receive Interrupt */
|
||||
#define CVI_DMA_STATUS_TI 0x00000001 /* Transmit Interrupt */
|
||||
|
||||
/* Bus mode register definitions */
|
||||
|
||||
#define CVI_DMAMAC_SRST (1 << 0)
|
||||
#define CVI_RXHIGHPRIO (1 << 1)
|
||||
#define CVI_FIXEDBURST (1 << 16)
|
||||
#define CVI_PRIORXTX_11 (0 << 14)
|
||||
#define CVI_PRIORXTX_21 (1 << 14)
|
||||
#define CVI_PRIORXTX_31 (2 << 14)
|
||||
#define CVI_PRIORXTX_41 (3 << 14)
|
||||
#define CVI_DMA_PBL (CONFIG_DW_GMAC_DEFAULT_DMA_PBL<<8)
|
||||
|
||||
/* Poll demand definitions */
|
||||
#define CVI_POLL_DATA (0xFFFFFFFF)
|
||||
|
||||
|
||||
/* Descriptior related definitions */
|
||||
#define CVI_MAC_MAX_FRAME_SZ (1600)
|
||||
|
||||
struct dmamacdescr {
|
||||
unsigned int txrx_status;
|
||||
unsigned int dmamac_cntl;
|
||||
unsigned int dmamac_addr;
|
||||
unsigned int dmamac_next;
|
||||
} __attribute__((aligned(DW_GMAC_DMA_ALIGN)));
|
||||
|
||||
/*
|
||||
* txrx_status definitions
|
||||
*/
|
||||
|
||||
/* tx status bits definitions */
|
||||
#if defined(CONFIG_DW_ALTDESCRIPTOR)
|
||||
|
||||
#define CVI_DESC_TXSTS_OWNBYDMA (1 << 31)
|
||||
#define CVI_DESC_TXSTS_TXINT (1 << 30)
|
||||
#define CVI_DESC_TXSTS_TXLAST (1 << 29)
|
||||
#define CVI_DESC_TXSTS_TXFIRST (1 << 28)
|
||||
#define CVI_DESC_TXSTS_TXCRCDIS (1 << 27)
|
||||
|
||||
#define CVI_DESC_TXSTS_TXPADDIS (1 << 26)
|
||||
#define CVI_DESC_TXSTS_TXCHECKINSCTRL (3 << 22)
|
||||
#define CVI_DESC_TXSTS_TXRINGEND (1 << 21)
|
||||
#define CVI_DESC_TXSTS_TXCHAIN (1 << 20)
|
||||
#define CVI_DESC_TXSTS_MSK (0x1FFFF << 0)
|
||||
|
||||
#else
|
||||
|
||||
#define CVI_DESC_TXSTS_OWNBYDMA (1 << 31)
|
||||
#define CVI_DESC_TXSTS_MSK (0x1FFFF << 0)
|
||||
|
||||
#endif
|
||||
|
||||
/* rx status bits definitions */
|
||||
#define CVI_DESC_RXSTS_OWNBYDMA (1 << 31)
|
||||
#define CVI_DESC_RXSTS_DAFILTERFAIL (1 << 30)
|
||||
#define CVI_DESC_RXSTS_FRMLENMSK (0x3FFF << 16)
|
||||
#define CVI_DESC_RXSTS_FRMLENSHFT (16)
|
||||
|
||||
#define CVI_DESC_RXSTS_ERROR (1 << 15)
|
||||
#define CVI_DESC_RXSTS_RXTRUNCATED (1 << 14)
|
||||
#define CVI_DESC_RXSTS_SAFILTERFAIL (1 << 13)
|
||||
#define CVI_DESC_RXSTS_RXIPC_GIANTFRAME (1 << 12)
|
||||
#define CVI_DESC_RXSTS_RXDAMAGED (1 << 11)
|
||||
#define CVI_DESC_RXSTS_RXVLANTAG (1 << 10)
|
||||
#define CVI_DESC_RXSTS_RXFIRST (1 << 9)
|
||||
#define CVI_DESC_RXSTS_RXLAST (1 << 8)
|
||||
#define CVI_DESC_RXSTS_RXIPC_GIANT (1 << 7)
|
||||
#define CVI_DESC_RXSTS_RXCOLLISION (1 << 6)
|
||||
#define CVI_DESC_RXSTS_RXFRAMEETHER (1 << 5)
|
||||
#define CVI_DESC_RXSTS_RXWATCHDOG (1 << 4)
|
||||
#define CVI_DESC_RXSTS_RXMIIERROR (1 << 3)
|
||||
#define CVI_DESC_RXSTS_RXDRIBBLING (1 << 2)
|
||||
#define CVI_DESC_RXSTS_RXCRC (1 << 1)
|
||||
|
||||
/*
|
||||
* dmamac_cntl definitions
|
||||
*/
|
||||
|
||||
/* tx control bits definitions */
|
||||
#if defined(CONFIG_DW_ALTDESCRIPTOR)
|
||||
|
||||
#define CVI_DESC_TXCTRL_SIZE1MASK (0x1FFF << 0)
|
||||
#define CVI_DESC_TXCTRL_SIZE1SHFT (0)
|
||||
#define CVI_DESC_TXCTRL_SIZE2MASK (0x1FFF << 16)
|
||||
#define CVI_DESC_TXCTRL_SIZE2SHFT (16)
|
||||
|
||||
#else
|
||||
|
||||
#define CVI_DESC_TXCTRL_TXINT (1 << 31)
|
||||
#define CVI_DESC_TXCTRL_TXLAST (1 << 30)
|
||||
#define CVI_DESC_TXCTRL_TXFIRST (1 << 29)
|
||||
#define CVI_DESC_TXCTRL_TXCHECKINSCTRL (3 << 27)
|
||||
#define CVI_DESC_TXCTRL_TXCRCDIS (1 << 26)
|
||||
#define CVI_DESC_TXCTRL_TXRINGEND (1 << 25)
|
||||
#define CVI_DESC_TXCTRL_TXCHAIN (1 << 24)
|
||||
|
||||
#define CVI_DESC_TXCTRL_SIZE1MASK (0x7FF << 0)
|
||||
#define CVI_DESC_TXCTRL_SIZE1SHFT (0)
|
||||
#define CVI_DESC_TXCTRL_SIZE2MASK (0x7FF << 11)
|
||||
#define CVI_DESC_TXCTRL_SIZE2SHFT (11)
|
||||
|
||||
#endif
|
||||
|
||||
/* rx control bits definitions */
|
||||
#if defined(CONFIG_DW_ALTDESCRIPTOR)
|
||||
|
||||
#define CVI_DESC_RXCTRL_RXINTDIS (1 << 31)
|
||||
#define CVI_DESC_RXCTRL_RXRINGEND (1 << 15)
|
||||
#define CVI_DESC_RXCTRL_RXCHAIN (1 << 14)
|
||||
|
||||
#define CVI_DESC_RXCTRL_SIZE1MASK (0x1FFF << 0)
|
||||
#define CVI_DESC_RXCTRL_SIZE1SHFT (0)
|
||||
#define CVI_DESC_RXCTRL_SIZE2MASK (0x1FFF << 16)
|
||||
#define CVI_DESC_RXCTRL_SIZE2SHFT (16)
|
||||
|
||||
#else
|
||||
|
||||
#define CVI_DESC_RXCTRL_RXINTDIS (1 << 31)
|
||||
#define CVI_DESC_RXCTRL_RXRINGEND (1 << 25)
|
||||
#define CVI_DESC_RXCTRL_RXCHAIN (1 << 24)
|
||||
|
||||
#define CVI_DESC_RXCTRL_SIZE1MASK (0x7FF << 0)
|
||||
#define CVI_DESC_RXCTRL_SIZE1SHFT (0)
|
||||
#define CVI_DESC_RXCTRL_SIZE2MASK (0x7FF << 11)
|
||||
#define CVI_DESC_RXCTRL_SIZE2SHFT (11)
|
||||
|
||||
#endif
|
||||
|
||||
struct dw_gmac_priv {
|
||||
struct dmamacdescr tx_mac_descrtable[CVI_CONFIG_TX_DESCR_NUM] __aligned(DW_GMAC_DMA_ALIGN);
|
||||
struct dmamacdescr rx_mac_descrtable[CVI_CONFIG_RX_DESCR_NUM] __aligned(DW_GMAC_DMA_ALIGN);
|
||||
char txbuffs[CVI_TX_TOTAL_BUFSIZE] __aligned(DW_GMAC_DMA_ALIGN);
|
||||
char rxbuffs[CVI_RX_TOTAL_BUFSIZE] __aligned(DW_GMAC_DMA_ALIGN);
|
||||
|
||||
uint32_t interface;
|
||||
uint32_t max_speed;
|
||||
uint32_t tx_currdescnum;
|
||||
uint32_t rx_currdescnum;
|
||||
|
||||
struct dw_gmac_mac_regs *mac_regs_p;
|
||||
struct dw_gmac_dma_regs *dma_regs_p;
|
||||
|
||||
//struct gpio_desc reset_gpio;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DM_ETH
|
||||
int designware_eth_ofdata_to_platdata(struct udevice *dev);
|
||||
int designware_eth_probe(struct udevice *dev);
|
||||
extern const struct eth_ops designware_eth_ops;
|
||||
|
||||
struct dw_eth_pdata {
|
||||
struct eth_pdata eth_pdata;
|
||||
u32 reset_delays[3];
|
||||
};
|
||||
|
||||
int designware_eth_init(struct dw_eth_dev *priv, u8 *enetaddr);
|
||||
int designware_eth_enable(struct dw_eth_dev *priv);
|
||||
int designware_eth_send(struct udevice *dev, void *packet, int length);
|
||||
int designware_eth_recv(struct udevice *dev, int flags, uchar **packetp);
|
||||
int designware_eth_free_pkt(struct udevice *dev, uchar *packet,
|
||||
int length);
|
||||
void designware_eth_stop(struct udevice *dev);
|
||||
int designware_eth_write_hwaddr(struct udevice *dev);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
// csi_dev_t dev;
|
||||
eth_phy_dev_t *phy_dev;
|
||||
unsigned long base;
|
||||
uint8_t irq;
|
||||
// eth_event_cb_t cb_event;
|
||||
uint8_t mac_addr[6];
|
||||
struct dw_gmac_priv *priv_unalign;
|
||||
struct dw_gmac_priv *priv;
|
||||
} gmac_dev_t;
|
||||
|
||||
/**
|
||||
\brief Ethernet MAC Address
|
||||
*/
|
||||
typedef struct eth_mac_addr {
|
||||
uint8_t b[6]; ///< MAC Address (6 bytes), MSB first
|
||||
} eth_mac_addr_t;
|
||||
|
||||
static inline void *memalign(uint32_t align, uint32_t size, void **mem_unalign)
|
||||
{
|
||||
void *mem;
|
||||
uint32_t offset;
|
||||
|
||||
*mem_unalign = (void *)rt_malloc(size + align);
|
||||
|
||||
if (!*mem_unalign) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
offset = *(uint32_t *)mem_unalign % align;
|
||||
|
||||
if (offset == 0) {
|
||||
mem = (struct eqos_priv *)*mem_unalign;
|
||||
} else {
|
||||
mem = (struct eqos_priv *)(*mem_unalign + (align - offset));
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _DW_GMAC_182x_H_ */
|
|
@ -0,0 +1,383 @@
|
|||
/*
|
||||
* Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// #include <mmio.h>
|
||||
|
||||
#include "cvi_eth_phy.h"
|
||||
#include "mii.h"
|
||||
|
||||
|
||||
|
||||
// #define CVI_ETH_PHY_LOOPBACK
|
||||
#define LOOPBACK_XMII2MAC 0x8000
|
||||
#define LOOPBACK_PCS2MAC 0x2000
|
||||
#define LOOPBACK_PMA2MAC 0x1000
|
||||
#define LOOPBACK_RMII2PHY 0x0080
|
||||
|
||||
#define EPHY_EFUSE_VALID_BIT_BASE 0x03050120
|
||||
#define EPHY_EFUSE_TXECHORC_FLAG 0x00000100 // bit 8
|
||||
#define EPHY_EFUSE_TXITUNE_FLAG 0x00000200 // bit 9
|
||||
#define EPHY_EFUSE_TXRXTERM_FLAG 0x00000800 // bit 11
|
||||
|
||||
static inline bool phy_if_mode_is_rgmii(phy_if_mode_t interface)
|
||||
{
|
||||
return interface >= PHY_IF_MODE_RGMII && interface <= PHY_IF_MODE_RGMII_TXID;
|
||||
}
|
||||
|
||||
#if defined(CVI_ETH_PHY_LOOPBACK)
|
||||
static int cv181x_set_phy_loopback(eth_phy_handle_t handle, phy_loopback_mode_t mode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
\brief Configure the cv181x before make it start up.
|
||||
\param[in] handle phy handle
|
||||
\return error code
|
||||
*/
|
||||
/* CVITEK cv181x */
|
||||
int32_t cv181x_config(eth_phy_handle_t handle)
|
||||
{
|
||||
assert(handle);
|
||||
eth_phy_dev_t *dev = (eth_phy_dev_t *)handle;
|
||||
uint32_t val = 0;
|
||||
|
||||
// eth_phy_reset(dev);
|
||||
|
||||
// set rg_ephy_apb_rw_sel 0x0804@[0]=1/APB by using APB interface
|
||||
mmio_write_32(0x03009804, 0x0001);
|
||||
|
||||
// Release 0x0800[0]=0/shutdown
|
||||
// mmio_write_32(0x03009800, 0x0900);
|
||||
|
||||
// Release 0x0800[2]=1/dig_rst_n, Let mii_reg can be accessabile
|
||||
// mmio_write_32(0x03009800, 0x0904);
|
||||
|
||||
//mdelay(10);
|
||||
|
||||
// ANA INIT (PD/EN), switch to MII-page5
|
||||
mmio_write_32(0x0300907c, 0x0500);
|
||||
// Release ANA_PD p5.0x10@[13:8] = 6'b001100
|
||||
mmio_write_32(0x03009040, 0x0c00);
|
||||
// Release ANA_EN p5.0x10@[7:0] = 8'b01111110
|
||||
mmio_write_32(0x03009040, 0x0c7e);
|
||||
|
||||
// Wait PLL_Lock, Lock_Status p5.0x12@[15] = 1
|
||||
//mdelay(1);
|
||||
|
||||
// Release 0x0800[1] = 1/ana_rst_n
|
||||
mmio_write_32(0x03009800, 0x0906);
|
||||
|
||||
// ANA INIT
|
||||
// @Switch to MII-page5
|
||||
mmio_write_32(0x0300907c, 0x0500);
|
||||
|
||||
// Efuse register
|
||||
// Set Double Bias Current
|
||||
//Set rg_eth_txitune1 0x03009064 [15:8]
|
||||
//Set rg_eth_txitune0 0x03009064 [7:0]
|
||||
if ((mmio_read_32(EPHY_EFUSE_VALID_BIT_BASE) & EPHY_EFUSE_TXITUNE_FLAG) ==
|
||||
EPHY_EFUSE_TXITUNE_FLAG) {
|
||||
val = ((mmio_read_32(0x03051024) >> 24) & 0xFF) |
|
||||
(((mmio_read_32(0x03051024) >> 16) & 0xFF) << 8);
|
||||
mmio_clrsetbits_32(0x03009064, 0xFFFF, val);
|
||||
} else
|
||||
mmio_write_32(0x03009064, 0x5a5a);
|
||||
|
||||
// Set Echo_I
|
||||
// Set rg_eth_txechoiadj 0x03009054 [15:8]
|
||||
if ((mmio_read_32(EPHY_EFUSE_VALID_BIT_BASE) & EPHY_EFUSE_TXECHORC_FLAG) ==
|
||||
EPHY_EFUSE_TXECHORC_FLAG) {
|
||||
mmio_clrsetbits_32(0x03009054, 0xFF00, ((mmio_read_32(0x03051024) >> 8) & 0xFF) << 8);
|
||||
} else
|
||||
mmio_write_32(0x03009054, 0x0000);
|
||||
|
||||
//Set TX_Rterm & Echo_RC_Delay
|
||||
// Set rg_eth_txrterm_p1 0x03009058 [11:8]
|
||||
// Set rg_eth_txrterm 0x03009058 [7:4]
|
||||
// Set rg_eth_txechorcadj 0x03009058 [3:0]
|
||||
if ((mmio_read_32(EPHY_EFUSE_VALID_BIT_BASE) & EPHY_EFUSE_TXRXTERM_FLAG) ==
|
||||
EPHY_EFUSE_TXRXTERM_FLAG) {
|
||||
val = (((mmio_read_32(0x03051020) >> 28) & 0xF) << 4) |
|
||||
(((mmio_read_32(0x03051020) >> 24) & 0xF) << 8);
|
||||
mmio_clrsetbits_32(0x03009058, 0xFF0, val);
|
||||
} else
|
||||
mmio_write_32(0x03009058, 0x0bb0);
|
||||
|
||||
// ETH_100BaseT
|
||||
// Set Rise update
|
||||
mmio_write_32(0x0300905c, 0x0c10);
|
||||
|
||||
// Set Falling phase
|
||||
mmio_write_32(0x03009068, 0x0003);
|
||||
|
||||
// Set Double TX Bias Current
|
||||
mmio_write_32(0x03009054, 0x0000);
|
||||
|
||||
// Switch to MII-page16
|
||||
mmio_write_32(0x0300907c, 0x1000);
|
||||
|
||||
// Set MLT3 Positive phase code, Set MLT3 +0
|
||||
mmio_write_32(0x03009068, 0x1000);
|
||||
mmio_write_32(0x0300906c, 0x3020);
|
||||
mmio_write_32(0x03009070, 0x5040);
|
||||
mmio_write_32(0x03009074, 0x7060);
|
||||
|
||||
// Set MLT3 +I
|
||||
mmio_write_32(0x03009058, 0x1708);
|
||||
mmio_write_32(0x0300905c, 0x3827);
|
||||
mmio_write_32(0x03009060, 0x5748);
|
||||
mmio_write_32(0x03009064, 0x7867);
|
||||
|
||||
// Switch to MII-page17
|
||||
mmio_write_32(0x0300907c, 0x1100);
|
||||
|
||||
// Set MLT3 Negative phase code, Set MLT3 -0
|
||||
mmio_write_32(0x03009040, 0x9080);
|
||||
mmio_write_32(0x03009044, 0xb0a0);
|
||||
mmio_write_32(0x03009048, 0xd0c0);
|
||||
mmio_write_32(0x0300904c, 0xf0e0);
|
||||
|
||||
// Set MLT3 -I
|
||||
mmio_write_32(0x03009050, 0x9788);
|
||||
mmio_write_32(0x03009054, 0xb8a7);
|
||||
mmio_write_32(0x03009058, 0xd7c8);
|
||||
mmio_write_32(0x0300905c, 0xf8e7);
|
||||
|
||||
// @Switch to MII-page5
|
||||
mmio_write_32(0x0300907c, 0x0500);
|
||||
|
||||
// En TX_Rterm
|
||||
mmio_write_32(0x03009040, (0x0001 | mmio_read_32(0x03009040)));
|
||||
|
||||
// Link Pulse
|
||||
// Switch to MII-page10
|
||||
mmio_write_32(0x0300907c, 0x0a00);
|
||||
|
||||
// Set Link Pulse
|
||||
mmio_write_32(0x03009040, 0x2000);
|
||||
mmio_write_32(0x03009044, 0x3832);
|
||||
mmio_write_32(0x03009048, 0x3132);
|
||||
mmio_write_32(0x0300904c, 0x2d2f);
|
||||
mmio_write_32(0x03009050, 0x2c2d);
|
||||
mmio_write_32(0x03009054, 0x1b2b);
|
||||
mmio_write_32(0x03009058, 0x94a0);
|
||||
mmio_write_32(0x0300905c, 0x8990);
|
||||
mmio_write_32(0x03009060, 0x8788);
|
||||
mmio_write_32(0x03009064, 0x8485);
|
||||
mmio_write_32(0x03009068, 0x8283);
|
||||
mmio_write_32(0x0300906c, 0x8182);
|
||||
mmio_write_32(0x03009070, 0x0081);
|
||||
|
||||
// TP_IDLE
|
||||
// Switch to MII-page11
|
||||
mmio_write_32(0x0300907c, 0x0b00);
|
||||
|
||||
// Set TP_IDLE
|
||||
mmio_write_32(0x03009040, 0x5252);
|
||||
mmio_write_32(0x03009044, 0x5252);
|
||||
mmio_write_32(0x03009048, 0x4B52);
|
||||
mmio_write_32(0x0300904c, 0x3D47);
|
||||
mmio_write_32(0x03009050, 0xAA99);
|
||||
mmio_write_32(0x03009054, 0x989E);
|
||||
mmio_write_32(0x03009058, 0x9395);
|
||||
mmio_write_32(0x0300905C, 0x9091);
|
||||
mmio_write_32(0x03009060, 0x8E8F);
|
||||
mmio_write_32(0x03009064, 0x8D8E);
|
||||
mmio_write_32(0x03009068, 0x8C8C);
|
||||
mmio_write_32(0x0300906C, 0x8B8B);
|
||||
mmio_write_32(0x03009070, 0x008A);
|
||||
|
||||
// ETH 10BaseT Data
|
||||
// Switch to MII-page13
|
||||
mmio_write_32(0x0300907c, 0x0d00);
|
||||
|
||||
mmio_write_32(0x03009040, 0x1E0A);
|
||||
mmio_write_32(0x03009044, 0x3862);
|
||||
mmio_write_32(0x03009048, 0x1E62);
|
||||
mmio_write_32(0x0300904c, 0x2A08);
|
||||
mmio_write_32(0x03009050, 0x244C);
|
||||
mmio_write_32(0x03009054, 0x1A44);
|
||||
mmio_write_32(0x03009058, 0x061C);
|
||||
|
||||
// Switch to MII-page14
|
||||
mmio_write_32(0x0300907c, 0x0e00);
|
||||
|
||||
mmio_write_32(0x03009040, 0x2D30);
|
||||
mmio_write_32(0x03009044, 0x3470);
|
||||
mmio_write_32(0x03009048, 0x0648);
|
||||
mmio_write_32(0x0300904c, 0x261C);
|
||||
mmio_write_32(0x03009050, 0x3160);
|
||||
mmio_write_32(0x03009054, 0x2D5E);
|
||||
|
||||
// Switch to MII-page15
|
||||
mmio_write_32(0x0300907c, 0x0f00);
|
||||
|
||||
mmio_write_32(0x03009040, 0x2922);
|
||||
mmio_write_32(0x03009044, 0x366E);
|
||||
mmio_write_32(0x03009048, 0x0752);
|
||||
mmio_write_32(0x0300904c, 0x2556);
|
||||
mmio_write_32(0x03009050, 0x2348);
|
||||
mmio_write_32(0x03009054, 0x0C30);
|
||||
|
||||
// Switch to MII-page16
|
||||
mmio_write_32(0x0300907c, 0x1000);
|
||||
|
||||
mmio_write_32(0x03009040, 0x1E08);
|
||||
mmio_write_32(0x03009044, 0x3868);
|
||||
mmio_write_32(0x03009048, 0x1462);
|
||||
mmio_write_32(0x0300904c, 0x1A0E);
|
||||
mmio_write_32(0x03009050, 0x305E);
|
||||
mmio_write_32(0x03009054, 0x2F62);
|
||||
|
||||
// LED PAD MUX
|
||||
mmio_write_32(0x030010e0, 0x05);
|
||||
mmio_write_32(0x030010e4, 0x05);
|
||||
//(SD1_CLK selphy)
|
||||
mmio_write_32(0x050270b0, 0x11111111);
|
||||
//(SD1_CMD selphy)
|
||||
mmio_write_32(0x050270b4, 0x11111111);
|
||||
|
||||
// LED
|
||||
// Switch to MII-page1
|
||||
mmio_write_32(0x0300907c, 0x0100);
|
||||
|
||||
// select LED_LNK/SPD/DPX out to LED_PAD
|
||||
mmio_write_32(0x03009068, (mmio_read_32(0x03009068) & ~0x0f00));
|
||||
|
||||
// @Switch to MII-page0
|
||||
mmio_write_32(0x0300907c, 0x0000);
|
||||
|
||||
// PHY_ID
|
||||
mmio_write_32(0x03009008, 0x0043);
|
||||
mmio_write_32(0x0300900c, 0x5649);
|
||||
|
||||
// Switch to MII-page19
|
||||
mmio_write_32(0x0300907c, 0x1300);
|
||||
mmio_write_32(0x03009058, 0x0012);
|
||||
// set agc max/min swing
|
||||
mmio_write_32(0x0300905C, 0x6848);
|
||||
|
||||
// Switch to MII-page18
|
||||
mmio_write_32(0x0300907c, 0x1200);
|
||||
// p18.0x12, lpf
|
||||
mmio_write_32(0x03009048, 0x0808);
|
||||
mmio_write_32(0x0300904C, 0x0808);
|
||||
// hpf
|
||||
//sean
|
||||
mmio_write_32(0x03009050, 0x32f8);
|
||||
mmio_write_32(0x03009054, 0xf8dc);
|
||||
|
||||
// Switch to MII-page0
|
||||
mmio_write_32(0x0300907c, 0x0000);
|
||||
// EPHY start auto-neg procedure
|
||||
mmio_write_32(0x03009800, 0x090e);
|
||||
|
||||
// switch to MDIO control by ETH_MAC
|
||||
mmio_write_32(0x03009804, 0x0000);
|
||||
|
||||
genphy_config(dev);
|
||||
|
||||
#if defined(CVI_ETH_PHY_LOOPBACK)
|
||||
cv181x_set_phy_loopback(handle, LOOPBACK_PCS2MAC);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Parse 88E1xxx's speed and duplex from status register.
|
||||
\param[in] dev phy device pointer
|
||||
\return error code
|
||||
*/
|
||||
static int32_t cv181x_parse_status(eth_phy_dev_t *dev)
|
||||
{
|
||||
assert(dev);
|
||||
assert(dev->priv);
|
||||
eth_phy_priv_t *priv = dev->priv;
|
||||
uint8_t phy_addr = dev->phy_addr;
|
||||
uint16_t mii_reg;
|
||||
int32_t ret;
|
||||
|
||||
ret = eth_phy_read(priv, phy_addr, CVI_MII_BMSR, &mii_reg);
|
||||
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (mii_reg & (CVI_BMSR_100FULL | CVI_BMSR_100HALF))
|
||||
priv->link_info.speed = CSI_ETH_SPEED_100M;
|
||||
else
|
||||
priv->link_info.speed = CSI_ETH_SPEED_10M;
|
||||
|
||||
if (mii_reg & (CVI_BMSR_10FULL | CVI_BMSR_100FULL))
|
||||
priv->link_info.duplex = CSI_ETH_DUPLEX_FULL;
|
||||
else
|
||||
priv->link_info.duplex = CSI_ETH_DUPLEX_HALF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Start up the 88E1111.
|
||||
\param[in] handle phy handle
|
||||
\return error code
|
||||
*/
|
||||
int32_t cv181x_start(eth_phy_handle_t handle)
|
||||
{
|
||||
assert(handle);
|
||||
|
||||
eth_phy_dev_t *dev = (eth_phy_dev_t *)handle;
|
||||
int32_t ret;
|
||||
|
||||
/* Read the Status (2x to make sure link is right) */
|
||||
ret = genphy_update_link(dev);
|
||||
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return cv181x_parse_status(dev);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Halt the cv181x.
|
||||
\param[in] handle phy handle
|
||||
\return error code
|
||||
*/
|
||||
int32_t cv181x_stop(eth_phy_handle_t handle)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Update the cv181x's link state.
|
||||
\param[in] handle phy handle
|
||||
\return error code
|
||||
*/
|
||||
int32_t cv181x_update_link(eth_phy_handle_t handle)
|
||||
{
|
||||
assert(handle);
|
||||
eth_phy_dev_t *dev = (eth_phy_dev_t *)handle;
|
||||
return cv181x_parse_status(dev);;
|
||||
}
|
||||
|
||||
|
||||
/* Support for cv181x PHYs */
|
||||
eth_phy_dev_t cv181x_device = {
|
||||
.name = "CVITEK,CV181X",
|
||||
.phy_id = 0x00435649,
|
||||
.mask = 0xffffffff,
|
||||
.features = CVI_PHY_BASIC_FEATURES,
|
||||
.config = &cv181x_config,
|
||||
.start = &cv181x_start,
|
||||
.stop = &cv181x_stop,
|
||||
//.loopback = &cv181x_loopback,
|
||||
//.update_link = &cv181x_update_link,
|
||||
};
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright (C) Cvitek Co., Ltd. 2019-2020. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef __MII_H__
|
||||
#define __MII_H__
|
||||
|
||||
/* Basic mode control register. */
|
||||
#define CVI_BMCR_RESV (0x003f)
|
||||
#define CVI_BMCR_SPEED1000 (0x0040)
|
||||
#define CVI_BMCR_CTST (0x0080)
|
||||
#define CVI_BMCR_FULLDPLX (0x0100)
|
||||
#define CVI_BMCR_ANRESTART (0x0200)
|
||||
#define CVI_BMCR_ISOLATE (0x0400)
|
||||
#define CVI_BMCR_PDOWN (0x0800)
|
||||
#define CVI_BMCR_ANENABLE (0x1000)
|
||||
#define CVI_BMCR_SPEED100 (0x2000)
|
||||
#define CVI_BMCR_LOOPBACK (0x4000)
|
||||
#define CVI_BMCR_RESET (0x8000)
|
||||
|
||||
/* Basic mode status register. */
|
||||
#define CVI_BMSR_ERCAP (0x0001)
|
||||
#define CVI_BMSR_JCD (0x0002)
|
||||
#define CVI_BMSR_LSTATUS (0x0004)
|
||||
#define CVI_BMSR_ANEGCAPABLE (0x0008)
|
||||
#define CVI_BMSR_RFAULT (0x0010)
|
||||
#define CVI_BMSR_ANEGCOMPLETE (0x0020)
|
||||
#define CVI_BMSR_RESV (0x00c0)
|
||||
#define CVI_BMSR_ESTATEN (0x0100)
|
||||
#define CVI_BMSR_100HALF2 (0x0200)
|
||||
#define CVI_BMSR_100FULL2 (0x0400)
|
||||
#define CVI_BMSR_10HALF (0x0800)
|
||||
#define CVI_BMSR_10FULL (0x1000)
|
||||
#define CVI_BMSR_100HALF (0x2000)
|
||||
#define CVI_BMSR_100FULL (0x4000)
|
||||
#define CVI_BMSR_100BASE4 (0x8000)
|
||||
|
||||
/* Advertisement control register. */
|
||||
#define CVI_ADVERTISE_CSMA (0x0001)
|
||||
#define CVI_ADVERTISE_SLCT (0x001f)
|
||||
#define CVI_ADVERTISE_10HALF (0x0020)
|
||||
#define CVI_ADVERTISE_1000XFULL (0x0020)
|
||||
#define CVI_ADVERTISE_10FULL (0x0040)
|
||||
#define CVI_ADVERTISE_1000XHALF (0x0040)
|
||||
#define CVI_ADVERTISE_100HALF (0x0080)
|
||||
#define CVI_ADVERTISE_1000XPAUSE (0x0080)
|
||||
#define CVI_ADVERTISE_100FULL (0x0100)
|
||||
#define CVI_ADVERTISE_1000XPSE_ASYM (0x0100)
|
||||
#define CVI_ADVERTISE_100BASE4 (0x0200)
|
||||
#define CVI_ADVERTISE_PAUSE_CAP (0x0400)
|
||||
#define CVI_ADVERTISE_PAUSE_ASYM (0x0800)
|
||||
#define CVI_ADVERTISE_RESV (0x1000)
|
||||
#define CVI_ADVERTISE_RFAULT (0x2000)
|
||||
#define CVI_ADVERTISE_LPACK (0x4000)
|
||||
#define CVI_ADVERTISE_NPAGE (0x8000)
|
||||
|
||||
/* Generic MII registers. */
|
||||
|
||||
#define CVI_MII_BMCR (0x00)
|
||||
#define CVI_MII_BMSR (0x01)
|
||||
#define CVI_MII_PHYSID1 (0x02)
|
||||
#define CVI_MII_PHYSID2 (0x03)
|
||||
#define CVI_MII_ADVERTISE (0x04)
|
||||
#define CVI_MII_LPA (0x05)
|
||||
#define CVI_MII_EXPANSION (0x06)
|
||||
#define CVI_MII_CTRL1000 (0x09)
|
||||
#define CVI_MII_STAT1000 (0x0a)
|
||||
#define CVI_MII_ESTATUS (0x0f)
|
||||
#define CVI_MII_DCOUNTER (0x12)
|
||||
#define CVI_MII_FCSCOUNTER (0x13)
|
||||
#define CVI_MII_NWAYTEST (0x14)
|
||||
#define CVI_MII_RERRCOUNTER (0x15)
|
||||
#define CVI_MII_SREVISION (0x16)
|
||||
#define CVI_MII_RESV1 (0x17)
|
||||
#define CVI_MII_LBRERROR (0x18)
|
||||
#define CVI_MII_PHYADDR (0x19)
|
||||
#define CVI_MII_RESV2 (0x1a)
|
||||
#define CVI_MII_TPISTATUS (0x1b)
|
||||
#define CVI_MII_NCONFIG (0x1c)
|
||||
|
||||
#define CVI_ADVERTISE_FULL (CVI_ADVERTISE_100FULL | CVI_ADVERTISE_10FULL | \
|
||||
CVI_ADVERTISE_CSMA)
|
||||
#define CVI_ADVERTISE_ALL (CVI_ADVERTISE_10HALF | CVI_ADVERTISE_10FULL | \
|
||||
CVI_ADVERTISE_100HALF | CVI_ADVERTISE_100FULL)
|
||||
|
||||
/* Expansion register for auto-negotiation. */
|
||||
#define CVI_EXPANSION_NWAY (0x0001)
|
||||
#define CVI_EXPANSION_LCWP (0x0002)
|
||||
#define CVI_EXPANSION_ENABLENPAGE (0x0004)
|
||||
#define CVI_EXPANSION_NPCAPABLE (0x0008)
|
||||
#define CVI_EXPANSION_MFAULTS (0x0010)
|
||||
#define CVI_ESTATUS_1000_THALF (0x1000)
|
||||
#define CVI_ESTATUS_1000_TFULL (0x2000)
|
||||
#define CVI_ESTATUS_1000_XHALF (0x4000)
|
||||
#define CVI_ESTATUS_1000_XFULL (0x8000)
|
||||
#define CVI_EXPANSION_RESV (0xffe0)
|
||||
|
||||
/* Link partner ability register. */
|
||||
#define CVI_LPA_SLCT (0x001f)
|
||||
#define CVI_LPA_10HALF (0x0020)
|
||||
#define CVI_LPA_1000XFULL (0x0020)
|
||||
#define CVI_LPA_10FULL (0x0040)
|
||||
#define CVI_LPA_1000XHALF (0x0040)
|
||||
#define CVI_LPA_100HALF (0x0080)
|
||||
#define CVI_LPA_1000XPAUSE (0x0080)
|
||||
#define CVI_LPA_100FULL (0x0100)
|
||||
#define CVI_LPA_1000XPAUSE_ASYM (0x0100)
|
||||
#define CVI_LPA_100BASE4 (0x0200)
|
||||
#define CVI_LPA_PAUSE_CAP (0x0400)
|
||||
#define CVI_LPA_PAUSE_ASYM (0x0800)
|
||||
#define CVI_LPA_RESV (0x1000)
|
||||
#define CVI_LPA_RFAULT (0x2000)
|
||||
#define CVI_LPA_LPACK (0x4000)
|
||||
#define CVI_LPA_NPAGE (0x8000)
|
||||
|
||||
#define CVI_LPA_DUPLEX (CVI_LPA_10FULL | CVI_LPA_100FULL)
|
||||
#define CVI_LPA_100 (CVI_LPA_100FULL | CVI_LPA_100HALF | CVI_LPA_100BASE4)
|
||||
/* N-way test register. */
|
||||
#define CVI_NWAYTEST_RESV1 (0x00ff)
|
||||
#define CVI_NWAYTEST_LOOPBACK (0x0100)
|
||||
#define CVI_NWAYTEST_RESV2 (0xfe00)
|
||||
|
||||
/* 1000BASE-T Control register */
|
||||
#define CVI_ADVERTISE_1000FULL 0x0200
|
||||
#define CVI_ADVERTISE_1000HALF 0x0100
|
||||
|
||||
/* 1000BASE-T Status register */
|
||||
#define CVI_LPA_1000LOCALRXOK 0x2000
|
||||
#define CVI_LPA_1000REMRXOK 0x1000
|
||||
#define CVI_LPA_1000FULL 0x0800
|
||||
#define CVI_LPA_1000HALF 0x0400
|
||||
|
||||
/* Flow control flags */
|
||||
#define CVI_FLOW_CTRL_TX 0x01
|
||||
#define CVI_FLOW_CTRL_RX 0x02
|
||||
|
||||
/**
|
||||
* mii_nway_result
|
||||
* @negotiated: value of MII ANAR and'd with ANLPAR
|
||||
*
|
||||
* Given a set of MII abilities, check each bit and returns the
|
||||
* currently supported media, in the priority order defined by
|
||||
* IEEE 802.3u. We use LPA_xxx constants but note this is not the
|
||||
* value of LPA solely, as described above.
|
||||
*
|
||||
* The one exception to IEEE 802.3u is that 100baseT4 is placed
|
||||
* between 100T-full and 100T-half. If your phy does not support
|
||||
* 100T4 this is fine. If your phy places 100T4 elsewhere in the
|
||||
* priority order, you will need to roll your own function.
|
||||
*/
|
||||
static inline unsigned int mii_nway_result (unsigned int negotiated)
|
||||
{
|
||||
unsigned int ret;
|
||||
|
||||
if (negotiated & CVI_LPA_100FULL)
|
||||
ret = CVI_LPA_100FULL;
|
||||
else if (negotiated & CVI_LPA_100BASE4)
|
||||
ret = CVI_LPA_100BASE4;
|
||||
else if (negotiated & CVI_LPA_100HALF)
|
||||
ret = CVI_LPA_100HALF;
|
||||
else if (negotiated & CVI_LPA_10FULL)
|
||||
ret = CVI_LPA_10FULL;
|
||||
else
|
||||
ret = CVI_LPA_10HALF;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* mii_duplex
|
||||
* @duplex_lock: Non-zero if duplex is locked at full
|
||||
* @negotiated: value of MII ANAR and'd with ANLPAR
|
||||
*
|
||||
* A small helper function for a common case. Returns one
|
||||
* if the media is operating or locked at full duplex, and
|
||||
* returns zero otherwise.
|
||||
*/
|
||||
static inline unsigned int mii_duplex (unsigned int duplex_lock,
|
||||
unsigned int negotiated)
|
||||
{
|
||||
if (duplex_lock)
|
||||
return 1;
|
||||
if (mii_nway_result(negotiated) & CVI_LPA_DUPLEX)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __LINUX_MII_H__ */
|
Loading…
Reference in New Issue