add ethernet driver for zynqmp-r5-axu4ev

This commit is contained in:
Wang-Huachen 2021-05-13 16:33:40 +08:00
parent e58ea3ded4
commit d205721462
42 changed files with 11554 additions and 58 deletions

View File

@ -23,6 +23,12 @@ CONFIG_IDLE_THREAD_STACK_SIZE=512
CONFIG_RT_USING_TIMER_SOFT=y
CONFIG_RT_TIMER_THREAD_PRIO=4
CONFIG_RT_TIMER_THREAD_STACK_SIZE=512
#
# kservice optimization
#
# CONFIG_RT_KSERVICE_USING_STDLIB is not set
# CONFIG_RT_KSERVICE_USING_TINY_SIZE is not set
CONFIG_RT_DEBUG=y
# CONFIG_RT_DEBUG_COLOR is not set
# CONFIG_RT_DEBUG_INIT_CONFIG is not set
@ -52,8 +58,9 @@ CONFIG_RT_USING_MESSAGEQUEUE=y
CONFIG_RT_USING_MEMPOOL=y
# CONFIG_RT_USING_MEMHEAP is not set
# CONFIG_RT_USING_NOHEAP is not set
CONFIG_RT_USING_SMALL_MEM=y
# CONFIG_RT_USING_SLAB is not set
# CONFIG_RT_USING_SMALL_MEM is not set
CONFIG_RT_USING_SLAB=y
# CONFIG_RT_USING_USERHEAP is not set
# CONFIG_RT_USING_MEMTRACE is not set
CONFIG_RT_USING_HEAP=y
@ -66,7 +73,7 @@ CONFIG_RT_USING_DEVICE=y
CONFIG_RT_USING_CONSOLE=y
CONFIG_RT_CONSOLEBUF_SIZE=128
CONFIG_RT_CONSOLE_DEVICE_NAME="uart0"
CONFIG_RT_VER_NUM=0x40003
CONFIG_RT_VER_NUM=0x40004
# CONFIG_RT_USING_CPU_FFS is not set
# CONFIG_ARCH_CPU_STACK_GROWS_UPWARD is not set
@ -123,6 +130,11 @@ CONFIG_RT_DFS_ELM_WORD_ACCESS=y
# CONFIG_RT_DFS_ELM_USE_LFN_2 is not set
CONFIG_RT_DFS_ELM_USE_LFN_3=y
CONFIG_RT_DFS_ELM_USE_LFN=3
CONFIG_RT_DFS_ELM_LFN_UNICODE_0=y
# CONFIG_RT_DFS_ELM_LFN_UNICODE_1 is not set
# CONFIG_RT_DFS_ELM_LFN_UNICODE_2 is not set
# CONFIG_RT_DFS_ELM_LFN_UNICODE_3 is not set
CONFIG_RT_DFS_ELM_LFN_UNICODE=0
CONFIG_RT_DFS_ELM_MAX_LFN=255
CONFIG_RT_DFS_ELM_DRIVES=2
CONFIG_RT_DFS_ELM_MAX_SECTOR_SIZE=512
@ -131,15 +143,16 @@ CONFIG_RT_DFS_ELM_REENTRANT=y
CONFIG_RT_USING_DFS_DEVFS=y
# CONFIG_RT_USING_DFS_ROMFS is not set
# CONFIG_RT_USING_DFS_RAMFS is not set
# CONFIG_RT_USING_DFS_UFFS is not set
# CONFIG_RT_USING_DFS_JFFS2 is not set
# CONFIG_RT_USING_DFS_NFS is not set
#
# Device Drivers
#
CONFIG_RT_USING_DEVICE_IPC=y
CONFIG_RT_PIPE_BUFSZ=512
# CONFIG_RT_USING_SYSTEM_WORKQUEUE is not set
CONFIG_RT_USING_SYSTEM_WORKQUEUE=y
CONFIG_RT_SYSTEM_WORKQUEUE_STACKSIZE=2048
CONFIG_RT_SYSTEM_WORKQUEUE_PRIORITY=23
CONFIG_RT_USING_SERIAL=y
CONFIG_RT_SERIAL_USING_DMA=y
CONFIG_RT_SERIAL_RB_BUFSZ=64
@ -147,6 +160,7 @@ CONFIG_RT_SERIAL_RB_BUFSZ=64
# CONFIG_RT_USING_HWTIMER is not set
# CONFIG_RT_USING_CPUTIME is not set
# CONFIG_RT_USING_I2C is not set
# CONFIG_RT_USING_PHY is not set
CONFIG_RT_USING_PIN=y
# CONFIG_RT_USING_ADC is not set
# CONFIG_RT_USING_DAC is not set
@ -172,11 +186,6 @@ CONFIG_RT_USING_PIN=y
# CONFIG_RT_USING_USB_HOST is not set
# CONFIG_RT_USING_USB_DEVICE is not set
#
# Using RapidIO
#
# CONFIG_RT_USING_RAPIDIO is not set
#
# POSIX layer and C standard library
#
@ -188,6 +197,7 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_RT_USING_POSIX_GETLINE is not set
# CONFIG_RT_USING_POSIX_AIO is not set
# CONFIG_RT_USING_MODULE is not set
CONFIG_RT_LIBC_FIXED_TIMEZONE=8
#
# Network
@ -196,22 +206,91 @@ CONFIG_RT_USING_POSIX=y
#
# Socket abstraction layer
#
# CONFIG_RT_USING_SAL is not set
CONFIG_RT_USING_SAL=y
CONFIG_SAL_INTERNET_CHECK=y
#
# protocol stack implement
#
CONFIG_SAL_USING_LWIP=y
CONFIG_SAL_USING_POSIX=y
#
# Network interface device
#
# CONFIG_RT_USING_NETDEV is not set
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_NETDEV_IPV6_SCOPES is not set
#
# light weight TCP/IP stack
#
# CONFIG_RT_USING_LWIP is not set
CONFIG_RT_USING_LWIP=y
# CONFIG_RT_USING_LWIP141 is not set
CONFIG_RT_USING_LWIP202=y
# CONFIG_RT_USING_LWIP212 is not set
# CONFIG_RT_USING_LWIP_IPV6 is not set
CONFIG_RT_LWIP_MEM_ALIGNMENT=32
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"
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=256
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=2048
# 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=1024
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_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_RT_LWIP_DEBUG is not set
#
# AT commands
#
# CONFIG_RT_USING_AT is not set
# CONFIG_LWIP_USING_DHCPD is not set
#
# VBUS(Virtual Software BUS)
@ -225,6 +304,11 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_RT_USING_ULOG is not set
# CONFIG_RT_USING_UTEST is not set
#
# RT-Thread Utestcases
#
# CONFIG_RT_USING_UTESTCASES is not set
#
# RT-Thread online packages
#
@ -292,8 +376,6 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_LIBRWS is not set
# CONFIG_PKG_USING_TCPSERVER is not set
# CONFIG_PKG_USING_PROTOBUF_C is not set
# CONFIG_PKG_USING_ONNX_PARSER is not set
# CONFIG_PKG_USING_ONNX_BACKEND is not set
# CONFIG_PKG_USING_DLT645 is not set
# CONFIG_PKG_USING_QXWZ is not set
# CONFIG_PKG_USING_SMTP_CLIENT is not set
@ -307,6 +389,13 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_PDULIB is not set
# CONFIG_PKG_USING_BTSTACK is not set
# CONFIG_PKG_USING_LORAWAN_ED_STACK is not set
# CONFIG_PKG_USING_WAYZ_IOTKIT is not set
# CONFIG_PKG_USING_MAVLINK is not set
# CONFIG_PKG_USING_RAPIDJSON is not set
# CONFIG_PKG_USING_BSAL is not set
# CONFIG_PKG_USING_AGILE_MODBUS is not set
# CONFIG_PKG_USING_AGILE_FTP is not set
# CONFIG_PKG_USING_EMBEDDEDPROTO is not set
#
# security packages
@ -332,8 +421,11 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_STEMWIN is not set
# CONFIG_PKG_USING_WAVPLAYER is not set
# CONFIG_PKG_USING_TJPGD is not set
# CONFIG_PKG_USING_PDFGEN is not set
# CONFIG_PKG_USING_HELIX is not set
# CONFIG_PKG_USING_AZUREGUIX is not set
# CONFIG_PKG_USING_TOUCHGFX2RTT is not set
# CONFIG_PKG_USING_NUEMWIN is not set
#
# tools packages
@ -345,6 +437,8 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_RDB is not set
# CONFIG_PKG_USING_QRCODE is not set
# CONFIG_PKG_USING_ULOG_EASYFLASH is not set
# CONFIG_PKG_USING_ULOG_FILE is not set
# CONFIG_PKG_USING_LOGMGR is not set
# CONFIG_PKG_USING_ADBD is not set
# CONFIG_PKG_USING_COREMARK is not set
# CONFIG_PKG_USING_DHRYSTONE is not set
@ -357,6 +451,22 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_URLENCODE is not set
# CONFIG_PKG_USING_UMCN is not set
# CONFIG_PKG_USING_LWRB2RTT is not set
# CONFIG_PKG_USING_CPU_USAGE is not set
# CONFIG_PKG_USING_GBK2UTF8 is not set
# CONFIG_PKG_USING_VCONSOLE is not set
# CONFIG_PKG_USING_KDB is not set
# CONFIG_PKG_USING_WAMR is not set
# CONFIG_PKG_USING_MICRO_XRCE_DDS_CLIENT is not set
# CONFIG_PKG_USING_LWLOG is not set
# CONFIG_PKG_USING_ANV_TRACE is not set
# CONFIG_PKG_USING_ANV_MEMLEAK is not set
# CONFIG_PKG_USING_ANV_TESTSUIT is not set
# CONFIG_PKG_USING_ANV_BENCH is not set
# CONFIG_PKG_USING_DEVMEM is not set
# CONFIG_PKG_USING_REGEX is not set
# CONFIG_PKG_USING_MEM_SANDBOX is not set
# CONFIG_PKG_USING_SOLAR_TERMS is not set
# CONFIG_PKG_USING_GAN_ZHI is not set
#
# system packages
@ -364,7 +474,6 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_GUIENGINE is not set
# CONFIG_PKG_USING_CAIRO is not set
# CONFIG_PKG_USING_PIXMAN is not set
# CONFIG_PKG_USING_LWEXT4 is not set
# CONFIG_PKG_USING_PARTITION is not set
# CONFIG_PKG_USING_FAL is not set
# CONFIG_PKG_USING_FLASHDB is not set
@ -374,6 +483,9 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_CMSIS is not set
# CONFIG_PKG_USING_DFS_YAFFS is not set
# CONFIG_PKG_USING_LITTLEFS is not set
# CONFIG_PKG_USING_DFS_JFFS2 is not set
# CONFIG_PKG_USING_DFS_UFFS is not set
# CONFIG_PKG_USING_LWEXT4 is not set
# CONFIG_PKG_USING_THREAD_POOL is not set
# CONFIG_PKG_USING_ROBOTS is not set
# CONFIG_PKG_USING_EV is not set
@ -388,11 +500,21 @@ CONFIG_RT_USING_POSIX=y
# Micrium: Micrium software products porting for RT-Thread
#
# CONFIG_PKG_USING_UCOSIII_WRAPPER is not set
# CONFIG_PKG_USING_UCOSII_WRAPPER is not set
# CONFIG_PKG_USING_UC_CRC is not set
# CONFIG_PKG_USING_UC_CLK is not set
# CONFIG_PKG_USING_UC_COMMON is not set
# CONFIG_PKG_USING_UC_MODBUS is not set
# CONFIG_PKG_USING_PPOOL is not set
# CONFIG_PKG_USING_OPENAMP is not set
# CONFIG_PKG_USING_RT_KPRINTF_THREADSAFE is not set
# CONFIG_PKG_USING_RT_MEMCPY_CM is not set
# CONFIG_PKG_USING_QFPLIB_M0_FULL is not set
# CONFIG_PKG_USING_QFPLIB_M0_TINY is not set
# CONFIG_PKG_USING_QFPLIB_M3 is not set
# CONFIG_PKG_USING_LPM is not set
# CONFIG_PKG_USING_TLSF is not set
# CONFIG_PKG_USING_EVENT_RECORDER is not set
#
# peripheral libraries and drivers
@ -401,6 +523,7 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_REALTEK_AMEBA is not set
# CONFIG_PKG_USING_SHT2X is not set
# CONFIG_PKG_USING_SHT3X is not set
# CONFIG_PKG_USING_AS7341 is not set
# CONFIG_PKG_USING_STM32_SDIO is not set
# CONFIG_PKG_USING_ICM20608 is not set
# CONFIG_PKG_USING_U8G2 is not set
@ -449,6 +572,30 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_DM9051 is not set
# CONFIG_PKG_USING_SSD1306 is not set
# CONFIG_PKG_USING_QKEY is not set
# CONFIG_PKG_USING_RS485 is not set
# CONFIG_PKG_USING_NES is not set
# CONFIG_PKG_USING_VIRTUAL_SENSOR is not set
# CONFIG_PKG_USING_VDEVICE is not set
# CONFIG_PKG_USING_SGM706 is not set
# CONFIG_PKG_USING_STM32WB55_SDK is not set
# CONFIG_PKG_USING_RDA58XX is not set
# CONFIG_PKG_USING_LIBNFC is not set
# CONFIG_PKG_USING_MFOC is not set
# CONFIG_PKG_USING_TMC51XX is not set
# CONFIG_PKG_USING_TCA9534 is not set
#
# AI packages
#
# CONFIG_PKG_USING_LIBANN is not set
# CONFIG_PKG_USING_NNOM is not set
# CONFIG_PKG_USING_ONNX_BACKEND is not set
# CONFIG_PKG_USING_ONNX_PARSER is not set
# CONFIG_PKG_USING_TENSORFLOWLITEMICRO is not set
# CONFIG_PKG_USING_ELAPACK is not set
# CONFIG_PKG_USING_ULAPACK is not set
# CONFIG_PKG_USING_QUEST is not set
# CONFIG_PKG_USING_NAXOS is not set
#
# miscellaneous packages
@ -458,6 +605,7 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_FASTLZ is not set
# CONFIG_PKG_USING_MINILZO is not set
# CONFIG_PKG_USING_QUICKLZ is not set
# CONFIG_PKG_USING_LZMA is not set
# CONFIG_PKG_USING_MULTIBUTTON is not set
# CONFIG_PKG_USING_FLEXIBLE_BUTTON is not set
# CONFIG_PKG_USING_CANFESTIVAL is not set
@ -479,19 +627,24 @@ CONFIG_RT_USING_POSIX=y
# CONFIG_PKG_USING_HELLO is not set
# CONFIG_PKG_USING_VI is not set
# CONFIG_PKG_USING_KI is not set
# CONFIG_PKG_USING_NNOM is not set
# CONFIG_PKG_USING_LIBANN is not set
# CONFIG_PKG_USING_ELAPACK is not set
# CONFIG_PKG_USING_ARMv7M_DWT is not set
# CONFIG_PKG_USING_VT100 is not set
# CONFIG_PKG_USING_TETRIS is not set
# CONFIG_PKG_USING_ULAPACK is not set
# CONFIG_PKG_USING_UKAL is not set
# CONFIG_PKG_USING_CRCLIB is not set
#
# entertainment: terminal games and other interesting software packages
#
# CONFIG_PKG_USING_THREES is not set
# CONFIG_PKG_USING_2048 is not set
# CONFIG_PKG_USING_SNAKE is not set
# CONFIG_PKG_USING_TETRIS is not set
# CONFIG_PKG_USING_DONUT is not set
# CONFIG_PKG_USING_ACLOCK is not set
# CONFIG_PKG_USING_LWGPS is not set
# CONFIG_PKG_USING_TENSORFLOWLITEMICRO is not set
# CONFIG_PKG_USING_STATE_MACHINE is not set
# CONFIG_PKG_USING_MCURSES is not set
# CONFIG_PKG_USING_COWSAY is not set
CONFIG_SOC_ZYNQMP_R5=y
#
@ -510,6 +663,16 @@ CONFIG_BSP_USING_UART0=y
CONFIG_BSP_USING_SDIO=y
CONFIG_BSP_USING_SD0=y
#
# Please set RT_LWIP_PBUF_NUM is at least 256 if Enable Ethernet!
#
#
# Please set RT_LWIP_MEM_ALIGNMENT is at 32 if Enable Ethernet!
#
CONFIG_BSP_USING_ETH=y
CONFIG_RT_LWIP_PBUF_POOL_BUFSIZE=1700
#
# Board extended module Drivers
#

View File

@ -35,6 +35,7 @@ Each peripheral supporting condition for this BSP is as follows:
| UART | Support | UART0 |
| TIMER | Support | TTC0 provides system clock |
| EMMC | Support | SD0 Controller |
| EMAC | Support | e0 Net Interface |
## Execution Instruction
@ -99,14 +100,31 @@ msh />
This BSP enables EMMC driver and DFS file system by default. If you need to use a file system, you can format and mount it by yourself.
This BSP is enabled and configured with net interface driver and LwIP protocol stack by default, and note the following configuration:
1. Note that `RT_LWIP_PBUF_NUM` is set to at least 256
2. Note that `RT_ LWIP_ MEM_ Alignment` is set to 32. If the version other than lwip 2.0.2 in RTT is used, the `MEM_ALIGNMENT` in `lwipopts.h` needs to be modified manually because the macro is not used in other versions.
## BSP Migration
If you need to ported the BSP to another development board of Xilinx Zynq UltraScale+ MPSOC development platform, it is also convenient. The main modifications are as follows:
1. Memory: `psu_r5_ddr_0_MEM_0` in `zynqmp-r5.ld` (if DDR memory is less than 2G)
1. Memory: `psu_r5_ddr_0_MEM_0` in `zynqmp-r5.ld` and `HEAP_END` in `board.h ` (if DDR memory is less than 2G)
2. Main Frequency: `XPAR_CPU_CORTEXR5_0_CPU_CLK_FREQ_HZ` in `zynqmp-r5.h`
3. Pin and Frequency of Serial Port: `rxmio`, `txmio` and `XPAR_PSU_UART_0_UART_CLK_FREQ_HZ` in `drv_uart.c`
4. Timer Frequency: `XPAR_PSU_TTC_0_TTC_CLK_FREQ_HZ` in `drv_timer.c`
5. SD Controller: Block device driver initialization in `drv_sdcard.c`
6. Net interface: If the PHY chip used is not in the range of driver support, it may be necessary to realize the rate identification function of the corresponding chip in `xemacpsif_physpeed.c`. You can refer to the corresponding tutorial of Alinx.
The parameter macro definition in `xparameters.h` does not need to be modified manually. You can directly copy the `xparameters.h` file of the development board generated in Xilinx Vitis.
## Attention
-None
## Contact
Maintainer:
- [Wang Huachen](https://github.com/Wang-Huachen/)

View File

@ -32,6 +32,7 @@ AXU4EV-E 开发板是 芯驿电子科技(上海)有限公司 推出的一款
| UART | 支持 | UART0 |
| TIMER | 支持 | TTC0提供系统时钟 |
| EMMC | 支持 | SD0控制器 |
| EMAC | 支持 | e0网卡 |
## 使用说明
@ -107,16 +108,22 @@ msh />
此 BSP 默认开启了 EMMC 驱动和 DFS 文件系统,如果需要使用文件系统可以自行格式化并挂载。
此 BSP 默认开启并配置了网卡驱动及lwip协议栈相关配置需要注意如下几点
1. 注意将`RT_LWIP_PBUF_NUM`至少设置为256
2. 注意将`RT_LWIP_MEM_ALIGNMENT`设置为32。若使用RTT中lwip 2.0.2以外的版本时,由于其他版本未使用该宏,需要手动修改`lwipopts.h`中的`MEM_ALIGNMENT`宏。
## 板级移植
如果需要将BSP移植到其他 XILINX Zynq UltraScale+ MPSoCs 开发平台的开发板上也比较方便,主要修改的地方有以下几点:
1. 内存: 如果 DDR memory 小于 2G需要修改`zynqmp-r5.ld`链接文件中的`psu_r5_ddr_0_MEM_0`
1. 内存: 如果 DDR memory 小于 2G需要修改`zynqmp-r5.ld`链接文件中的`psu_r5_ddr_0_MEM_0` 以及`board.h`中的`HEAP_END`
2. 主频: `xparameters.h`中的`XPAR_CPU_CORTEXR5_0_CPU_CLK_FREQ_HZ`
3. 串口引脚和频率:`drv_uart.c`中的`rxmio`, `txmio` 和`xparameters.h`中的`XPAR_PSU_UART_0_UART_CLK_FREQ_HZ`
4. 定时器频率:`xparameters.h`中的`XPAR_PSU_TTC_0_TTC_CLK_FREQ_HZ`
5. SD控制器`drv_sdcard.c`中的块设备驱动初始化
6. 网卡驱动若使用的PHY芯片不在驱动支持范围内可能需要在`xemacpsif_physpeed.c`中实现相应芯片的速率识别函数可参考ALINX的相应教程。
以上需要修改的`xparameters.h`中的参数宏定义不需要手动修改可以直接将Xilinx Vitis中产生的开发板的`xparameters.h`文件复制过来即可。

View File

@ -24,6 +24,19 @@ menu "Hardware Drivers Config"
bool "Enable SD0 EMMC"
default y
endif
comment "Please set RT_LWIP_PBUF_NUM is at least 256 if Enable Ethernet!"
comment "Please set RT_LWIP_MEM_ALIGNMENT is at 32 if Enable Ethernet!"
menuconfig BSP_USING_ETH
bool "Enable Ethernet"
default n
select RT_USING_NETDEV
select RT_USING_LWIP
if BSP_USING_ETH
config RT_LWIP_PBUF_POOL_BUFSIZE
int "The size of each pbuf in the pbuf pool"
range 1500 2000
default 1700
endif
endmenu

View File

@ -11,6 +11,9 @@ if GetDepend('BSP_USING_SDIO'):
objs = objs + SConscript('sdps_v3_9/SConscript')
if GetDepend('RT_USING_PIN'):
objs = objs + SConscript('gpiops_v3_7/SConscript')
if GetDepend('BSP_USING_ETH'):
objs = objs + SConscript('emacps_v3_11/SConscript')
objs = objs + SConscript('xemacpsif/SConscript')
objs = objs + group

View File

@ -0,0 +1,15 @@
import rtconfig
from building import *
# get current directory
cwd = GetCurrentDir()
CPPPATH = [cwd]
# The set of source files associated with this SConscript file.
src = Glob('*.c')
path = cwd
group = DefineGroup('ZYNQMP_HAL', src, depend = [''], CPPPATH = CPPPATH)
Return('group')

View File

@ -0,0 +1,480 @@
/******************************************************************************
* Copyright (C) 2010 - 2020 Xilinx, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xemacps.c
* @addtogroup emacps_v3_11
* @{
*
* The XEmacPs driver. Functions in this file are the minimum required functions
* for this driver. See xemacps.h for a detailed description of the driver.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a wsy 01/10/10 First release
* 2.1 srt 07/15/14 Add support for Zynq Ultrascale Mp GEM specification and
* 64-bit changes.
* 3.00 kvn 02/13/15 Modified code for MISRA-C:2012 compliance.
* 3.0 hk 02/20/15 Added support for jumbo frames. Increase AHB burst.
* Disable extended mode. Perform all 64 bit changes under
* check for arch64.
* 3.1 hk 08/10/15 Update upper 32 bit tx and rx queue ptr registers
* 3.5 hk 08/14/17 Update cache coherency information of the interface in
* its config structure.
* 3.8 hk 09/17/18 Cleanup stale comments.
* 3.8 mus 11/05/18 Support 64 bit DMA addresses for Microblaze-X platform.
* 3.10 hk 05/16/19 Clear status registers properly in reset
* 3.11 sd 02/14/20 Add clock support
*
* </pre>
******************************************************************************/
/***************************** Include Files *********************************/
#include "xemacps.h"
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
void XEmacPs_StubHandler(void); /* Default handler routine */
/************************** Variable Definitions *****************************/
/*****************************************************************************/
/**
* Initialize a specific XEmacPs instance/driver. The initialization entails:
* - Initialize fields of the XEmacPs instance structure
* - Reset hardware and apply default options
* - Configure the DMA channels
*
* The PHY is setup independently from the device. Use the MII or whatever other
* interface may be present for setup.
*
* @param InstancePtr is a pointer to the instance to be worked on.
* @param CfgPtr is the device configuration structure containing required
* hardware build data.
* @param EffectiveAddress is the base address of the device. If address
* translation is not utilized, this parameter can be passed in using
* CfgPtr->Config.BaseAddress to specify the physical base address.
*
* @return
* - XST_SUCCESS if initialization was successful
*
******************************************************************************/
LONG XEmacPs_CfgInitialize(XEmacPs *InstancePtr, XEmacPs_Config * CfgPtr,
UINTPTR EffectiveAddress)
{
/* Verify arguments */
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(CfgPtr != NULL);
/* Set device base address and ID */
InstancePtr->Config.DeviceId = CfgPtr->DeviceId;
InstancePtr->Config.BaseAddress = EffectiveAddress;
InstancePtr->Config.IsCacheCoherent = CfgPtr->IsCacheCoherent;
#if defined (XCLOCKING)
InstancePtr->Config.RefClk = CfgPtr->RefClk;
#endif
/* Set callbacks to an initial stub routine */
InstancePtr->SendHandler = ((XEmacPs_Handler)((void*)XEmacPs_StubHandler));
InstancePtr->RecvHandler = ((XEmacPs_Handler)(void*)XEmacPs_StubHandler);
InstancePtr->ErrorHandler = ((XEmacPs_ErrHandler)(void*)XEmacPs_StubHandler);
/* Reset the hardware and set default options */
InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
XEmacPs_Reset(InstancePtr);
return (LONG)(XST_SUCCESS);
}
/*****************************************************************************/
/**
* Start the Ethernet controller as follows:
* - Enable transmitter if XTE_TRANSMIT_ENABLE_OPTION is set
* - Enable receiver if XTE_RECEIVER_ENABLE_OPTION is set
* - Start the SG DMA send and receive channels and enable the device
* interrupt
*
* @param InstancePtr is a pointer to the instance to be worked on.
*
* @return N/A
*
* @note
* Hardware is configured with scatter-gather DMA, the driver expects to start
* the scatter-gather channels and expects that the user has previously set up
* the buffer descriptor lists.
*
* This function makes use of internal resources that are shared between the
* Start, Stop, and Set/ClearOptions functions. So if one task might be setting
* device options while another is trying to start the device, the user is
* required to provide protection of this shared data (typically using a
* semaphore).
*
* This function must not be preempted by an interrupt that may service the
* device.
*
******************************************************************************/
void XEmacPs_Start(XEmacPs *InstancePtr)
{
u32 Reg;
/* Assert bad arguments and conditions */
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
#if defined (XCLOCKING)
if (InstancePtr->IsStarted != (u32)XIL_COMPONENT_IS_STARTED) {
Xil_ClockEnable(InstancePtr->Config.RefClk);
}
#endif
/* Start DMA */
/* When starting the DMA channels, both transmit and receive sides
* need an initialized BD list.
*/
if (InstancePtr->Version == 2) {
Xil_AssertVoid(InstancePtr->RxBdRing.BaseBdAddr != 0);
Xil_AssertVoid(InstancePtr->TxBdRing.BaseBdAddr != 0);
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_RXQBASE_OFFSET,
InstancePtr->RxBdRing.BaseBdAddr);
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_TXQBASE_OFFSET,
InstancePtr->TxBdRing.BaseBdAddr);
}
/* clear any existed int status */
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_ISR_OFFSET,
XEMACPS_IXR_ALL_MASK);
/* Enable transmitter if not already enabled */
if ((InstancePtr->Options & (u32)XEMACPS_TRANSMITTER_ENABLE_OPTION)!=0x00000000U) {
Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET);
if ((!(Reg & XEMACPS_NWCTRL_TXEN_MASK))==TRUE) {
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET,
Reg | (u32)XEMACPS_NWCTRL_TXEN_MASK);
}
}
/* Enable receiver if not already enabled */
if ((InstancePtr->Options & XEMACPS_RECEIVER_ENABLE_OPTION) != 0x00000000U) {
Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET);
if ((!(Reg & XEMACPS_NWCTRL_RXEN_MASK))==TRUE) {
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET,
Reg | (u32)XEMACPS_NWCTRL_RXEN_MASK);
}
}
/* Enable TX and RX interrupts */
XEmacPs_IntEnable(InstancePtr, (XEMACPS_IXR_TX_ERR_MASK |
XEMACPS_IXR_RX_ERR_MASK | (u32)XEMACPS_IXR_FRAMERX_MASK |
(u32)XEMACPS_IXR_TXCOMPL_MASK));
/* Enable TX Q1 Interrupts */
if (InstancePtr->Version > 2)
XEmacPs_IntQ1Enable(InstancePtr, XEMACPS_INTQ1_IXR_ALL_MASK);
/* Mark as started */
InstancePtr->IsStarted = XIL_COMPONENT_IS_STARTED;
return;
}
/*****************************************************************************/
/**
* Gracefully stop the Ethernet MAC as follows:
* - Disable all interrupts from this device
* - Stop DMA channels
* - Disable the tansmitter and receiver
*
* Device options currently in effect are not changed.
*
* This function will disable all interrupts. Default interrupts settings that
* had been enabled will be restored when XEmacPs_Start() is called.
*
* @param InstancePtr is a pointer to the instance to be worked on.
*
* @note
* This function makes use of internal resources that are shared between the
* Start, Stop, SetOptions, and ClearOptions functions. So if one task might be
* setting device options while another is trying to start the device, the user
* is required to provide protection of this shared data (typically using a
* semaphore).
*
* Stopping the DMA channels causes this function to block until the DMA
* operation is complete.
*
******************************************************************************/
void XEmacPs_Stop(XEmacPs *InstancePtr)
{
u32 Reg;
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
/* Disable all interrupts */
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_IDR_OFFSET,
XEMACPS_IXR_ALL_MASK);
/* Disable the receiver & transmitter */
Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET);
Reg &= (u32)(~XEMACPS_NWCTRL_RXEN_MASK);
Reg &= (u32)(~XEMACPS_NWCTRL_TXEN_MASK);
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET, Reg);
/* Mark as stopped */
InstancePtr->IsStarted = 0U;
#if defined (XCLOCKING)
Xil_ClockDisable(InstancePtr->Config.RefClk);
#endif
}
/*****************************************************************************/
/**
* Perform a graceful reset of the Ethernet MAC. Resets the DMA channels, the
* transmitter, and the receiver.
*
* Steps to reset
* - Stops transmit and receive channels
* - Stops DMA
* - Configure transmit and receive buffer size to default
* - Clear transmit and receive status register and counters
* - Clear all interrupt sources
* - Clear phy (if there is any previously detected) address
* - Clear MAC addresses (1-4) as well as Type IDs and hash value
*
* All options are placed in their default state. Any frames in the
* descriptor lists will remain in the lists. The side effect of doing
* this is that after a reset and following a restart of the device, frames
* were in the list before the reset may be transmitted or received.
*
* The upper layer software is responsible for re-configuring (if necessary)
* and restarting the MAC after the reset. Note also that driver statistics
* are not cleared on reset. It is up to the upper layer software to clear the
* statistics if needed.
*
* When a reset is required, the driver notifies the upper layer software of
* this need through the ErrorHandler callback and specific status codes.
* The upper layer software is responsible for calling this Reset function
* and then re-configuring the device.
*
* @param InstancePtr is a pointer to the instance to be worked on.
*
******************************************************************************/
void XEmacPs_Reset(XEmacPs *InstancePtr)
{
u32 Reg;
u8 i;
s8 EmacPs_zero_MAC[6] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
/* Stop the device and reset hardware */
XEmacPs_Stop(InstancePtr);
InstancePtr->Options = XEMACPS_DEFAULT_OPTIONS;
InstancePtr->Version = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, 0xFC);
InstancePtr->Version = (InstancePtr->Version >> 16) & 0xFFF;
InstancePtr->MaxMtuSize = XEMACPS_MTU;
InstancePtr->MaxFrameSize = XEMACPS_MTU + XEMACPS_HDR_SIZE +
XEMACPS_TRL_SIZE;
InstancePtr->MaxVlanFrameSize = InstancePtr->MaxFrameSize +
XEMACPS_HDR_VLAN_SIZE;
InstancePtr->RxBufMask = XEMACPS_RXBUF_LEN_MASK;
/* Setup hardware with default values */
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET,
(XEMACPS_NWCTRL_STATCLR_MASK |
XEMACPS_NWCTRL_MDEN_MASK) &
(u32)(~XEMACPS_NWCTRL_LOOPEN_MASK));
Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
XEMACPS_NWCFG_OFFSET);
Reg &= XEMACPS_NWCFG_MDCCLKDIV_MASK;
Reg = Reg | (u32)XEMACPS_NWCFG_100_MASK |
(u32)XEMACPS_NWCFG_FDEN_MASK |
(u32)XEMACPS_NWCFG_UCASTHASHEN_MASK;
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_NWCFG_OFFSET, Reg);
if (InstancePtr->Version > 2) {
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCFG_OFFSET,
(XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_NWCFG_OFFSET) |
XEMACPS_NWCFG_DWIDTH_64_MASK));
}
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_DMACR_OFFSET,
(((((u32)XEMACPS_RX_BUF_SIZE / (u32)XEMACPS_RX_BUF_UNIT) +
(((((u32)XEMACPS_RX_BUF_SIZE %
(u32)XEMACPS_RX_BUF_UNIT))!=(u32)0) ? 1U : 0U)) <<
(u32)(XEMACPS_DMACR_RXBUF_SHIFT)) &
(u32)(XEMACPS_DMACR_RXBUF_MASK)) |
(u32)XEMACPS_DMACR_RXSIZE_MASK |
(u32)XEMACPS_DMACR_TXSIZE_MASK);
if (InstancePtr->Version > 2) {
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_DMACR_OFFSET,
(XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, XEMACPS_DMACR_OFFSET) |
#if defined(__aarch64__) || defined(__arch64__)
(u32)XEMACPS_DMACR_ADDR_WIDTH_64 |
#endif
(u32)XEMACPS_DMACR_INCR16_AHB_BURST));
}
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_TXSR_OFFSET, XEMACPS_SR_ALL_MASK);
XEmacPs_SetQueuePtr(InstancePtr, 0, 0x00U, (u16)XEMACPS_SEND);
if (InstancePtr->Version > 2)
XEmacPs_SetQueuePtr(InstancePtr, 0, 0x01U, (u16)XEMACPS_SEND);
XEmacPs_SetQueuePtr(InstancePtr, 0, 0x00U, (u16)XEMACPS_RECV);
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_RXSR_OFFSET, XEMACPS_SR_ALL_MASK);
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_IDR_OFFSET,
XEMACPS_IXR_ALL_MASK);
Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
XEMACPS_ISR_OFFSET);
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_ISR_OFFSET,
Reg);
XEmacPs_ClearHash(InstancePtr);
for (i = 1U; i < 5U; i++) {
(void)XEmacPs_SetMacAddress(InstancePtr, EmacPs_zero_MAC, i);
(void)XEmacPs_SetTypeIdCheck(InstancePtr, 0x00000000U, i);
}
/* clear all counters */
for (i = 0U; i < (u8)((XEMACPS_LAST_OFFSET - XEMACPS_OCTTXL_OFFSET) / 4U);
i++) {
(void)XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
XEMACPS_OCTTXL_OFFSET + (u32)(((u32)i) * ((u32)4)));
}
/* Disable the receiver */
Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET);
Reg &= (u32)(~XEMACPS_NWCTRL_RXEN_MASK);
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET, Reg);
/* Sync default options with hardware but leave receiver and
* transmitter disabled. They get enabled with XEmacPs_Start() if
* XEMACPS_TRANSMITTER_ENABLE_OPTION and
* XEMACPS_RECEIVER_ENABLE_OPTION are set.
*/
(void)XEmacPs_SetOptions(InstancePtr, InstancePtr->Options &
~((u32)XEMACPS_TRANSMITTER_ENABLE_OPTION |
(u32)XEMACPS_RECEIVER_ENABLE_OPTION));
(void)XEmacPs_ClearOptions(InstancePtr, ~InstancePtr->Options);
}
/******************************************************************************/
/**
* This is a stub for the asynchronous callbacks. The stub is here in case the
* upper layer forgot to set the handler(s). On initialization, all handlers are
* set to this callback. It is considered an error for this handler to be
* invoked.
*
******************************************************************************/
void XEmacPs_StubHandler(void)
{
Xil_AssertVoidAlways();
}
/*****************************************************************************/
/**
* This function sets the start address of the transmit/receive buffer queue.
*
* @param InstancePtr is a pointer to the instance to be worked on.
* @param QPtr is the address of the Queue to be written
* @param QueueNum is the Buffer Queue Index
* @param Direction indicates Transmit/Receive
*
* @note
* The buffer queue addresses has to be set before starting the transfer, so
* this function has to be called in prior to XEmacPs_Start()
*
******************************************************************************/
void XEmacPs_SetQueuePtr(XEmacPs *InstancePtr, UINTPTR QPtr, u8 QueueNum,
u16 Direction)
{
/* Assert bad arguments and conditions */
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
/* If already started, then there is nothing to do */
if (InstancePtr->IsStarted == (u32)XIL_COMPONENT_IS_STARTED) {
return;
}
if (QueueNum == 0x00U) {
if (Direction == XEMACPS_SEND) {
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_TXQBASE_OFFSET,
(QPtr & ULONG64_LO_MASK));
} else {
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_RXQBASE_OFFSET,
(QPtr & ULONG64_LO_MASK));
}
}
else {
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_TXQ1BASE_OFFSET,
(QPtr & ULONG64_LO_MASK));
}
#ifdef __aarch64__
if (Direction == XEMACPS_SEND) {
/* Set the MSB of TX Queue start address */
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_MSBBUF_TXQBASE_OFFSET,
(u32)((QPtr & ULONG64_HI_MASK) >> 32U));
} else {
/* Set the MSB of RX Queue start address */
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_MSBBUF_RXQBASE_OFFSET,
(u32)((QPtr & ULONG64_HI_MASK) >> 32U));
}
#endif
}
/** @} */

View File

@ -0,0 +1,836 @@
/******************************************************************************
* Copyright (C) 2010 - 2020 Xilinx, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/
/****************************************************************************/
/**
*
* @file xemacps.h
* @addtogroup emacps_v3_11
* @{
* @details
*
* The Xilinx Embedded Processor Block Ethernet driver.
*
* For a full description of XEMACPS features, please see the hardware spec.
* This driver supports the following features:
* - Memory mapped access to host interface registers
* - Statistics counter registers for RMON/MIB
* - API for interrupt driven frame transfers for hardware configured DMA
* - Virtual memory support
* - Unicast, broadcast, and multicast receive address filtering
* - Full and half duplex operation
* - Automatic PAD & FCS insertion and stripping
* - Flow control
* - Support up to four 48bit addresses
* - Address checking for four specific 48bit addresses
* - VLAN frame support
* - Pause frame support
* - Large frame support up to 1536 bytes
* - Checksum offload
*
* <b>Driver Description</b>
*
* The device driver enables higher layer software (e.g., an application) to
* communicate to the XEmacPs. The driver handles transmission and reception
* of Ethernet frames, as well as configuration and control. No pre or post
* processing of frame data is performed. The driver does not validate the
* contents of an incoming frame in addition to what has already occurred in
* hardware.
* A single device driver can support multiple devices even when those devices
* have significantly different configurations.
*
* <b>Initialization & Configuration</b>
*
* The XEmacPs_Config structure is used by the driver to configure itself.
* This configuration structure is typically created by the tool-chain based
* on hardware build properties.
*
* The driver instance can be initialized in
*
* - XEmacPs_CfgInitialize(InstancePtr, CfgPtr, EffectiveAddress): Uses a
* configuration structure provided by the caller. If running in a system
* with address translation, the provided virtual memory base address
* replaces the physical address present in the configuration structure.
*
* The device supports DMA only as current development plan. No FIFO mode is
* supported. The driver expects to start the DMA channels and expects that
* the user has set up the buffer descriptor lists.
*
* <b>Interrupts and Asynchronous Callbacks</b>
*
* The driver has no dependencies on the interrupt controller. When an
* interrupt occurs, the handler will perform a small amount of
* housekeeping work, determine the source of the interrupt, and call the
* appropriate callback function. All callbacks are registered by the user
* level application.
*
* <b>Virtual Memory</b>
*
* All virtual to physical memory mappings must occur prior to accessing the
* driver API.
*
* For DMA transactions, user buffers supplied to the driver must be in terms
* of their physical address.
*
* <b>DMA</b>
*
* The DMA engine uses buffer descriptors (BDs) to describe Ethernet frames.
* These BDs are typically chained together into a list the hardware follows
* when transferring data in and out of the packet buffers. Each BD describes
* a memory region containing either a full or partial Ethernet packet.
*
* Interrupt coalescing is not supported from this built-in DMA engine.
*
* This API requires the user to understand how the DMA operates. The
* following paragraphs provide some explanation, but the user is encouraged
* to read documentation in xemacps_bdring.h as well as study example code
* that accompanies this driver.
*
* The API is designed to get BDs to and from the DMA engine in the most
* efficient means possible. The first step is to establish a memory region
* to contain all BDs for a specific channel. This is done with
* XEmacPs_BdRingCreate(). This function sets up a BD ring that hardware will
* follow as BDs are processed. The ring will consist of a user defined number
* of BDs which will all be partially initialized. For example on the transmit
* channel, the driver will initialize all BDs' so that they are configured
* for transmit. The more fields that can be permanently setup at
* initialization, then the fewer accesses will be needed to each BD while
* the DMA engine is in operation resulting in better throughput and CPU
* utilization. The best case initialization would require the user to set
* only a frame buffer address and length prior to submitting the BD to the
* engine.
*
* BDs move through the engine with the help of functions
* XEmacPs_BdRingAlloc(), XEmacPs_BdRingToHw(), XEmacPs_BdRingFromHw(),
* and XEmacPs_BdRingFree().
* All these functions handle BDs that are in place. That is, there are no
* copies of BDs kept anywhere and any BD the user interacts with is an actual
* BD from the same ring hardware accesses.
*
* BDs in the ring go through a series of states as follows:
* 1. Idle. The driver controls BDs in this state.
* 2. The user has data to transfer. XEmacPs_BdRingAlloc() is called to
* reserve BD(s). Once allocated, the user may setup the BD(s) with
* frame buffer address, length, and other attributes. The user controls
* BDs in this state.
* 3. The user submits BDs to the DMA engine with XEmacPs_BdRingToHw. BDs
* in this state are either waiting to be processed by hardware, are in
* process, or have been processed. The DMA engine controls BDs in this
* state.
* 4. Processed BDs are retrieved with XEmacEpv_BdRingFromHw() by the
* user. Once retrieved, the user can examine each BD for the outcome of
* the DMA transfer. The user controls BDs in this state. After examining
* the BDs the user calls XEmacPs_BdRingFree() which places the BDs back
* into state 1.
*
* Each of the four BD accessor functions operate on a set of BDs. A set is
* defined as a segment of the BD ring consisting of one or more BDs. The user
* views the set as a pointer to the first BD along with the number of BDs for
* that set. The set can be navigated by using macros XEmacPs_BdNext(). The
* user must exercise extreme caution when changing BDs in a set as there is
* nothing to prevent doing a mBdNext past the end of the set and modifying a
* BD out of bounds.
*
* XEmacPs_BdRingAlloc() + XEmacPs_BdRingToHw(), as well as
* XEmacPs_BdRingFromHw() + XEmacPs_BdRingFree() are designed to be used in
* tandem. The same BD set retrieved with BdRingAlloc should be the same one
* provided to hardware with BdRingToHw. Same goes with BdRingFromHw and
* BdRIngFree.
*
* <b>Alignment & Data Cache Restrictions</b>
*
* Due to the design of the hardware, all RX buffers, BDs need to be 4-byte
* aligned. Please reference xemacps_bd.h for cache related macros.
*
* DMA Tx:
*
* - If frame buffers exist in cached memory, then they must be flushed
* prior to committing them to hardware.
*
* DMA Rx:
*
* - If frame buffers exist in cached memory, then the cache must be
* invalidated for the memory region containing the frame prior to data
* access
*
* Both cache invalidate/flush are taken care of in driver code.
*
* <b>Buffer Copying</b>
*
* The driver is designed for a zero-copy buffer scheme. That is, the driver
* will not copy buffers. This avoids potential throughput bottlenecks within
* the driver. If byte copying is required, then the transfer will take longer
* to complete.
*
* <b>Checksum Offloading</b>
*
* The Embedded Processor Block Ethernet can be configured to perform IP, TCP
* and UDP checksum offloading in both receive and transmit directions.
*
* IP packets contain a 16-bit checksum field, which is the 16-bit 1s
* complement of the 1s complement sum of all 16-bit words in the header.
* TCP and UDP packets contain a 16-bit checksum field, which is the 16-bit
* 1s complement of the 1s complement sum of all 16-bit words in the header,
* the data and a conceptual pseudo header.
*
* To calculate these checksums in software requires each byte of the packet
* to be read. For TCP and UDP this can use a large amount of processing power.
* Offloading the checksum calculation to hardware can result in significant
* performance improvements.
*
* The transmit checksum offload is only available to use DMA in packet buffer
* mode. This is because the complete frame to be transmitted must be read
* into the packet buffer memory before the checksum can be calculated and
* written to the header at the beginning of the frame.
*
* For IP, TCP or UDP receive checksum offload to be useful, the operating
* system containing the protocol stack must be aware that this offload is
* available so that it can make use of the fact that the hardware has verified
* the checksum.
*
* When receive checksum offloading is enabled in the hardware, the IP header
* checksum is checked, where the packet meets the following criteria:
*
* 1. If present, the VLAN header must be four octets long and the CFI bit
* must not be set.
* 2. Encapsulation must be RFC 894 Ethernet Type Encoding or RFC 1042 SNAP
* encoding.
* 3. IP v4 packet.
* 4. IP header is of a valid length.
* 5. Good IP header checksum.
* 6. No IP fragmentation.
* 7. TCP or UDP packet.
*
* When an IP, TCP or UDP frame is received, the receive buffer descriptor
* gives an indication if the hardware was able to verify the checksums.
* There is also an indication if the frame had SNAP encapsulation. These
* indication bits will replace the type ID match indication bits when the
* receive checksum offload is enabled.
*
* If any of the checksums are verified incorrect by the hardware, the packet
* is discarded and the appropriate statistics counter incremented.
*
* <b>PHY Interfaces</b>
*
* RGMII 1.3 is the only interface supported.
*
* <b>Asserts</b>
*
* Asserts are used within all Xilinx drivers to enforce constraints on
* parameters. Asserts can be turned off on a system-wide basis by defining,
* at compile time, the NDEBUG identifier. By default, asserts are turned on
* and it is recommended that users leave asserts on during development. For
* deployment use -DNDEBUG compiler switch to remove assert code.
*
* @note
*
* Xilinx drivers are typically composed of two parts, one is the driver
* and the other is the adapter. The driver is independent of OS and processor
* and is intended to be highly portable. The adapter is OS-specific and
* facilitates communication between the driver and an OS.
* This driver is intended to be RTOS and processor independent. Any needs for
* dynamic memory management, threads or thread mutual exclusion, or cache
* control must be satisfied bythe layer above this driver.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a wsy 01/10/10 First release
* 1.00a asa 11/21/11 The function XEmacPs_BdRingFromHwTx in file
* xemacps_bdring.c is modified. Earlier it was checking for
* "BdLimit"(passed argument) number of BDs for finding out
* which BDs are successfully processed. Now one more check
* is added. It looks for BDs till the current BD pointer
* reaches HwTail. By doing this processing time is saved.
* 1.00a asa 01/24/12 The function XEmacPs_BdRingFromHwTx in file
* xemacps_bdring.c is modified. Now start of packet is
* searched for returning the number of BDs processed.
* 1.02a asa 11/05/12 Added a new API for deleting an entry from the HASH
* registers. Added a new API to set the bust length.
* Added some new hash-defines.
* 1.03a asa 01/23/12 Fix for CR #692702 which updates error handling for
* Rx errors. Under heavy Rx traffic, there will be a large
* number of errors related to receive buffer not available.
* Because of a HW bug (SI #692601), under such heavy errors,
* the Rx data path can become unresponsive. To reduce the
* probabilities for hitting this HW bug, the SW writes to
* bit 18 to flush a packet from Rx DPRAM immediately. The
* changes for it are done in the function
* XEmacPs_IntrHandler.
* 1.05a asa 09/23/13 Cache operations on BDs are not required and hence
* removed. It is expected that all BDs are allocated in
* from uncached area.
* 1.06a asa 11/02/13 Changed the value for XEMACPS_RXBUF_LEN_MASK from 0x3fff
* to 0x1fff. This fixes the CR#744902.
* Made changes in example file xemacps_example.h to fix compilation
* issues with iarcc compiler.
* 2.0 adk 10/12/13 Updated as per the New Tcl API's
* 2.1 adk 11/08/14 Fixed the CR#811288. Changes are made in the driver tcl file.
* 2.1 bss 09/08/14 Modified driver tcl to fix CR#820349 to export phy
* address in xparameters.h when GMII to RGMII converter
* is present in hw.
* 2.1 srt 07/15/14 Add support for Zynq Ultrascale Mp GEM specification and 64-bit
* changes.
* 2.2 adk 29/10/14 Fixed CR#827686 when PCS/PMA core is configured with
* 1000BASE-X mode export proper values to the xparameters.h
* file. Changes are made in the driver tcl file.
* 3.0 adk 08/1/15 Don't include gem in peripheral test when gem is
* configured with PCS/PMA Core. Changes are made in the
* test app tcl(CR:827686).
* 3.0 kvn 02/13/15 Modified code for MISRA-C:2012 compliance.
* 3.0 hk 03/18/15 Added support for jumbo frames. Increase AHB burst.
* Disable extended mode. Perform all 64 bit changes under
* check for arch64.
* Remove "used bit set" from TX error interrupt masks.
* 3.1 hk 07/27/15 Do not call error handler with '0' error code when
* there is no error. CR# 869403
* 08/10/15 Update upper 32 bit tx and rx queue ptr registers.
* 3.2 hk 02/22/16 Added SGMII support for Zynq Ultrascale+ MPSoC.
* 3.4 ms 01/23/17 Modified xil_printf statement in main function for all
* examples to ensure that "Successfully ran" and "Failed"
* strings are available in all examples. This is a fix
* for CR-965028.
* ms 03/17/17 Modified text file in examples folder for doxygen
* generation.
* ms 04/05/17 Added tabspace for return statements in functions of
* xemacps_ieee1588_example.c for proper documentation
* while generating doxygen.
* 3.5 hk 08/14/17 Update cache coherency information of the interface in
* its config structure.
* 3.6 rb 09/08/17 HwCnt variable (in XEmacPs_BdRing structure) is
* changed to volatile.
* Add API XEmacPs_BdRingPtrReset() to reset pointers
* 3.8 hk 07/19/18 Fixed CPP, GCC and doxygen warnings - CR-1006327
* hk 09/17/18 Fix PTP interrupt masks and cleanup comments.
* 3.9 hk 01/23/19 Add RX watermark support
* 3.11 sd 02/14/20 Add clock support
*
* </pre>
*
****************************************************************************/
#ifndef XEMACPS_H /* prevent circular inclusions */
#define XEMACPS_H /* by using protection macros */
#ifdef __cplusplus
extern "C" {
#endif
/***************************** Include Files ********************************/
#include "xil_types.h"
#include "xil_assert.h"
#include "xstatus.h"
#include "xemacps_hw.h"
#include "xemacps_bd.h"
#include "xemacps_bdring.h"
#if defined (XCLOCKING)
#include "xil_clocking.h"
#endif
/************************** Constant Definitions ****************************/
/*
* Device information
*/
#define XEMACPS_DEVICE_NAME "xemacps"
#define XEMACPS_DEVICE_DESC "Xilinx PS 10/100/1000 MAC"
/** @name Configuration options
*
* Device configuration options. See the XEmacPs_SetOptions(),
* XEmacPs_ClearOptions() and XEmacPs_GetOptions() for information on how to
* use options.
*
* The default state of the options are noted and are what the device and
* driver will be set to after calling XEmacPs_Reset() or
* XEmacPs_Initialize().
*
* @{
*/
#define XEMACPS_PROMISC_OPTION 0x00000001U
/**< Accept all incoming packets.
* This option defaults to disabled (cleared) */
#define XEMACPS_FRAME1536_OPTION 0x00000002U
/**< Frame larger than 1516 support for Tx & Rx.
* This option defaults to disabled (cleared) */
#define XEMACPS_VLAN_OPTION 0x00000004U
/**< VLAN Rx & Tx frame support.
* This option defaults to disabled (cleared) */
#define XEMACPS_FLOW_CONTROL_OPTION 0x00000010U
/**< Enable recognition of flow control frames on Rx
* This option defaults to enabled (set) */
#define XEMACPS_FCS_STRIP_OPTION 0x00000020U
/**< Strip FCS and PAD from incoming frames. Note: PAD from VLAN frames is not
* stripped.
* This option defaults to enabled (set) */
#define XEMACPS_FCS_INSERT_OPTION 0x00000040U
/**< Generate FCS field and add PAD automatically for outgoing frames.
* This option defaults to disabled (cleared) */
#define XEMACPS_LENTYPE_ERR_OPTION 0x00000080U
/**< Enable Length/Type error checking for incoming frames. When this option is
* set, the MAC will filter frames that have a mismatched type/length field
* and if XEMACPS_REPORT_RXERR_OPTION is set, the user is notified when these
* types of frames are encountered. When this option is cleared, the MAC will
* allow these types of frames to be received.
*
* This option defaults to disabled (cleared) */
#define XEMACPS_TRANSMITTER_ENABLE_OPTION 0x00000100U
/**< Enable the transmitter.
* This option defaults to enabled (set) */
#define XEMACPS_RECEIVER_ENABLE_OPTION 0x00000200U
/**< Enable the receiver
* This option defaults to enabled (set) */
#define XEMACPS_BROADCAST_OPTION 0x00000400U
/**< Allow reception of the broadcast address
* This option defaults to enabled (set) */
#define XEMACPS_MULTICAST_OPTION 0x00000800U
/**< Allows reception of multicast addresses programmed into hash
* This option defaults to disabled (clear) */
#define XEMACPS_RX_CHKSUM_ENABLE_OPTION 0x00001000U
/**< Enable the RX checksum offload
* This option defaults to enabled (set) */
#define XEMACPS_TX_CHKSUM_ENABLE_OPTION 0x00002000U
/**< Enable the TX checksum offload
* This option defaults to enabled (set) */
#define XEMACPS_JUMBO_ENABLE_OPTION 0x00004000U
#define XEMACPS_SGMII_ENABLE_OPTION 0x00008000U
#define XEMACPS_DEFAULT_OPTIONS \
((u32)XEMACPS_FLOW_CONTROL_OPTION | \
(u32)XEMACPS_FCS_INSERT_OPTION | \
(u32)XEMACPS_FCS_STRIP_OPTION | \
(u32)XEMACPS_BROADCAST_OPTION | \
(u32)XEMACPS_LENTYPE_ERR_OPTION | \
(u32)XEMACPS_TRANSMITTER_ENABLE_OPTION | \
(u32)XEMACPS_RECEIVER_ENABLE_OPTION | \
(u32)XEMACPS_RX_CHKSUM_ENABLE_OPTION | \
(u32)XEMACPS_TX_CHKSUM_ENABLE_OPTION)
/**< Default options set when device is initialized or reset */
/*@}*/
/** @name Callback identifiers
*
* These constants are used as parameters to XEmacPs_SetHandler()
* @{
*/
#define XEMACPS_HANDLER_DMASEND 1U
#define XEMACPS_HANDLER_DMARECV 2U
#define XEMACPS_HANDLER_ERROR 3U
/*@}*/
/* Constants to determine the configuration of the hardware device. They are
* used to allow the driver to verify it can operate with the hardware.
*/
#define XEMACPS_MDIO_DIV_DFT MDC_DIV_32 /**< Default MDIO clock divisor */
/* The next few constants help upper layers determine the size of memory
* pools used for Ethernet buffers and descriptor lists.
*/
#define XEMACPS_MAC_ADDR_SIZE 6U /* size of Ethernet header */
#define XEMACPS_MTU 1500U /* max MTU size of Ethernet frame */
#define XEMACPS_MTU_JUMBO 10240U /* max MTU size of jumbo frame */
#define XEMACPS_HDR_SIZE 14U /* size of Ethernet header */
#define XEMACPS_HDR_VLAN_SIZE 18U /* size of Ethernet header with VLAN */
#define XEMACPS_TRL_SIZE 4U /* size of Ethernet trailer (FCS) */
#define XEMACPS_MAX_FRAME_SIZE (XEMACPS_MTU + XEMACPS_HDR_SIZE + \
XEMACPS_TRL_SIZE)
#define XEMACPS_MAX_VLAN_FRAME_SIZE (XEMACPS_MTU + XEMACPS_HDR_SIZE + \
XEMACPS_HDR_VLAN_SIZE + XEMACPS_TRL_SIZE)
#define XEMACPS_MAX_VLAN_FRAME_SIZE_JUMBO (XEMACPS_MTU_JUMBO + XEMACPS_HDR_SIZE + \
XEMACPS_HDR_VLAN_SIZE + XEMACPS_TRL_SIZE)
/* DMACR Bust length hash defines */
#define XEMACPS_SINGLE_BURST 0x00000001
#define XEMACPS_4BYTE_BURST 0x00000004
#define XEMACPS_8BYTE_BURST 0x00000008
#define XEMACPS_16BYTE_BURST 0x00000010
/**************************** Type Definitions ******************************/
/** @name Typedefs for callback functions
*
* These callbacks are invoked in interrupt context.
* @{
*/
/**
* Callback invoked when frame(s) have been sent or received in interrupt
* driven DMA mode. To set the send callback, invoke XEmacPs_SetHandler().
*
* @param CallBackRef is user data assigned when the callback was set.
*
* @note
* See xemacps_hw.h for bitmasks definitions and the device hardware spec for
* further information on their meaning.
*
*/
typedef void (*XEmacPs_Handler) (void *CallBackRef);
/**
* Callback when an asynchronous error occurs. To set this callback, invoke
* XEmacPs_SetHandler() with XEMACPS_HANDLER_ERROR in the HandlerType
* parameter.
*
* @param CallBackRef is user data assigned when the callback was set.
* @param Direction defines either receive or transmit error(s) has occurred.
* @param ErrorWord definition varies with Direction
*
*/
typedef void (*XEmacPs_ErrHandler) (void *CallBackRef, u8 Direction,
u32 ErrorWord);
/*@}*/
/**
* This typedef contains configuration information for a device.
*/
typedef struct {
u16 DeviceId; /**< Unique ID of device */
UINTPTR BaseAddress;/**< Physical base address of IPIF registers */
u8 IsCacheCoherent; /**< Applicable only to A53 in EL1 mode;
* describes whether Cache Coherent or not */
#if defined (XCLOCKING)
u32 RefClk; /**< Input clock */
#endif
} XEmacPs_Config;
/**
* The XEmacPs driver instance data. The user is required to allocate a
* structure of this type for every XEmacPs device in the system. A pointer
* to a structure of this type is then passed to the driver API functions.
*/
typedef struct XEmacPs_Instance {
XEmacPs_Config Config; /* Hardware configuration */
u32 IsStarted; /* Device is currently started */
u32 IsReady; /* Device is initialized and ready */
u32 Options; /* Current options word */
XEmacPs_BdRing TxBdRing; /* Transmit BD ring */
XEmacPs_BdRing RxBdRing; /* Receive BD ring */
XEmacPs_Handler SendHandler;
XEmacPs_Handler RecvHandler;
void *SendRef;
void *RecvRef;
XEmacPs_ErrHandler ErrorHandler;
void *ErrorRef;
u32 Version;
u32 RxBufMask;
u32 MaxMtuSize;
u32 MaxFrameSize;
u32 MaxVlanFrameSize;
} XEmacPs;
/***************** Macros (Inline Functions) Definitions ********************/
/****************************************************************************/
/**
* Retrieve the Tx ring object. This object can be used in the various Ring
* API functions.
*
* @param InstancePtr is the DMA channel to operate on.
*
* @return TxBdRing attribute
*
* @note
* C-style signature:
* XEmacPs_BdRing XEmacPs_GetTxRing(XEmacPs *InstancePtr)
*
*****************************************************************************/
#define XEmacPs_GetTxRing(InstancePtr) ((InstancePtr)->TxBdRing)
/****************************************************************************/
/**
* Retrieve the Rx ring object. This object can be used in the various Ring
* API functions.
*
* @param InstancePtr is the DMA channel to operate on.
*
* @return RxBdRing attribute
*
* @note
* C-style signature:
* XEmacPs_BdRing XEmacPs_GetRxRing(XEmacPs *InstancePtr)
*
*****************************************************************************/
#define XEmacPs_GetRxRing(InstancePtr) ((InstancePtr)->RxBdRing)
/****************************************************************************/
/**
*
* Enable interrupts specified in <i>Mask</i>. The corresponding interrupt for
* each bit set to 1 in <i>Mask</i>, will be enabled.
*
* @param InstancePtr is a pointer to the instance to be worked on.
* @param Mask contains a bit mask of interrupts to enable. The mask can
* be formed using a set of bitwise or'd values.
*
* @note
* The state of the transmitter and receiver are not modified by this function.
* C-style signature
* void XEmacPs_IntEnable(XEmacPs *InstancePtr, u32 Mask)
*
*****************************************************************************/
#define XEmacPs_IntEnable(InstancePtr, Mask) \
XEmacPs_WriteReg((InstancePtr)->Config.BaseAddress, \
XEMACPS_IER_OFFSET, \
((Mask) & XEMACPS_IXR_ALL_MASK));
/****************************************************************************/
/**
*
* Disable interrupts specified in <i>Mask</i>. The corresponding interrupt for
* each bit set to 1 in <i>Mask</i>, will be enabled.
*
* @param InstancePtr is a pointer to the instance to be worked on.
* @param Mask contains a bit mask of interrupts to disable. The mask can
* be formed using a set of bitwise or'd values.
*
* @note
* The state of the transmitter and receiver are not modified by this function.
* C-style signature
* void XEmacPs_IntDisable(XEmacPs *InstancePtr, u32 Mask)
*
*****************************************************************************/
#define XEmacPs_IntDisable(InstancePtr, Mask) \
XEmacPs_WriteReg((InstancePtr)->Config.BaseAddress, \
XEMACPS_IDR_OFFSET, \
((Mask) & XEMACPS_IXR_ALL_MASK));
/****************************************************************************/
/**
*
* Enable interrupts specified in <i>Mask</i>. The corresponding interrupt for
* each bit set to 1 in <i>Mask</i>, will be enabled.
*
* @param InstancePtr is a pointer to the instance to be worked on.
* @param Mask contains a bit mask of interrupts to enable. The mask can
* be formed using a set of bitwise or'd values.
*
* @note
* The state of the transmitter and receiver are not modified by this function.
* C-style signature
* void XEmacPs_IntQ1Enable(XEmacPs *InstancePtr, u32 Mask)
*
*****************************************************************************/
#define XEmacPs_IntQ1Enable(InstancePtr, Mask) \
XEmacPs_WriteReg((InstancePtr)->Config.BaseAddress, \
XEMACPS_INTQ1_IER_OFFSET, \
((Mask) & XEMACPS_INTQ1_IXR_ALL_MASK));
/****************************************************************************/
/**
*
* Disable interrupts specified in <i>Mask</i>. The corresponding interrupt for
* each bit set to 1 in <i>Mask</i>, will be enabled.
*
* @param InstancePtr is a pointer to the instance to be worked on.
* @param Mask contains a bit mask of interrupts to disable. The mask can
* be formed using a set of bitwise or'd values.
*
* @note
* The state of the transmitter and receiver are not modified by this function.
* C-style signature
* void XEmacPs_IntDisable(XEmacPs *InstancePtr, u32 Mask)
*
*****************************************************************************/
#define XEmacPs_IntQ1Disable(InstancePtr, Mask) \
XEmacPs_WriteReg((InstancePtr)->Config.BaseAddress, \
XEMACPS_INTQ1_IDR_OFFSET, \
((Mask) & XEMACPS_INTQ1_IXR_ALL_MASK));
/****************************************************************************/
/**
*
* This macro triggers trasmit circuit to send data currently in TX buffer(s).
*
* @param InstancePtr is a pointer to the XEmacPs instance to be worked on.
*
* @return
*
* @note
*
* Signature: void XEmacPs_Transmit(XEmacPs *InstancePtr)
*
*****************************************************************************/
#define XEmacPs_Transmit(InstancePtr) \
XEmacPs_WriteReg((InstancePtr)->Config.BaseAddress, \
XEMACPS_NWCTRL_OFFSET, \
(XEmacPs_ReadReg((InstancePtr)->Config.BaseAddress, \
XEMACPS_NWCTRL_OFFSET) | XEMACPS_NWCTRL_STARTTX_MASK))
/****************************************************************************/
/**
*
* This macro determines if the device is configured with checksum offloading
* on the receive channel
*
* @param InstancePtr is a pointer to the XEmacPs instance to be worked on.
*
* @return
*
* Boolean TRUE if the device is configured with checksum offloading, or
* FALSE otherwise.
*
* @note
*
* Signature: u32 XEmacPs_IsRxCsum(XEmacPs *InstancePtr)
*
*****************************************************************************/
#define XEmacPs_IsRxCsum(InstancePtr) \
((XEmacPs_ReadReg((InstancePtr)->Config.BaseAddress, \
XEMACPS_NWCFG_OFFSET) & XEMACPS_NWCFG_RXCHKSUMEN_MASK) != 0U \
? TRUE : FALSE)
/****************************************************************************/
/**
*
* This macro determines if the device is configured with checksum offloading
* on the transmit channel
*
* @param InstancePtr is a pointer to the XEmacPs instance to be worked on.
*
* @return
*
* Boolean TRUE if the device is configured with checksum offloading, or
* FALSE otherwise.
*
* @note
*
* Signature: u32 XEmacPs_IsTxCsum(XEmacPs *InstancePtr)
*
*****************************************************************************/
#define XEmacPs_IsTxCsum(InstancePtr) \
((XEmacPs_ReadReg((InstancePtr)->Config.BaseAddress, \
XEMACPS_DMACR_OFFSET) & XEMACPS_DMACR_TCPCKSUM_MASK) != 0U \
? TRUE : FALSE)
/************************** Function Prototypes *****************************/
/****************************************************************************/
/**
*
* This macro sets RX watermark register.
*
* @param InstancePtr is a pointer to the XEmacPs instance to be worked on.
* @param High is the non-zero RX high watermark value. When SRAM fill level
* is above this, a pause frame will be sent.
* @param Low is the non-zero RX low watermark value. When SRAM fill level
* is below this, a zero length pause frame will be sent IF the last
* pause frame sent was non-zero.
*
* @return None
*
* @note
*
* Signature: void XEmacPs_SetRXWatermark(XEmacPs *InstancePtr, u16 High,
* u16 Low)
*
*****************************************************************************/
#define XEmacPs_SetRXWatermark(InstancePtr, High, Low) \
XEmacPs_WriteReg((InstancePtr)->Config.BaseAddress, \
XEMACPS_RXWATERMARK_OFFSET, \
(High & XEMACPS_RXWM_HIGH_MASK) | \
((Low << XEMACPS_RXWM_LOW_SHFT_MSK) & XEMACPS_RXWM_LOW_MASK) |)
/****************************************************************************/
/**
*
* This macro gets RX watermark register.
*
* @param InstancePtr is a pointer to the XEmacPs instance to be worked on.
*
* @return RX watermark register value
*
* @note
*
* Signature: void XEmacPs_GetRXWatermark(XEmacPs *InstancePtr)
*
*****************************************************************************/
#define XEmacPs_GetRXWatermark(InstancePtr) \
XEmacPs_ReadReg((InstancePtr)->Config.BaseAddress, \
XEMACPS_RXWATERMARK_OFFSET)
/*
* Initialization functions in xemacps.c
*/
LONG XEmacPs_CfgInitialize(XEmacPs *InstancePtr, XEmacPs_Config *CfgPtr,
UINTPTR EffectiveAddress);
void XEmacPs_Start(XEmacPs *InstancePtr);
void XEmacPs_Stop(XEmacPs *InstancePtr);
void XEmacPs_Reset(XEmacPs *InstancePtr);
void XEmacPs_SetQueuePtr(XEmacPs *InstancePtr, UINTPTR QPtr, u8 QueueNum,
u16 Direction);
/*
* Lookup configuration in xemacps_sinit.c
*/
XEmacPs_Config *XEmacPs_LookupConfig(u16 DeviceId);
/*
* Interrupt-related functions in xemacps_intr.c
* DMA only and FIFO is not supported. This DMA does not support coalescing.
*/
LONG XEmacPs_SetHandler(XEmacPs *InstancePtr, u32 HandlerType,
void *FuncPointer, void *CallBackRef);
void XEmacPs_IntrHandler(void *XEmacPsPtr);
/*
* MAC configuration/control functions in XEmacPs_control.c
*/
LONG XEmacPs_SetOptions(XEmacPs *InstancePtr, u32 Options);
LONG XEmacPs_ClearOptions(XEmacPs *InstancePtr, u32 Options);
u32 XEmacPs_GetOptions(XEmacPs *InstancePtr);
LONG XEmacPs_SetMacAddress(XEmacPs *InstancePtr, void *AddressPtr, u8 Index);
LONG XEmacPs_DeleteHash(XEmacPs *InstancePtr, void *AddressPtr);
void XEmacPs_GetMacAddress(XEmacPs *InstancePtr, void *AddressPtr, u8 Index);
LONG XEmacPs_SetHash(XEmacPs *InstancePtr, void *AddressPtr);
void XEmacPs_ClearHash(XEmacPs *InstancePtr);
void XEmacPs_GetHash(XEmacPs *InstancePtr, void *AddressPtr);
void XEmacPs_SetMdioDivisor(XEmacPs *InstancePtr,
XEmacPs_MdcDiv Divisor);
void XEmacPs_SetOperatingSpeed(XEmacPs *InstancePtr, u16 Speed);
u16 XEmacPs_GetOperatingSpeed(XEmacPs *InstancePtr);
LONG XEmacPs_PhyRead(XEmacPs *InstancePtr, u32 PhyAddress,
u32 RegisterNum, u16 *PhyDataPtr);
LONG XEmacPs_PhyWrite(XEmacPs *InstancePtr, u32 PhyAddress,
u32 RegisterNum, u16 PhyData);
LONG XEmacPs_SetTypeIdCheck(XEmacPs *InstancePtr, u32 Id_Check, u8 Index);
LONG XEmacPs_SendPausePacket(XEmacPs *InstancePtr);
void XEmacPs_DMABLengthUpdate(XEmacPs *InstancePtr, s32 BLength);
#ifdef __cplusplus
}
#endif
#endif /* end of protection macro */
/** @} */

View File

@ -0,0 +1,762 @@
/******************************************************************************
* Copyright (C) 2010 - 2020 Xilinx, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xemacps_bd.h
* @addtogroup emacps_v3_11
* @{
*
* This header provides operations to manage buffer descriptors in support
* of scatter-gather DMA.
*
* The API exported by this header defines abstracted macros that allow the
* user to read/write specific BD fields.
*
* <b>Buffer Descriptors</b>
*
* A buffer descriptor (BD) defines a DMA transaction. The macros defined by
* this header file allow access to most fields within a BD to tailor a DMA
* transaction according to user and hardware requirements. See the hardware
* IP DMA spec for more information on BD fields and how they affect transfers.
*
* The XEmacPs_Bd structure defines a BD. The organization of this structure
* is driven mainly by the hardware for use in scatter-gather DMA transfers.
*
* <b>Performance</b>
*
* Limiting I/O to BDs can improve overall performance of the DMA channel.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a wsy 01/10/10 First release
* 2.1 srt 07/15/14 Add support for Zynq Ultrascale MP GEM specification
* and 64-bit changes.
* 3.0 kvn 02/13/15 Modified code for MISRA-C:2012 compliance.
* 3.0 hk 02/20/15 Added support for jumbo frames.
* Disable extended mode. Perform all 64 bit changes under
* check for arch64.
* 3.2 hk 11/18/15 Change BD typedef and number of words.
* 3.8 hk 08/18/18 Remove duplicate definition of XEmacPs_BdSetLength
* 3.8 mus 11/05/18 Support 64 bit DMA addresses for Microblaze-X platform.
*
* </pre>
*
* ***************************************************************************
*/
#ifndef XEMACPS_BD_H /* prevent circular inclusions */
#define XEMACPS_BD_H /* by using protection macros */
#ifdef __cplusplus
extern "C" {
#endif
/***************************** Include Files *********************************/
#include <string.h>
#include "xil_types.h"
#include "xil_assert.h"
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
#ifdef __aarch64__
/* Minimum BD alignment */
#define XEMACPS_DMABD_MINIMUM_ALIGNMENT 64U
#define XEMACPS_BD_NUM_WORDS 4U
#else
/* Minimum BD alignment */
#define XEMACPS_DMABD_MINIMUM_ALIGNMENT 4U
#define XEMACPS_BD_NUM_WORDS 2U
#endif
/**
* The XEmacPs_Bd is the type for buffer descriptors (BDs).
*/
typedef u32 XEmacPs_Bd[XEMACPS_BD_NUM_WORDS];
/***************** Macros (Inline Functions) Definitions *********************/
/*****************************************************************************/
/**
* Zero out BD fields
*
* @param BdPtr is the BD pointer to operate on
*
* @return Nothing
*
* @note
* C-style signature:
* void XEmacPs_BdClear(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdClear(BdPtr) \
memset((BdPtr), 0, sizeof(XEmacPs_Bd))
/****************************************************************************/
/**
*
* Read the given Buffer Descriptor word.
*
* @param BaseAddress is the base address of the BD to read
* @param Offset is the word offset to be read
*
* @return The 32-bit value of the field
*
* @note
* C-style signature:
* u32 XEmacPs_BdRead(UINTPTR BaseAddress, UINTPTR Offset)
*
*****************************************************************************/
#define XEmacPs_BdRead(BaseAddress, Offset) \
(*(u32 *)((UINTPTR)((void*)(BaseAddress)) + (u32)(Offset)))
/****************************************************************************/
/**
*
* Write the given Buffer Descriptor word.
*
* @param BaseAddress is the base address of the BD to write
* @param Offset is the word offset to be written
* @param Data is the 32-bit value to write to the field
*
* @return None.
*
* @note
* C-style signature:
* void XEmacPs_BdWrite(UINTPTR BaseAddress, UINTPTR Offset, UINTPTR Data)
*
*****************************************************************************/
#define XEmacPs_BdWrite(BaseAddress, Offset, Data) \
(*(u32 *)((UINTPTR)(void*)(BaseAddress) + (u32)(Offset)) = (u32)(Data))
/*****************************************************************************/
/**
* Set the BD's Address field (word 0).
*
* @param BdPtr is the BD pointer to operate on
* @param Addr is the value to write to BD's status field.
*
* @note :
*
* C-style signature:
* void XEmacPs_BdSetAddressTx(XEmacPs_Bd* BdPtr, UINTPTR Addr)
*
*****************************************************************************/
#if defined(__aarch64__) || defined(__arch64__)
#define XEmacPs_BdSetAddressTx(BdPtr, Addr) \
XEmacPs_BdWrite((BdPtr), XEMACPS_BD_ADDR_OFFSET, \
(u32)((Addr) & ULONG64_LO_MASK)); \
XEmacPs_BdWrite((BdPtr), XEMACPS_BD_ADDR_HI_OFFSET, \
(u32)(((Addr) & ULONG64_HI_MASK) >> 32U));
#else
#define XEmacPs_BdSetAddressTx(BdPtr, Addr) \
XEmacPs_BdWrite((BdPtr), XEMACPS_BD_ADDR_OFFSET, (u32)(Addr))
#endif
/*****************************************************************************/
/**
* Set the BD's Address field (word 0).
*
* @param BdPtr is the BD pointer to operate on
* @param Addr is the value to write to BD's status field.
*
* @note : Due to some bits are mixed within receive BD's address field,
* read-modify-write is performed.
*
* C-style signature:
* void XEmacPs_BdSetAddressRx(XEmacPs_Bd* BdPtr, UINTPTR Addr)
*
*****************************************************************************/
#ifdef __aarch64__
#define XEmacPs_BdSetAddressRx(BdPtr, Addr) \
XEmacPs_BdWrite((BdPtr), XEMACPS_BD_ADDR_OFFSET, \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_ADDR_OFFSET) & \
~XEMACPS_RXBUF_ADD_MASK) | ((u32)((Addr) & ULONG64_LO_MASK)))); \
XEmacPs_BdWrite((BdPtr), XEMACPS_BD_ADDR_HI_OFFSET, \
(u32)(((Addr) & ULONG64_HI_MASK) >> 32U));
#else
#define XEmacPs_BdSetAddressRx(BdPtr, Addr) \
XEmacPs_BdWrite((BdPtr), XEMACPS_BD_ADDR_OFFSET, \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_ADDR_OFFSET) & \
~XEMACPS_RXBUF_ADD_MASK) | (UINTPTR)(Addr)))
#endif
/*****************************************************************************/
/**
* Set the BD's Status field (word 1).
*
* @param BdPtr is the BD pointer to operate on
* @param Data is the value to write to BD's status field.
*
* @note
* C-style signature:
* void XEmacPs_BdSetStatus(XEmacPs_Bd* BdPtr, UINTPTR Data)
*
*****************************************************************************/
#define XEmacPs_BdSetStatus(BdPtr, Data) \
XEmacPs_BdWrite((BdPtr), XEMACPS_BD_STAT_OFFSET, \
XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) | (Data))
/*****************************************************************************/
/**
* Retrieve the BD's Packet DMA transfer status word (word 1).
*
* @param BdPtr is the BD pointer to operate on
*
* @return Status word
*
* @note
* C-style signature:
* u32 XEmacPs_BdGetStatus(XEmacPs_Bd* BdPtr)
*
* Due to the BD bit layout differences in transmit and receive. User's
* caution is required.
*****************************************************************************/
#define XEmacPs_BdGetStatus(BdPtr) \
XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET)
/*****************************************************************************/
/**
* Get the address (bits 0..31) of the BD's buffer address (word 0)
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* UINTPTR XEmacPs_BdGetBufAddr(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#if defined(__aarch64__) || defined(__arch64__)
#define XEmacPs_BdGetBufAddr(BdPtr) \
(XEmacPs_BdRead((BdPtr), XEMACPS_BD_ADDR_OFFSET) | \
(XEmacPs_BdRead((BdPtr), XEMACPS_BD_ADDR_HI_OFFSET)) << 32U)
#else
#define XEmacPs_BdGetBufAddr(BdPtr) \
(XEmacPs_BdRead((BdPtr), XEMACPS_BD_ADDR_OFFSET))
#endif
/*****************************************************************************/
/**
* Set transfer length in bytes for the given BD. The length must be set each
* time a BD is submitted to hardware.
*
* @param BdPtr is the BD pointer to operate on
* @param LenBytes is the number of bytes to transfer.
*
* @note
* C-style signature:
* void XEmacPs_BdSetLength(XEmacPs_Bd* BdPtr, u32 LenBytes)
*
*****************************************************************************/
#define XEmacPs_BdSetLength(BdPtr, LenBytes) \
XEmacPs_BdWrite((BdPtr), XEMACPS_BD_STAT_OFFSET, \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
~XEMACPS_TXBUF_LEN_MASK) | (LenBytes)))
/*****************************************************************************/
/**
* Retrieve the BD length field.
*
* For Tx channels, the returned value is the same as that written with
* XEmacPs_BdSetLength().
*
* For Rx channels, the returned value is the size of the received packet.
*
* @param BdPtr is the BD pointer to operate on
*
* @return Length field processed by hardware or set by
* XEmacPs_BdSetLength().
*
* @note
* C-style signature:
* UINTPTR XEmacPs_BdGetLength(XEmacPs_Bd* BdPtr)
* XEAMCPS_RXBUF_LEN_MASK is same as XEMACPS_TXBUF_LEN_MASK.
*
*****************************************************************************/
#define XEmacPs_BdGetLength(BdPtr) \
(XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
XEMACPS_RXBUF_LEN_MASK)
/*****************************************************************************/
/**
* Retrieve the RX frame size.
*
* The returned value is the size of the received packet.
* This API supports jumbo frame sizes if enabled.
*
* @param InstancePtr is the pointer to XEmacps instance
*
* @param BdPtr is the BD pointer to operate on
*
* @return Length field processed by hardware or set by
* XEmacPs_BdSetLength().
*
* @note
* C-style signature:
* UINTPTR XEmacPs_GetRxFrameSize(XEmacPs* InstancePtr, XEmacPs_Bd* BdPtr)
* RxBufMask is dependent on whether jumbo is enabled or not.
*
*****************************************************************************/
#define XEmacPs_GetRxFrameSize(InstancePtr, BdPtr) \
(XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
(InstancePtr)->RxBufMask)
/*****************************************************************************/
/**
* Test whether the given BD has been marked as the last BD of a packet.
*
* @param BdPtr is the BD pointer to operate on
*
* @return TRUE if BD represents the "Last" BD of a packet, FALSE otherwise
*
* @note
* C-style signature:
* UINTPTR XEmacPs_BdIsLast(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdIsLast(BdPtr) \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
XEMACPS_RXBUF_EOF_MASK)!=0U ? TRUE : FALSE)
/*****************************************************************************/
/**
* Tell the DMA engine that the given transmit BD marks the end of the current
* packet to be processed.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* void XEmacPs_BdSetLast(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdSetLast(BdPtr) \
(XEmacPs_BdWrite((BdPtr), XEMACPS_BD_STAT_OFFSET, \
XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) | \
XEMACPS_TXBUF_LAST_MASK))
/*****************************************************************************/
/**
* Tell the DMA engine that the current packet does not end with the given
* BD.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* void XEmacPs_BdClearLast(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdClearLast(BdPtr) \
(XEmacPs_BdWrite((BdPtr), XEMACPS_BD_STAT_OFFSET, \
XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
~XEMACPS_TXBUF_LAST_MASK))
/*****************************************************************************/
/**
* Set this bit to mark the last descriptor in the receive buffer descriptor
* list.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* void XEmacPs_BdSetRxWrap(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
/*#define XEmacPs_BdSetRxWrap(BdPtr) \
(XEmacPs_BdWrite((BdPtr), XEMACPS_BD_ADDR_OFFSET, \
XEmacPs_BdRead((BdPtr), XEMACPS_BD_ADDR_OFFSET) | \
XEMACPS_RXBUF_WRAP_MASK))
*/
/*****************************************************************************/
/**
* Determine the wrap bit of the receive BD which indicates end of the
* BD list.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* u8 XEmacPs_BdIsRxWrap(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdIsRxWrap(BdPtr) \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_ADDR_OFFSET) & \
XEMACPS_RXBUF_WRAP_MASK)!=0U ? TRUE : FALSE)
/*****************************************************************************/
/**
* Sets this bit to mark the last descriptor in the transmit buffer
* descriptor list.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* void XEmacPs_BdSetTxWrap(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
/*#define XEmacPs_BdSetTxWrap(BdPtr) \
(XEmacPs_BdWrite((BdPtr), XEMACPS_BD_STAT_OFFSET, \
XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) | \
XEMACPS_TXBUF_WRAP_MASK))
*/
/*****************************************************************************/
/**
* Determine the wrap bit of the transmit BD which indicates end of the
* BD list.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* u8 XEmacPs_BdGetTxWrap(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdIsTxWrap(BdPtr) \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
XEMACPS_TXBUF_WRAP_MASK)!=0U ? TRUE : FALSE)
/*****************************************************************************/
/*
* Must clear this bit to enable the MAC to write data to the receive
* buffer. Hardware sets this bit once it has successfully written a frame to
* memory. Once set, software has to clear the bit before the buffer can be
* used again. This macro clear the new bit of the receive BD.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* void XEmacPs_BdClearRxNew(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdClearRxNew(BdPtr) \
(XEmacPs_BdWrite((BdPtr), XEMACPS_BD_ADDR_OFFSET, \
XEmacPs_BdRead((BdPtr), XEMACPS_BD_ADDR_OFFSET) & \
~XEMACPS_RXBUF_NEW_MASK))
/*****************************************************************************/
/**
* Determine the new bit of the receive BD.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* UINTPTR XEmacPs_BdIsRxNew(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdIsRxNew(BdPtr) \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_ADDR_OFFSET) & \
XEMACPS_RXBUF_NEW_MASK)!=0U ? TRUE : FALSE)
/*****************************************************************************/
/**
* Software sets this bit to disable the buffer to be read by the hardware.
* Hardware sets this bit for the first buffer of a frame once it has been
* successfully transmitted. This macro sets this bit of transmit BD to avoid
* confusion.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* void XEmacPs_BdSetTxUsed(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdSetTxUsed(BdPtr) \
(XEmacPs_BdWrite((BdPtr), XEMACPS_BD_STAT_OFFSET, \
XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) | \
XEMACPS_TXBUF_USED_MASK))
/*****************************************************************************/
/**
* Software clears this bit to enable the buffer to be read by the hardware.
* Hardware sets this bit for the first buffer of a frame once it has been
* successfully transmitted. This macro clears this bit of transmit BD.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* void XEmacPs_BdClearTxUsed(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdClearTxUsed(BdPtr) \
(XEmacPs_BdWrite((BdPtr), XEMACPS_BD_STAT_OFFSET, \
XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
~XEMACPS_TXBUF_USED_MASK))
/*****************************************************************************/
/**
* Determine the used bit of the transmit BD.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* UINTPTR XEmacPs_BdIsTxUsed(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdIsTxUsed(BdPtr) \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
XEMACPS_TXBUF_USED_MASK)!=0U ? TRUE : FALSE)
/*****************************************************************************/
/**
* Determine if a frame fails to be transmitted due to too many retries.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* UINTPTR XEmacPs_BdIsTxRetry(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdIsTxRetry(BdPtr) \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
XEMACPS_TXBUF_RETRY_MASK)!=0U ? TRUE : FALSE)
/*****************************************************************************/
/**
* Determine if a frame fails to be transmitted due to data can not be
* feteched in time or buffers are exhausted.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* UINTPTR XEmacPs_BdIsTxUrun(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdIsTxUrun(BdPtr) \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
XEMACPS_TXBUF_URUN_MASK)!=0U ? TRUE : FALSE)
/*****************************************************************************/
/**
* Determine if a frame fails to be transmitted due to buffer is exhausted
* mid-frame.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* UINTPTR XEmacPs_BdIsTxExh(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdIsTxExh(BdPtr) \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
XEMACPS_TXBUF_EXH_MASK)!=0U ? TRUE : FALSE)
/*****************************************************************************/
/**
* Sets this bit, no CRC will be appended to the current frame. This control
* bit must be set for the first buffer in a frame and will be ignored for
* the subsequent buffers of a frame.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* This bit must be clear when using the transmit checksum generation offload,
* otherwise checksum generation and substitution will not occur.
*
* C-style signature:
* UINTPTR XEmacPs_BdSetTxNoCRC(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdSetTxNoCRC(BdPtr) \
(XEmacPs_BdWrite((BdPtr), XEMACPS_BD_STAT_OFFSET, \
XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) | \
XEMACPS_TXBUF_NOCRC_MASK))
/*****************************************************************************/
/**
* Clear this bit, CRC will be appended to the current frame. This control
* bit must be set for the first buffer in a frame and will be ignored for
* the subsequent buffers of a frame.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* This bit must be clear when using the transmit checksum generation offload,
* otherwise checksum generation and substitution will not occur.
*
* C-style signature:
* UINTPTR XEmacPs_BdClearTxNoCRC(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdClearTxNoCRC(BdPtr) \
(XEmacPs_BdWrite((BdPtr), XEMACPS_BD_STAT_OFFSET, \
XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
~XEMACPS_TXBUF_NOCRC_MASK))
/*****************************************************************************/
/**
* Determine the broadcast bit of the receive BD.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* UINTPTR XEmacPs_BdIsRxBcast(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdIsRxBcast(BdPtr) \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
XEMACPS_RXBUF_BCAST_MASK)!=0U ? TRUE : FALSE)
/*****************************************************************************/
/**
* Determine the multicast hash bit of the receive BD.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* UINTPTR XEmacPs_BdIsRxMultiHash(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdIsRxMultiHash(BdPtr) \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
XEMACPS_RXBUF_MULTIHASH_MASK)!=0U ? TRUE : FALSE)
/*****************************************************************************/
/**
* Determine the unicast hash bit of the receive BD.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* UINTPTR XEmacPs_BdIsRxUniHash(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdIsRxUniHash(BdPtr) \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
XEMACPS_RXBUF_UNIHASH_MASK)!=0U ? TRUE : FALSE)
/*****************************************************************************/
/**
* Determine if the received frame is a VLAN Tagged frame.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* UINTPTR XEmacPs_BdIsRxVlan(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdIsRxVlan(BdPtr) \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
XEMACPS_RXBUF_VLAN_MASK)!=0U ? TRUE : FALSE)
/*****************************************************************************/
/**
* Determine if the received frame has Type ID of 8100h and null VLAN
* identifier(Priority tag).
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* UINTPTR XEmacPs_BdIsRxPri(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdIsRxPri(BdPtr) \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
XEMACPS_RXBUF_PRI_MASK)!=0U ? TRUE : FALSE)
/*****************************************************************************/
/**
* Determine if the received frame's Concatenation Format Indicator (CFI) of
* the frames VLANTCI field was set.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* UINTPTR XEmacPs_BdIsRxCFI(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdIsRxCFI(BdPtr) \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
XEMACPS_RXBUF_CFI_MASK)!=0U ? TRUE : FALSE)
/*****************************************************************************/
/**
* Determine the End Of Frame (EOF) bit of the receive BD.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* UINTPTR XEmacPs_BdGetRxEOF(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdIsRxEOF(BdPtr) \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
XEMACPS_RXBUF_EOF_MASK)!=0U ? TRUE : FALSE)
/*****************************************************************************/
/**
* Determine the Start Of Frame (SOF) bit of the receive BD.
*
* @param BdPtr is the BD pointer to operate on
*
* @note
* C-style signature:
* UINTPTR XEmacPs_BdGetRxSOF(XEmacPs_Bd* BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdIsRxSOF(BdPtr) \
((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \
XEMACPS_RXBUF_SOF_MASK)!=0U ? TRUE : FALSE)
/************************** Function Prototypes ******************************/
#ifdef __cplusplus
}
#endif
#endif /* end of protection macro */
/** @} */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,215 @@
/******************************************************************************
* Copyright (C) 2010 - 2020 Xilinx, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xemacps_bdring.h
* @addtogroup emacps_v3_11
* @{
*
* The Xiline EmacPs Buffer Descriptor ring driver. This is part of EmacPs
* DMA functionalities.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a wsy 01/10/10 First release
* 2.1 srt 07/15/14 Add support for Zynq Ultrascale Mp architecture.
* 3.0 kvn 02/13/15 Modified code for MISRA-C:2012 compliance.
* 3.6 rb 09/08/17 HwCnt variable (in XEmacPs_BdRing structure) is
* changed to volatile.
*
* </pre>
*
******************************************************************************/
#ifndef XEMACPS_BDRING_H /* prevent curcular inclusions */
#define XEMACPS_BDRING_H /* by using protection macros */
#ifdef __cplusplus
extern "C" {
#endif
/**************************** Type Definitions *******************************/
/** This is an internal structure used to maintain the DMA list */
typedef struct {
UINTPTR PhysBaseAddr;/**< Physical address of 1st BD in list */
UINTPTR BaseBdAddr; /**< Virtual address of 1st BD in list */
UINTPTR HighBdAddr; /**< Virtual address of last BD in the list */
u32 Length; /**< Total size of ring in bytes */
u32 RunState; /**< Flag to indicate DMA is started */
u32 Separation; /**< Number of bytes between the starting address
of adjacent BDs */
XEmacPs_Bd *FreeHead;
/**< First BD in the free group */
XEmacPs_Bd *PreHead;/**< First BD in the pre-work group */
XEmacPs_Bd *HwHead; /**< First BD in the work group */
XEmacPs_Bd *HwTail; /**< Last BD in the work group */
XEmacPs_Bd *PostHead;
/**< First BD in the post-work group */
XEmacPs_Bd *BdaRestart;
/**< BDA to load when channel is started */
volatile u32 HwCnt; /**< Number of BDs in work group */
u32 PreCnt; /**< Number of BDs in pre-work group */
u32 FreeCnt; /**< Number of allocatable BDs in the free group */
u32 PostCnt; /**< Number of BDs in post-work group */
u32 AllCnt; /**< Total Number of BDs for channel */
} XEmacPs_BdRing;
/***************** Macros (Inline Functions) Definitions *********************/
/*****************************************************************************/
/**
* Use this macro at initialization time to determine how many BDs will fit
* in a BD list within the given memory constraints.
*
* The results of this macro can be provided to XEmacPs_BdRingCreate().
*
* @param Alignment specifies what byte alignment the BDs must fall on and
* must be a power of 2 to get an accurate calculation (32, 64, 128,...)
* @param Bytes is the number of bytes to be used to store BDs.
*
* @return Number of BDs that can fit in the given memory area
*
* @note
* C-style signature:
* u32 XEmacPs_BdRingCntCalc(u32 Alignment, u32 Bytes)
*
******************************************************************************/
#define XEmacPs_BdRingCntCalc(Alignment, Bytes) \
(u32)((Bytes) / (sizeof(XEmacPs_Bd)))
/*****************************************************************************/
/**
* Use this macro at initialization time to determine how many bytes of memory
* is required to contain a given number of BDs at a given alignment.
*
* @param Alignment specifies what byte alignment the BDs must fall on. This
* parameter must be a power of 2 to get an accurate calculation (32, 64,
* 128,...)
* @param NumBd is the number of BDs to calculate memory size requirements for
*
* @return The number of bytes of memory required to create a BD list with the
* given memory constraints.
*
* @note
* C-style signature:
* u32 XEmacPs_BdRingMemCalc(u32 Alignment, u32 NumBd)
*
******************************************************************************/
#define XEmacPs_BdRingMemCalc(Alignment, NumBd) \
(u32)(sizeof(XEmacPs_Bd) * (NumBd))
/****************************************************************************/
/**
* Return the total number of BDs allocated by this channel with
* XEmacPs_BdRingCreate().
*
* @param RingPtr is the DMA channel to operate on.
*
* @return The total number of BDs allocated for this channel.
*
* @note
* C-style signature:
* u32 XEmacPs_BdRingGetCnt(XEmacPs_BdRing* RingPtr)
*
*****************************************************************************/
#define XEmacPs_BdRingGetCnt(RingPtr) ((RingPtr)->AllCnt)
/****************************************************************************/
/**
* Return the number of BDs allocatable with XEmacPs_BdRingAlloc() for pre-
* processing.
*
* @param RingPtr is the DMA channel to operate on.
*
* @return The number of BDs currently allocatable.
*
* @note
* C-style signature:
* u32 XEmacPs_BdRingGetFreeCnt(XEmacPs_BdRing* RingPtr)
*
*****************************************************************************/
#define XEmacPs_BdRingGetFreeCnt(RingPtr) ((RingPtr)->FreeCnt)
/****************************************************************************/
/**
* Return the next BD from BdPtr in a list.
*
* @param RingPtr is the DMA channel to operate on.
* @param BdPtr is the BD to operate on.
*
* @return The next BD in the list relative to the BdPtr parameter.
*
* @note
* C-style signature:
* XEmacPs_Bd *XEmacPs_BdRingNext(XEmacPs_BdRing* RingPtr,
* XEmacPs_Bd *BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdRingNext(RingPtr, BdPtr) \
(((UINTPTR)((void *)(BdPtr)) >= (RingPtr)->HighBdAddr) ? \
(XEmacPs_Bd*)((void*)(RingPtr)->BaseBdAddr) : \
(XEmacPs_Bd*)((UINTPTR)((void *)(BdPtr)) + (RingPtr)->Separation))
/****************************************************************************/
/**
* Return the previous BD from BdPtr in the list.
*
* @param RingPtr is the DMA channel to operate on.
* @param BdPtr is the BD to operate on
*
* @return The previous BD in the list relative to the BdPtr parameter.
*
* @note
* C-style signature:
* XEmacPs_Bd *XEmacPs_BdRingPrev(XEmacPs_BdRing* RingPtr,
* XEmacPs_Bd *BdPtr)
*
*****************************************************************************/
#define XEmacPs_BdRingPrev(RingPtr, BdPtr) \
(((UINTPTR)(BdPtr) <= (RingPtr)->BaseBdAddr) ? \
(XEmacPs_Bd*)(RingPtr)->HighBdAddr : \
(XEmacPs_Bd*)((UINTPTR)(BdPtr) - (RingPtr)->Separation))
/************************** Function Prototypes ******************************/
/*
* Scatter gather DMA related functions in xemacps_bdring.c
*/
LONG XEmacPs_BdRingCreate(XEmacPs_BdRing * RingPtr, UINTPTR PhysAddr,
UINTPTR VirtAddr, u32 Alignment, u32 BdCount);
LONG XEmacPs_BdRingClone(XEmacPs_BdRing * RingPtr, XEmacPs_Bd * SrcBdPtr,
u8 Direction);
LONG XEmacPs_BdRingAlloc(XEmacPs_BdRing * RingPtr, u32 NumBd,
XEmacPs_Bd ** BdSetPtr);
LONG XEmacPs_BdRingUnAlloc(XEmacPs_BdRing * RingPtr, u32 NumBd,
XEmacPs_Bd * BdSetPtr);
LONG XEmacPs_BdRingToHw(XEmacPs_BdRing * RingPtr, u32 NumBd,
XEmacPs_Bd * BdSetPtr);
LONG XEmacPs_BdRingFree(XEmacPs_BdRing * RingPtr, u32 NumBd,
XEmacPs_Bd * BdSetPtr);
u32 XEmacPs_BdRingFromHwTx(XEmacPs_BdRing * RingPtr, u32 BdLimit,
XEmacPs_Bd ** BdSetPtr);
u32 XEmacPs_BdRingFromHwRx(XEmacPs_BdRing * RingPtr, u32 BdLimit,
XEmacPs_Bd ** BdSetPtr);
LONG XEmacPs_BdRingCheck(XEmacPs_BdRing * RingPtr, u8 Direction);
void XEmacPs_BdRingPtrReset(XEmacPs_BdRing * RingPtr, void *virtaddrloc);
#ifdef __cplusplus
}
#endif
#endif /* end of protection macros */
/** @} */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
/*******************************************************************
*
* CAUTION: This file is automatically generated by HSI.
* Version: 2020.1
* DO NOT EDIT.
*
* Copyright (C) 2010-2021 Xilinx, Inc. All Rights Reserved.
* SPDX-License-Identifier: MIT
*
* Description: Driver configuration
*
*******************************************************************/
#include "xparameters.h"
#include "xemacps.h"
/*
* The configuration table for devices
*/
XEmacPs_Config XEmacPs_ConfigTable[XPAR_XEMACPS_NUM_INSTANCES] =
{
{
XPAR_PSU_ETHERNET_3_DEVICE_ID,
XPAR_PSU_ETHERNET_3_BASEADDR,
XPAR_PSU_ETHERNET_3_IS_CACHE_COHERENT
}
};

View File

@ -0,0 +1,97 @@
/******************************************************************************
* Copyright (C) 2010 - 2020 Xilinx, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xemacps_hw.c
* @addtogroup emacps_v3_11
* @{
*
* This file contains the implementation of the ethernet interface reset sequence
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.05a kpc 28/06/13 First release
* 3.00 kvn 02/13/15 Modified code for MISRA-C:2012 compliance.
* </pre>
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "xemacps_hw.h"
#include "xparameters.h"
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
/*****************************************************************************/
/**
* This function perform the reset sequence to the given emacps interface by
* configuring the appropriate control bits in the emacps specific registers.
* the emacps reset sequence involves the following steps
* Disable all the interuupts
* Clear the status registers
* Disable Rx and Tx engines
* Update the Tx and Rx descriptor queue registers with reset values
* Update the other relevant control registers with reset value
*
* @param BaseAddr of the interface
*
* @return N/A
*
* @note
* This function will not modify the slcr registers that are relevant for
* emacps controller
******************************************************************************/
void XEmacPs_ResetHw(u32 BaseAddr)
{
u32 RegVal;
/* Disable the interrupts */
XEmacPs_WriteReg(BaseAddr,XEMACPS_IDR_OFFSET,0x0U);
/* Stop transmission,disable loopback and Stop tx and Rx engines */
RegVal = XEmacPs_ReadReg(BaseAddr,XEMACPS_NWCTRL_OFFSET);
RegVal &= ~((u32)XEMACPS_NWCTRL_TXEN_MASK|
(u32)XEMACPS_NWCTRL_RXEN_MASK|
(u32)XEMACPS_NWCTRL_HALTTX_MASK|
(u32)XEMACPS_NWCTRL_LOOPEN_MASK);
/* Clear the statistic registers, flush the packets in DPRAM*/
RegVal |= (XEMACPS_NWCTRL_STATCLR_MASK|
XEMACPS_NWCTRL_FLUSH_DPRAM_MASK);
XEmacPs_WriteReg(BaseAddr,XEMACPS_NWCTRL_OFFSET,RegVal);
/* Clear the interrupt status */
XEmacPs_WriteReg(BaseAddr,XEMACPS_ISR_OFFSET,XEMACPS_IXR_ALL_MASK);
/* Clear the tx status */
XEmacPs_WriteReg(BaseAddr,XEMACPS_TXSR_OFFSET,(XEMACPS_TXSR_ERROR_MASK|
(u32)XEMACPS_TXSR_TXCOMPL_MASK|
(u32)XEMACPS_TXSR_TXGO_MASK));
/* Clear the rx status */
XEmacPs_WriteReg(BaseAddr,XEMACPS_RXSR_OFFSET,
XEMACPS_RXSR_FRAMERX_MASK);
/* Clear the tx base address */
XEmacPs_WriteReg(BaseAddr,XEMACPS_TXQBASE_OFFSET,0x0U);
/* Clear the rx base address */
XEmacPs_WriteReg(BaseAddr,XEMACPS_RXQBASE_OFFSET,0x0U);
/* Update the network config register with reset value */
XEmacPs_WriteReg(BaseAddr,XEMACPS_NWCFG_OFFSET,XEMACPS_NWCFG_RESET_MASK);
/* Update the hash address registers with reset value */
XEmacPs_WriteReg(BaseAddr,XEMACPS_HASHL_OFFSET,0x0U);
XEmacPs_WriteReg(BaseAddr,XEMACPS_HASHH_OFFSET,0x0U);
}
/** @} */

View File

@ -0,0 +1,646 @@
/******************************************************************************
* Copyright (C) 2010 - 2020 Xilinx, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xemacps_hw.h
* @addtogroup emacps_v3_11
* @{
*
* This header file contains identifiers and low-level driver functions (or
* macros) that can be used to access the PS Ethernet MAC (XEmacPs) device.
* High-level driver functions are defined in xemacps.h.
*
* @note
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a wsy 01/10/10 First release.
* 1.02a asa 11/05/12 Added hash defines for DMACR burst length configuration.
* 1.05a kpc 28/06/13 Added XEmacPs_ResetHw function prototype
* 1.06a asa 11/02/13 Changed the value for XEMACPS_RXBUF_LEN_MASK from 0x3fff
* to 0x1fff. This fixes the CR#744902.
* 2.1 srt 07/15/14 Add support for Zynq Ultrascale Mp GEM specification.
* 3.0 kvn 12/16/14 Changed name of XEMACPS_NWCFG_LENGTHERRDSCRD_MASK to
* XEMACPS_NWCFG_LENERRDSCRD_MASK as it exceeds 31 characters.
* 3.0 kpc 1/23/15 Corrected the extended descriptor macro values.
* 3.0 kvn 02/13/15 Modified code for MISRA-C:2012 compliance.
* 3.0 hk 03/18/15 Added support for jumbo frames.
* Remove "used bit set" from TX error interrupt masks.
* 3.1 hk 08/10/15 Update upper 32 bit tx and rx queue ptr register offsets.
* 3.2 hk 02/22/16 Added SGMII support for Zynq Ultrascale+ MPSoC.
* 3.8 hk 09/17/18 Fix PTP interrupt masks.
* 3.9 hk 01/23/19 Add RX watermark support
* 3.10 hk 05/16/19 Clear status registers properly in reset
* </pre>
*
******************************************************************************/
#ifndef XEMACPS_HW_H /* prevent circular inclusions */
#define XEMACPS_HW_H /* by using protection macros */
/***************************** Include Files *********************************/
#include "xil_types.h"
#include "xil_assert.h"
#include "xil_io.h"
#ifdef __cplusplus
extern "C" {
#endif
/************************** Constant Definitions *****************************/
#define XEMACPS_MAX_MAC_ADDR 4U /**< Maxmum number of mac address
supported */
#define XEMACPS_MAX_TYPE_ID 4U /**< Maxmum number of type id supported */
#ifdef __aarch64__
#define XEMACPS_BD_ALIGNMENT 64U /**< Minimum buffer descriptor alignment
on the local bus */
#else
#define XEMACPS_BD_ALIGNMENT 4U /**< Minimum buffer descriptor alignment
on the local bus */
#endif
#define XEMACPS_RX_BUF_ALIGNMENT 4U /**< Minimum buffer alignment when using
options that impose alignment
restrictions on the buffer data on
the local bus */
/** @name Direction identifiers
*
* These are used by several functions and callbacks that need
* to specify whether an operation specifies a send or receive channel.
* @{
*/
#define XEMACPS_SEND 1U /**< send direction */
#define XEMACPS_RECV 2U /**< receive direction */
/*@}*/
/** @name MDC clock division
* currently supporting 8, 16, 32, 48, 64, 96, 128, 224.
* @{
*/
typedef enum { MDC_DIV_8 = 0U, MDC_DIV_16, MDC_DIV_32, MDC_DIV_48,
MDC_DIV_64, MDC_DIV_96, MDC_DIV_128, MDC_DIV_224
} XEmacPs_MdcDiv;
/*@}*/
#define XEMACPS_RX_BUF_SIZE 1536U /**< Specify the receive buffer size in
bytes, 64, 128, ... 10240 */
#define XEMACPS_RX_BUF_SIZE_JUMBO 10240U
#define XEMACPS_RX_BUF_UNIT 64U /**< Number of receive buffer bytes as a
unit, this is HW setup */
#define XEMACPS_MAX_RXBD 128U /**< Size of RX buffer descriptor queues */
#define XEMACPS_MAX_TXBD 128U /**< Size of TX buffer descriptor queues */
#define XEMACPS_MAX_HASH_BITS 64U /**< Maximum value for hash bits. 2**6 */
/* Register offset definitions. Unless otherwise noted, register access is
* 32 bit. Names are self explained here.
*/
#define XEMACPS_NWCTRL_OFFSET 0x00000000U /**< Network Control reg */
#define XEMACPS_NWCFG_OFFSET 0x00000004U /**< Network Config reg */
#define XEMACPS_NWSR_OFFSET 0x00000008U /**< Network Status reg */
#define XEMACPS_DMACR_OFFSET 0x00000010U /**< DMA Control reg */
#define XEMACPS_TXSR_OFFSET 0x00000014U /**< TX Status reg */
#define XEMACPS_RXQBASE_OFFSET 0x00000018U /**< RX Q Base address reg */
#define XEMACPS_TXQBASE_OFFSET 0x0000001CU /**< TX Q Base address reg */
#define XEMACPS_RXSR_OFFSET 0x00000020U /**< RX Status reg */
#define XEMACPS_ISR_OFFSET 0x00000024U /**< Interrupt Status reg */
#define XEMACPS_IER_OFFSET 0x00000028U /**< Interrupt Enable reg */
#define XEMACPS_IDR_OFFSET 0x0000002CU /**< Interrupt Disable reg */
#define XEMACPS_IMR_OFFSET 0x00000030U /**< Interrupt Mask reg */
#define XEMACPS_PHYMNTNC_OFFSET 0x00000034U /**< Phy Maintaince reg */
#define XEMACPS_RXPAUSE_OFFSET 0x00000038U /**< RX Pause Time reg */
#define XEMACPS_TXPAUSE_OFFSET 0x0000003CU /**< TX Pause Time reg */
#define XEMACPS_JUMBOMAXLEN_OFFSET 0x00000048U /**< Jumbo max length reg */
#define XEMACPS_RXWATERMARK_OFFSET 0x0000007CU /**< RX watermark reg */
#define XEMACPS_HASHL_OFFSET 0x00000080U /**< Hash Low address reg */
#define XEMACPS_HASHH_OFFSET 0x00000084U /**< Hash High address reg */
#define XEMACPS_LADDR1L_OFFSET 0x00000088U /**< Specific1 addr low reg */
#define XEMACPS_LADDR1H_OFFSET 0x0000008CU /**< Specific1 addr high reg */
#define XEMACPS_LADDR2L_OFFSET 0x00000090U /**< Specific2 addr low reg */
#define XEMACPS_LADDR2H_OFFSET 0x00000094U /**< Specific2 addr high reg */
#define XEMACPS_LADDR3L_OFFSET 0x00000098U /**< Specific3 addr low reg */
#define XEMACPS_LADDR3H_OFFSET 0x0000009CU /**< Specific3 addr high reg */
#define XEMACPS_LADDR4L_OFFSET 0x000000A0U /**< Specific4 addr low reg */
#define XEMACPS_LADDR4H_OFFSET 0x000000A4U /**< Specific4 addr high reg */
#define XEMACPS_MATCH1_OFFSET 0x000000A8U /**< Type ID1 Match reg */
#define XEMACPS_MATCH2_OFFSET 0x000000ACU /**< Type ID2 Match reg */
#define XEMACPS_MATCH3_OFFSET 0x000000B0U /**< Type ID3 Match reg */
#define XEMACPS_MATCH4_OFFSET 0x000000B4U /**< Type ID4 Match reg */
#define XEMACPS_STRETCH_OFFSET 0x000000BCU /**< IPG Stretch reg */
#define XEMACPS_OCTTXL_OFFSET 0x00000100U /**< Octects transmitted Low
reg */
#define XEMACPS_OCTTXH_OFFSET 0x00000104U /**< Octects transmitted High
reg */
#define XEMACPS_TXCNT_OFFSET 0x00000108U /**< Error-free Frmaes
transmitted counter */
#define XEMACPS_TXBCCNT_OFFSET 0x0000010CU /**< Error-free Broadcast
Frames counter*/
#define XEMACPS_TXMCCNT_OFFSET 0x00000110U /**< Error-free Multicast
Frame counter */
#define XEMACPS_TXPAUSECNT_OFFSET 0x00000114U /**< Pause Frames Transmitted
Counter */
#define XEMACPS_TX64CNT_OFFSET 0x00000118U /**< Error-free 64 byte Frames
Transmitted counter */
#define XEMACPS_TX65CNT_OFFSET 0x0000011CU /**< Error-free 65-127 byte
Frames Transmitted
counter */
#define XEMACPS_TX128CNT_OFFSET 0x00000120U /**< Error-free 128-255 byte
Frames Transmitted
counter*/
#define XEMACPS_TX256CNT_OFFSET 0x00000124U /**< Error-free 256-511 byte
Frames transmitted
counter */
#define XEMACPS_TX512CNT_OFFSET 0x00000128U /**< Error-free 512-1023 byte
Frames transmitted
counter */
#define XEMACPS_TX1024CNT_OFFSET 0x0000012CU /**< Error-free 1024-1518 byte
Frames transmitted
counter */
#define XEMACPS_TX1519CNT_OFFSET 0x00000130U /**< Error-free larger than
1519 byte Frames
transmitted counter */
#define XEMACPS_TXURUNCNT_OFFSET 0x00000134U /**< TX under run error
counter */
#define XEMACPS_SNGLCOLLCNT_OFFSET 0x00000138U /**< Single Collision Frame
Counter */
#define XEMACPS_MULTICOLLCNT_OFFSET 0x0000013CU /**< Multiple Collision Frame
Counter */
#define XEMACPS_EXCESSCOLLCNT_OFFSET 0x00000140U /**< Excessive Collision Frame
Counter */
#define XEMACPS_LATECOLLCNT_OFFSET 0x00000144U /**< Late Collision Frame
Counter */
#define XEMACPS_TXDEFERCNT_OFFSET 0x00000148U /**< Deferred Transmission
Frame Counter */
#define XEMACPS_TXCSENSECNT_OFFSET 0x0000014CU /**< Transmit Carrier Sense
Error Counter */
#define XEMACPS_OCTRXL_OFFSET 0x00000150U /**< Octects Received register
Low */
#define XEMACPS_OCTRXH_OFFSET 0x00000154U /**< Octects Received register
High */
#define XEMACPS_RXCNT_OFFSET 0x00000158U /**< Error-free Frames
Received Counter */
#define XEMACPS_RXBROADCNT_OFFSET 0x0000015CU /**< Error-free Broadcast
Frames Received Counter */
#define XEMACPS_RXMULTICNT_OFFSET 0x00000160U /**< Error-free Multicast
Frames Received Counter */
#define XEMACPS_RXPAUSECNT_OFFSET 0x00000164U /**< Pause Frames
Received Counter */
#define XEMACPS_RX64CNT_OFFSET 0x00000168U /**< Error-free 64 byte Frames
Received Counter */
#define XEMACPS_RX65CNT_OFFSET 0x0000016CU /**< Error-free 65-127 byte
Frames Received Counter */
#define XEMACPS_RX128CNT_OFFSET 0x00000170U /**< Error-free 128-255 byte
Frames Received Counter */
#define XEMACPS_RX256CNT_OFFSET 0x00000174U /**< Error-free 256-512 byte
Frames Received Counter */
#define XEMACPS_RX512CNT_OFFSET 0x00000178U /**< Error-free 512-1023 byte
Frames Received Counter */
#define XEMACPS_RX1024CNT_OFFSET 0x0000017CU /**< Error-free 1024-1518 byte
Frames Received Counter */
#define XEMACPS_RX1519CNT_OFFSET 0x00000180U /**< Error-free 1519-max byte
Frames Received Counter */
#define XEMACPS_RXUNDRCNT_OFFSET 0x00000184U /**< Undersize Frames Received
Counter */
#define XEMACPS_RXOVRCNT_OFFSET 0x00000188U /**< Oversize Frames Received
Counter */
#define XEMACPS_RXJABCNT_OFFSET 0x0000018CU /**< Jabbers Received
Counter */
#define XEMACPS_RXFCSCNT_OFFSET 0x00000190U /**< Frame Check Sequence
Error Counter */
#define XEMACPS_RXLENGTHCNT_OFFSET 0x00000194U /**< Length Field Error
Counter */
#define XEMACPS_RXSYMBCNT_OFFSET 0x00000198U /**< Symbol Error Counter */
#define XEMACPS_RXALIGNCNT_OFFSET 0x0000019CU /**< Alignment Error Counter */
#define XEMACPS_RXRESERRCNT_OFFSET 0x000001A0U /**< Receive Resource Error
Counter */
#define XEMACPS_RXORCNT_OFFSET 0x000001A4U /**< Receive Overrun Counter */
#define XEMACPS_RXIPCCNT_OFFSET 0x000001A8U /**< IP header Checksum Error
Counter */
#define XEMACPS_RXTCPCCNT_OFFSET 0x000001ACU /**< TCP Checksum Error
Counter */
#define XEMACPS_RXUDPCCNT_OFFSET 0x000001B0U /**< UDP Checksum Error
Counter */
#define XEMACPS_LAST_OFFSET 0x000001B4U /**< Last statistic counter
offset, for clearing */
#define XEMACPS_1588_SEC_OFFSET 0x000001D0U /**< 1588 second counter */
#define XEMACPS_1588_NANOSEC_OFFSET 0x000001D4U /**< 1588 nanosecond counter */
#define XEMACPS_1588_ADJ_OFFSET 0x000001D8U /**< 1588 nanosecond
adjustment counter */
#define XEMACPS_1588_INC_OFFSET 0x000001DCU /**< 1588 nanosecond
increment counter */
#define XEMACPS_PTP_TXSEC_OFFSET 0x000001E0U /**< 1588 PTP transmit second
counter */
#define XEMACPS_PTP_TXNANOSEC_OFFSET 0x000001E4U /**< 1588 PTP transmit
nanosecond counter */
#define XEMACPS_PTP_RXSEC_OFFSET 0x000001E8U /**< 1588 PTP receive second
counter */
#define XEMACPS_PTP_RXNANOSEC_OFFSET 0x000001ECU /**< 1588 PTP receive
nanosecond counter */
#define XEMACPS_PTPP_TXSEC_OFFSET 0x000001F0U /**< 1588 PTP peer transmit
second counter */
#define XEMACPS_PTPP_TXNANOSEC_OFFSET 0x000001F4U /**< 1588 PTP peer transmit
nanosecond counter */
#define XEMACPS_PTPP_RXSEC_OFFSET 0x000001F8U /**< 1588 PTP peer receive
second counter */
#define XEMACPS_PTPP_RXNANOSEC_OFFSET 0x000001FCU /**< 1588 PTP peer receive
nanosecond counter */
#define XEMACPS_INTQ1_STS_OFFSET 0x00000400U /**< Interrupt Q1 Status
reg */
#define XEMACPS_TXQ1BASE_OFFSET 0x00000440U /**< TX Q1 Base address
reg */
#define XEMACPS_RXQ1BASE_OFFSET 0x00000480U /**< RX Q1 Base address
reg */
#define XEMACPS_MSBBUF_TXQBASE_OFFSET 0x000004C8U /**< MSB Buffer TX Q Base
reg */
#define XEMACPS_MSBBUF_RXQBASE_OFFSET 0x000004D4U /**< MSB Buffer RX Q Base
reg */
#define XEMACPS_INTQ1_IER_OFFSET 0x00000600U /**< Interrupt Q1 Enable
reg */
#define XEMACPS_INTQ1_IDR_OFFSET 0x00000620U /**< Interrupt Q1 Disable
reg */
#define XEMACPS_INTQ1_IMR_OFFSET 0x00000640U /**< Interrupt Q1 Mask
reg */
/* Define some bit positions for registers. */
/** @name network control register bit definitions
* @{
*/
#define XEMACPS_NWCTRL_FLUSH_DPRAM_MASK 0x00040000U /**< Flush a packet from
Rx SRAM */
#define XEMACPS_NWCTRL_ZEROPAUSETX_MASK 0x00000800U /**< Transmit zero quantum
pause frame */
#define XEMACPS_NWCTRL_PAUSETX_MASK 0x00000800U /**< Transmit pause frame */
#define XEMACPS_NWCTRL_HALTTX_MASK 0x00000400U /**< Halt transmission
after current frame */
#define XEMACPS_NWCTRL_STARTTX_MASK 0x00000200U /**< Start tx (tx_go) */
#define XEMACPS_NWCTRL_STATWEN_MASK 0x00000080U /**< Enable writing to
stat counters */
#define XEMACPS_NWCTRL_STATINC_MASK 0x00000040U /**< Increment statistic
registers */
#define XEMACPS_NWCTRL_STATCLR_MASK 0x00000020U /**< Clear statistic
registers */
#define XEMACPS_NWCTRL_MDEN_MASK 0x00000010U /**< Enable MDIO port */
#define XEMACPS_NWCTRL_TXEN_MASK 0x00000008U /**< Enable transmit */
#define XEMACPS_NWCTRL_RXEN_MASK 0x00000004U /**< Enable receive */
#define XEMACPS_NWCTRL_LOOPEN_MASK 0x00000002U /**< local loopback */
/*@}*/
/** @name network configuration register bit definitions
* @{
*/
#define XEMACPS_NWCFG_BADPREAMBEN_MASK 0x20000000U /**< disable rejection of
non-standard preamble */
#define XEMACPS_NWCFG_IPDSTRETCH_MASK 0x10000000U /**< enable transmit IPG */
#define XEMACPS_NWCFG_SGMIIEN_MASK 0x08000000U /**< SGMII Enable */
#define XEMACPS_NWCFG_FCSIGNORE_MASK 0x04000000U /**< disable rejection of
FCS error */
#define XEMACPS_NWCFG_HDRXEN_MASK 0x02000000U /**< RX half duplex */
#define XEMACPS_NWCFG_RXCHKSUMEN_MASK 0x01000000U /**< enable RX checksum
offload */
#define XEMACPS_NWCFG_PAUSECOPYDI_MASK 0x00800000U /**< Do not copy pause
Frames to memory */
#define XEMACPS_NWCFG_DWIDTH_64_MASK 0x00200000U /**< 64 bit Data bus width */
#define XEMACPS_NWCFG_MDC_SHIFT_MASK 18U /**< shift bits for MDC */
#define XEMACPS_NWCFG_MDCCLKDIV_MASK 0x001C0000U /**< MDC Mask PCLK divisor */
#define XEMACPS_NWCFG_FCSREM_MASK 0x00020000U /**< Discard FCS from
received frames */
#define XEMACPS_NWCFG_LENERRDSCRD_MASK 0x00010000U
/**< RX length error discard */
#define XEMACPS_NWCFG_RXOFFS_MASK 0x0000C000U /**< RX buffer offset */
#define XEMACPS_NWCFG_PAUSEEN_MASK 0x00002000U /**< Enable pause RX */
#define XEMACPS_NWCFG_RETRYTESTEN_MASK 0x00001000U /**< Retry test */
#define XEMACPS_NWCFG_XTADDMACHEN_MASK 0x00000200U
/**< External address match enable */
#define XEMACPS_NWCFG_PCSSEL_MASK 0x00000800U /**< PCS Select */
#define XEMACPS_NWCFG_1000_MASK 0x00000400U /**< 1000 Mbps */
#define XEMACPS_NWCFG_1536RXEN_MASK 0x00000100U /**< Enable 1536 byte
frames reception */
#define XEMACPS_NWCFG_UCASTHASHEN_MASK 0x00000080U /**< Receive unicast hash
frames */
#define XEMACPS_NWCFG_MCASTHASHEN_MASK 0x00000040U /**< Receive multicast hash
frames */
#define XEMACPS_NWCFG_BCASTDI_MASK 0x00000020U /**< Do not receive
broadcast frames */
#define XEMACPS_NWCFG_COPYALLEN_MASK 0x00000010U /**< Copy all frames */
#define XEMACPS_NWCFG_JUMBO_MASK 0x00000008U /**< Jumbo frames */
#define XEMACPS_NWCFG_NVLANDISC_MASK 0x00000004U /**< Receive only VLAN
frames */
#define XEMACPS_NWCFG_FDEN_MASK 0x00000002U/**< full duplex */
#define XEMACPS_NWCFG_100_MASK 0x00000001U /**< 100 Mbps */
#define XEMACPS_NWCFG_RESET_MASK 0x00080000U/**< reset value */
/*@}*/
/** @name network status register bit definitaions
* @{
*/
#define XEMACPS_NWSR_MDIOIDLE_MASK 0x00000004U /**< PHY management idle */
#define XEMACPS_NWSR_MDIO_MASK 0x00000002U /**< Status of mdio_in */
/*@}*/
/** @name MAC address register word 1 mask
* @{
*/
#define XEMACPS_LADDR_MACH_MASK 0x0000FFFFU /**< Address bits[47:32]
bit[31:0] are in BOTTOM */
/*@}*/
/** @name DMA control register bit definitions
* @{
*/
#define XEMACPS_DMACR_ADDR_WIDTH_64 0x40000000U /**< 64 bit address bus */
#define XEMACPS_DMACR_TXEXTEND_MASK 0x20000000U /**< Tx Extended desc mode */
#define XEMACPS_DMACR_RXEXTEND_MASK 0x10000000U /**< Rx Extended desc mode */
#define XEMACPS_DMACR_RXBUF_MASK 0x00FF0000U /**< Mask bit for RX buffer
size */
#define XEMACPS_DMACR_RXBUF_SHIFT 16U /**< Shift bit for RX buffer
size */
#define XEMACPS_DMACR_TCPCKSUM_MASK 0x00000800U /**< enable/disable TX
checksum offload */
#define XEMACPS_DMACR_TXSIZE_MASK 0x00000400U /**< TX buffer memory size */
#define XEMACPS_DMACR_RXSIZE_MASK 0x00000300U /**< RX buffer memory size */
#define XEMACPS_DMACR_ENDIAN_MASK 0x00000080U /**< endian configuration */
#define XEMACPS_DMACR_BLENGTH_MASK 0x0000001FU /**< buffer burst length */
#define XEMACPS_DMACR_SINGLE_AHB_BURST 0x00000001U /**< single AHB bursts */
#define XEMACPS_DMACR_INCR4_AHB_BURST 0x00000004U /**< 4 bytes AHB bursts */
#define XEMACPS_DMACR_INCR8_AHB_BURST 0x00000008U /**< 8 bytes AHB bursts */
#define XEMACPS_DMACR_INCR16_AHB_BURST 0x00000010U /**< 16 bytes AHB bursts */
/*@}*/
/** @name transmit status register bit definitions
* @{
*/
#define XEMACPS_TXSR_HRESPNOK_MASK 0x00000100U /**< Transmit hresp not OK */
#define XEMACPS_TXSR_URUN_MASK 0x00000040U /**< Transmit underrun */
#define XEMACPS_TXSR_TXCOMPL_MASK 0x00000020U /**< Transmit completed OK */
#define XEMACPS_TXSR_BUFEXH_MASK 0x00000010U /**< Transmit buffs exhausted
mid frame */
#define XEMACPS_TXSR_TXGO_MASK 0x00000008U /**< Status of go flag */
#define XEMACPS_TXSR_RXOVR_MASK 0x00000004U /**< Retry limit exceeded */
#define XEMACPS_TXSR_FRAMERX_MASK 0x00000002U /**< Collision tx frame */
#define XEMACPS_TXSR_USEDREAD_MASK 0x00000001U /**< TX buffer used bit set */
#define XEMACPS_TXSR_ERROR_MASK ((u32)XEMACPS_TXSR_HRESPNOK_MASK | \
(u32)XEMACPS_TXSR_URUN_MASK | \
(u32)XEMACPS_TXSR_BUFEXH_MASK | \
(u32)XEMACPS_TXSR_RXOVR_MASK | \
(u32)XEMACPS_TXSR_FRAMERX_MASK | \
(u32)XEMACPS_TXSR_USEDREAD_MASK)
/*@}*/
/**
* @name receive status register bit definitions
* @{
*/
#define XEMACPS_RXSR_HRESPNOK_MASK 0x00000008U /**< Receive hresp not OK */
#define XEMACPS_RXSR_RXOVR_MASK 0x00000004U /**< Receive overrun */
#define XEMACPS_RXSR_FRAMERX_MASK 0x00000002U /**< Frame received OK */
#define XEMACPS_RXSR_BUFFNA_MASK 0x00000001U /**< RX buffer used bit set */
#define XEMACPS_RXSR_ERROR_MASK ((u32)XEMACPS_RXSR_HRESPNOK_MASK | \
(u32)XEMACPS_RXSR_RXOVR_MASK | \
(u32)XEMACPS_RXSR_BUFFNA_MASK)
#define XEMACPS_SR_ALL_MASK 0xFFFFFFFFU /**< Mask for full register */
/*@}*/
/**
* @name Interrupt Q1 status register bit definitions
* @{
*/
#define XEMACPS_INTQ1SR_TXCOMPL_MASK 0x00000080U /**< Transmit completed OK */
#define XEMACPS_INTQ1SR_TXERR_MASK 0x00000040U /**< Transmit AMBA Error */
#define XEMACPS_INTQ1_IXR_ALL_MASK ((u32)XEMACPS_INTQ1SR_TXCOMPL_MASK | \
(u32)XEMACPS_INTQ1SR_TXERR_MASK)
/*@}*/
/**
* @name interrupts bit definitions
* Bits definitions are same in XEMACPS_ISR_OFFSET,
* XEMACPS_IER_OFFSET, XEMACPS_IDR_OFFSET, and XEMACPS_IMR_OFFSET
* @{
*/
#define XEMACPS_IXR_PTPPSTX_MASK 0x02000000U /**< PTP Pdelay_resp TXed */
#define XEMACPS_IXR_PTPPDRTX_MASK 0x01000000U /**< PTP Pdelay_req TXed */
#define XEMACPS_IXR_PTPPSRX_MASK 0x00800000U /**< PTP Pdelay_resp RXed */
#define XEMACPS_IXR_PTPPDRRX_MASK 0x00400000U /**< PTP Pdelay_req RXed */
#define XEMACPS_IXR_PTPSTX_MASK 0x00200000U /**< PTP Sync TXed */
#define XEMACPS_IXR_PTPDRTX_MASK 0x00100000U /**< PTP Delay_req TXed */
#define XEMACPS_IXR_PTPSRX_MASK 0x00080000U /**< PTP Sync RXed */
#define XEMACPS_IXR_PTPDRRX_MASK 0x00040000U /**< PTP Delay_req RXed */
#define XEMACPS_IXR_PAUSETX_MASK 0x00004000U /**< Pause frame transmitted */
#define XEMACPS_IXR_PAUSEZERO_MASK 0x00002000U /**< Pause time has reached
zero */
#define XEMACPS_IXR_PAUSENZERO_MASK 0x00001000U /**< Pause frame received */
#define XEMACPS_IXR_HRESPNOK_MASK 0x00000800U /**< hresp not ok */
#define XEMACPS_IXR_RXOVR_MASK 0x00000400U /**< Receive overrun occurred */
#define XEMACPS_IXR_TXCOMPL_MASK 0x00000080U /**< Frame transmitted ok */
#define XEMACPS_IXR_TXEXH_MASK 0x00000040U /**< Transmit err occurred or
no buffers*/
#define XEMACPS_IXR_RETRY_MASK 0x00000020U /**< Retry limit exceeded */
#define XEMACPS_IXR_URUN_MASK 0x00000010U /**< Transmit underrun */
#define XEMACPS_IXR_TXUSED_MASK 0x00000008U /**< Tx buffer used bit read */
#define XEMACPS_IXR_RXUSED_MASK 0x00000004U /**< Rx buffer used bit read */
#define XEMACPS_IXR_FRAMERX_MASK 0x00000002U /**< Frame received ok */
#define XEMACPS_IXR_MGMNT_MASK 0x00000001U /**< PHY management complete */
#define XEMACPS_IXR_ALL_MASK 0x00007FFFU /**< Everything! */
#define XEMACPS_IXR_TX_ERR_MASK ((u32)XEMACPS_IXR_TXEXH_MASK | \
(u32)XEMACPS_IXR_RETRY_MASK | \
(u32)XEMACPS_IXR_URUN_MASK)
#define XEMACPS_IXR_RX_ERR_MASK ((u32)XEMACPS_IXR_HRESPNOK_MASK | \
(u32)XEMACPS_IXR_RXUSED_MASK | \
(u32)XEMACPS_IXR_RXOVR_MASK)
/*@}*/
/** @name PHY Maintenance bit definitions
* @{
*/
#define XEMACPS_PHYMNTNC_OP_MASK 0x40020000U /**< operation mask bits */
#define XEMACPS_PHYMNTNC_OP_R_MASK 0x20000000U /**< read operation */
#define XEMACPS_PHYMNTNC_OP_W_MASK 0x10000000U /**< write operation */
#define XEMACPS_PHYMNTNC_ADDR_MASK 0x0F800000U /**< Address bits */
#define XEMACPS_PHYMNTNC_REG_MASK 0x007C0000U /**< register bits */
#define XEMACPS_PHYMNTNC_DATA_MASK 0x00000FFFU /**< data bits */
#define XEMACPS_PHYMNTNC_PHAD_SHFT_MSK 23U /**< Shift bits for PHYAD */
#define XEMACPS_PHYMNTNC_PREG_SHFT_MSK 18U /**< Shift bits for PHREG */
/*@}*/
/** @name RX watermark bit definitions
* @{
*/
#define XEMACPS_RXWM_HIGH_MASK 0x0000FFFFU /**< RXWM high mask */
#define XEMACPS_RXWM_LOW_MASK 0xFFFF0000U /**< RXWM low mask */
#define XEMACPS_RXWM_LOW_SHFT_MSK 16U /**< Shift for RXWM low */
/*@}*/
/* Transmit buffer descriptor status words offset
* @{
*/
#define XEMACPS_BD_ADDR_OFFSET 0x00000000U /**< word 0/addr of BDs */
#define XEMACPS_BD_STAT_OFFSET 0x00000004U /**< word 1/status of BDs */
#define XEMACPS_BD_ADDR_HI_OFFSET 0x00000008U /**< word 2/addr of BDs */
/*
* @}
*/
/* Transmit buffer descriptor status words bit positions.
* Transmit buffer descriptor consists of two 32-bit registers,
* the first - word0 contains a 32-bit address pointing to the location of
* the transmit data.
* The following register - word1, consists of various information to control
* the XEmacPs transmit process. After transmit, this is updated with status
* information, whether the frame was transmitted OK or why it had failed.
* @{
*/
#define XEMACPS_TXBUF_USED_MASK 0x80000000U /**< Used bit. */
#define XEMACPS_TXBUF_WRAP_MASK 0x40000000U /**< Wrap bit, last descriptor */
#define XEMACPS_TXBUF_RETRY_MASK 0x20000000U /**< Retry limit exceeded */
#define XEMACPS_TXBUF_URUN_MASK 0x10000000U /**< Transmit underrun occurred */
#define XEMACPS_TXBUF_EXH_MASK 0x08000000U /**< Buffers exhausted */
#define XEMACPS_TXBUF_TCP_MASK 0x04000000U /**< Late collision. */
#define XEMACPS_TXBUF_NOCRC_MASK 0x00010000U /**< No CRC */
#define XEMACPS_TXBUF_LAST_MASK 0x00008000U /**< Last buffer */
#define XEMACPS_TXBUF_LEN_MASK 0x00003FFFU /**< Mask for length field */
/*
* @}
*/
/* Receive buffer descriptor status words bit positions.
* Receive buffer descriptor consists of two 32-bit registers,
* the first - word0 contains a 32-bit word aligned address pointing to the
* address of the buffer. The lower two bits make up the wrap bit indicating
* the last descriptor and the ownership bit to indicate it has been used by
* the XEmacPs.
* The following register - word1, contains status information regarding why
* the frame was received (the filter match condition) as well as other
* useful info.
* @{
*/
#define XEMACPS_RXBUF_BCAST_MASK 0x80000000U /**< Broadcast frame */
#define XEMACPS_RXBUF_MULTIHASH_MASK 0x40000000U /**< Multicast hashed frame */
#define XEMACPS_RXBUF_UNIHASH_MASK 0x20000000U /**< Unicast hashed frame */
#define XEMACPS_RXBUF_EXH_MASK 0x08000000U /**< buffer exhausted */
#define XEMACPS_RXBUF_AMATCH_MASK 0x06000000U /**< Specific address
matched */
#define XEMACPS_RXBUF_IDFOUND_MASK 0x01000000U /**< Type ID matched */
#define XEMACPS_RXBUF_IDMATCH_MASK 0x00C00000U /**< ID matched mask */
#define XEMACPS_RXBUF_VLAN_MASK 0x00200000U /**< VLAN tagged */
#define XEMACPS_RXBUF_PRI_MASK 0x00100000U /**< Priority tagged */
#define XEMACPS_RXBUF_VPRI_MASK 0x000E0000U /**< Vlan priority */
#define XEMACPS_RXBUF_CFI_MASK 0x00010000U /**< CFI frame */
#define XEMACPS_RXBUF_EOF_MASK 0x00008000U /**< End of frame. */
#define XEMACPS_RXBUF_SOF_MASK 0x00004000U /**< Start of frame. */
#define XEMACPS_RXBUF_LEN_MASK 0x00001FFFU /**< Mask for length field */
#define XEMACPS_RXBUF_LEN_JUMBO_MASK 0x00003FFFU /**< Mask for jumbo length */
#define XEMACPS_RXBUF_WRAP_MASK 0x00000002U /**< Wrap bit, last BD */
#define XEMACPS_RXBUF_NEW_MASK 0x00000001U /**< Used bit.. */
#define XEMACPS_RXBUF_ADD_MASK 0xFFFFFFFCU /**< Mask for address */
/*
* @}
*/
/*
* Define appropriate I/O access method to memory mapped I/O or other
* interface if necessary.
*/
#define XEmacPs_In32 Xil_In32
#define XEmacPs_Out32 Xil_Out32
/****************************************************************************/
/**
*
* Read the given register.
*
* @param BaseAddress is the base address of the device
* @param RegOffset is the register offset to be read
*
* @return The 32-bit value of the register
*
* @note
* C-style signature:
* u32 XEmacPs_ReadReg(u32 BaseAddress, u32 RegOffset)
*
*****************************************************************************/
#define XEmacPs_ReadReg(BaseAddress, RegOffset) \
XEmacPs_In32((BaseAddress) + (u32)(RegOffset))
/****************************************************************************/
/**
*
* Write the given register.
*
* @param BaseAddress is the base address of the device
* @param RegOffset is the register offset to be written
* @param Data is the 32-bit value to write to the register
*
* @return None.
*
* @note
* C-style signature:
* void XEmacPs_WriteReg(u32 BaseAddress, u32 RegOffset,
* u32 Data)
*
*****************************************************************************/
#define XEmacPs_WriteReg(BaseAddress, RegOffset, Data) \
XEmacPs_Out32((BaseAddress) + (u32)(RegOffset), (u32)(Data))
/************************** Function Prototypes *****************************/
/*
* Perform reset operation to the emacps interface
*/
void XEmacPs_ResetHw(u32 BaseAddr);
#ifdef __cplusplus
}
#endif
#endif /* end of protection macro */
/** @} */

View File

@ -0,0 +1,242 @@
/******************************************************************************
* Copyright (C) 2010 - 2020 Xilinx, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xemacps_intr.c
* @addtogroup emacps_v3_11
* @{
*
* Functions in this file implement general purpose interrupt processing related
* functionality. See xemacps.h for a detailed description of the driver.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a wsy 01/10/10 First release
* 1.03a asa 01/24/13 Fix for CR #692702 which updates error handling for
* Rx errors. Under heavy Rx traffic, there will be a large
* number of errors related to receive buffer not available.
* Because of a HW bug (SI #692601), under such heavy errors,
* the Rx data path can become unresponsive. To reduce the
* probabilities for hitting this HW bug, the SW writes to
* bit 18 to flush a packet from Rx DPRAM immediately. The
* changes for it are done in the function
* XEmacPs_IntrHandler.
* 2.1 srt 07/15/14 Add support for Zynq Ultrascale Mp GEM specification
* and 64-bit changes.
* 3.0 kvn 02/13/15 Modified code for MISRA-C:2012 compliance.
* 3.1 hk 07/27/15 Do not call error handler with '0' error code when
* there is no error. CR# 869403
* </pre>
******************************************************************************/
/***************************** Include Files *********************************/
#include "xemacps.h"
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
/************************** Variable Definitions *****************************/
/*****************************************************************************/
/**
* Install an asynchronous handler function for the given HandlerType:
*
* @param InstancePtr is a pointer to the instance to be worked on.
* @param HandlerType indicates what interrupt handler type is.
* XEMACPS_HANDLER_DMASEND, XEMACPS_HANDLER_DMARECV and
* XEMACPS_HANDLER_ERROR.
* @param FuncPointer is the pointer to the callback function
* @param CallBackRef is the upper layer callback reference passed back when
* when the callback function is invoked.
*
* @return
*
* None.
*
* @note
* There is no assert on the CallBackRef since the driver doesn't know what
* it is.
*
*****************************************************************************/
LONG XEmacPs_SetHandler(XEmacPs *InstancePtr, u32 HandlerType,
void *FuncPointer, void *CallBackRef)
{
LONG Status;
Xil_AssertNonvoid(InstancePtr != NULL);
Xil_AssertNonvoid(FuncPointer != NULL);
Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
switch (HandlerType) {
case XEMACPS_HANDLER_DMASEND:
Status = (LONG)(XST_SUCCESS);
InstancePtr->SendHandler = ((XEmacPs_Handler)(void *)FuncPointer);
InstancePtr->SendRef = CallBackRef;
break;
case XEMACPS_HANDLER_DMARECV:
Status = (LONG)(XST_SUCCESS);
InstancePtr->RecvHandler = ((XEmacPs_Handler)(void *)FuncPointer);
InstancePtr->RecvRef = CallBackRef;
break;
case XEMACPS_HANDLER_ERROR:
Status = (LONG)(XST_SUCCESS);
InstancePtr->ErrorHandler = ((XEmacPs_ErrHandler)(void *)FuncPointer);
InstancePtr->ErrorRef = CallBackRef;
break;
default:
Status = (LONG)(XST_INVALID_PARAM);
break;
}
return Status;
}
/*****************************************************************************/
/**
* Master interrupt handler for EMAC driver. This routine will query the
* status of the device, bump statistics, and invoke user callbacks.
*
* This routine must be connected to an interrupt controller using OS/BSP
* specific methods.
*
* @param XEmacPsPtr is a pointer to the XEMACPS instance that has caused the
* interrupt.
*
******************************************************************************/
void XEmacPs_IntrHandler(void *XEmacPsPtr)
{
u32 RegISR;
u32 RegSR;
u32 RegCtrl;
u32 RegQ1ISR = 0U;
XEmacPs *InstancePtr = (XEmacPs *) XEmacPsPtr;
Xil_AssertVoid(InstancePtr != NULL);
Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
/* This ISR will try to handle as many interrupts as it can in a single
* call. However, in most of the places where the user's error handler
* is called, this ISR exits because it is expected that the user will
* reset the device in nearly all instances.
*/
RegISR = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
XEMACPS_ISR_OFFSET);
/* Read Transmit Q1 ISR */
if (InstancePtr->Version > 2)
RegQ1ISR = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
XEMACPS_INTQ1_STS_OFFSET);
/* Clear the interrupt status register */
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_ISR_OFFSET,
RegISR);
/* Receive complete interrupt */
if ((RegISR & XEMACPS_IXR_FRAMERX_MASK) != 0x00000000U) {
/* Clear RX status register RX complete indication but preserve
* error bits if there is any */
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_RXSR_OFFSET,
((u32)XEMACPS_RXSR_FRAMERX_MASK |
(u32)XEMACPS_RXSR_BUFFNA_MASK));
InstancePtr->RecvHandler(InstancePtr->RecvRef);
}
/* Transmit Q1 complete interrupt */
if ((InstancePtr->Version > 2) &&
((RegQ1ISR & XEMACPS_INTQ1SR_TXCOMPL_MASK) != 0x00000000U)) {
/* Clear TX status register TX complete indication but preserve
* error bits if there is any */
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_INTQ1_STS_OFFSET,
XEMACPS_INTQ1SR_TXCOMPL_MASK);
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_TXSR_OFFSET,
((u32)XEMACPS_TXSR_TXCOMPL_MASK |
(u32)XEMACPS_TXSR_USEDREAD_MASK));
InstancePtr->SendHandler(InstancePtr->SendRef);
}
/* Transmit complete interrupt */
if ((RegISR & XEMACPS_IXR_TXCOMPL_MASK) != 0x00000000U) {
/* Clear TX status register TX complete indication but preserve
* error bits if there is any */
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_TXSR_OFFSET,
((u32)XEMACPS_TXSR_TXCOMPL_MASK |
(u32)XEMACPS_TXSR_USEDREAD_MASK));
InstancePtr->SendHandler(InstancePtr->SendRef);
}
/* Receive error conditions interrupt */
if ((RegISR & XEMACPS_IXR_RX_ERR_MASK) != 0x00000000U) {
/* Clear RX status register */
RegSR = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
XEMACPS_RXSR_OFFSET);
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_RXSR_OFFSET, RegSR);
/* Fix for CR # 692702. Write to bit 18 of net_ctrl
* register to flush a packet out of Rx SRAM upon
* an error for receive buffer not available. */
if ((RegISR & XEMACPS_IXR_RXUSED_MASK) != 0x00000000U) {
RegCtrl =
XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET);
RegCtrl |= (u32)XEMACPS_NWCTRL_FLUSH_DPRAM_MASK;
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET, RegCtrl);
}
if(RegSR != 0) {
InstancePtr->ErrorHandler(InstancePtr->ErrorRef,
XEMACPS_RECV, RegSR);
}
}
/* When XEMACPS_IXR_TXCOMPL_MASK is flagged, XEMACPS_IXR_TXUSED_MASK
* will be asserted the same time.
* Have to distinguish this bit to handle the real error condition.
*/
/* Transmit Q1 error conditions interrupt */
if ((InstancePtr->Version > 2) &&
((RegQ1ISR & XEMACPS_INTQ1SR_TXERR_MASK) != 0x00000000U) &&
((RegQ1ISR & XEMACPS_INTQ1SR_TXCOMPL_MASK) != 0x00000000U)) {
/* Clear Interrupt Q1 status register */
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_INTQ1_STS_OFFSET, RegQ1ISR);
InstancePtr->ErrorHandler(InstancePtr->ErrorRef, XEMACPS_SEND,
RegQ1ISR);
}
/* Transmit error conditions interrupt */
if (((RegISR & XEMACPS_IXR_TX_ERR_MASK) != 0x00000000U) &&
(!(RegISR & XEMACPS_IXR_TXCOMPL_MASK) != 0x00000000U)) {
/* Clear TX status register */
RegSR = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
XEMACPS_TXSR_OFFSET);
XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
XEMACPS_TXSR_OFFSET, RegSR);
InstancePtr->ErrorHandler(InstancePtr->ErrorRef, XEMACPS_SEND,
RegSR);
}
}
/** @} */

View File

@ -0,0 +1,71 @@
/******************************************************************************
* Copyright (C) 2010 - 2020 Xilinx, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/
/*****************************************************************************/
/**
*
* @file xemacps_sinit.c
* @addtogroup emacps_v3_11
* @{
*
* This file contains lookup method by device ID when success, it returns
* pointer to config table to be used to initialize the device.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- -------------------------------------------------------
* 1.00a wsy 01/10/10 New
* 3.00 kvn 02/13/15 Modified code for MISRA-C:2012 compliance.
* </pre>
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "xemacps.h"
#include "xparameters.h"
/************************** Constant Definitions *****************************/
/**************************** Type Definitions *******************************/
/*************************** Variable Definitions *****************************/
extern XEmacPs_Config XEmacPs_ConfigTable[XPAR_XEMACPS_NUM_INSTANCES];
/***************** Macros (Inline Functions) Definitions *********************/
/************************** Function Prototypes ******************************/
/*****************************************************************************/
/**
* Lookup the device configuration based on the unique device ID. The table
* contains the configuration info for each device in the system.
*
* @param DeviceId is the unique device ID of the device being looked up.
*
* @return
* A pointer to the configuration table entry corresponding to the given
* device ID, or NULL if no match is found.
*
******************************************************************************/
XEmacPs_Config *XEmacPs_LookupConfig(u16 DeviceId)
{
XEmacPs_Config *CfgPtr = NULL;
u32 i;
for (i = 0U; i < (u32)XPAR_XEMACPS_NUM_INSTANCES; i++) {
if (XEmacPs_ConfigTable[i].DeviceId == DeviceId) {
CfgPtr = &XEmacPs_ConfigTable[i];
break;
}
}
return (XEmacPs_Config *)(CfgPtr);
}
/** @} */

View File

@ -21,7 +21,7 @@ static inline void usleep(unsigned long useconds)
static inline void sleep(unsigned int seconds)
{
rt_thread_delay(seconds);
rt_thread_delay(seconds*RT_TICK_PER_SECOND);
}
#ifdef __cplusplus

View File

@ -0,0 +1,15 @@
import rtconfig
from building import *
# get current directory
cwd = GetCurrentDir()
CPPPATH = [cwd]
# The set of source files associated with this SConscript file.
src = Glob('*.c')
path = cwd
group = DefineGroup('ZYNQMP_HAL', src, depend = [''], CPPPATH = CPPPATH)
Return('group')

View File

@ -0,0 +1,94 @@
/*
* Copyright (C) 2007 - 2019 Xilinx, Inc.
* Copyright (C) 2021 WangHuachen.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#ifndef __XADAPTER_H_
#define __XADAPTER_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "lwipopts.h"
#if !NO_SYS
#ifdef OS_IS_XILKERNEL
#include "xmk.h"
#endif
#include "lwip/sys.h"
#endif
#include "lwip/netif.h"
#include "lwip/ip.h"
#include "netif/xtopology.h"
#include <netif/ethernetif.h>
struct xemac_s {
enum xemac_types type;
int topology_index;
void *state;
#if 0
sys_sem_t sem_rx_data_available;
#else
struct eth_device *rt_eth_device;
#endif
#if defined(OS_IS_FREERTOS) && defined(__arm__) && !defined(ARMR5)
TimerHandle_t xTimer;
#endif
};
enum ethernet_link_status {
ETH_LINK_UNDEFINED = 0,
ETH_LINK_UP,
ETH_LINK_DOWN,
ETH_LINK_NEGOTIATING
};
void eth_link_detect(struct netif *netif);
void lwip_raw_init();
int xemacif_input(struct netif *netif);
void xemacif_input_thread(struct netif *netif);
struct netif * xemac_add(struct netif *netif,
ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw,
unsigned char *mac_ethernet_address,
unsigned mac_baseaddr);
#if defined (__arm__) || defined (__aarch64__)
void xemacpsif_resetrx_on_no_rxdata(struct netif *netif);
#endif
/* global lwip debug variable used for debugging */
extern int lwip_runtime_debug;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,163 @@
/*
* Copyright (C) 2010 - 2019 Xilinx, Inc.
* Copyright (C) 2021 WangHuachen.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#ifndef __NETIF_XEMACPSIF_H__
#define __NETIF_XEMACPSIF_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "xlwipconfig.h"
#include "lwip/netif.h"
#include "netif/etharp.h"
#include "lwip/sys.h"
#include "netif/xadapter.h"
#include "xstatus.h"
#include "sleep.h"
#include "xparameters.h"
#include "xparameters_ps.h" /* defines XPAR values */
#include "xil_types.h"
#include "xil_assert.h"
#include "xil_io.h"
// #include "xil_exception.h"
// #include "xpseudo_asm.h"
#include "xpseudo_asm_gcc.h"
#include "xil_cache.h"
#include "xil_printf.h"
// #include "xscugic.h"
#include "xemacps.h" /* defines XEmacPs API */
#include "netif/xpqueue.h"
#include "xlwipconfig.h"
#if EL1_NONSECURE
#include "xil_smc.h"
#endif
#define ZYNQ_EMACPS_0_BASEADDR 0xE000B000
#define ZYNQ_EMACPS_1_BASEADDR 0xE000C000
#define ZYNQMP_EMACPS_0_BASEADDR 0xFF0B0000
#define ZYNQMP_EMACPS_1_BASEADDR 0xFF0C0000
#define ZYNQMP_EMACPS_2_BASEADDR 0xFF0D0000
#define ZYNQMP_EMACPS_3_BASEADDR 0xFF0E0000
#define CRL_APB_GEM0_REF_CTRL 0xFF5E0050
#define CRL_APB_GEM1_REF_CTRL 0xFF5E0054
#define CRL_APB_GEM2_REF_CTRL 0xFF5E0058
#define CRL_APB_GEM3_REF_CTRL 0xFF5E005C
#define CRL_APB_GEM_DIV0_MASK 0x00003F00
#define CRL_APB_GEM_DIV0_SHIFT 8
#define CRL_APB_GEM_DIV1_MASK 0x003F0000
#define CRL_APB_GEM_DIV1_SHIFT 16
#define VERSAL_EMACPS_0_BASEADDR 0xFF0C0000
#define VERSAL_EMACPS_1_BASEADDR 0xFF0D0000
#define VERSAL_CRL_GEM0_REF_CTRL 0xFF5E0118
#define VERSAL_CRL_GEM1_REF_CTRL 0xFF5E011C
#define VERSAL_CRL_GEM_DIV_MASK 0x0003FF00
#define VERSAL_CRL_APB_GEM_DIV_SHIFT 8
#if defined (ARMR5) || (__aarch64__) || (ARMA53_32) || (__MICROBLAZE__)
#if defined (USE_JUMBO_FRAMES)
#define ZYNQMP_USE_JUMBO
#endif
#endif
#define GEM_VERSION_ZYNQMP 7
#define GEM_VERSION_VERSAL 0x107
#define MAX_FRAME_SIZE_JUMBO (XEMACPS_MTU_JUMBO + XEMACPS_HDR_SIZE + XEMACPS_TRL_SIZE)
void xemacpsif_setmac(u32_t index, u8_t *addr);
u8_t* xemacpsif_getmac(u32_t index);
err_t xemacpsif_init(struct netif *netif);
s32_t xemacpsif_input(struct netif *netif);
/* xaxiemacif_hw.c */
void xemacps_error_handler(XEmacPs * Temac);
/* structure within each netif, encapsulating all information required for
* using a particular temac instance
*/
typedef struct {
XEmacPs emacps;
/* queue to store overflow packets */
pq_queue_t *recv_q;
pq_queue_t *send_q;
/* pointers to memory holding buffer descriptors (used only with SDMA) */
void *rx_bdspace;
void *tx_bdspace;
unsigned int last_rx_frms_cntr;
} xemacpsif_s;
extern xemacpsif_s xemacpsif;
s32_t is_tx_space_available(xemacpsif_s *emac);
/* xemacpsif_dma.c */
void process_sent_bds(xemacpsif_s *xemacpsif, XEmacPs_BdRing *txring);
u32_t phy_setup_emacps (XEmacPs *xemacpsp, u32_t phy_addr);
void detect_phy(XEmacPs *xemacpsp);
void emacps_send_handler(void *arg);
XStatus emacps_sgsend(xemacpsif_s *xemacpsif, struct pbuf *p);
void emacps_recv_handler(void *arg);
void emacps_error_handler(void *arg,u8 Direction, u32 ErrorWord);
void setup_rx_bds(xemacpsif_s *xemacpsif, XEmacPs_BdRing *rxring);
void HandleTxErrors(struct xemac_s *xemac);
void HandleEmacPsError(struct xemac_s *xemac);
XEmacPs_Config *xemacps_lookup_config(unsigned mac_base);
void init_emacps(xemacpsif_s *xemacps, struct netif *netif);
void setup_isr (struct xemac_s *xemac);
XStatus init_dma(struct xemac_s *xemac);
void start_emacps (xemacpsif_s *xemacps);
void free_txrx_pbufs(xemacpsif_s *xemacpsif);
void free_onlytx_pbufs(xemacpsif_s *xemacpsif);
void init_emacps_on_error (xemacpsif_s *xemacps, struct netif *netif);
void clean_dma_txdescs(struct xemac_s *xemac);
void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif);
void reset_dma(struct xemac_s *xemac);
#ifdef __cplusplus
}
#endif
#endif /* __NETIF_XAXIEMACIF_H__ */

View File

@ -0,0 +1,54 @@
/*
* Copyright (C) 2007 - 2019 Xilinx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#ifndef __LWIP_PBUF_QUEUE_H_
#define __LWIP_PBUF_QUEUE_H_
#ifdef __cplusplus
extern "C" {
#endif
#define PQ_QUEUE_SIZE 4096
typedef struct {
void *data[PQ_QUEUE_SIZE];
int head, tail, len;
} pq_queue_t;
pq_queue_t* pq_create_queue();
int pq_enqueue(pq_queue_t *q, void *p);
void* pq_dequeue(pq_queue_t *q);
int pq_qlength(pq_queue_t *q);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2007 - 2019 Xilinx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#ifndef __XTOPOLOGY_H_
#define __XTOPOLOGY_H_
#ifdef __cplusplus
extern "C" {
#endif
enum xemac_types { xemac_type_unknown = -1, xemac_type_xps_emaclite, xemac_type_xps_ll_temac, xemac_type_axi_ethernet, xemac_type_emacps };
struct xtopology_t {
unsigned emac_baseaddr;
enum xemac_types emac_type;
unsigned intc_baseaddr;
unsigned intc_emac_intr; /* valid only for xemac_type_xps_emaclite */
unsigned scugic_baseaddr; /* valid only for Zynq */
unsigned scugic_emac_intr; /* valid only for GEM */
};
extern int xtopology_n_emacs;
extern struct xtopology_t xtopology[];
int xtopology_find_index(unsigned base);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,432 @@
/*
* Copyright (C) 2007 - 2019 Xilinx, Inc.
* Copyright (C) 2021 WangHuachen.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#include "lwipopts.h"
#include "xlwipconfig.h"
#include "xemac_ieee_reg.h"
#if !NO_SYS
#ifdef OS_IS_XILKERNEL
#include "xmk.h"
#include "sys/process.h"
#endif
#endif
#include "lwip/mem.h"
#include "lwip/stats.h"
#include "lwip/sys.h"
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include "lwip/udp.h"
#include "lwip/priv/tcp_priv.h"
#include "netif/etharp.h"
#include "netif/xadapter.h"
#ifdef XLWIP_CONFIG_INCLUDE_EMACLITE
#include "netif/xemacliteif.h"
#endif
#ifdef XLWIP_CONFIG_INCLUDE_AXI_ETHERNET
#include "netif/xaxiemacif.h"
#endif
#ifdef XLWIP_CONFIG_INCLUDE_GEM
#include "netif/xemacpsif.h"
#endif
#if !NO_SYS
#include "lwip/tcpip.h"
#endif
#ifdef OS_IS_FREERTOS
#define THREAD_STACKSIZE 256
#define LINK_DETECT_THREAD_INTERVAL 1000 /* one second */
void link_detect_thread(void *p);
#endif
/* global lwip debug variable used for debugging */
int lwip_runtime_debug = 0;
enum ethernet_link_status eth_link_status = ETH_LINK_UNDEFINED;
u32_t phyaddrforemac;
void
lwip_raw_init()
{
ip_init(); /* Doesn't do much, it should be called to handle future changes. */
#if LWIP_UDP
udp_init(); /* Clears the UDP PCB list. */
#endif
#if LWIP_TCP
tcp_init(); /* Clears the TCP PCB list and clears some internal TCP timers. */
/* Note: you must call tcp_fasttmr() and tcp_slowtmr() at the */
/* predefined regular intervals after this initialization. */
#endif
}
static enum xemac_types
find_mac_type(unsigned base)
{
int i;
for (i = 0; i < xtopology_n_emacs; i++) {
if (xtopology[i].emac_baseaddr == base)
return xtopology[i].emac_type;
}
return xemac_type_unknown;
}
int
xtopology_find_index(unsigned base)
{
int i;
for (i = 0; i < xtopology_n_emacs; i++) {
if (xtopology[i].emac_baseaddr == base)
return i;
}
return -1;
}
/*
* xemac_add: this is a wrapper around lwIP's netif_add function.
* The objective is to provide portability between the different Xilinx MAC's
* This function can be used to add both xps_ethernetlite and xps_ll_temac
* based interfaces
*/
struct netif *
xemac_add(struct netif *netif,
ip_addr_t *ipaddr, ip_addr_t *netmask, ip_addr_t *gw,
unsigned char *mac_ethernet_address,
unsigned mac_baseaddr)
{
int i;
#ifdef OS_IS_FREERTOS
/* Start thread to detect link periodically for Hot Plug autodetect */
sys_thread_new("link_detect_thread", link_detect_thread, netif,
THREAD_STACKSIZE, tskIDLE_PRIORITY);
#endif
/* set mac address */
netif->hwaddr_len = 6;
for (i = 0; i < 6; i++)
netif->hwaddr[i] = mac_ethernet_address[i];
/* initialize based on MAC type */
switch (find_mac_type(mac_baseaddr)) {
case xemac_type_xps_emaclite:
#ifdef XLWIP_CONFIG_INCLUDE_EMACLITE
return netif_add(netif, ipaddr, netmask, gw,
(void*)(UINTPTR)mac_baseaddr,
xemacliteif_init,
#if NO_SYS
ethernet_input
#else
tcpip_input
#endif
);
#else
return NULL;
#endif
case xemac_type_axi_ethernet:
#ifdef XLWIP_CONFIG_INCLUDE_AXI_ETHERNET
return netif_add(netif, ipaddr, netmask, gw,
(void*)(UINTPTR)mac_baseaddr,
xaxiemacif_init,
#if NO_SYS
ethernet_input
#else
tcpip_input
#endif
);
#else
return NULL;
#endif
#if defined (__arm__) || defined (__aarch64__)
case xemac_type_emacps:
#ifdef XLWIP_CONFIG_INCLUDE_GEM
return netif_add(netif, ipaddr, netmask, gw,
(void*)(UINTPTR)mac_baseaddr,
xemacpsif_init,
#if NO_SYS
ethernet_input
#else
tcpip_input
#endif
);
#endif
#endif
default:
xil_printf("unable to determine type of EMAC with baseaddress 0x%08x\r\n",
mac_baseaddr);
return NULL;
}
}
#if 0
/*
* The input thread calls lwIP to process any received packets.
* This thread waits until a packet is received (sem_rx_data_available),
* and then calls xemacif_input which processes 1 packet at a time.
*/
void
xemacif_input_thread(struct netif *netif)
{
struct xemac_s *emac = (struct xemac_s *)netif->state;
while (1) {
/* sleep until there are packets to process
* This semaphore is set by the packet receive interrupt
* routine.
*/
sys_sem_wait(&emac->sem_rx_data_available);
/* move all received packets to lwIP */
xemacif_input(netif);
}
}
#endif
int
xemacif_input(struct netif *netif)
{
struct xemac_s *emac = (struct xemac_s *)netif->state;
int n_packets = 0;
switch (emac->type) {
case xemac_type_xps_emaclite:
#ifdef XLWIP_CONFIG_INCLUDE_EMACLITE
n_packets = xemacliteif_input(netif);
break;
#else
// print("incorrect configuration: xps_ethernetlite drivers not present?");
while(1);
return 0;
#endif
case xemac_type_axi_ethernet:
#ifdef XLWIP_CONFIG_INCLUDE_AXI_ETHERNET
n_packets = xaxiemacif_input(netif);
break;
#else
// print("incorrect configuration: axi_ethernet drivers not present?");
while(1);
return 0;
#endif
#if defined (__arm__) || defined (__aarch64__)
case xemac_type_emacps:
#ifdef XLWIP_CONFIG_INCLUDE_GEM
n_packets = xemacpsif_input(netif);
break;
#else
xil_printf("incorrect configuration: ps7_ethernet drivers not present?\r\n");
while(1);
return 0;
#endif
#endif
default:
// print("incorrect configuration: unknown temac type");
while(1);
return 0;
}
return n_packets;
}
#if defined(XLWIP_CONFIG_INCLUDE_GEM)
u32_t phy_link_detect(XEmacPs *xemacp, u32_t phy_addr)
{
u16_t status;
/* Read Phy Status register twice to get the confirmation of the current
* link status.
*/
XEmacPs_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
XEmacPs_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
if (status & IEEE_STAT_LINK_STATUS)
return 1;
return 0;
}
#elif defined(XLWIP_CONFIG_INCLUDE_AXI_ETHERNET)
static u32_t phy_link_detect(XAxiEthernet *xemacp, u32_t phy_addr)
{
u16_t status;
/* Read Phy Status register twice to get the confirmation of the current
* link status.
*/
XAxiEthernet_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
XAxiEthernet_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
if (status & IEEE_STAT_LINK_STATUS)
return 1;
return 0;
}
#elif defined(XLWIP_CONFIG_INCLUDE_EMACLITE)
static u32_t phy_link_detect(XEmacLite *xemacp, u32_t phy_addr)
{
u16_t status;
/* Read Phy Status register twice to get the confirmation of the current
* link status.
*/
XEmacLite_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
XEmacLite_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
if (status & IEEE_STAT_LINK_STATUS)
return 1;
return 0;
}
#endif
#if defined(XLWIP_CONFIG_INCLUDE_GEM)
u32_t phy_autoneg_status(XEmacPs *xemacp, u32_t phy_addr)
{
u16_t status;
/* Read Phy Status register twice to get the confirmation of the current
* link status.
*/
XEmacPs_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
XEmacPs_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
if (status & IEEE_STAT_AUTONEGOTIATE_COMPLETE)
return 1;
return 0;
}
#elif defined(XLWIP_CONFIG_INCLUDE_AXI_ETHERNET)
static u32_t phy_autoneg_status(XAxiEthernet *xemacp, u32_t phy_addr)
{
u16_t status;
/* Read Phy Status register twice to get the confirmation of the current
* link status.
*/
XAxiEthernet_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
XAxiEthernet_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
if (status & IEEE_STAT_AUTONEGOTIATE_COMPLETE)
return 1;
return 0;
}
#elif defined(XLWIP_CONFIG_INCLUDE_EMACLITE)
static u32_t phy_autoneg_status(XEmacLite *xemacp, u32_t phy_addr)
{
u16_t status;
/* Read Phy Status register twice to get the confirmation of the current
* link status.
*/
XEmacLite_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
XEmacLite_PhyRead(xemacp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
if (status & IEEE_STAT_AUTONEGOTIATE_COMPLETE)
return 1;
return 0;
}
#endif
void eth_link_detect(struct netif *netif)
{
u32_t link_speed, phy_link_status;
struct xemac_s *xemac = (struct xemac_s *)(netif->state);
#if defined(XLWIP_CONFIG_INCLUDE_GEM)
xemacpsif_s *xemacs = (xemacpsif_s *)(xemac->state);
XEmacPs *xemacp = &xemacs->emacps;
#elif defined(XLWIP_CONFIG_INCLUDE_AXI_ETHERNET)
xaxiemacif_s *xemacs = (xaxiemacif_s *)(xemac->state);
XAxiEthernet *xemacp = &xemacs->axi_ethernet;
#elif defined(XLWIP_CONFIG_INCLUDE_EMACLITE)
xemacliteif_s *xemacs = (xemacliteif_s *)(xemac->state);
XEmacLite *xemacp = xemacs->instance;
#endif
if ((xemacp->IsReady != (u32)XIL_COMPONENT_IS_READY) ||
(eth_link_status == ETH_LINK_UNDEFINED))
return;
phy_link_status = phy_link_detect(xemacp, phyaddrforemac);
if ((eth_link_status == ETH_LINK_UP) && (!phy_link_status))
eth_link_status = ETH_LINK_DOWN;
switch (eth_link_status) {
case ETH_LINK_UNDEFINED:
case ETH_LINK_UP:
return;
case ETH_LINK_DOWN:
netif_set_link_down(netif);
eth_link_status = ETH_LINK_NEGOTIATING;
xil_printf("Ethernet Link down\r\n");
break;
case ETH_LINK_NEGOTIATING:
if (phy_link_status &&
phy_autoneg_status(xemacp, phyaddrforemac)) {
/* Initiate Phy setup to get link speed */
#if defined(XLWIP_CONFIG_INCLUDE_GEM)
link_speed = phy_setup_emacps(xemacp,
phyaddrforemac);
XEmacPs_SetOperatingSpeed(xemacp, link_speed);
#elif defined(XLWIP_CONFIG_INCLUDE_AXI_ETHERNET)
link_speed = phy_setup_axiemac(xemacp);
XAxiEthernet_SetOperatingSpeed(xemacp,
link_speed);
#endif
netif_set_link_up(netif);
eth_link_status = ETH_LINK_UP;
xil_printf("Ethernet Link up\r\n");
}
break;
}
}
#ifdef OS_IS_FREERTOS
void link_detect_thread(void *p)
{
struct netif *netif = (struct netif *) p;
while (1) {
/* Call eth_link_detect() every second to detect Ethernet link
* change.
*/
eth_link_detect(netif);
vTaskDelay(LINK_DETECT_THREAD_INTERVAL / portTICK_RATE_MS);
}
}
#endif

View File

@ -0,0 +1,101 @@
/*
* Copyright (C) 2018 - 2019 Xilinx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#ifndef __XEMAC_IEEE_REGS_H_
#define __XEMAC_IEEE_REGS_H_
/* Advertisement control register. */
#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */
#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */
#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */
#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */
#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */
#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */
#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */
#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */
#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */
#define ADVERTISE_100_AND_10 (ADVERTISE_10FULL | ADVERTISE_100FULL | \
ADVERTISE_10HALF | ADVERTISE_100HALF)
#define ADVERTISE_100 (ADVERTISE_100FULL | ADVERTISE_100HALF)
#define ADVERTISE_10 (ADVERTISE_10FULL | ADVERTISE_10HALF)
#define ADVERTISE_1000 0x0300
#define IEEE_CONTROL_REG_OFFSET 0
#define IEEE_STATUS_REG_OFFSET 1
#define IEEE_AUTONEGO_ADVERTISE_REG 4
#define IEEE_PARTNER_ABILITIES_1_REG_OFFSET 5
#define IEEE_PARTNER_ABILITIES_2_REG_OFFSET 8
#define IEEE_PARTNER_ABILITIES_3_REG_OFFSET 10
#define IEEE_1000_ADVERTISE_REG_OFFSET 9
#define IEEE_MMD_ACCESS_CONTROL_REG 13
#define IEEE_MMD_ACCESS_ADDRESS_DATA_REG 14
#define IEEE_COPPER_SPECIFIC_CONTROL_REG 16
#define IEEE_SPECIFIC_STATUS_REG 17
#define IEEE_COPPER_SPECIFIC_STATUS_REG_2 19
#define IEEE_EXT_PHY_SPECIFIC_CONTROL_REG 20
#define IEEE_CONTROL_REG_MAC 21
#define IEEE_PAGE_ADDRESS_REGISTER 22
#define IEEE_CTRL_1GBPS_LINKSPEED_MASK 0x2040
#define IEEE_CTRL_LINKSPEED_MASK 0x0040
#define IEEE_CTRL_LINKSPEED_1000M 0x0040
#define IEEE_CTRL_LINKSPEED_100M 0x2000
#define IEEE_CTRL_LINKSPEED_10M 0x0000
#define IEEE_CTRL_FULL_DUPLEX 0x100
#define IEEE_CTRL_RESET_MASK 0x8000
#define IEEE_CTRL_AUTONEGOTIATE_ENABLE 0x1000
#define IEEE_STAT_AUTONEGOTIATE_CAPABLE 0x0008
#define IEEE_STAT_AUTONEGOTIATE_COMPLETE 0x0020
#define IEEE_STAT_AUTONEGOTIATE_RESTART 0x0200
#define IEEE_STAT_LINK_STATUS 0x0004
#define IEEE_STAT_1GBPS_EXTENSIONS 0x0100
#define IEEE_AN1_ABILITY_MASK 0x1FE0
#define IEEE_AN3_ABILITY_MASK_1GBPS 0x0C00
#define IEEE_AN1_ABILITY_MASK_100MBPS 0x0380
#define IEEE_AN1_ABILITY_MASK_10MBPS 0x0060
#define IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK 0x0030
#define IEEE_SPEED_MASK 0xC000
#define IEEE_SPEED_1000 0x8000
#define IEEE_SPEED_100 0x4000
#define IEEE_ASYMMETRIC_PAUSE_MASK 0x0800
#define IEEE_PAUSE_MASK 0x0400
#define IEEE_AUTONEG_ERROR_MASK 0x8000
#define IEEE_MMD_ACCESS_CTRL_DEVAD_MASK 0x1F
#define IEEE_MMD_ACCESS_CTRL_PIDEVAD_MASK 0x801F
#define IEEE_MMD_ACCESS_CTRL_NOPIDEVAD_MASK 0x401F
#endif /* __XEMAC_IEEE_REGS_H_ */

View File

@ -0,0 +1,759 @@
/*
* Copyright (C) 2010 - 2019 Xilinx, Inc.
* Copyright (C) 2021 WangHuachen.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#include <stdio.h>
#include <string.h>
#include <xparameters.h>
#include "lwipopts.h"
#include "xlwipconfig.h"
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "lwip/stats.h"
#include "lwip/igmp.h"
#include "netif/etharp.h"
#include "netif/xemacpsif.h"
#include "netif/xadapter.h"
#include "netif/xpqueue.h"
#include "xparameters.h"
// #include "xscugic.h"
#include "xemacps.h"
#if LWIP_IPV6
#include "lwip/ethip6.h"
#endif
#ifdef SYS_ARCH_DECL_PROTECT
#undef SYS_ARCH_DECL_PROTECT
#endif
#define SYS_ARCH_DECL_PROTECT(lev) rt_base_t lev;
#ifdef SYS_ARCH_PROTECT
#undef SYS_ARCH_PROTECT
#endif
#define SYS_ARCH_PROTECT(lev) lev = rt_hw_interrupt_disable();
#ifdef SYS_ARCH_UNPROTECT
#undef SYS_ARCH_UNPROTECT
#endif
#define SYS_ARCH_UNPROTECT(lev) rt_hw_interrupt_enable(lev);
/* Define those to better describe your network interface. */
#define IFNAME0 't'
#define IFNAME1 'e'
#if LWIP_IGMP
static err_t xemacpsif_mac_filter_update (struct netif *netif,
ip_addr_t *group, u8_t action);
static u8_t xemacps_mcast_entry_mask = 0;
#endif
#if LWIP_IPV6 && LWIP_IPV6_MLD
static err_t xemacpsif_mld6_mac_filter_update (struct netif *netif,
ip_addr_t *group, u8_t action);
static u8_t xemacps_mld6_mcast_entry_mask;
#endif
XEmacPs_Config *mac_config;
struct netif *NetIf;
#if defined(OS_IS_FREERTOS) && defined(__arm__) && !defined(ARMR5)
int32_t lExpireCounter = 0;
#define RESETRXTIMEOUT 10
#endif
/*
* this function is always called with interrupts off
* this function also assumes that there are available BD's
*/
err_t _unbuffered_low_level_output(xemacpsif_s *xemacpsif,
struct pbuf *p)
{
XStatus status = 0;
#if ETH_PAD_SIZE
pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */
#endif
status = emacps_sgsend(xemacpsif, p);
if (status != XST_SUCCESS) {
#if LINK_STATS
lwip_stats.link.drop++;
#endif
}
#if ETH_PAD_SIZE
pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */
#endif
#if LINK_STATS
lwip_stats.link.xmit++;
#endif /* LINK_STATS */
return ERR_OK;
}
/*
* low_level_output():
*
* Should do the actual transmission of the packet. The packet is
* contained in the pbuf that is passed to the function. This pbuf
* might be chained.
*
*/
static err_t low_level_output(struct netif *netif, struct pbuf *p)
{
SYS_ARCH_DECL_PROTECT(lev);
err_t err;
s32_t freecnt;
XEmacPs_BdRing *txring;
struct xemac_s *xemac = (struct xemac_s *)(netif->state);
xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
SYS_ARCH_PROTECT(lev);
/* check if space is available to send */
freecnt = is_tx_space_available(xemacpsif);
if (freecnt <= 5) {
txring = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
process_sent_bds(xemacpsif, txring);
}
if (is_tx_space_available(xemacpsif)) {
_unbuffered_low_level_output(xemacpsif, p);
err = ERR_OK;
} else {
#if LINK_STATS
lwip_stats.link.drop++;
#endif
rt_kprintf("pack dropped, no space\r\n");
err = ERR_MEM;
}
SYS_ARCH_UNPROTECT(lev);
return err;
}
/*
* low_level_input():
*
* Should allocate a pbuf and transfer the bytes of the incoming
* packet from the interface into the pbuf.
*
*/
static struct pbuf * low_level_input(struct netif *netif)
{
struct xemac_s *xemac = (struct xemac_s *)(netif->state);
xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
struct pbuf *p;
/* see if there is data to process */
if (pq_qlength(xemacpsif->recv_q) == 0)
return NULL;
/* return one packet from receive q */
p = (struct pbuf *)pq_dequeue(xemacpsif->recv_q);
return p;
}
/*
* xemacpsif_output():
*
* This function is called by the TCP/IP stack when an IP packet
* should be sent. It calls the function called low_level_output() to
* do the actual transmission of the packet.
*
*/
static err_t xemacpsif_output(struct netif *netif, struct pbuf *p,
const ip_addr_t *ipaddr)
{
/* resolve hardware address, then send (or queue) packet */
return etharp_output(netif, p, ipaddr);
}
/*
* xemacpsif_input():
*
* This function should be called when a packet is ready to be read
* from the interface. It uses the function low_level_input() that
* should handle the actual reception of bytes from the network
* interface.
*
* Returns the number of packets read (max 1 packet on success,
* 0 if there are no packets)
*
*/
s32_t xemacpsif_input(struct netif *netif)
{
struct eth_hdr *ethhdr;
struct pbuf *p;
SYS_ARCH_DECL_PROTECT(lev);
#ifdef OS_IS_FREERTOS
while (1)
#endif
{
/* move received packet into a new pbuf */
SYS_ARCH_PROTECT(lev);
p = low_level_input(netif);
SYS_ARCH_UNPROTECT(lev);
/* no packet could be read, silently ignore this */
if (p == NULL) {
return 0;
}
/* points to packet payload, which starts with an Ethernet header */
ethhdr = p->payload;
#if LINK_STATS
lwip_stats.link.recv++;
#endif /* LINK_STATS */
switch (htons(ethhdr->type)) {
/* IP or ARP packet? */
case ETHTYPE_IP:
case ETHTYPE_ARP:
#if LWIP_IPV6
/*IPv6 Packet?*/
case ETHTYPE_IPV6:
#endif
#if PPPOE_SUPPORT
/* PPPoE packet? */
case ETHTYPE_PPPOEDISC:
case ETHTYPE_PPPOE:
#endif /* PPPOE_SUPPORT */
/* full packet send to tcpip_thread to process */
if (netif->input(p, netif) != ERR_OK) {
LWIP_DEBUGF(NETIF_DEBUG, ("xemacpsif_input: IP input error\r\n"));
pbuf_free(p);
p = NULL;
}
break;
default:
pbuf_free(p);
p = NULL;
break;
}
}
return 1;
}
#if defined(OS_IS_FREERTOS) && defined(__arm__) && !defined(ARMR5)
void vTimerCallback( TimerHandle_t pxTimer )
{
/* Do something if the pxTimer parameter is NULL */
configASSERT(pxTimer);
lExpireCounter++;
/* If the timer has expired 100 times then reset RX */
if(lExpireCounter >= RESETRXTIMEOUT) {
lExpireCounter = 0;
xemacpsif_resetrx_on_no_rxdata(NetIf);
}
}
#endif
static err_t low_level_init(struct netif *netif)
{
UINTPTR mac_address = (UINTPTR)(netif->state);
struct xemac_s *xemac;
xemacpsif_s *xemacpsif;
u32 dmacrreg;
s32_t status = XST_SUCCESS;
NetIf = netif;
xemacpsif = mem_malloc(sizeof *xemacpsif);
if (xemacpsif == NULL) {
LWIP_DEBUGF(NETIF_DEBUG, ("xemacpsif_init: out of memory\r\n"));
return ERR_MEM;
}
xemac = mem_malloc(sizeof *xemac);
if (xemac == NULL) {
LWIP_DEBUGF(NETIF_DEBUG, ("xemacpsif_init: out of memory\r\n"));
return ERR_MEM;
}
xemac->state = (void *)xemacpsif;
xemac->topology_index = xtopology_find_index(mac_address);
xemac->type = xemac_type_emacps;
xemacpsif->send_q = NULL;
xemacpsif->recv_q = pq_create_queue();
if (!xemacpsif->recv_q)
return ERR_MEM;
/* maximum transfer unit */
#ifdef ZYNQMP_USE_JUMBO
netif->mtu = XEMACPS_MTU_JUMBO - XEMACPS_HDR_SIZE;
#else
netif->mtu = XEMACPS_MTU - XEMACPS_HDR_SIZE;
#endif
#if LWIP_IGMP
netif->igmp_mac_filter = xemacpsif_mac_filter_update;
#endif
#if LWIP_IPV6 && LWIP_IPV6_MLD
netif->mld_mac_filter = xemacpsif_mld6_mac_filter_update;
#endif
netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP |
NETIF_FLAG_LINK_UP;
#if LWIP_IPV6 && LWIP_IPV6_MLD
netif->flags |= NETIF_FLAG_MLD6;
#endif
#if LWIP_IGMP
netif->flags |= NETIF_FLAG_IGMP;
#endif
#if 0
sys_sem_new(&xemac->sem_rx_data_available, 0);
#endif
/* obtain config of this emac */
mac_config = (XEmacPs_Config *)xemacps_lookup_config((unsigned)(UINTPTR)netif->state);
#if EL1_NONSECURE
/* Request device to indicate that this library is using it */
if (mac_config->BaseAddress == VERSAL_EMACPS_0_BASEADDR) {
Xil_Smc(PM_REQUEST_DEVICE_SMC_FID, DEV_GEM_0, 1, 0, 100, 1, 0, 0);
}
if (mac_config->BaseAddress == VERSAL_EMACPS_0_BASEADDR) {
Xil_Smc(PM_REQUEST_DEVICE_SMC_FID, DEV_GEM_1, 1, 0, 100, 1, 0, 0);
}
#endif
status = XEmacPs_CfgInitialize(&xemacpsif->emacps, mac_config,
mac_config->BaseAddress);
if (status != XST_SUCCESS) {
xil_printf("In %s:EmacPs Configuration Failed....\r\n", __func__);
}
/* initialize the mac */
init_emacps(xemacpsif, netif);
dmacrreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
XEMACPS_DMACR_OFFSET);
dmacrreg = dmacrreg | (0x00000010);
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
XEMACPS_DMACR_OFFSET, dmacrreg);
#if defined(OS_IS_FREERTOS) && defined(__arm__) && !defined(ARMR5)
/* Freertos tick is 10ms by default; set period to the same */
xemac->xTimer = xTimerCreate("Timer", 10, pdTRUE, ( void * ) 1, vTimerCallback);
if (xemac->xTimer == NULL) {
xil_printf("In %s:Timer creation failed....\r\n", __func__);
} else {
if(xTimerStart(xemac->xTimer, 0) != pdPASS) {
xil_printf("In %s:Timer start failed....\r\n", __func__);
}
}
#endif
setup_isr(xemac);
init_dma(xemac);
start_emacps(xemacpsif);
/* replace the state in netif (currently the emac baseaddress)
* with the mac instance pointer.
*/
netif->state = (void *)xemac;
return ERR_OK;
}
void HandleEmacPsError(struct xemac_s *xemac)
{
xemacpsif_s *xemacpsif;
s32_t status = XST_SUCCESS;
u32 dmacrreg;
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
xemacpsif = (xemacpsif_s *)(xemac->state);
free_txrx_pbufs(xemacpsif);
status = XEmacPs_CfgInitialize(&xemacpsif->emacps, mac_config,
mac_config->BaseAddress);
if (status != XST_SUCCESS) {
xil_printf("In %s:EmacPs Configuration Failed....\r\n", __func__);
}
/* initialize the mac */
init_emacps_on_error(xemacpsif, NetIf);
dmacrreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
XEMACPS_DMACR_OFFSET);
dmacrreg = dmacrreg | (0x01000000);
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
XEMACPS_DMACR_OFFSET, dmacrreg);
setup_isr(xemac);
init_dma(xemac);
start_emacps(xemacpsif);
SYS_ARCH_UNPROTECT(lev);
}
void HandleTxErrors(struct xemac_s *xemac)
{
xemacpsif_s *xemacpsif;
u32 netctrlreg;
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
xemacpsif = (xemacpsif_s *)(xemac->state);
netctrlreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET);
netctrlreg = netctrlreg & (~XEMACPS_NWCTRL_TXEN_MASK);
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET, netctrlreg);
free_onlytx_pbufs(xemacpsif);
clean_dma_txdescs(xemac);
netctrlreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET);
netctrlreg = netctrlreg | (XEMACPS_NWCTRL_TXEN_MASK);
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET, netctrlreg);
SYS_ARCH_UNPROTECT(lev);
}
#if LWIP_IPV6 && LWIP_IPV6_MLD
static u8_t xemacpsif_ip6_addr_ismulticast(ip6_addr_t* ip_addr)
{
if(ip6_addr_ismulticast_linklocal(ip_addr)||
ip6_addr_ismulticast_iflocal(ip_addr) ||
ip6_addr_ismulticast_adminlocal(ip_addr)||
ip6_addr_ismulticast_sitelocal(ip_addr) ||
ip6_addr_ismulticast_orglocal(ip_addr) ||
ip6_addr_ismulticast_global(ip_addr)) {
/*Return TRUE if IPv6 is Multicast type*/
return TRUE;
} else {
return FALSE;
}
}
static void xemacpsif_mld6_mac_hash_update (struct netif *netif, u8_t *ip_addr,
u8_t action)
{
u8_t multicast_mac_addr[6];
struct xemac_s *xemac = (struct xemac_s *) (netif->state);
xemacpsif_s *xemacpsif = (xemacpsif_s *) (xemac->state);
XEmacPs_BdRing *txring;
txring = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
multicast_mac_addr[0] = LL_IP6_MULTICAST_ADDR_0;
multicast_mac_addr[1] = LL_IP6_MULTICAST_ADDR_1;
multicast_mac_addr[2] = ip_addr[12];
multicast_mac_addr[3] = ip_addr[13];
multicast_mac_addr[4] = ip_addr[14];
multicast_mac_addr[5] = ip_addr[15];
/* Wait till all sent packets are acknowledged from HW */
while(txring->HwCnt);
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
/* Stop Ethernet */
XEmacPs_Stop(&xemacpsif->emacps);
if (action == NETIF_ADD_MAC_FILTER) {
/* Set Mulitcast mac address in hash table */
XEmacPs_SetHash(&xemacpsif->emacps, multicast_mac_addr);
} else if (action == NETIF_DEL_MAC_FILTER) {
/* Remove Mulitcast mac address in hash table */
XEmacPs_DeleteHash(&xemacpsif->emacps, multicast_mac_addr);
}
/* Reset DMA */
reset_dma(xemac);
/* Start Ethernet */
XEmacPs_Start(&xemacpsif->emacps);
SYS_ARCH_UNPROTECT(lev);
}
static err_t xemacpsif_mld6_mac_filter_update (struct netif *netif, ip_addr_t *group,
u8_t action)
{
u8_t temp_mask;
unsigned int i;
u8_t * ip_addr = (u8_t *) group;
if(!(xemacpsif_ip6_addr_ismulticast((ip6_addr_t*) ip_addr))) {
LWIP_DEBUGF(NETIF_DEBUG,
("%s: The requested MAC address is not a multicast address.\r\n", __func__)); LWIP_DEBUGF(NETIF_DEBUG,
("Multicast address add operation failure !!\r\n"));
return ERR_ARG;
}
if (action == NETIF_ADD_MAC_FILTER) {
for (i = 0; i < XEMACPS_MAX_MAC_ADDR; i++) {
temp_mask = (0x01) << i;
if ((xemacps_mld6_mcast_entry_mask & temp_mask) == temp_mask) {
continue;
}
xemacps_mld6_mcast_entry_mask |= temp_mask;
/* Update mac address in hash table */
xemacpsif_mld6_mac_hash_update(netif, ip_addr, action);
LWIP_DEBUGF(NETIF_DEBUG,
("%s: Multicast MAC address successfully added.\r\n", __func__));
return ERR_OK;
}
LWIP_DEBUGF(NETIF_DEBUG,
("%s: No multicast address registers left.\r\n", __func__));
LWIP_DEBUGF(NETIF_DEBUG,
("Multicast MAC address add operation failure !!\r\n"));
return ERR_MEM;
} else if (action == NETIF_DEL_MAC_FILTER) {
for (i = 0; i < XEMACPS_MAX_MAC_ADDR; i++) {
temp_mask = (0x01) << i;
if ((xemacps_mld6_mcast_entry_mask & temp_mask) != temp_mask) {
continue;
}
xemacps_mld6_mcast_entry_mask &= (~temp_mask);
/* Update mac address in hash table */
xemacpsif_mld6_mac_hash_update(netif, ip_addr, action);
LWIP_DEBUGF(NETIF_DEBUG,
("%s: Multicast MAC address successfully removed.\r\n", __func__));
return ERR_OK;
}
LWIP_DEBUGF(NETIF_DEBUG,
("%s: No multicast address registers present with\r\n", __func__));
LWIP_DEBUGF(NETIF_DEBUG,
("the requested Multicast MAC address.\r\n"));
LWIP_DEBUGF(NETIF_DEBUG,
("Multicast MAC address removal failure!!.\r\n"));
return ERR_MEM;
}
return ERR_ARG;
}
#endif
#if LWIP_IGMP
static void xemacpsif_mac_hash_update (struct netif *netif, u8_t *ip_addr,
u8_t action)
{
u8_t multicast_mac_addr[6];
struct xemac_s *xemac = (struct xemac_s *) (netif->state);
xemacpsif_s *xemacpsif = (xemacpsif_s *) (xemac->state);
XEmacPs_BdRing *txring;
txring = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
multicast_mac_addr[0] = 0x01;
multicast_mac_addr[1] = 0x00;
multicast_mac_addr[2] = 0x5E;
multicast_mac_addr[3] = ip_addr[1] & 0x7F;
multicast_mac_addr[4] = ip_addr[2];
multicast_mac_addr[5] = ip_addr[3];
/* Wait till all sent packets are acknowledged from HW */
while(txring->HwCnt);
SYS_ARCH_DECL_PROTECT(lev);
SYS_ARCH_PROTECT(lev);
/* Stop Ethernet */
XEmacPs_Stop(&xemacpsif->emacps);
if (action == IGMP_ADD_MAC_FILTER) {
/* Set Mulitcast mac address in hash table */
XEmacPs_SetHash(&xemacpsif->emacps, multicast_mac_addr);
} else if (action == IGMP_DEL_MAC_FILTER) {
/* Remove Mulitcast mac address in hash table */
XEmacPs_DeleteHash(&xemacpsif->emacps, multicast_mac_addr);
}
/* Reset DMA */
reset_dma(xemac);
/* Start Ethernet */
XEmacPs_Start(&xemacpsif->emacps);
SYS_ARCH_UNPROTECT(lev);
}
static err_t xemacpsif_mac_filter_update (struct netif *netif, ip_addr_t *group,
u8_t action)
{
u8_t temp_mask;
unsigned int i;
u8_t * ip_addr = (u8_t *) group;
if ((ip_addr[0] < 224) && (ip_addr[0] > 239)) {
LWIP_DEBUGF(NETIF_DEBUG,
("%s: The requested MAC address is not a multicast address.\r\n", __func__));
LWIP_DEBUGF(NETIF_DEBUG,
("Multicast address add operation failure !!\r\n"));
return ERR_ARG;
}
if (action == IGMP_ADD_MAC_FILTER) {
for (i = 0; i < XEMACPS_MAX_MAC_ADDR; i++) {
temp_mask = (0x01) << i;
if ((xemacps_mcast_entry_mask & temp_mask) == temp_mask) {
continue;
}
xemacps_mcast_entry_mask |= temp_mask;
/* Update mac address in hash table */
xemacpsif_mac_hash_update(netif, ip_addr, action);
LWIP_DEBUGF(NETIF_DEBUG,
("%s: Multicast MAC address successfully added.\r\n", __func__));
return ERR_OK;
}
if (i == XEMACPS_MAX_MAC_ADDR) {
LWIP_DEBUGF(NETIF_DEBUG,
("%s: No multicast address registers left.\r\n", __func__));
LWIP_DEBUGF(NETIF_DEBUG,
("Multicast MAC address add operation failure !!\r\n"));
return ERR_MEM;
}
} else if (action == IGMP_DEL_MAC_FILTER) {
for (i = 0; i < XEMACPS_MAX_MAC_ADDR; i++) {
temp_mask = (0x01) << i;
if ((xemacps_mcast_entry_mask & temp_mask) != temp_mask) {
continue;
}
xemacps_mcast_entry_mask &= (~temp_mask);
/* Update mac address in hash table */
xemacpsif_mac_hash_update(netif, ip_addr, action);
LWIP_DEBUGF(NETIF_DEBUG,
("%s: Multicast MAC address successfully removed.\r\n", __func__));
return ERR_OK;
}
if (i == XEMACPS_MAX_MAC_ADDR) {
LWIP_DEBUGF(NETIF_DEBUG,
("%s: No multicast address registers present with\r\n", __func__));
LWIP_DEBUGF(NETIF_DEBUG,
("the requested Multicast MAC address.\r\n"));
LWIP_DEBUGF(NETIF_DEBUG,
("Multicast MAC address removal failure!!.\r\n"));
return ERR_MEM;
}
}
return ERR_OK;
}
#endif
/*
* xemacpsif_init():
*
* Should be called at the beginning of the program to set up the
* network interface. It calls the function low_level_init() to do the
* actual setup of the hardware.
*
*/
err_t xemacpsif_init(struct netif *netif)
{
#if LWIP_SNMP
/* ifType ethernetCsmacd(6) @see RFC1213 */
netif->link_type = 6;
/* your link speed here */
netif->link_speed = ;
netif->ts = 0;
netif->ifinoctets = 0;
netif->ifinucastpkts = 0;
netif->ifinnucastpkts = 0;
netif->ifindiscards = 0;
netif->ifoutoctets = 0;
netif->ifoutucastpkts = 0;
netif->ifoutnucastpkts = 0;
netif->ifoutdiscards = 0;
#endif
netif->name[0] = IFNAME0;
netif->name[1] = IFNAME1;
netif->output = xemacpsif_output;
netif->linkoutput = low_level_output;
#if LWIP_IPV6
netif->output_ip6 = ethip6_output;
#endif
low_level_init(netif);
return ERR_OK;
}
/*
* xemacpsif_resetrx_on_no_rxdata():
*
* Should be called by the user at regular intervals, typically
* from a timer (100 msecond). This is to provide a SW workaround
* for the HW bug (SI #692601). Please refer to the function header
* for the function resetrx_on_no_rxdata in xemacpsif_dma.c to
* know more about the SI.
*
*/
void xemacpsif_resetrx_on_no_rxdata(struct netif *netif)
{
struct xemac_s *xemac = (struct xemac_s *)(netif->state);
xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
resetrx_on_no_rxdata(xemacpsif);
}

View File

@ -0,0 +1,873 @@
/*
* Copyright (C) 2010 - 2019 Xilinx, Inc.
* Copyright (C) 2021 WangHuachen.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#include "lwipopts.h"
#include "lwip/stats.h"
#include "lwip/sys.h"
#include "lwip/inet_chksum.h"
#include "netif/xadapter.h"
#include "netif/xemacpsif.h"
#include "xstatus.h"
#include "xlwipconfig.h"
#include "xparameters.h"
#include "xparameters_ps.h"
// #include "xil_exception.h"
#include "xil_mmu.h"
#if defined (ARMR5)
#include "xreg_cortexr5.h"
#endif
#ifdef CONFIG_XTRACE
#include "xtrace.h"
#endif
#ifdef OS_IS_FREERTOS
#include "FreeRTOS.h"
#include "semphr.h"
#include "timers.h"
#endif
#include <stdio.h>
#define INTC_BASE_ADDR XPAR_SCUGIC_0_CPU_BASEADDR
#define INTC_DIST_BASE_ADDR XPAR_SCUGIC_0_DIST_BASEADDR
/* Byte alignment of BDs */
#define BD_ALIGNMENT (XEMACPS_DMABD_MINIMUM_ALIGNMENT*2)
/* A max of 4 different ethernet interfaces are supported */
static UINTPTR tx_pbufs_storage[4*XLWIP_CONFIG_N_TX_DESC];
static UINTPTR rx_pbufs_storage[4*XLWIP_CONFIG_N_RX_DESC];
static s32_t emac_intr_num;
/******************************************************************************
* Each BD is of 8 bytes of size and the BDs (BD chain) need to be put
* at uncached memory location. If they are not put at uncached
* locations, the user needs to flush or invalidate for each BD/packet.
* However, the flush or invalidate can happen over a cache line which can
* span multiple BDs. This means a flush or invalidate of one BD can actually
* flush/invalidate multiple BDs adjacent to the targeted BD.Assuming that
* the user and hardware both update the BD fields, this operation from user
* can potentially overwrite the updates done by hardware or user.
* To avoid this, it is always safe to put the BD chains for Rx and tx side
* at uncached memory location.
*
* The Xilinx standalone BSP for Cortex A9 implements only primary page tables.
* Each table entry corresponds to 1 MB of address map. This means, if a memory
* region has to be made uncached, the minimum granularity will be of 1 MB.
*
* The implementation below allocates a 1 MB of u8 array aligned to 1 MB.
* This ensures that this array is put at 1 MB aligned memory (e.g. 0x1200000)
* and accupies memory of 1 MB. The init_dma function then changes 1 MB of this
* region to make it uncached (strongly ordered).
* This increases the bss section of the program significantly and can be a
* wastage of memory. The reason beings, BDs will hardly occupy few KBs of
* memory and the rest of 1 MB of memory will be unused.
*
* If a program uses other peripherals that have DMAs/bus masters and need
* uncached memory, they may also end of following the same approach. This
* definitely aggravates the memory wastage issue. To avoid all this, the user
* can create a new 1 MB section in the linker script and reserve it for such
* use cases that need uncached memory location. They can then have their own
* memory allocation logic in their application that allocates uncached memory
* from this 1 MB location. For such a case, changes need to be done in this
* file and appropriate uncached memory allocated through other means can be
* used.
*
* The present implementation here allocates 1 MB of uncached memory. It
* reserves of 64 KB of memory for each BD chain. 64 KB of memory means 8192 of
* BDs for each BD chain which is more than enough for any application.
* Assuming that both emac0 and emac1 are present, 256 KB of memory is allocated
* for BDs. The rest 768 KB of memory is just unused.
*********************************************************************************/
#if defined __aarch64__
u8_t bd_space[0x200000] __attribute__ ((aligned (0x200000)));
#else
u8_t bd_space[0x100000] __attribute__ ((aligned (0x100000)));
#endif
static volatile u32_t bd_space_index = 0;
static volatile u32_t bd_space_attr_set = 0;
#ifdef OS_IS_FREERTOS
long xInsideISR = 0;
#endif
#define XEMACPS_BD_TO_INDEX(ringptr, bdptr) \
(((UINTPTR)bdptr - (UINTPTR)(ringptr)->BaseBdAddr) / (ringptr)->Separation)
s32_t is_tx_space_available(xemacpsif_s *emac)
{
XEmacPs_BdRing *txring;
s32_t freecnt = 0;
txring = &(XEmacPs_GetTxRing(&emac->emacps));
/* tx space is available as long as there are valid BD's */
freecnt = XEmacPs_BdRingGetFreeCnt(txring);
return freecnt;
}
static inline
u32_t get_base_index_txpbufsstorage (xemacpsif_s *xemacpsif)
{
u32_t index;
#ifdef XPAR_XEMACPS_0_BASEADDR
if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR) {
index = 0;
}
#endif
#ifdef XPAR_XEMACPS_1_BASEADDR
if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_1_BASEADDR) {
index = XLWIP_CONFIG_N_TX_DESC;
}
#endif
#ifdef XPAR_XEMACPS_2_BASEADDR
if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_2_BASEADDR) {
index = 2 * XLWIP_CONFIG_N_TX_DESC;
}
#endif
#ifdef XPAR_XEMACPS_3_BASEADDR
if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_3_BASEADDR) {
index = 3 * XLWIP_CONFIG_N_TX_DESC;
}
#endif
return index;
}
static inline
u32_t get_base_index_rxpbufsstorage (xemacpsif_s *xemacpsif)
{
u32_t index;
#ifdef XPAR_XEMACPS_0_BASEADDR
if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR) {
index = 0;
}
#endif
#ifdef XPAR_XEMACPS_1_BASEADDR
if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_1_BASEADDR) {
index = XLWIP_CONFIG_N_RX_DESC;
}
#endif
#ifdef XPAR_XEMACPS_2_BASEADDR
if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_2_BASEADDR) {
index = 2 * XLWIP_CONFIG_N_RX_DESC;
}
#endif
#ifdef XPAR_XEMACPS_3_BASEADDR
if (xemacpsif->emacps.Config.BaseAddress == XPAR_XEMACPS_3_BASEADDR) {
index = 3 * XLWIP_CONFIG_N_RX_DESC;
}
#endif
return index;
}
void process_sent_bds(xemacpsif_s *xemacpsif, XEmacPs_BdRing *txring)
{
XEmacPs_Bd *txbdset;
XEmacPs_Bd *curbdpntr;
s32_t n_bds;
XStatus status;
s32_t n_pbufs_freed = 0;
u32_t bdindex;
struct pbuf *p;
u32 *temp;
u32_t index;
index = get_base_index_txpbufsstorage (xemacpsif);
while (1) {
/* obtain processed BD's */
n_bds = XEmacPs_BdRingFromHwTx(txring,
XLWIP_CONFIG_N_TX_DESC, &txbdset);
if (n_bds == 0) {
return;
}
/* free the processed BD's */
n_pbufs_freed = n_bds;
curbdpntr = txbdset;
while (n_pbufs_freed > 0) {
bdindex = XEMACPS_BD_TO_INDEX(txring, curbdpntr);
temp = (u32 *)curbdpntr;
*temp = 0;
temp++;
if (bdindex == (XLWIP_CONFIG_N_TX_DESC - 1)) {
*temp = 0xC0000000;
} else {
*temp = 0x80000000;
}
dsb();
p = (struct pbuf *)tx_pbufs_storage[index + bdindex];
if (p != NULL) {
pbuf_free(p);
}
tx_pbufs_storage[index + bdindex] = 0;
curbdpntr = XEmacPs_BdRingNext(txring, curbdpntr);
n_pbufs_freed--;
dsb();
}
status = XEmacPs_BdRingFree(txring, n_bds, txbdset);
if (status != XST_SUCCESS) {
LWIP_DEBUGF(NETIF_DEBUG, ("Failure while freeing in Tx Done ISR\r\n"));
}
}
return;
}
void emacps_send_handler(void *arg)
{
struct xemac_s *xemac;
xemacpsif_s *xemacpsif;
XEmacPs_BdRing *txringptr;
u32_t regval;
#ifdef OS_IS_FREERTOS
xInsideISR++;
#endif
xemac = (struct xemac_s *)(arg);
xemacpsif = (xemacpsif_s *)(xemac->state);
txringptr = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
regval = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_TXSR_OFFSET);
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,XEMACPS_TXSR_OFFSET, regval);
/* If Transmit done interrupt is asserted, process completed BD's */
/* Since RT-Thread does not support freeing memory in interrupts, comment it out */
// process_sent_bds(xemacpsif, txringptr);
#ifdef OS_IS_FREERTOS
xInsideISR--;
#endif
}
XStatus emacps_sgsend(xemacpsif_s *xemacpsif, struct pbuf *p)
{
struct pbuf *q;
s32_t n_pbufs;
XEmacPs_Bd *txbdset, *txbd, *last_txbd = NULL;
XEmacPs_Bd *temp_txbd;
XStatus status;
XEmacPs_BdRing *txring;
u32_t bdindex;
u32_t lev;
u32_t index;
u32_t max_fr_size;
lev = mfcpsr();
mtcpsr(lev | 0x000000C0);
txring = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
index = get_base_index_txpbufsstorage (xemacpsif);
/* first count the number of pbufs */
for (q = p, n_pbufs = 0; q != NULL; q = q->next)
n_pbufs++;
/* obtain as many BD's */
status = XEmacPs_BdRingAlloc(txring, n_pbufs, &txbdset);
if (status != XST_SUCCESS) {
mtcpsr(lev);
LWIP_DEBUGF(NETIF_DEBUG, ("sgsend: Error allocating TxBD\r\n"));
return XST_FAILURE;
}
for(q = p, txbd = txbdset; q != NULL; q = q->next) {
bdindex = XEMACPS_BD_TO_INDEX(txring, txbd);
if (tx_pbufs_storage[index + bdindex] != 0) {
mtcpsr(lev);
LWIP_DEBUGF(NETIF_DEBUG, ("PBUFS not available\r\n"));
return XST_FAILURE;
}
/* 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. */
if (xemacpsif->emacps.Config.IsCacheCoherent == 0) {
Xil_DCacheFlushRange((UINTPTR)q->payload, (UINTPTR)q->len);
}
XEmacPs_BdSetAddressTx(txbd, (UINTPTR)q->payload);
#ifdef ZYNQMP_USE_JUMBO
max_fr_size = MAX_FRAME_SIZE_JUMBO - 18;
#else
max_fr_size = XEMACPS_MAX_FRAME_SIZE - 18;
#endif
if (q->len > max_fr_size)
XEmacPs_BdSetLength(txbd, max_fr_size & 0x3FFF);
else
XEmacPs_BdSetLength(txbd, q->len & 0x3FFF);
tx_pbufs_storage[index + bdindex] = (UINTPTR)q;
pbuf_ref(q);
last_txbd = txbd;
XEmacPs_BdClearLast(txbd);
txbd = XEmacPs_BdRingNext(txring, txbd);
}
XEmacPs_BdSetLast(last_txbd);
/* For fragmented packets, remember the 1st BD allocated for the 1st
packet fragment. The used bit for this BD should be cleared at the end
after clearing out used bits for other fragments. For packets without
just remember the allocated BD. */
temp_txbd = txbdset;
txbd = txbdset;
txbd = XEmacPs_BdRingNext(txring, txbd);
q = p->next;
for(; q != NULL; q = q->next) {
XEmacPs_BdClearTxUsed(txbd);
dsb();
txbd = XEmacPs_BdRingNext(txring, txbd);
}
XEmacPs_BdClearTxUsed(temp_txbd);
dsb();
status = XEmacPs_BdRingToHw(txring, n_pbufs, txbdset);
if (status != XST_SUCCESS) {
mtcpsr(lev);
LWIP_DEBUGF(NETIF_DEBUG, ("sgsend: Error submitting TxBD\r\n"));
return XST_FAILURE;
}
/* Start transmit */
XEmacPs_WriteReg((xemacpsif->emacps).Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET,
(XEmacPs_ReadReg((xemacpsif->emacps).Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET) | XEMACPS_NWCTRL_STARTTX_MASK));
mtcpsr(lev);
return status;
}
void setup_rx_bds(xemacpsif_s *xemacpsif, XEmacPs_BdRing *rxring)
{
XEmacPs_Bd *rxbd;
XStatus status;
struct pbuf *p;
u32_t freebds;
u32_t bdindex;
u32 *temp;
u32_t index;
index = get_base_index_rxpbufsstorage (xemacpsif);
freebds = XEmacPs_BdRingGetFreeCnt (rxring);
while (freebds > 0) {
freebds--;
#ifdef ZYNQMP_USE_JUMBO
p = pbuf_alloc(PBUF_RAW, MAX_FRAME_SIZE_JUMBO, PBUF_POOL);
#else
p = pbuf_alloc(PBUF_RAW, XEMACPS_MAX_FRAME_SIZE, PBUF_POOL);
#endif
if (!p) {
#if LINK_STATS
lwip_stats.link.memerr++;
lwip_stats.link.drop++;
#endif
rt_kprintf("unable to alloc pbuf in recv_handler\r\n");
return;
}
status = XEmacPs_BdRingAlloc(rxring, 1, &rxbd);
if (status != XST_SUCCESS) {
LWIP_DEBUGF(NETIF_DEBUG, ("setup_rx_bds: Error allocating RxBD\r\n"));
pbuf_free(p);
return;
}
status = XEmacPs_BdRingToHw(rxring, 1, rxbd);
if (status != XST_SUCCESS) {
LWIP_DEBUGF(NETIF_DEBUG, ("Error committing RxBD to hardware: "));
if (status == XST_DMA_SG_LIST_ERROR) {
LWIP_DEBUGF(NETIF_DEBUG, ("XST_DMA_SG_LIST_ERROR: this function was called out of sequence with XEmacPs_BdRingAlloc()\r\n"));
}
else {
LWIP_DEBUGF(NETIF_DEBUG, ("set of BDs was rejected because the first BD did not have its start-of-packet bit set, or the last BD did not have its end-of-packet bit set, or any one of the BD set has 0 as length value\r\n"));
}
pbuf_free(p);
XEmacPs_BdRingUnAlloc(rxring, 1, rxbd);
return;
}
#ifdef ZYNQMP_USE_JUMBO
if (xemacpsif->emacps.Config.IsCacheCoherent == 0) {
Xil_DCacheInvalidateRange((UINTPTR)p->payload, (UINTPTR)MAX_FRAME_SIZE_JUMBO);
}
#else
if (xemacpsif->emacps.Config.IsCacheCoherent == 0) {
Xil_DCacheInvalidateRange((UINTPTR)p->payload, (UINTPTR)XEMACPS_MAX_FRAME_SIZE);
}
#endif
bdindex = XEMACPS_BD_TO_INDEX(rxring, rxbd);
temp = (u32 *)rxbd;
if (bdindex == (XLWIP_CONFIG_N_RX_DESC - 1)) {
*temp = 0x00000002;
} else {
*temp = 0;
}
temp++;
*temp = 0;
dsb();
XEmacPs_BdSetAddressRx(rxbd, (UINTPTR)p->payload);
rx_pbufs_storage[index + bdindex] = (UINTPTR)p;
}
}
void emacps_recv_handler(void *arg)
{
struct pbuf *p;
XEmacPs_Bd *rxbdset, *curbdptr;
struct xemac_s *xemac;
xemacpsif_s *xemacpsif;
XEmacPs_BdRing *rxring;
volatile s32_t bd_processed;
s32_t rx_bytes, k;
u32_t bdindex;
u32_t regval;
u32_t index;
u32_t gigeversion;
xemac = (struct xemac_s *)(arg);
xemacpsif = (xemacpsif_s *)(xemac->state);
rxring = &XEmacPs_GetRxRing(&xemacpsif->emacps);
#ifdef OS_IS_FREERTOS
xInsideISR++;
#endif
gigeversion = ((Xil_In32(xemacpsif->emacps.Config.BaseAddress + 0xFC)) >> 16) & 0xFFF;
index = get_base_index_rxpbufsstorage (xemacpsif);
/*
* If Reception done interrupt is asserted, call RX call back function
* to handle the processed BDs and then raise the according flag.
*/
regval = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXSR_OFFSET);
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXSR_OFFSET, regval);
if (gigeversion <= 2) {
resetrx_on_no_rxdata(xemacpsif);
}
while(1) {
bd_processed = XEmacPs_BdRingFromHwRx(rxring, XLWIP_CONFIG_N_RX_DESC, &rxbdset);
if (bd_processed <= 0) {
break;
}
for (k = 0, curbdptr=rxbdset; k < bd_processed; k++) {
bdindex = XEMACPS_BD_TO_INDEX(rxring, curbdptr);
p = (struct pbuf *)rx_pbufs_storage[index + bdindex];
/*
* Adjust the buffer size to the actual number of bytes received.
*/
#ifdef ZYNQMP_USE_JUMBO
rx_bytes = XEmacPs_GetRxFrameSize(&xemacpsif->emacps, curbdptr);
#else
rx_bytes = XEmacPs_BdGetLength(curbdptr);
#endif
pbuf_realloc(p, rx_bytes);
/* Invalidate RX frame before queuing to handle
* L1 cache prefetch conditions on any architecture.
*/
Xil_DCacheInvalidateRange((UINTPTR)p->payload, rx_bytes);
/* store it in the receive queue,
* where it'll be processed by a different handler
*/
if (pq_enqueue(xemacpsif->recv_q, (void*)p) < 0) {
#if LINK_STATS
lwip_stats.link.memerr++;
lwip_stats.link.drop++;
#endif
pbuf_free(p);
}
curbdptr = XEmacPs_BdRingNext( rxring, curbdptr);
}
/* free up the BD's */
XEmacPs_BdRingFree(rxring, bd_processed, rxbdset);
setup_rx_bds(xemacpsif, rxring);
#if 0
sys_sem_signal(&xemac->sem_rx_data_available);
#else
eth_device_ready(xemac->rt_eth_device);
#endif
}
#ifdef OS_IS_FREERTOS
xInsideISR--;
#endif
return;
}
void clean_dma_txdescs(struct xemac_s *xemac)
{
XEmacPs_Bd bdtemplate;
XEmacPs_BdRing *txringptr;
xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
txringptr = &XEmacPs_GetTxRing(&xemacpsif->emacps);
XEmacPs_BdClear(&bdtemplate);
XEmacPs_BdSetStatus(&bdtemplate, XEMACPS_TXBUF_USED_MASK);
/*
* Create the TxBD ring
*/
XEmacPs_BdRingCreate(txringptr, (UINTPTR) xemacpsif->tx_bdspace,
(UINTPTR) xemacpsif->tx_bdspace, BD_ALIGNMENT,
XLWIP_CONFIG_N_TX_DESC);
XEmacPs_BdRingClone(txringptr, &bdtemplate, XEMACPS_SEND);
}
XStatus init_dma(struct xemac_s *xemac)
{
XEmacPs_Bd bdtemplate;
XEmacPs_BdRing *rxringptr, *txringptr;
XEmacPs_Bd *rxbd;
struct pbuf *p;
XStatus status;
s32_t i;
u32_t bdindex;
volatile UINTPTR tempaddress;
u32_t index;
u32_t gigeversion;
XEmacPs_Bd *bdtxterminate;
XEmacPs_Bd *bdrxterminate;
u32 *temp;
xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
struct xtopology_t *xtopologyp = &xtopology[xemac->topology_index];
index = get_base_index_rxpbufsstorage (xemacpsif);
gigeversion = ((Xil_In32(xemacpsif->emacps.Config.BaseAddress + 0xFC)) >> 16) & 0xFFF;
/*
* The BDs need to be allocated in uncached memory. Hence the 1 MB
* address range allocated for Bd_Space is made uncached
* by setting appropriate attributes in the translation table.
* The Bd_Space is aligned to 1MB and has a size of 1 MB. This ensures
* a reserved uncached area used only for BDs.
*/
if (bd_space_attr_set == 0) {
#if defined (ARMR5)
Xil_SetTlbAttributes((s32_t)bd_space, STRONG_ORDERD_SHARED | PRIV_RW_USER_RW); // addr, attr
#else
#if defined __aarch64__
Xil_SetTlbAttributes((u64)bd_space, NORM_NONCACHE | INNER_SHAREABLE);
#else
Xil_SetTlbAttributes((s32_t)bd_space, DEVICE_MEMORY); // addr, attr
#endif
#endif
bd_space_attr_set = 1;
}
rxringptr = &XEmacPs_GetRxRing(&xemacpsif->emacps);
txringptr = &XEmacPs_GetTxRing(&xemacpsif->emacps);
LWIP_DEBUGF(NETIF_DEBUG, ("rxringptr: 0x%08x\r\n", rxringptr));
LWIP_DEBUGF(NETIF_DEBUG, ("txringptr: 0x%08x\r\n", txringptr));
/* Allocate 64k for Rx and Tx bds each to take care of extreme cases */
tempaddress = (UINTPTR)&(bd_space[bd_space_index]);
xemacpsif->rx_bdspace = (void *)tempaddress;
bd_space_index += 0x10000;
tempaddress = (UINTPTR)&(bd_space[bd_space_index]);
xemacpsif->tx_bdspace = (void *)tempaddress;
bd_space_index += 0x10000;
if (gigeversion > 2) {
tempaddress = (UINTPTR)&(bd_space[bd_space_index]);
bdrxterminate = (XEmacPs_Bd *)tempaddress;
bd_space_index += 0x10000;
tempaddress = (UINTPTR)&(bd_space[bd_space_index]);
bdtxterminate = (XEmacPs_Bd *)tempaddress;
bd_space_index += 0x10000;
}
LWIP_DEBUGF(NETIF_DEBUG, ("rx_bdspace: %p \r\n", xemacpsif->rx_bdspace));
LWIP_DEBUGF(NETIF_DEBUG, ("tx_bdspace: %p \r\n", xemacpsif->tx_bdspace));
if (!xemacpsif->rx_bdspace || !xemacpsif->tx_bdspace) {
xil_printf("%s@%d: Error: Unable to allocate memory for TX/RX buffer descriptors",
__FILE__, __LINE__);
return ERR_IF;
}
/*
* Setup RxBD space.
*
* Setup a BD template for the Rx channel. This template will be copied to
* every RxBD. We will not have to explicitly set these again.
*/
XEmacPs_BdClear(&bdtemplate);
/*
* Create the RxBD ring
*/
status = XEmacPs_BdRingCreate(rxringptr, (UINTPTR) xemacpsif->rx_bdspace,
(UINTPTR) xemacpsif->rx_bdspace, BD_ALIGNMENT,
XLWIP_CONFIG_N_RX_DESC);
if (status != XST_SUCCESS) {
LWIP_DEBUGF(NETIF_DEBUG, ("Error setting up RxBD space\r\n"));
return ERR_IF;
}
status = XEmacPs_BdRingClone(rxringptr, &bdtemplate, XEMACPS_RECV);
if (status != XST_SUCCESS) {
LWIP_DEBUGF(NETIF_DEBUG, ("Error initializing RxBD space\r\n"));
return ERR_IF;
}
XEmacPs_BdClear(&bdtemplate);
XEmacPs_BdSetStatus(&bdtemplate, XEMACPS_TXBUF_USED_MASK);
/*
* Create the TxBD ring
*/
status = XEmacPs_BdRingCreate(txringptr, (UINTPTR) xemacpsif->tx_bdspace,
(UINTPTR) xemacpsif->tx_bdspace, BD_ALIGNMENT,
XLWIP_CONFIG_N_TX_DESC);
if (status != XST_SUCCESS) {
return ERR_IF;
}
/* We reuse the bd template, as the same one will work for both rx and tx. */
status = XEmacPs_BdRingClone(txringptr, &bdtemplate, XEMACPS_SEND);
if (status != XST_SUCCESS) {
return ERR_IF;
}
/*
* Allocate RX descriptors, 1 RxBD at a time.
*/
for (i = 0; i < XLWIP_CONFIG_N_RX_DESC; i++) {
#ifdef ZYNQMP_USE_JUMBO
p = pbuf_alloc(PBUF_RAW, MAX_FRAME_SIZE_JUMBO, PBUF_POOL);
#else
p = pbuf_alloc(PBUF_RAW, XEMACPS_MAX_FRAME_SIZE, PBUF_POOL);
#endif
if (!p) {
#if LINK_STATS
lwip_stats.link.memerr++;
lwip_stats.link.drop++;
#endif
rt_kprintf("unable to alloc pbuf in init_dma\r\n");
return ERR_IF;
}
status = XEmacPs_BdRingAlloc(rxringptr, 1, &rxbd);
if (status != XST_SUCCESS) {
LWIP_DEBUGF(NETIF_DEBUG, ("init_dma: Error allocating RxBD\r\n"));
pbuf_free(p);
return ERR_IF;
}
/* Enqueue to HW */
status = XEmacPs_BdRingToHw(rxringptr, 1, rxbd);
if (status != XST_SUCCESS) {
LWIP_DEBUGF(NETIF_DEBUG, ("Error: committing RxBD to HW\r\n"));
pbuf_free(p);
XEmacPs_BdRingUnAlloc(rxringptr, 1, rxbd);
return ERR_IF;
}
bdindex = XEMACPS_BD_TO_INDEX(rxringptr, rxbd);
temp = (u32 *)rxbd;
*temp = 0;
if (bdindex == (XLWIP_CONFIG_N_RX_DESC - 1)) {
*temp = 0x00000002;
}
temp++;
*temp = 0;
dsb();
#ifdef ZYNQMP_USE_JUMBO
if (xemacpsif->emacps.Config.IsCacheCoherent == 0) {
Xil_DCacheInvalidateRange((UINTPTR)p->payload, (UINTPTR)MAX_FRAME_SIZE_JUMBO);
}
#else
if (xemacpsif->emacps.Config.IsCacheCoherent == 0) {
Xil_DCacheInvalidateRange((UINTPTR)p->payload, (UINTPTR)XEMACPS_MAX_FRAME_SIZE);
}
#endif
XEmacPs_BdSetAddressRx(rxbd, (UINTPTR)p->payload);
rx_pbufs_storage[index + bdindex] = (UINTPTR)p;
}
XEmacPs_SetQueuePtr(&(xemacpsif->emacps), xemacpsif->emacps.RxBdRing.BaseBdAddr, 0, XEMACPS_RECV);
if (gigeversion > 2) {
XEmacPs_SetQueuePtr(&(xemacpsif->emacps), xemacpsif->emacps.TxBdRing.BaseBdAddr, 1, XEMACPS_SEND);
}else {
XEmacPs_SetQueuePtr(&(xemacpsif->emacps), xemacpsif->emacps.TxBdRing.BaseBdAddr, 0, XEMACPS_SEND);
}
if (gigeversion > 2)
{
/*
* This version of GEM supports priority queuing and the current
* driver is using tx priority queue 1 and normal rx queue for
* packet transmit and receive. The below code ensure that the
* other queue pointers are parked to known state for avoiding
* the controller to malfunction by fetching the descriptors
* from these queues.
*/
XEmacPs_BdClear(bdrxterminate);
XEmacPs_BdSetAddressRx(bdrxterminate, (XEMACPS_RXBUF_NEW_MASK |
XEMACPS_RXBUF_WRAP_MASK));
XEmacPs_Out32((xemacpsif->emacps.Config.BaseAddress + XEMACPS_RXQ1BASE_OFFSET),
(UINTPTR)bdrxterminate);
XEmacPs_BdClear(bdtxterminate);
XEmacPs_BdSetStatus(bdtxterminate, (XEMACPS_TXBUF_USED_MASK |
XEMACPS_TXBUF_WRAP_MASK));
XEmacPs_Out32((xemacpsif->emacps.Config.BaseAddress + XEMACPS_TXQBASE_OFFSET),
(UINTPTR)bdtxterminate);
}
/*
* Connect the device driver handler that will be called when an
* interrupt for the device occurs, the handler defined above performs
* the specific interrupt processing for the device.
*/
// XScuGic_RegisterHandler(INTC_BASE_ADDR, xtopologyp->scugic_emac_intr,
// (Xil_ExceptionHandler)XEmacPs_IntrHandler,
// (void *)&xemacpsif->emacps);
/*
* Enable the interrupt for emacps.
*/
// XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, (u32) xtopologyp->scugic_emac_intr);
emac_intr_num = (u32) xtopologyp->scugic_emac_intr;
return 0;
}
/*
* resetrx_on_no_rxdata():
*
* It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata
* called by the user.
* The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic.
* Under heavy Rx traffic because of the HW bug there are times when the Rx path
* becomes unresponsive. The workaround for it is to check for the Rx path for
* traffic (by reading the stats registers regularly). If the stats register
* does not increment for sometime (proving no Rx traffic), the function resets
* the Rx data path.
*
*/
void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif)
{
u32_t regctrl;
u32_t tempcntr;
u32_t gigeversion;
gigeversion = ((Xil_In32(xemacpsif->emacps.Config.BaseAddress + 0xFC)) >> 16) & 0xFFF;
if (gigeversion == 2) {
tempcntr = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET);
if ((!tempcntr) && (!(xemacpsif->last_rx_frms_cntr))) {
regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET);
regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK);
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET, regctrl);
regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET);
regctrl |= (XEMACPS_NWCTRL_RXEN_MASK);
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl);
}
xemacpsif->last_rx_frms_cntr = tempcntr;
}
}
void free_txrx_pbufs(xemacpsif_s *xemacpsif)
{
s32_t index;
s32_t index1;
struct pbuf *p;
index1 = get_base_index_txpbufsstorage (xemacpsif);
for (index = index1; index < (index1 + XLWIP_CONFIG_N_TX_DESC); index++) {
if (tx_pbufs_storage[index] != 0) {
p = (struct pbuf *)tx_pbufs_storage[index];
pbuf_free(p);
tx_pbufs_storage[index] = 0;
}
}
for (index = index1; index < (index1 + XLWIP_CONFIG_N_TX_DESC); index++) {
p = (struct pbuf *)rx_pbufs_storage[index];
pbuf_free(p);
}
}
void free_onlytx_pbufs(xemacpsif_s *xemacpsif)
{
s32_t index;
s32_t index1;
struct pbuf *p;
index1 = get_base_index_txpbufsstorage (xemacpsif);
for (index = index1; index < (index1 + XLWIP_CONFIG_N_TX_DESC); index++) {
if (tx_pbufs_storage[index] != 0) {
p = (struct pbuf *)tx_pbufs_storage[index];
pbuf_free(p);
tx_pbufs_storage[index] = 0;
}
}
}
/* reset Tx and Rx DMA pointers after XEmacPs_Stop */
void reset_dma(struct xemac_s *xemac)
{
u8 txqueuenum;
u32_t gigeversion;
xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
XEmacPs_BdRing *txringptr = &XEmacPs_GetTxRing(&xemacpsif->emacps);
XEmacPs_BdRing *rxringptr = &XEmacPs_GetRxRing(&xemacpsif->emacps);
XEmacPs_BdRingPtrReset(txringptr, xemacpsif->tx_bdspace);
XEmacPs_BdRingPtrReset(rxringptr, xemacpsif->rx_bdspace);
gigeversion = ((Xil_In32(xemacpsif->emacps.Config.BaseAddress + 0xFC)) >> 16) & 0xFFF;
if (gigeversion > 2) {
txqueuenum = 1;
} else {
txqueuenum = 0;
}
XEmacPs_SetQueuePtr(&(xemacpsif->emacps), xemacpsif->emacps.RxBdRing.BaseBdAddr, 0, XEMACPS_RECV);
XEmacPs_SetQueuePtr(&(xemacpsif->emacps), xemacpsif->emacps.TxBdRing.BaseBdAddr, txqueuenum, XEMACPS_SEND);
}
void emac_disable_intr(void)
{
// XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, emac_intr_num);
rt_hw_interrupt_mask(emac_intr_num);
}
void emac_enable_intr(void)
{
// XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, emac_intr_num);
rt_hw_interrupt_umask(emac_intr_num);
}

View File

@ -0,0 +1,276 @@
/*
* Copyright (C) 2010 - 2019 Xilinx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#include "netif/xemacpsif.h"
#include "lwipopts.h"
#if XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1 || \
XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1
#define PCM_PMA_CORE_PRESENT
#else
#undef PCM_PMA_CORE_PRESENT
#endif
u32_t link_speed = 100;
extern XEmacPs_Config XEmacPs_ConfigTable[];
extern u32_t phymapemac0[32];
extern u32_t phymapemac1[32];
extern u32_t phyaddrforemac;
extern enum ethernet_link_status eth_link_status;
#ifdef OS_IS_FREERTOS
extern long xInsideISR;
#endif
XEmacPs_Config *xemacps_lookup_config(unsigned mac_base)
{
XEmacPs_Config *cfgptr = NULL;
s32_t i;
for (i = 0; i < XPAR_XEMACPS_NUM_INSTANCES; i++) {
if (XEmacPs_ConfigTable[i].BaseAddress == mac_base) {
cfgptr = &XEmacPs_ConfigTable[i];
break;
}
}
return (cfgptr);
}
void init_emacps(xemacpsif_s *xemacps, struct netif *netif)
{
XEmacPs *xemacpsp;
s32_t status = XST_SUCCESS;
u32_t i;
u32_t phyfoundforemac0 = FALSE;
u32_t phyfoundforemac1 = FALSE;
xemacpsp = &xemacps->emacps;
#ifdef ZYNQMP_USE_JUMBO
XEmacPs_SetOptions(xemacpsp, XEMACPS_JUMBO_ENABLE_OPTION);
#endif
#ifdef LWIP_IGMP
XEmacPs_SetOptions(xemacpsp, XEMACPS_MULTICAST_OPTION);
#endif
/* set mac address */
status = XEmacPs_SetMacAddress(xemacpsp, (void*)(netif->hwaddr), 1);
if (status != XST_SUCCESS) {
xil_printf("In %s:Emac Mac Address set failed...\r\n",__func__);
}
XEmacPs_SetMdioDivisor(xemacpsp, MDC_DIV_224);
/* Please refer to file header comments for the file xemacpsif_physpeed.c
* to know more about the PHY programming sequence.
* For PCS PMA core, phy_setup_emacps is called with the predefined PHY address
* exposed through xaparemeters.h
* For RGMII case, assuming multiple PHYs can be present on the MDIO bus,
* detect_phy is called to get the addresses of the PHY present on
* a particular MDIO bus (emac0 or emac1). This address map is populated
* in phymapemac0 or phymapemac1.
* phy_setup_emacps is then called for each PHY present on the MDIO bus.
*/
#ifdef PCM_PMA_CORE_PRESENT
#ifdef XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT
link_speed = phy_setup_emacps(xemacpsp, XPAR_PCSPMA_1000BASEX_PHYADDR);
#elif XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT
link_speed = phy_setup_emacps(xemacpsp, XPAR_PCSPMA_SGMII_PHYADDR);
#endif
#else
detect_phy(xemacpsp);
for (i = 31; i > 0; i--) {
if (xemacpsp->Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR) {
if (phymapemac0[i] == TRUE) {
link_speed = phy_setup_emacps(xemacpsp, i);
phyfoundforemac0 = TRUE;
phyaddrforemac = i;
}
} else {
if (phymapemac1[i] == TRUE) {
link_speed = phy_setup_emacps(xemacpsp, i);
phyfoundforemac1 = TRUE;
phyaddrforemac = i;
}
}
}
/* If no PHY was detected, use broadcast PHY address of 0 */
if (xemacpsp->Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR) {
if (phyfoundforemac0 == FALSE)
link_speed = phy_setup_emacps(xemacpsp, 0);
} else {
if (phyfoundforemac1 == FALSE)
link_speed = phy_setup_emacps(xemacpsp, 0);
}
#endif
if (link_speed == XST_FAILURE) {
eth_link_status = ETH_LINK_DOWN;
xil_printf("Phy setup failure %s \n\r",__func__);
return;
} else {
eth_link_status = ETH_LINK_UP;
}
XEmacPs_SetOperatingSpeed(xemacpsp, link_speed);
/* Setting the operating speed of the MAC needs a delay. */
{
volatile s32_t wait;
for (wait=0; wait < 20000; wait++);
}
}
void init_emacps_on_error (xemacpsif_s *xemacps, struct netif *netif)
{
XEmacPs *xemacpsp;
s32_t status = XST_SUCCESS;
xemacpsp = &xemacps->emacps;
/* set mac address */
status = XEmacPs_SetMacAddress(xemacpsp, (void*)(netif->hwaddr), 1);
if (status != XST_SUCCESS) {
xil_printf("In %s:Emac Mac Address set failed...\r\n",__func__);
}
XEmacPs_SetOperatingSpeed(xemacpsp, link_speed);
/* Setting the operating speed of the MAC needs a delay. */
{
volatile s32_t wait;
for (wait=0; wait < 20000; wait++);
}
}
void setup_isr (struct xemac_s *xemac)
{
xemacpsif_s *xemacpsif;
xemacpsif = (xemacpsif_s *)(xemac->state);
/*
* Setup callbacks
*/
XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMASEND,
(void *) emacps_send_handler,
(void *) xemac);
XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_DMARECV,
(void *) emacps_recv_handler,
(void *) xemac);
XEmacPs_SetHandler(&xemacpsif->emacps, XEMACPS_HANDLER_ERROR,
(void *) emacps_error_handler,
(void *) xemac);
}
void start_emacps (xemacpsif_s *xemacps)
{
/* start the temac */
XEmacPs_Start(&xemacps->emacps);
}
void restart_emacps_transmitter (xemacpsif_s *xemacps) {
u32_t Reg;
Reg = XEmacPs_ReadReg(xemacps->emacps.Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET);
Reg = Reg & (~XEMACPS_NWCTRL_TXEN_MASK);
XEmacPs_WriteReg(xemacps->emacps.Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET, Reg);
Reg = XEmacPs_ReadReg(xemacps->emacps.Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET);
Reg = Reg | (XEMACPS_NWCTRL_TXEN_MASK);
XEmacPs_WriteReg(xemacps->emacps.Config.BaseAddress,
XEMACPS_NWCTRL_OFFSET, Reg);
}
void emacps_error_handler(void *arg,u8 Direction, u32 ErrorWord)
{
struct xemac_s *xemac;
xemacpsif_s *xemacpsif;
XEmacPs_BdRing *rxring;
XEmacPs_BdRing *txring;
#ifdef OS_IS_FREERTOS
xInsideISR++;
#endif
xemac = (struct xemac_s *)(arg);
xemacpsif = (xemacpsif_s *)(xemac->state);
rxring = &XEmacPs_GetRxRing(&xemacpsif->emacps);
txring = &XEmacPs_GetTxRing(&xemacpsif->emacps);
if (ErrorWord != 0) {
switch (Direction) {
case XEMACPS_RECV:
if (ErrorWord & XEMACPS_RXSR_HRESPNOK_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("Receive DMA error\r\n"));
HandleEmacPsError(xemac);
}
if (ErrorWord & XEMACPS_RXSR_RXOVR_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("Receive over run\r\n"));
emacps_recv_handler(arg);
setup_rx_bds(xemacpsif, rxring);
}
if (ErrorWord & XEMACPS_RXSR_BUFFNA_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("Receive buffer not available\r\n"));
emacps_recv_handler(arg);
setup_rx_bds(xemacpsif, rxring);
}
break;
case XEMACPS_SEND:
if (ErrorWord & XEMACPS_TXSR_HRESPNOK_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("Transmit DMA error\r\n"));
HandleEmacPsError(xemac);
}
if (ErrorWord & XEMACPS_TXSR_URUN_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("Transmit under run\r\n"));
HandleTxErrors(xemac);
}
if (ErrorWord & XEMACPS_TXSR_BUFEXH_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("Transmit buffer exhausted\r\n"));
HandleTxErrors(xemac);
}
if (ErrorWord & XEMACPS_TXSR_RXOVR_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("Transmit retry excessed limits\r\n"));
HandleTxErrors(xemac);
}
if (ErrorWord & XEMACPS_TXSR_FRAMERX_MASK) {
LWIP_DEBUGF(NETIF_DEBUG, ("Transmit collision\r\n"));
// process_sent_bds(xemacpsif, txring);
}
break;
}
}
#ifdef OS_IS_FREERTOS
xInsideISR--;
#endif
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2010 - 2019 Xilinx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#ifndef __XEMACPSIF_HW_H_
#define __XEMACPSIF_HW_H_
#include "netif/xemacpsif.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
XEmacPs_Config * lookup_config(unsigned mac_base);
void init_emacps(xemacpsif_s *xemacpsif, struct netif *netif);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
* Copyright (C) 2007 - 2018 Xilinx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __XLWIPCONFIG_H_
#define __XLWIPCONFIG_H_
/* This is a generated file - do not edit */
#define XLWIP_CONFIG_INCLUDE_GEM 1
#define XLWIP_CONFIG_EMAC_NUMBER 0
#define XLWIP_CONFIG_N_TX_DESC 64
#define XLWIP_CONFIG_N_RX_DESC 64
#endif

View File

@ -0,0 +1,93 @@
/*
* Copyright (C) 2007 - 2019 Xilinx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#include <stdlib.h>
#include "netif/xpqueue.h"
#include "xil_printf.h"
#define NUM_QUEUES 2
pq_queue_t pq_queue[NUM_QUEUES];
pq_queue_t *
pq_create_queue()
{
static int i;
pq_queue_t *q = NULL;
if (i >= NUM_QUEUES) {
xil_printf("ERR: Max Queues allocated\n\r");
return q;
}
q = &pq_queue[i++];
if (!q)
return q;
q->head = q->tail = q->len = 0;
return q;
}
int
pq_enqueue(pq_queue_t *q, void *p)
{
if (q->len == PQ_QUEUE_SIZE)
return -1;
q->data[q->head] = p;
q->head = (q->head + 1)%PQ_QUEUE_SIZE;
q->len++;
return 0;
}
void*
pq_dequeue(pq_queue_t *q)
{
int ptail;
if (q->len == 0)
return NULL;
ptail = q->tail;
q->tail = (q->tail + 1)%PQ_QUEUE_SIZE;
q->len--;
return q->data[ptail];
}
int
pq_qlength(pq_queue_t *q)
{
return q->len;
}

View File

@ -0,0 +1,15 @@
#include "netif/xtopology.h"
#include "xparameters.h"
struct xtopology_t xtopology[] = {
{
0xFF0E0000,
xemac_type_emacps,
0x0,
0x0,
0xF8F00100,
XPAR_XEMACPS_3_INTR,
},
};
int xtopology_n_emacs = 1;

View File

@ -54,6 +54,9 @@ typedef long LONG;
typedef unsigned long ULONG;
#endif
#define ULONG64_HI_MASK 0xFFFFFFFF00000000U
#define ULONG64_LO_MASK ~ULONG64_HI_MASK
/** @{ */
/**
* This data type defines an interrupt handler for a device.

View File

@ -0,0 +1,349 @@
/*
* Copyright (c) 2021, WangHuachen
*
* SPDX-License-Identifier: MIT
*
* Change Logs:
* Date Author Notes
* 2021-5-10 WangHuachen the first version
*/
#include "board.h"
#include <netif/ethernetif.h>
#include "lwipopts.h"
#include "lwip/opt.h"
#include "drv_eth.h"
#include "lwip/netif.h"
#include "netif/xadapter.h"
#include "netif/xemacpsif.h"
#include "xparameters.h"
#include "xemacps.h"
#define DBG_TAG "drv.emac"
#define DBG_LEVEL DBG_INFO
#include <rtdbg.h>
#define MAC_BASE_ADDR XPAR_PSU_ETHERNET_3_BASEADDR
#define MAX_ADDR_LEN 6
struct rt_zynqmp_eth
{
/* inherit from ethernet device */
struct eth_device parent;
/* interface address info, hw address */
rt_uint8_t dev_addr[MAX_ADDR_LEN];
struct xemac_s *xemac;
};
static struct rt_zynqmp_eth zynqmp_eth_device;
extern XEmacPs_Config *mac_config;
extern struct netif *NetIf;
static void rt_hw_eth_isr(int irqno, void *param)
{
struct rt_zynqmp_eth *eth_dev = (struct rt_zynqmp_eth *)param;
xemacpsif_s *xemacpsif = (xemacpsif_s *)eth_dev->xemac->state;
XEmacPs_IntrHandler(&xemacpsif->emacps);
}
extern enum ethernet_link_status eth_link_status;
extern u32_t phy_link_detect(XEmacPs *xemacp, u32_t phy_addr);
extern u32_t phy_autoneg_status(XEmacPs *xemacp, u32_t phy_addr);
extern u32_t phyaddrforemac;
void rt_zynqmp_eth_link_detect(struct rt_zynqmp_eth *eth_dev)
{
u32_t link_speed, phy_link_status;
struct xemac_s *xemac = eth_dev->xemac;
xemacpsif_s *xemacs = (xemacpsif_s *)(xemac->state);
XEmacPs *xemacp = &xemacs->emacps;
if ((xemacp->IsReady != (u32)XIL_COMPONENT_IS_READY) ||
(eth_link_status == ETH_LINK_UNDEFINED))
return;
phy_link_status = phy_link_detect(xemacp, phyaddrforemac);
if ((eth_link_status == ETH_LINK_UP) && (!phy_link_status))
eth_link_status = ETH_LINK_DOWN;
switch (eth_link_status) {
case ETH_LINK_UNDEFINED:
case ETH_LINK_UP:
return;
case ETH_LINK_DOWN:
eth_device_linkchange(&zynqmp_eth_device.parent, RT_FALSE);
eth_link_status = ETH_LINK_NEGOTIATING;
LOG_D("Ethernet Link down");
break;
case ETH_LINK_NEGOTIATING:
if (phy_link_status &&
phy_autoneg_status(xemacp, phyaddrforemac)) {
/* Initiate Phy setup to get link speed */
link_speed = phy_setup_emacps(xemacp,
phyaddrforemac);
XEmacPs_SetOperatingSpeed(xemacp, link_speed);
eth_device_linkchange(&zynqmp_eth_device.parent, RT_TRUE);
eth_link_status = ETH_LINK_UP;
LOG_D("Ethernet Link up");
}
break;
}
}
static void phy_monitor_thread(void *parameter)
{
struct rt_zynqmp_eth *eth_dev = (struct rt_zynqmp_eth *)parameter;
while (1)
{
rt_zynqmp_eth_link_detect(eth_dev);
rt_thread_delay(RT_TICK_PER_SECOND);
}
}
static rt_err_t rt_zynqmp_eth_init(rt_device_t dev)
{
struct rt_zynqmp_eth *eth_dev = (struct rt_zynqmp_eth *)dev->user_data;
struct netif *netif = eth_dev->parent.netif;
struct xemac_s *xemac;
xemacpsif_s *xemacpsif;
u32 dmacrreg;
s32_t status = XST_SUCCESS;
struct xtopology_t *xtopologyp;
if (eth_dev->xemac != RT_NULL)
{
LOG_W("rt_zynqmp_eth_init: device has been initialized");
return -RT_ERROR;
}
NetIf = netif;
xemacpsif = rt_malloc(sizeof *xemacpsif);
if (xemacpsif == NULL)
{
LOG_E("rt_zynqmp_eth_init: out of memory");
return -RT_ENOMEM;
}
xemac = rt_malloc(sizeof *xemac);
if (xemac == NULL)
{
LOG_E("rt_zynqmp_eth_init: out of memory");
return -RT_ENOMEM;
}
xemac->state = (void *)xemacpsif;
xemac->topology_index = xtopology_find_index(MAC_BASE_ADDR);
xemac->type = xemac_type_emacps;
xemac->rt_eth_device = &eth_dev->parent;
xemacpsif->send_q = NULL;
xemacpsif->recv_q = pq_create_queue();
if (!xemacpsif->recv_q)
return -RT_ENOMEM;
eth_dev->xemac = xemac;
/* obtain config of this emac */
mac_config = (XEmacPs_Config *)xemacps_lookup_config(MAC_BASE_ADDR);
status = XEmacPs_CfgInitialize(&xemacpsif->emacps, mac_config,
mac_config->BaseAddress);
if (status != XST_SUCCESS)
{
LOG_W("In %s:EmacPs Configuration Failed....", __func__);
return -RT_ERROR;
}
/* initialize the mac */
init_emacps(xemacpsif, netif);
dmacrreg = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,
XEMACPS_DMACR_OFFSET);
dmacrreg = dmacrreg | (0x00000010);
XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,
XEMACPS_DMACR_OFFSET, dmacrreg);
setup_isr(xemac);
init_dma(xemac);
xtopologyp = &xtopology[xemac->topology_index];
/*
* Connect the device driver handler that will be called when an
* interrupt for the device occurs, the handler defined above performs
* the specific interrupt processing for the device.
*/
rt_hw_interrupt_install(xtopologyp->scugic_emac_intr, rt_hw_eth_isr, (void *)eth_dev, "eth");
/*
* Enable the interrupt for emacps.
*/
rt_hw_interrupt_umask(xtopologyp->scugic_emac_intr);
start_emacps(xemacpsif);
if (eth_link_status == ETH_LINK_UP)
eth_device_linkchange(&eth_dev->parent, RT_TRUE);
rt_thread_t tid;
tid = rt_thread_create("phylnk",
phy_monitor_thread,
eth_dev,
1024,
RT_THREAD_PRIORITY_MAX - 2,
2);
if (tid != RT_NULL)
rt_thread_startup(tid);
else
return -RT_ERROR;
return RT_EOK;
}
static rt_err_t rt_zynqmp_eth_open(rt_device_t dev, rt_uint16_t oflag)
{
LOG_D("emac open");
return RT_EOK;
}
static rt_err_t rt_zynqmp_eth_close(rt_device_t dev)
{
LOG_D("emac close");
return RT_EOK;
}
static rt_size_t rt_zynqmp_eth_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
LOG_D("emac read");
rt_set_errno(-RT_ENOSYS);
return 0;
}
static rt_size_t rt_zynqmp_eth_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
LOG_D("emac write");
rt_set_errno(-RT_ENOSYS);
return 0;
}
static rt_err_t rt_zynqmp_eth_control(rt_device_t dev, int cmd, void *args)
{
struct rt_zynqmp_eth *eth_dev = (struct rt_zynqmp_eth *)dev->user_data;
switch (cmd)
{
case NIOCTL_GADDR:
/* get mac address */
if (args) rt_memcpy(args, eth_dev->dev_addr, 6);
else return -RT_ERROR;
break;
default :
break;
}
return RT_EOK;
}
extern err_t _unbuffered_low_level_output(xemacpsif_s *xemacpsif, struct pbuf *p);
rt_err_t rt_zynqmp_eth_tx(rt_device_t dev, struct pbuf *p)
{
rt_base_t lev;
rt_err_t err;
XEmacPs_BdRing *txring;
struct rt_zynqmp_eth *eth_dev = (struct rt_zynqmp_eth *)dev->user_data;
struct xemac_s *xemac = eth_dev->xemac;
xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
lev = rt_hw_interrupt_disable();
txring = &(XEmacPs_GetTxRing(&xemacpsif->emacps));
process_sent_bds(xemacpsif, txring);
if (is_tx_space_available(xemacpsif))
{
_unbuffered_low_level_output(xemacpsif, p);
err = RT_EOK;
}
else
{
#if LINK_STATS
lwip_stats.link.drop++;
#endif
LOG_D("pack dropped, no space");
err = -RT_ENOMEM;
}
rt_hw_interrupt_enable(lev);
return err;
}
struct pbuf *rt_zynqmp_eth_rx(rt_device_t dev)
{
rt_base_t lev;
struct rt_zynqmp_eth *eth_dev = (struct rt_zynqmp_eth *)dev->user_data;
struct xemac_s *xemac = eth_dev->xemac;
xemacpsif_s *xemacpsif = (xemacpsif_s *)(xemac->state);
struct pbuf *p;
lev = rt_hw_interrupt_disable();
/* see if there is data to process */
if (pq_qlength(xemacpsif->recv_q) == 0)
return NULL;
/* return one packet from receive q */
p = (struct pbuf *)pq_dequeue(xemacpsif->recv_q);
rt_hw_interrupt_enable(lev);
return p;
}
static int rt_hw_zynqmp_eth_init(void)
{
rt_err_t state = RT_EOK;
zynqmp_eth_device.xemac = RT_NULL;
zynqmp_eth_device.dev_addr[0] = 0x00;
zynqmp_eth_device.dev_addr[1] = 0x0A;
zynqmp_eth_device.dev_addr[2] = 0x35;
zynqmp_eth_device.dev_addr[3] = 0x00;
zynqmp_eth_device.dev_addr[4] = 0x01;
zynqmp_eth_device.dev_addr[5] = 0x02;
zynqmp_eth_device.parent.parent.init = rt_zynqmp_eth_init;
zynqmp_eth_device.parent.parent.open = rt_zynqmp_eth_open;
zynqmp_eth_device.parent.parent.close = rt_zynqmp_eth_close;
zynqmp_eth_device.parent.parent.read = rt_zynqmp_eth_read;
zynqmp_eth_device.parent.parent.write = rt_zynqmp_eth_write;
zynqmp_eth_device.parent.parent.control = rt_zynqmp_eth_control;
zynqmp_eth_device.parent.parent.user_data = &zynqmp_eth_device;
zynqmp_eth_device.parent.eth_rx = rt_zynqmp_eth_rx;
zynqmp_eth_device.parent.eth_tx = rt_zynqmp_eth_tx;
/* register eth device */
state = eth_device_init(&(zynqmp_eth_device.parent), "e0");
if (RT_EOK == state)
{
LOG_D("emac device init success");
}
else
{
LOG_E("emac device init faild: %d", state);
state = -RT_ERROR;
return state;
}
return state;
}
INIT_DEVICE_EXPORT(rt_hw_zynqmp_eth_init);

View File

@ -0,0 +1,13 @@
#ifndef __DRV_ETH_H__
#define __DRV_ETH_H__
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif

View File

@ -19,6 +19,9 @@
#define RT_USING_TIMER_SOFT
#define RT_TIMER_THREAD_PRIO 4
#define RT_TIMER_THREAD_STACK_SIZE 512
/* kservice optimization */
#define RT_DEBUG
/* Inter-Thread communication */
@ -32,7 +35,7 @@
/* Memory Management */
#define RT_USING_MEMPOOL
#define RT_USING_SMALL_MEM
#define RT_USING_SLAB
#define RT_USING_HEAP
/* Kernel Device Object */
@ -41,7 +44,7 @@
#define RT_USING_CONSOLE
#define RT_CONSOLEBUF_SIZE 128
#define RT_CONSOLE_DEVICE_NAME "uart0"
#define RT_VER_NUM 0x40003
#define RT_VER_NUM 0x40004
/* RT-Thread Components */
@ -83,6 +86,8 @@
#define RT_DFS_ELM_WORD_ACCESS
#define RT_DFS_ELM_USE_LFN_3
#define RT_DFS_ELM_USE_LFN 3
#define RT_DFS_ELM_LFN_UNICODE_0
#define RT_DFS_ELM_LFN_UNICODE 0
#define RT_DFS_ELM_MAX_LFN 255
#define RT_DFS_ELM_DRIVES 2
#define RT_DFS_ELM_MAX_SECTOR_SIZE 512
@ -93,6 +98,9 @@
#define RT_USING_DEVICE_IPC
#define RT_PIPE_BUFSZ 512
#define RT_USING_SYSTEM_WORKQUEUE
#define RT_SYSTEM_WORKQUEUE_STACKSIZE 2048
#define RT_SYSTEM_WORKQUEUE_PRIORITY 23
#define RT_USING_SERIAL
#define RT_SERIAL_USING_DMA
#define RT_SERIAL_RB_BUFSZ 64
@ -101,24 +109,77 @@
/* Using USB */
/* Using RapidIO */
/* POSIX layer and C standard library */
#define RT_USING_LIBC
#define RT_USING_POSIX
#define RT_LIBC_FIXED_TIMEZONE 8
/* Network */
/* Socket abstraction layer */
#define RT_USING_SAL
#define SAL_INTERNET_CHECK
/* protocol stack implement */
#define SAL_USING_LWIP
#define SAL_USING_POSIX
/* Network interface device */
#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
/* light weight TCP/IP stack */
#define RT_USING_LWIP
#define RT_USING_LWIP202
#define RT_LWIP_MEM_ALIGNMENT 32
#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"
#define RT_LWIP_UDP
#define RT_LWIP_TCP
#define RT_LWIP_RAW
#define RT_MEMP_NUM_NETCONN 8
#define RT_LWIP_PBUF_NUM 256
#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 2048
#define RT_LWIP_ETHTHREAD_PRIORITY 12
#define RT_LWIP_ETHTHREAD_STACKSIZE 1024
#define RT_LWIP_ETHTHREAD_MBOX_SIZE 8
#define LWIP_NETIF_STATUS_CALLBACK 1
#define LWIP_NETIF_LINK_CALLBACK 1
#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
/* AT commands */
@ -129,6 +190,9 @@
/* Utilities */
/* RT-Thread Utestcases */
/* RT-Thread online packages */
/* IoT - internet of things */
@ -166,11 +230,17 @@
/* peripheral libraries and drivers */
/* AI packages */
/* miscellaneous packages */
/* samples: kernel and components samples */
/* entertainment: terminal games and other interesting software packages */
#define SOC_ZYNQMP_R5
/* Hardware Drivers Config */
@ -184,6 +254,13 @@
#define BSP_USING_SDIO
#define BSP_USING_SD0
/* Please set RT_LWIP_PBUF_NUM is at least 256 if Enable Ethernet! */
/* Please set RT_LWIP_MEM_ALIGNMENT is at 32 if Enable Ethernet! */
#define BSP_USING_ETH
#define RT_LWIP_PBUF_POOL_BUFSIZE 1700
/* Board extended module Drivers */

View File

@ -1,11 +1,13 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
* Copyright (c) 2014 - 2020 Xilinx, Inc. All rights reserved.
* Copyright (c) 2021 WangHuachen. All rights reserved.
* SPDX-License-Identifier: MIT
*
* Change Logs:
* Date Author Notes
* 2020-03-19 WangHuachen first version
* 2021-05-10 WangHuachen add more functions
*/
#include <rthw.h>
#include <rtdef.h>
@ -44,41 +46,85 @@ typedef rt_uint32_t u32;
XREG_CP15_INVAL_IC_LINE_MVA_POU :: "r" (param))
#endif
void Xil_DCacheEnable(void);
void Xil_DCacheDisable(void);
void Xil_DCacheInvalidate(void);
void Xil_DCacheInvalidateRange(INTPTR adr, u32 len);
void Xil_DCacheFlush(void);
void Xil_DCacheFlushRange(INTPTR adr, u32 len);
void Xil_DCacheInvalidateLine(INTPTR adr);
void Xil_DCacheFlushLine(INTPTR adr);
void Xil_DCacheStoreLine(INTPTR adr);
void Xil_ICacheEnable(void);
void Xil_ICacheDisable(void);
void Xil_ICacheInvalidate(void);
void Xil_ICacheInvalidateRange(INTPTR adr, u32 len);
void Xil_ICacheInvalidateLine(INTPTR adr);
void Xil_ICacheInvalidateRange(INTPTR adr, u32 len)
void Xil_DCacheEnable(void)
{
register u32 CtrlReg;
/* enable caches only if they are disabled */
#if defined (__GNUC__)
CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_SYS_CONTROL,CtrlReg);
#endif
if ((CtrlReg & XREG_CP15_CONTROL_C_BIT)==0x00000000U) {
/* invalidate the Data cache */
Xil_DCacheInvalidate();
/* enable the Data cache */
CtrlReg |= (XREG_CP15_CONTROL_C_BIT);
mtcp(XREG_CP15_SYS_CONTROL, CtrlReg);
}
}
void Xil_DCacheDisable(void)
{
register u32 CtrlReg;
/* clean and invalidate the Data cache */
Xil_DCacheFlush();
/* disable the Data cache */
#if defined (__GNUC__)
CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_SYS_CONTROL,CtrlReg);
#endif
CtrlReg &= ~(XREG_CP15_CONTROL_C_BIT);
mtcp(XREG_CP15_SYS_CONTROL, CtrlReg);
}
void Xil_DCacheInvalidate(void)
{
u32 LocalAddr = adr;
const u32 cacheline = 32U;
u32 end;
u32 currmask;
currmask = mfcpsr();
mtcpsr(currmask | IRQ_FIQ_MASK);
if (len != 0x00000000U) {
/* Back the starting address up to the start of a cache line
* perform cache operations until adr+len
*/
end = LocalAddr + len;
LocalAddr = LocalAddr & ~(cacheline - 1U);
/* Select cache L0 I-cache in CSSR */
mtcp(XREG_CP15_CACHE_SIZE_SEL, 1U);
#if 0
stack_end = (u32 )&_stack_end;
stack_start = (u32 )&__undef_stack;
stack_size = stack_start-stack_end;
while (LocalAddr < end) {
/* Flush stack memory to save return address */
Xil_DCacheFlushRange(stack_end, stack_size);
#endif
mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);
/* Invalidate L1 I-cache line */
asm_inval_ic_line_mva_pou(LocalAddr);
/*invalidate all D cache*/
mtcp(XREG_CP15_INVAL_DC_ALL, 0);
LocalAddr += cacheline;
}
}
/* Wait for invalidate to complete */
dsb();
mtcpsr(currmask);
}
void Xil_DCacheFlushLine(INTPTR adr)
void Xil_DCacheInvalidateLine(INTPTR adr)
{
u32 currmask;
@ -86,11 +132,11 @@ void Xil_DCacheFlushLine(INTPTR adr)
mtcpsr(currmask | IRQ_FIQ_MASK);
mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);
mtcp(XREG_CP15_INVAL_DC_LINE_MVA_POC, (adr & (~0x1F)));
mtcp(XREG_CP15_CLEAN_INVAL_DC_LINE_MVA_POC, (adr & (~0x1F)));
/* Wait for flush to complete */
/* Wait for invalidate to complete */
dsb();
mtcpsr(currmask);
}
@ -135,6 +181,79 @@ void Xil_DCacheInvalidateRange(INTPTR adr, u32 len)
mtcpsr(currmask);
}
void Xil_DCacheFlush(void)
{
register u32 CsidReg, C7Reg;
u32 CacheSize, LineSize, NumWays;
u32 Way, WayIndex, Set, SetIndex, NumSet;
u32 currmask;
currmask = mfcpsr();
mtcpsr(currmask | IRQ_FIQ_MASK);
/* Select cache level 0 and D cache in CSSR */
mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);
#if defined (__GNUC__)
CsidReg = mfcp(XREG_CP15_CACHE_SIZE_ID);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_CACHE_SIZE_ID,CsidReg);
#endif
/* Determine Cache Size */
CacheSize = (CsidReg >> 13U) & 0x000001FFU;
CacheSize += 0x00000001U;
CacheSize *= (u32)128; /* to get number of bytes */
/* Number of Ways */
NumWays = (CsidReg & 0x000003ffU) >> 3U;
NumWays += 0x00000001U;
/* Get the cacheline size, way size, index size from csidr */
LineSize = (CsidReg & 0x00000007U) + 0x00000004U;
NumSet = CacheSize/NumWays;
NumSet /= (0x00000001U << LineSize);
Way = 0U;
Set = 0U;
/* Invalidate all the cachelines */
for (WayIndex = 0U; WayIndex < NumWays; WayIndex++) {
for (SetIndex = 0U; SetIndex < NumSet; SetIndex++) {
C7Reg = Way | Set;
/* Flush by Set/Way */
asm_clean_inval_dc_line_sw(C7Reg);
Set += (0x00000001U << LineSize);
}
Set = 0U;
Way += 0x40000000U;
}
/* Wait for flush to complete */
dsb();
mtcpsr(currmask);
mtcpsr(currmask);
}
void Xil_DCacheFlushLine(INTPTR adr)
{
u32 currmask;
currmask = mfcpsr();
mtcpsr(currmask | IRQ_FIQ_MASK);
mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);
mtcp(XREG_CP15_CLEAN_INVAL_DC_LINE_MVA_POC, (adr & (~0x1F)));
/* Wait for flush to complete */
dsb();
mtcpsr(currmask);
}
void Xil_DCacheFlushRange(INTPTR adr, u32 len)
{
u32 LocalAddr = adr;
@ -163,6 +282,130 @@ void Xil_DCacheFlushRange(INTPTR adr, u32 len)
mtcpsr(currmask);
}
void Xil_DCacheStoreLine(INTPTR adr)
{
u32 currmask;
currmask = mfcpsr();
mtcpsr(currmask | IRQ_FIQ_MASK);
mtcp(XREG_CP15_CACHE_SIZE_SEL, 0);
mtcp(XREG_CP15_CLEAN_DC_LINE_MVA_POC, (adr & (~0x1F)));
/* Wait for store to complete */
dsb();
isb();
mtcpsr(currmask);
}
void Xil_ICacheEnable(void)
{
register u32 CtrlReg;
/* enable caches only if they are disabled */
#if defined (__GNUC__)
CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_SYS_CONTROL, CtrlReg);
#endif
if ((CtrlReg & XREG_CP15_CONTROL_I_BIT)==0x00000000U) {
/* invalidate the instruction cache */
mtcp(XREG_CP15_INVAL_IC_POU, 0);
/* enable the instruction cache */
CtrlReg |= (XREG_CP15_CONTROL_I_BIT);
mtcp(XREG_CP15_SYS_CONTROL, CtrlReg);
}
}
void Xil_ICacheDisable(void)
{
register u32 CtrlReg;
dsb();
/* invalidate the instruction cache */
mtcp(XREG_CP15_INVAL_IC_POU, 0);
/* disable the instruction cache */
#if defined (__GNUC__)
CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_SYS_CONTROL,CtrlReg);
#endif
CtrlReg &= ~(XREG_CP15_CONTROL_I_BIT);
mtcp(XREG_CP15_SYS_CONTROL, CtrlReg);
}
void Xil_ICacheInvalidate(void)
{
u32 currmask;
currmask = mfcpsr();
mtcpsr(currmask | IRQ_FIQ_MASK);
mtcp(XREG_CP15_CACHE_SIZE_SEL, 1);
/* invalidate the instruction cache */
mtcp(XREG_CP15_INVAL_IC_POU, 0);
/* Wait for invalidate to complete */
dsb();
mtcpsr(currmask);
}
void Xil_ICacheInvalidateLine(INTPTR adr)
{
u32 currmask;
currmask = mfcpsr();
mtcpsr(currmask | IRQ_FIQ_MASK);
mtcp(XREG_CP15_CACHE_SIZE_SEL, 1);
mtcp(XREG_CP15_INVAL_IC_LINE_MVA_POU, (adr & (~0x1F)));
/* Wait for invalidate to complete */
dsb();
mtcpsr(currmask);
}
void Xil_ICacheInvalidateRange(INTPTR adr, u32 len)
{
u32 LocalAddr = adr;
const u32 cacheline = 32U;
u32 end;
u32 currmask;
currmask = mfcpsr();
mtcpsr(currmask | IRQ_FIQ_MASK);
if (len != 0x00000000U) {
/* Back the starting address up to the start of a cache line
* perform cache operations until adr+len
*/
end = LocalAddr + len;
LocalAddr = LocalAddr & ~(cacheline - 1U);
/* Select cache L0 I-cache in CSSR */
mtcp(XREG_CP15_CACHE_SIZE_SEL, 1U);
while (LocalAddr < end) {
/* Invalidate L1 I-cache line */
asm_inval_ic_line_mva_pou(LocalAddr);
LocalAddr += cacheline;
}
}
/* Wait for invalidate to complete */
dsb();
mtcpsr(currmask);
}
void rt_hw_cpu_icache_ops(int ops, void *addr, int size)
{
if (ops == RT_HW_CACHE_INVALIDATE)

View File

@ -6,6 +6,9 @@
* Change Logs:
* Date Author Notes
* 2020-03-19 WangHuachen first version
* 2021-05-11 WangHuachen Added call to Xil_InitializeExistingMPURegConfig to
* initialize the MPU configuration table with the MPU
* configurations already set in Init_Mpu function.
*/
.equ Mode_USR, 0x10
@ -234,6 +237,7 @@ ctor_loop:
b ctor_loop
ctor_end:
bl Xil_InitializeExistingMPURegConfig /* Initialize MPU config */
/* start RT-Thread Kernel */
ldr pc, _entry

View File

@ -0,0 +1,54 @@
/******************************************************************************
* Copyright (c) 2015 - 2020 Xilinx, Inc. All rights reserved.
* SPDX-License-Identifier: MIT
******************************************************************************/
/*****************************************************************************/
/**
* @file xil_mmu.h
* This file only includes xil_mpu.h which contains Xil_SetTlbAttributes API
* defined for MPU in R5. R5 does not have mmu and for usage of similar API
* the file has been created.
*
*
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- ---------------------------------------------------
* 5.0 pkp 2/12/15 Initial version
* </pre>
*
* @note
*
* None.
*
******************************************************************************/
#ifndef XIL_MMU_H
#define XIL_MMU_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/***************************** Include Files *********************************/
#include "xil_mpu.h"
/***************** Macros (Inline Functions) Definitions *********************/
/**************************** Type Definitions *******************************/
/************************** Constant Definitions *****************************/
/************************** Variable Definitions *****************************/
/************************** Function Prototypes ******************************/
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* XIL_MMU_H */

View File

@ -0,0 +1,637 @@
/******************************************************************************
*
* Copyright (C) 2014 - 2017 Xilinx, Inc. All rights reserved.
* Copyright (C) 2021 WangHuachen. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*
*
******************************************************************************/
/*****************************************************************************/
/**
* @file xil_mpu.c
*
* This file provides APIs for enabling/disabling MPU and setting the memory
* attributes for sections, in the MPU translation table.
*
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- ---------------------------------------------------
* 5.00 pkp 02/10/14 Initial version
* 6.2 mus 01/27/17 Updated to support IAR compiler
* 6.4 asa 08/16/17 Added many APIs for MPU access to make MPU usage
* user-friendly. The APIs added are: Xil_UpdateMPUConfig,
* Xil_GetMPUConfig, Xil_GetNumOfFreeRegions,
* Xil_GetNextMPURegion, Xil_DisableMPURegionByRegNum,
* Xil_GetMPUFreeRegMask, Xil_SetMPURegionByRegNum, and
* Xil_InitializeExistingMPURegConfig.
* Added a new array of structure of type XMpuConfig to
* represent the MPU configuration table.
* 6.8 aru 07/02/18 Returned the pointer instead of address
* of that pointer in Xil_MemMap().
* </pre>
*
*
******************************************************************************/
/***************************** Include Files *********************************/
#include "xil_cache.h"
#include "xpseudo_asm_gcc.h"
#include "xil_types.h"
#include "xil_mpu.h"
// #include "xdebug.h"
#include "xreg_cortexr5.h"
#include "xstatus.h"
#include <rtthread.h>
#define DBG_TAG "xil_mpu"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
extern void Xil_DCacheFlush(void);
extern void Xil_ICacheInvalidate(void);
extern void Xil_DCacheDisable(void);
extern void Xil_ICacheDisable(void);
extern void Xil_DCacheEnable(void);
extern void Xil_ICacheEnable(void);
/***************** Macros (Inline Functions) Definitions *********************/
/**************************** Type Definitions *******************************/
/************************** Constant Definitions *****************************/
#define MPU_REGION_SIZE_MIN 0x20
/************************** Variable Definitions *****************************/
static const struct {
u64 size;
unsigned int encoding;
}region_size[] = {
{ 0x20, REGION_32B },
{ 0x40, REGION_64B },
{ 0x80, REGION_128B },
{ 0x100, REGION_256B },
{ 0x200, REGION_512B },
{ 0x400, REGION_1K },
{ 0x800, REGION_2K },
{ 0x1000, REGION_4K },
{ 0x2000, REGION_8K },
{ 0x4000, REGION_16K },
{ 0x8000, REGION_32K },
{ 0x10000, REGION_64K },
{ 0x20000, REGION_128K },
{ 0x40000, REGION_256K },
{ 0x80000, REGION_512K },
{ 0x100000, REGION_1M },
{ 0x200000, REGION_2M },
{ 0x400000, REGION_4M },
{ 0x800000, REGION_8M },
{ 0x1000000, REGION_16M },
{ 0x2000000, REGION_32M },
{ 0x4000000, REGION_64M },
{ 0x8000000, REGION_128M },
{ 0x10000000, REGION_256M },
{ 0x20000000, REGION_512M },
{ 0x40000000, REGION_1G },
{ 0x80000000, REGION_2G },
{ 0x100000000, REGION_4G },
};
XMpu_Config Mpu_Config;
/************************** Function Prototypes ******************************/
void Xil_InitializeExistingMPURegConfig(void);
/*****************************************************************************/
/**
* @brief This function sets the memory attributes for a section covering
* 1MB, of memory in the translation table.
*
* @param Addr: 32-bit address for which memory attributes need to be set.
* @param attrib: Attribute for the given memory region.
* @return None.
*
*
******************************************************************************/
void Xil_SetTlbAttributes(INTPTR addr, u32 attrib)
{
INTPTR Localaddr = addr;
Localaddr &= (~(0xFFFFFU));
/* Setting the MPU region with given attribute with 1MB size */
Xil_SetMPURegion(Localaddr, 0x100000, attrib);
}
/*****************************************************************************/
/**
* @brief Set the memory attributes for a section of memory in the
* translation table.
*
* @param Addr: 32-bit address for which memory attributes need to be set..
* @param size: size is the size of the region.
* @param attrib: Attribute for the given memory region.
* @return None.
*
*
******************************************************************************/
u32 Xil_SetMPURegion(INTPTR addr, u64 size, u32 attrib)
{
u32 Regionsize = 0;
INTPTR Localaddr = addr;
u32 NextAvailableMemRegion;
unsigned int i;
NextAvailableMemRegion = Xil_GetNextMPURegion();
if (NextAvailableMemRegion == 0xFF) {
LOG_E("No regions available\r\n");
return XST_FAILURE;
}
Xil_DCacheFlush();
Xil_ICacheInvalidate();
mtcp(XREG_CP15_MPU_MEMORY_REG_NUMBER,NextAvailableMemRegion);
isb();
/* Lookup the size. */
for (i = 0; i < sizeof region_size / sizeof region_size[0]; i++) {
if (size <= region_size[i].size) {
Regionsize = region_size[i].encoding;
break;
}
}
Localaddr &= ~(region_size[i].size - 1);
Regionsize <<= 1;
Regionsize |= REGION_EN;
dsb();
mtcp(XREG_CP15_MPU_REG_BASEADDR, Localaddr); /* Set base address of a region */
mtcp(XREG_CP15_MPU_REG_ACCESS_CTRL, attrib); /* Set the control attribute */
mtcp(XREG_CP15_MPU_REG_SIZE_EN, Regionsize); /* set the region size and enable it*/
dsb();
isb();
Xil_UpdateMPUConfig(NextAvailableMemRegion, Localaddr, Regionsize, attrib);
return XST_SUCCESS;
}
/*****************************************************************************/
/**
* @brief Enable MPU for Cortex R5 processor. This function invalidates I
* cache and flush the D Caches, and then enables the MPU.
*
*
* @param None.
* @return None.
*
******************************************************************************/
void Xil_EnableMPU(void)
{
u32 CtrlReg, Reg;
s32 DCacheStatus=0, ICacheStatus=0;
/* enable caches only if they are disabled */
#if defined (__GNUC__)
CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_SYS_CONTROL,CtrlReg);
#endif
if ((CtrlReg & XREG_CP15_CONTROL_C_BIT) != 0x00000000U) {
DCacheStatus=1;
}
if ((CtrlReg & XREG_CP15_CONTROL_I_BIT) != 0x00000000U) {
ICacheStatus=1;
}
if(DCacheStatus != 0) {
Xil_DCacheDisable();
}
if(ICacheStatus != 0){
Xil_ICacheDisable();
}
#if defined (__GNUC__)
Reg = mfcp(XREG_CP15_SYS_CONTROL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_SYS_CONTROL,Reg);
#endif
Reg |= 0x00000001U;
dsb();
mtcp(XREG_CP15_SYS_CONTROL, Reg);
isb();
/* enable caches only if they are disabled in routine*/
if(DCacheStatus != 0) {
Xil_DCacheEnable();
}
if(ICacheStatus != 0) {
Xil_ICacheEnable();
}
}
/*****************************************************************************/
/**
* @brief Disable MPU for Cortex R5 processors. This function invalidates I
* cache and flush the D Caches, and then disabes the MPU.
*
* @param None.
*
* @return None.
*
******************************************************************************/
void Xil_DisableMPU(void)
{
u32 CtrlReg, Reg;
s32 DCacheStatus=0, ICacheStatus=0;
/* enable caches only if they are disabled */
#if defined (__GNUC__)
CtrlReg = mfcp(XREG_CP15_SYS_CONTROL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_SYS_CONTROL,CtrlReg);
#endif
if ((CtrlReg & XREG_CP15_CONTROL_C_BIT) != 0x00000000U) {
DCacheStatus=1;
}
if ((CtrlReg & XREG_CP15_CONTROL_I_BIT) != 0x00000000U) {
ICacheStatus=1;
}
if(DCacheStatus != 0) {
Xil_DCacheDisable();
}
if(ICacheStatus != 0){
Xil_ICacheDisable();
}
mtcp(XREG_CP15_INVAL_BRANCH_ARRAY, 0);
#if defined (__GNUC__)
Reg = mfcp(XREG_CP15_SYS_CONTROL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_SYS_CONTROL,Reg);
#endif
Reg &= ~(0x00000001U);
dsb();
mtcp(XREG_CP15_SYS_CONTROL, Reg);
isb();
/* enable caches only if they are disabled in routine*/
if(DCacheStatus != 0) {
Xil_DCacheEnable();
}
if(ICacheStatus != 0) {
Xil_ICacheEnable();
}
}
/*****************************************************************************/
/**
* @brief Update the MPU configuration for the requested region number in
* the global MPU configuration table.
*
* @param reg_num: The requested region number to be updated information for.
* @param address: 32 bit address for start of the region.
* @param size: Requested size of the region.
* @param attrib: Attribute for the corresponding region.
* @return XST_FAILURE: When the requested region number if 16 or more.
* XST_SUCCESS: When the MPU configuration table is updated.
*
*
******************************************************************************/
u32 Xil_UpdateMPUConfig(u32 reg_num, INTPTR address, u32 size, u32 attrib)
{
u32 ReturnVal = XST_SUCCESS;
u32 Tempsize = size;
u32 Index;
if (reg_num >= MAX_POSSIBLE_MPU_REGS) {
LOG_E("Invalid region number\r\n");
ReturnVal = XST_FAILURE;
goto exit;
}
if (size & REGION_EN) {
Mpu_Config[reg_num].RegionStatus = MPU_REG_ENABLED;
Mpu_Config[reg_num].BaseAddress = address;
Tempsize &= (~REGION_EN);
Tempsize >>= 1;
/* Lookup the size. */
for (Index = 0; Index <
sizeof region_size / sizeof region_size[0]; Index++) {
if (Tempsize <= region_size[Index].encoding) {
Mpu_Config[reg_num].Size = region_size[Index].size;
break;
}
}
Mpu_Config[reg_num].Attribute = attrib;
} else {
Mpu_Config[reg_num].RegionStatus = 0U;
Mpu_Config[reg_num].BaseAddress = 0U;
Mpu_Config[reg_num].Size = 0U;
Mpu_Config[reg_num].Attribute = 0U;
}
exit:
return ReturnVal;
}
/*****************************************************************************/
/**
* @brief The MPU configuration table is passed to the caller.
*
* @param mpuconfig: This is of type XMpu_Config which is an array of
* 16 entries of type structure representing the MPU config table
* @return none
*
*
******************************************************************************/
void Xil_GetMPUConfig (XMpu_Config mpuconfig) {
u32 Index = 0U;
while (Index < MAX_POSSIBLE_MPU_REGS) {
mpuconfig[Index].RegionStatus = Mpu_Config[Index].RegionStatus;
mpuconfig[Index].BaseAddress = Mpu_Config[Index].BaseAddress;
mpuconfig[Index].Attribute = Mpu_Config[Index].Attribute;
mpuconfig[Index].Size = Mpu_Config[Index].Size;
Index++;
}
}
/*****************************************************************************/
/**
* @brief Returns the total number of free MPU regions available.
*
* @param none
* @return Number of free regions available to users
*
*
******************************************************************************/
u32 Xil_GetNumOfFreeRegions (void) {
u32 Index = 0U;
int NumofFreeRegs = 0U;
while (Index < MAX_POSSIBLE_MPU_REGS) {
if (MPU_REG_DISABLED == Mpu_Config[Index].RegionStatus) {
NumofFreeRegs++;
}
Index++;
}
return NumofFreeRegs;
}
/*****************************************************************************/
/**
* @brief Returns the total number of free MPU regions available in the form
* of a mask. A bit of 1 in the returned 16 bit value represents the
* corresponding region number to be available.
* For example, if this function returns 0xC0000, this would mean, the
* regions 14 and 15 are available to users.
*
* @param none
* @return The free region mask as a 16 bit value
*
*
******************************************************************************/
u16 Xil_GetMPUFreeRegMask (void) {
u32 Index = 0U;
u16 FreeRegMask = 0U;
while (Index < MAX_POSSIBLE_MPU_REGS) {
if (MPU_REG_DISABLED == Mpu_Config[Index].RegionStatus) {
FreeRegMask |= (1U << Index);
}
Index++;
}
return FreeRegMask;
}
/*****************************************************************************/
/**
* @brief Disables the corresponding region number as passed by the user.
*
* @param reg_num: The region number to be disabled
* @return XST_SUCCESS: If the region could be disabled successfully
* XST_FAILURE: If the requested region number is 16 or more.
*
*
******************************************************************************/
u32 Xil_DisableMPURegionByRegNum (u32 reg_num) {
u32 Temp = 0U;
u32 ReturnVal = XST_FAILURE;
if (reg_num >= 16U) {
LOG_E("Invalid region number\r\n");
goto exit1;
}
Xil_DCacheFlush();
Xil_ICacheInvalidate();
mtcp(XREG_CP15_MPU_MEMORY_REG_NUMBER,reg_num);
#if defined (__GNUC__)
Temp = mfcp(XREG_CP15_MPU_REG_SIZE_EN);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_MPU_REG_SIZE_EN,Temp);
#endif
Temp &= (~REGION_EN);
dsb();
mtcp(XREG_CP15_MPU_REG_SIZE_EN,Temp);
dsb();
isb();
Xil_UpdateMPUConfig(reg_num, 0U, 0U, 0U);
ReturnVal = XST_SUCCESS;
exit1:
return ReturnVal;
}
/*****************************************************************************/
/**
* @brief Enables the corresponding region number as passed by the user.
*
* @param reg_num: The region number to be enabled
* @param address: 32 bit address for start of the region.
* @param size: Requested size of the region.
* @param attrib: Attribute for the corresponding region.
* @return XST_SUCCESS: If the region could be created successfully
* XST_FAILURE: If the requested region number is 16 or more.
*
*
******************************************************************************/
u32 Xil_SetMPURegionByRegNum (u32 reg_num, INTPTR addr, u64 size, u32 attrib)
{
u32 ReturnVal = XST_SUCCESS;
INTPTR Localaddr = addr;
u32 Regionsize = 0;
u32 Index;
if (reg_num >= 16U) {
LOG_E("Invalid region number\r\n");
ReturnVal = XST_FAILURE;
goto exit2;
}
if (Mpu_Config[reg_num].RegionStatus == MPU_REG_ENABLED) {
LOG_E("Region already enabled\r\n");
ReturnVal = XST_FAILURE;
goto exit2;
}
Xil_DCacheFlush();
Xil_ICacheInvalidate();
mtcp(XREG_CP15_MPU_MEMORY_REG_NUMBER,reg_num);
isb();
/* Lookup the size. */
for (Index = 0; Index <
sizeof region_size / sizeof region_size[0]; Index++) {
if (size <= region_size[Index].size) {
Regionsize = region_size[Index].encoding;
break;
}
}
Localaddr &= ~(region_size[Index].size - 1);
Regionsize <<= 1;
Regionsize |= REGION_EN;
dsb();
mtcp(XREG_CP15_MPU_REG_BASEADDR, Localaddr);
mtcp(XREG_CP15_MPU_REG_ACCESS_CTRL, attrib);
mtcp(XREG_CP15_MPU_REG_SIZE_EN, Regionsize);
dsb();
isb();
Xil_UpdateMPUConfig(reg_num, Localaddr, Regionsize, attrib);
exit2:
return ReturnVal;
}
/*****************************************************************************/
/**
* @brief Initializes the MPU configuration table that are setup in the
* R5 boot code in the Init_Mpu function called before C main.
*
* @param none
* @return none
*
*
******************************************************************************/
void Xil_InitializeExistingMPURegConfig(void)
{
u32 Index = 0U;
u32 Index1 = 0U;
u32 MPURegSize;
INTPTR MPURegBA;
u32 MPURegAttrib;
u32 Tempsize;
while (Index < MAX_POSSIBLE_MPU_REGS) {
mtcp(XREG_CP15_MPU_MEMORY_REG_NUMBER,Index);
#if defined (__GNUC__)
MPURegSize = mfcp(XREG_CP15_MPU_REG_SIZE_EN);
MPURegBA = mfcp(XREG_CP15_MPU_REG_BASEADDR);
MPURegAttrib = mfcp(XREG_CP15_MPU_REG_ACCESS_CTRL);
#elif defined (__ICCARM__)
mfcp(XREG_CP15_MPU_REG_SIZE_EN,MPURegSize);
mfcp(XREG_CP15_MPU_REG_BASEADDR, MPURegBA);
mfcp(XREG_CP15_MPU_REG_ACCESS_CTRL, MPURegAttrib);
#endif
if (MPURegSize & REGION_EN) {
Mpu_Config[Index].RegionStatus = MPU_REG_ENABLED;
Mpu_Config[Index].BaseAddress = MPURegBA;
Mpu_Config[Index].Attribute = MPURegAttrib;
Tempsize = MPURegSize & (~REGION_EN);
Tempsize >>= 1;
for (Index1 = 0; Index1 <
(sizeof (region_size) / sizeof (region_size[0])); Index1++) {
if (Tempsize <= region_size[Index1].encoding) {
Mpu_Config[Index].Size = region_size[Index1].size;
break;
}
}
}
Index++;
}
}
/*****************************************************************************/
/**
* @brief Returns the next available free MPU region
*
* @param none
* @return The free MPU region available
*
*
******************************************************************************/
u32 Xil_GetNextMPURegion(void)
{
u32 Index = 0U;
u32 NextAvailableReg = 0xFF;
while (Index < MAX_POSSIBLE_MPU_REGS) {
if (Mpu_Config[Index].RegionStatus != MPU_REG_ENABLED) {
NextAvailableReg = Index;
break;
}
Index++;
}
return NextAvailableReg;
}
/*****************************************************************************/
/**
* @brief Memory mapping for Cortex r5.
*
* @param Physaddr is base physical address at which to start mapping.
* NULL in Physaddr masks possible mapping errors.
* @param size of region to be mapped.
* @param flags used to set translation table.
*
* @return Physaddr on success, NULL on error. Ambiguous if Physaddr==NULL
*
* @note: u32overflow() is defined for readability and (for __GNUC__) to
* - force the type of the check to be the same as the first argument
* - hide the otherwise unused third argument of the builtin
* - improve safety by choosing the explicit _uadd_ version.
* Consider __builtin_add_overflow_p() when available.
* Use an alternative (less optimal?) for compilers w/o the builtin.
*
******************************************************************************/
#ifdef __GNUC__
#define u32overflow(a, b) ({typeof(a) s; __builtin_uadd_overflow(a, b, &s); })
#else
#define u32overflow(a, b) ((a) > ((a) + (b)))
#endif /* __GNUC__ */
void *Xil_MemMap(UINTPTR Physaddr, size_t size, u32 flags)
{
size_t Regionsize = MPU_REGION_SIZE_MIN;
UINTPTR Basephysaddr = 0, end = Physaddr + size;
if (!flags)
return (void *)Physaddr;
if (u32overflow(Physaddr, size))
return NULL;
for ( ; Regionsize != 0; Regionsize <<= 1) {
if (Regionsize >= size) {
Basephysaddr = Physaddr & ~(Regionsize - 1);
if (u32overflow(Basephysaddr, Regionsize))
break;
if ((Basephysaddr + Regionsize) >= end)
return Xil_SetMPURegion(Basephysaddr,
Regionsize, flags) == XST_SUCCESS ?
(void *)Physaddr : NULL;
}
}
return NULL;
}

View File

@ -0,0 +1,129 @@
/******************************************************************************
*
* Copyright (C) 2014 - 2017 Xilinx, Inc. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*
*
******************************************************************************/
/*****************************************************************************/
/**
* @file xil_mmu.h
*
* @addtogroup r5_mpu_apis Cortex R5 Processor MPU specific APIs
*
* MPU functions provides access to MPU operations such as enable MPU, disable
* MPU and set attribute for section of memory.
* Boot code invokes Init_MPU function to configure the MPU. A total of 10 MPU
* regions are allocated with another 6 being free for users. Overview of the
* memory attributes for different MPU regions is as given below,
*
*| | Memory Range | Attributes of MPURegion |
*|-----------------------|-------------------------|-----------------------------|
*| DDR | 0x00000000 - 0x7FFFFFFF | Normal write-back Cacheable |
*| PL | 0x80000000 - 0xBFFFFFFF | Strongly Ordered |
*| QSPI | 0xC0000000 - 0xDFFFFFFF | Device Memory |
*| PCIe | 0xE0000000 - 0xEFFFFFFF | Device Memory |
*| STM_CORESIGHT | 0xF8000000 - 0xF8FFFFFF | Device Memory |
*| RPU_R5_GIC | 0xF9000000 - 0xF90FFFFF | Device memory |
*| FPS | 0xFD000000 - 0xFDFFFFFF | Device Memory |
*| LPS | 0xFE000000 - 0xFFFFFFFF | Device Memory |
*| OCM | 0xFFFC0000 - 0xFFFFFFFF | Normal write-back Cacheable |
*
*
* @note
* For a system where DDR is less than 2GB, region after DDR and before PL is
* marked as undefined in translation table. Memory range 0xFE000000-0xFEFFFFFF is
* allocated for upper LPS slaves, where as memory region 0xFF000000-0xFFFFFFFF is
* allocated for lower LPS slaves.
*
* @{
* <pre>
* MODIFICATION HISTORY:
*
* Ver Who Date Changes
* ----- ---- -------- ---------------------------------------------------
* 5.00 pkp 02/10/14 Initial version
* 6.4 asa 08/16/17 Added many APIs for MPU access to make MPU usage
* user-friendly. The APIs added are: Xil_UpdateMPUConfig,
* Xil_GetMPUConfig, Xil_GetNumOfFreeRegions,
* Xil_GetNextMPURegion, Xil_DisableMPURegionByRegNum,
* Xil_GetMPUFreeRegMask, Xil_SetMPURegionByRegNum, and
* Xil_InitializeExistingMPURegConfig.
* Added a new array of structure of type XMpuConfig to
* represent the MPU configuration table.
* </pre>
*
*
*
******************************************************************************/
#ifndef XIL_MPU_H
#define XIL_MPU_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include "xil_types.h"
/***************************** Include Files *********************************/
/***************** Macros (Inline Functions) Definitions *********************/
#define MPU_REG_DISABLED 0U
#define MPU_REG_ENABLED 1U
#define MAX_POSSIBLE_MPU_REGS 16U
/**************************** Type Definitions *******************************/
struct XMpuConfig{
u32 RegionStatus; /* Enabled or disabled */
INTPTR BaseAddress;/* MPU region base address */
u64 Size; /* MPU region size address */
u32 Attribute; /* MPU region size attribute */
};
typedef struct XMpuConfig XMpu_Config[MAX_POSSIBLE_MPU_REGS];
extern XMpu_Config Mpu_Config;
/************************** Constant Definitions *****************************/
/************************** Variable Definitions *****************************/
/************************** Function Prototypes ******************************/
void Xil_SetTlbAttributes(INTPTR Addr, u32 attrib);
void Xil_EnableMPU(void);
void Xil_DisableMPU(void);
u32 Xil_SetMPURegion(INTPTR addr, u64 size, u32 attrib);
u32 Xil_UpdateMPUConfig(u32 reg_num, INTPTR address, u32 size, u32 attrib);
void Xil_GetMPUConfig (XMpu_Config mpuconfig);
u32 Xil_GetNumOfFreeRegions (void);
u32 Xil_GetNextMPURegion(void);
u32 Xil_DisableMPURegionByRegNum (u32 reg_num);
u16 Xil_GetMPUFreeRegMask (void);
u32 Xil_SetMPURegionByRegNum (u32 reg_num, INTPTR addr, u64 size, u32 attrib);
void* Xil_MemMap(UINTPTR Physaddr, size_t size, u32 flags);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* XIL_MPU_H */
/**
* @} End of "addtogroup r5_mpu_apis".
*/