diff --git a/bsp/zynqmp-r5-axu4ev/.config b/bsp/zynqmp-r5-axu4ev/.config index 629096a979..1f215d3c25 100644 --- a/bsp/zynqmp-r5-axu4ev/.config +++ b/bsp/zynqmp-r5-axu4ev/.config @@ -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 # diff --git a/bsp/zynqmp-r5-axu4ev/README.md b/bsp/zynqmp-r5-axu4ev/README.md index a67c9c86ee..8b8cfe2b7b 100644 --- a/bsp/zynqmp-r5-axu4ev/README.md +++ b/bsp/zynqmp-r5-axu4ev/README.md @@ -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/) \ No newline at end of file diff --git a/bsp/zynqmp-r5-axu4ev/README_zh.md b/bsp/zynqmp-r5-axu4ev/README_zh.md index 2735f9a353..f3c9582dd7 100644 --- a/bsp/zynqmp-r5-axu4ev/README_zh.md +++ b/bsp/zynqmp-r5-axu4ev/README_zh.md @@ -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`文件复制过来即可。 diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Kconfig b/bsp/zynqmp-r5-axu4ev/drivers/Kconfig index fd16c490f9..5461f7ecf5 100644 --- a/bsp/zynqmp-r5-axu4ev/drivers/Kconfig +++ b/bsp/zynqmp-r5-axu4ev/drivers/Kconfig @@ -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 diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/SConscript b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/SConscript index 03f0e5d26d..58a8169357 100644 --- a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/SConscript +++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/SConscript @@ -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 diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/SConscript b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/SConscript new file mode 100644 index 0000000000..8e5fc7069e --- /dev/null +++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/SConscript @@ -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') \ No newline at end of file diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps.c b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps.c new file mode 100644 index 0000000000..fb4a6483e9 --- /dev/null +++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps.c @@ -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. +* +*
+* 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 +* +*+******************************************************************************/ + +/***************************** 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 +} +/** @} */ diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps.h b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps.h new file mode 100644 index 0000000000..d3c5b6349f --- /dev/null +++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps.h @@ -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 + * + * Driver Description + * + * 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. + * + * Initialization & Configuration + * + * 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. + * + * Interrupts and Asynchronous Callbacks + * + * 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. + * + * Virtual Memory + * + * 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. + * + * DMA + * + * 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. + * + * Alignment & Data Cache Restrictions + * + * 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. + * + * Buffer Copying + * + * 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. + * + * Checksum Offloading + * + * 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. + * + * PHY Interfaces + * + * RGMII 1.3 is the only interface supported. + * + * Asserts + * + * 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. + * + *
+ * 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 + * + *+ * + ****************************************************************************/ + +#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 Mask. The corresponding interrupt for +* each bit set to 1 in Mask, 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 Mask. The corresponding interrupt for +* each bit set to 1 in Mask, 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 Mask. The corresponding interrupt for +* each bit set to 1 in Mask, 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 Mask. The corresponding interrupt for +* each bit set to 1 in Mask, 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 */ +/** @} */ diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_bd.h b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_bd.h new file mode 100644 index 0000000000..a757322615 --- /dev/null +++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_bd.h @@ -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. + * + * Buffer Descriptors + * + * 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. + * + * Performance + * + * Limiting I/O to BDs can improve overall performance of the DMA channel. + * + *
+ * 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. + * + *+ * + * *************************************************************************** + */ + +#ifndef XEMACPS_BD_H /* prevent circular inclusions */ +#define XEMACPS_BD_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a wsy 01/10/10 First release +* 1.00a asa 11/21/11 The function XEmacPs_BdRingFromHwTx is modified. +* Earlier it used to search in "BdLimit" number of BDs to +* know which BDs are 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.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. Fix for CR #663885. +* 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 Add XEmacPs_BdRingPtrReset() API to reset BD ring +* pointers +* +*+******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xstatus.h" +#include "xil_cache.h" +#include "xemacps_hw.h" +#include "xemacps_bd.h" +#include "xemacps_bdring.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/**************************************************************************** + * Compute the virtual address of a descriptor from its physical address + * + * @param BdPtr is the physical address of the BD + * + * @returns Virtual address of BdPtr + * + * @note Assume BdPtr is always a valid BD in the ring + ****************************************************************************/ +#define XEMACPS_PHYS_TO_VIRT(BdPtr) \ + ((UINTPTR)(BdPtr) + (RingPtr->BaseBdAddr - RingPtr->PhysBaseAddr)) + +/**************************************************************************** + * Compute the physical address of a descriptor from its virtual address + * + * @param BdPtr is the physical address of the BD + * + * @returns Physical address of BdPtr + * + * @note Assume BdPtr is always a valid BD in the ring + ****************************************************************************/ +#define XEMACPS_VIRT_TO_PHYS(BdPtr) \ + ((UINTPTR)(BdPtr) - (RingPtr->BaseBdAddr - RingPtr->PhysBaseAddr)) + +/**************************************************************************** + * Move the BdPtr argument ahead an arbitrary number of BDs wrapping around + * to the beginning of the ring if needed. + * + * We know if a wrapaound should occur if the new BdPtr is greater than + * the high address in the ring OR if the new BdPtr crosses over the + * 0xFFFFFFFF to 0 boundary. The latter test is a valid one since we do not + * allow a BD space to span this boundary. + * + * @param RingPtr is the ring BdPtr appears in + * @param BdPtr on input is the starting BD position and on output is the + * final BD position + * @param NumBd is the number of BD spaces to increment + * + ****************************************************************************/ +#define XEMACPS_RING_SEEKAHEAD(RingPtr, BdPtr, NumBd) \ + { \ + UINTPTR Addr = (UINTPTR)(void *)(BdPtr); \ + \ + Addr += ((RingPtr)->Separation * (NumBd)); \ + if ((Addr > (RingPtr)->HighBdAddr) || ((UINTPTR)(void *)(BdPtr) > Addr)) \ + { \ + Addr -= (RingPtr)->Length; \ + } \ + \ + (BdPtr) = (XEmacPs_Bd*)(void *)Addr; \ + } + +/**************************************************************************** + * Move the BdPtr argument backwards an arbitrary number of BDs wrapping + * around to the end of the ring if needed. + * + * We know if a wrapaound should occur if the new BdPtr is less than + * the base address in the ring OR if the new BdPtr crosses over the + * 0xFFFFFFFF to 0 boundary. The latter test is a valid one since we do not + * allow a BD space to span this boundary. + * + * @param RingPtr is the ring BdPtr appears in + * @param BdPtr on input is the starting BD position and on output is the + * final BD position + * @param NumBd is the number of BD spaces to increment + * + ****************************************************************************/ +#define XEMACPS_RING_SEEKBACK(RingPtr, BdPtr, NumBd) \ + { \ + UINTPTR Addr = (UINTPTR)(void *)(BdPtr); \ + \ + Addr -= ((RingPtr)->Separation * (NumBd)); \ + if ((Addr < (RingPtr)->BaseBdAddr) || ((UINTPTR)(void*)(BdPtr) < Addr)) \ + { \ + Addr += (RingPtr)->Length; \ + } \ + \ + (BdPtr) = (XEmacPs_Bd*)(void*)Addr; \ + } + + +/************************** Function Prototypes ******************************/ + +static void XEmacPs_BdSetRxWrap(UINTPTR BdPtr); +static void XEmacPs_BdSetTxWrap(UINTPTR BdPtr); + +/************************** Variable Definitions *****************************/ + +/*****************************************************************************/ +/** + * Using a memory segment allocated by the caller, create and setup the BD list + * for the given DMA channel. + * + * @param RingPtr is the instance to be worked on. + * @param PhysAddr is the physical base address of user memory region. + * @param VirtAddr is the virtual base address of the user memory region. If + * address translation is not being utilized, then VirtAddr should be + * equivalent to PhysAddr. + * @param Alignment governs the byte alignment of individual BDs. This function + * will enforce a minimum alignment of 4 bytes with no maximum as long + * as it is specified as a power of 2. + * @param BdCount is the number of BDs to setup in the user memory region. It + * is assumed the region is large enough to contain the BDs. + * + * @return + * + * - XST_SUCCESS if initialization was successful + * - XST_NO_FEATURE if the provided instance is a non DMA type + * channel. + * - XST_INVALID_PARAM under any of the following conditions: + * 1) PhysAddr and/or VirtAddr are not aligned to the given Alignment + * parameter. + * 2) Alignment parameter does not meet minimum requirements or is not a + * power of 2 value. + * 3) BdCount is 0. + * - XST_DMA_SG_LIST_ERROR if the memory segment containing the list spans + * over address 0x00000000 in virtual address space. + * + * @note + * Make sure to pass in the right alignment value. + *****************************************************************************/ +LONG XEmacPs_BdRingCreate(XEmacPs_BdRing * RingPtr, UINTPTR PhysAddr, + UINTPTR VirtAddr, u32 Alignment, u32 BdCount) +{ + u32 i; + UINTPTR BdVirtAddr; + UINTPTR BdPhyAddr; + UINTPTR VirtAddrLoc = VirtAddr; + + /* In case there is a failure prior to creating list, make sure the + * following attributes are 0 to prevent calls to other functions + * from doing anything. + */ + RingPtr->AllCnt = 0U; + RingPtr->FreeCnt = 0U; + RingPtr->HwCnt = 0U; + RingPtr->PreCnt = 0U; + RingPtr->PostCnt = 0U; + + /* Make sure Alignment parameter meets minimum requirements */ + if (Alignment < (u32)XEMACPS_DMABD_MINIMUM_ALIGNMENT) { + return (LONG)(XST_INVALID_PARAM); + } + + /* Make sure Alignment is a power of 2 */ + if (((Alignment - 0x00000001U) & Alignment)!=0x00000000U) { + return (LONG)(XST_INVALID_PARAM); + } + + /* Make sure PhysAddr and VirtAddr are on same Alignment */ + if (((PhysAddr % Alignment)!=(u32)0) || ((VirtAddrLoc % Alignment)!=(u32)0)) { + return (LONG)(XST_INVALID_PARAM); + } + + /* Is BdCount reasonable? */ + if (BdCount == 0x00000000U) { + return (LONG)(XST_INVALID_PARAM); + } + + /* Figure out how many bytes will be between the start of adjacent BDs */ + RingPtr->Separation = ((u32)sizeof(XEmacPs_Bd)); + + /* Must make sure the ring doesn't span address 0x00000000. If it does, + * then the next/prev BD traversal macros will fail. + */ + if (VirtAddrLoc > ((VirtAddrLoc + (RingPtr->Separation * BdCount)) - (u32)1)) { + return (LONG)(XST_DMA_SG_LIST_ERROR); + } + + /* Initial ring setup: + * - Clear the entire space + * - Setup each BD's BDA field with the physical address of the next BD + */ + (void)memset((void *) VirtAddrLoc, 0, (RingPtr->Separation * BdCount)); + + BdVirtAddr = VirtAddrLoc; + BdPhyAddr = PhysAddr + RingPtr->Separation; + for (i = 1U; i < BdCount; i++) { + BdVirtAddr += RingPtr->Separation; + BdPhyAddr += RingPtr->Separation; + } + + /* Setup and initialize pointers and counters */ + RingPtr->RunState = (u32)(XST_DMA_SG_IS_STOPPED); + RingPtr->BaseBdAddr = VirtAddrLoc; + RingPtr->PhysBaseAddr = PhysAddr; + RingPtr->HighBdAddr = BdVirtAddr; + RingPtr->Length = + ((RingPtr->HighBdAddr - RingPtr->BaseBdAddr) + RingPtr->Separation); + RingPtr->AllCnt = (u32)BdCount; + RingPtr->FreeCnt = (u32)BdCount; + RingPtr->FreeHead = (XEmacPs_Bd *)(void *)VirtAddrLoc; + RingPtr->PreHead = (XEmacPs_Bd *)VirtAddrLoc; + RingPtr->HwHead = (XEmacPs_Bd *)VirtAddrLoc; + RingPtr->HwTail = (XEmacPs_Bd *)VirtAddrLoc; + RingPtr->PostHead = (XEmacPs_Bd *)VirtAddrLoc; + RingPtr->BdaRestart = (XEmacPs_Bd *)(void *)PhysAddr; + + return (LONG)(XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Clone the given BD into every BD in the list. + * every field of the source BD is replicated in every BD of the list. + * + * This function can be called only when all BDs are in the free group such as + * they are immediately after initialization with XEmacPs_BdRingCreate(). + * This prevents modification of BDs while they are in use by hardware or the + * user. + * + * @param RingPtr is the pointer of BD ring instance to be worked on. + * @param SrcBdPtr is the source BD template to be cloned into the list. This + * BD will be modified. + * @param Direction is either XEMACPS_SEND or XEMACPS_RECV that indicates + * which direction. + * + * @return + * - XST_SUCCESS if the list was modified. + * - XST_DMA_SG_NO_LIST if a list has not been created. + * - XST_DMA_SG_LIST_ERROR if some of the BDs in this channel are under + * hardware or user control. + * - XST_DEVICE_IS_STARTED if the DMA channel has not been stopped. + * + *****************************************************************************/ +LONG XEmacPs_BdRingClone(XEmacPs_BdRing * RingPtr, XEmacPs_Bd * SrcBdPtr, + u8 Direction) +{ + u32 i; + UINTPTR CurBd; + + /* Can't do this function if there isn't a ring */ + if (RingPtr->AllCnt == 0x00000000U) { + return (LONG)(XST_DMA_SG_NO_LIST); + } + + /* Can't do this function with the channel running */ + if (RingPtr->RunState == (u32)XST_DMA_SG_IS_STARTED) { + return (LONG)(XST_DEVICE_IS_STARTED); + } + + /* Can't do this function with some of the BDs in use */ + if (RingPtr->FreeCnt != RingPtr->AllCnt) { + return (LONG)(XST_DMA_SG_LIST_ERROR); + } + + if ((Direction != (u8)XEMACPS_SEND) && (Direction != (u8)XEMACPS_RECV)) { + return (LONG)(XST_INVALID_PARAM); + } + + /* Starting from the top of the ring, save BD.Next, overwrite the entire + * BD with the template, then restore BD.Next + */ + CurBd = RingPtr->BaseBdAddr; + for (i = 0U; i < RingPtr->AllCnt; i++) { + memcpy((void *)CurBd, SrcBdPtr, sizeof(XEmacPs_Bd)); + CurBd += RingPtr->Separation; + } + + CurBd -= RingPtr->Separation; + + if (Direction == XEMACPS_RECV) { + XEmacPs_BdSetRxWrap(CurBd); + } + else { + XEmacPs_BdSetTxWrap(CurBd); + } + + return (LONG)(XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Reserve locations in the BD list. The set of returned BDs may be modified + * in preparation for future DMA transaction(s). Once the BDs are ready to be + * submitted to hardware, the user must call XEmacPs_BdRingToHw() in the same + * order which they were allocated here. Example: + * + *
+ * NumBd = 2,
+ * Status = XEmacPs_BdRingAlloc(MyRingPtr, NumBd, &MyBdSet),
+ *
+ * if (Status != XST_SUCCESS)
+ * {
+ * *Not enough BDs available for the request*
+ * }
+ *
+ * CurBd = MyBdSet,
+ * for (i=0; i
+ *
+ * A more advanced use of this function may allocate multiple sets of BDs.
+ * They must be allocated and given to hardware in the correct sequence:
+ *
+ * * Legal *
+ * XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1),
+ * XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1),
+ *
+ * * Legal *
+ * XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1),
+ * XEmacPs_BdRingAlloc(MyRingPtr, NumBd2, &MySet2),
+ * XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1),
+ * XEmacPs_BdRingToHw(MyRingPtr, NumBd2, MySet2),
+ *
+ * * Not legal *
+ * XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1),
+ * XEmacPs_BdRingAlloc(MyRingPtr, NumBd2, &MySet2),
+ * XEmacPs_BdRingToHw(MyRingPtr, NumBd2, MySet2),
+ * XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1),
+ *
+ *
+ * Use the API defined in xemacps_bd.h to modify individual BDs. Traversal
+ * of the BD set can be done using XEmacPs_BdRingNext() and
+ * XEmacPs_BdRingPrev().
+ *
+ * @param RingPtr is a pointer to the BD ring instance to be worked on.
+ * @param NumBd is the number of BDs to allocate
+ * @param BdSetPtr is an output parameter, it points to the first BD available
+ * for modification.
+ *
+ * @return
+ * - XST_SUCCESS if the requested number of BDs was returned in the BdSetPtr
+ * parameter.
+ * - XST_FAILURE if there were not enough free BDs to satisfy the request.
+ *
+ * @note This function should not be preempted by another XEmacPs_Bd function
+ * call that modifies the BD space. It is the caller's responsibility to
+ * provide a mutual exclusion mechanism.
+ *
+ * @note Do not modify more BDs than the number requested with the NumBd
+ * parameter. Doing so will lead to data corruption and system
+ * instability.
+ *
+ *****************************************************************************/
+LONG XEmacPs_BdRingAlloc(XEmacPs_BdRing * RingPtr, u32 NumBd,
+ XEmacPs_Bd ** BdSetPtr)
+{
+ LONG Status;
+ /* Enough free BDs available for the request? */
+ if (RingPtr->FreeCnt < NumBd) {
+ Status = (LONG)(XST_FAILURE);
+ } else {
+ /* Set the return argument and move FreeHead forward */
+ *BdSetPtr = RingPtr->FreeHead;
+ XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->FreeHead, NumBd);
+ RingPtr->FreeCnt -= NumBd;
+ RingPtr->PreCnt += NumBd;
+ Status = (LONG)(XST_SUCCESS);
+ }
+ return Status;
+}
+
+/*****************************************************************************/
+/**
+ * Fully or partially undo an XEmacPs_BdRingAlloc() operation. Use this
+ * function if all the BDs allocated by XEmacPs_BdRingAlloc() could not be
+ * transferred to hardware with XEmacPs_BdRingToHw().
+ *
+ * This function helps out in situations when an unrelated error occurs after
+ * BDs have been allocated but before they have been given to hardware.
+ * An example of this type of error would be an OS running out of resources.
+ *
+ * This function is not the same as XEmacPs_BdRingFree(). The Free function
+ * returns BDs to the free list after they have been processed by hardware,
+ * while UnAlloc returns them before being processed by hardware.
+ *
+ * There are two scenarios where this function can be used. Full UnAlloc or
+ * Partial UnAlloc. A Full UnAlloc means all the BDs Alloc'd will be returned:
+ *
+ *
+ * Status = XEmacPs_BdRingAlloc(MyRingPtr, 10, &BdPtr),
+ * ...
+ * if (Error)
+ * {
+ * Status = XEmacPs_BdRingUnAlloc(MyRingPtr, 10, &BdPtr),
+ * }
+ *
+ *
+ * A partial UnAlloc means some of the BDs Alloc'd will be returned:
+ *
+ *
+ * Status = XEmacPs_BdRingAlloc(MyRingPtr, 10, &BdPtr),
+ * BdsLeft = 10,
+ * CurBdPtr = BdPtr,
+ *
+ * while (BdsLeft)
+ * {
+ * if (Error)
+ * {
+ * Status = XEmacPs_BdRingUnAlloc(MyRingPtr, BdsLeft, CurBdPtr),
+ * }
+ *
+ * CurBdPtr = XEmacPs_BdRingNext(MyRingPtr, CurBdPtr),
+ * BdsLeft--,
+ * }
+ *
+ *
+ * A partial UnAlloc must include the last BD in the list that was Alloc'd.
+ *
+ * @param RingPtr is a pointer to the instance to be worked on.
+ * @param NumBd is the number of BDs to allocate
+ * @param BdSetPtr is an output parameter, it points to the first BD available
+ * for modification.
+ *
+ * @return
+ * - XST_SUCCESS if the BDs were unallocated.
+ * - XST_FAILURE if NumBd parameter was greater that the number of BDs in
+ * the preprocessing state.
+ *
+ * @note This function should not be preempted by another XEmacPs_Bd function
+ * call that modifies the BD space. It is the caller's responsibility to
+ * provide a mutual exclusion mechanism.
+ *
+ *****************************************************************************/
+LONG XEmacPs_BdRingUnAlloc(XEmacPs_BdRing * RingPtr, u32 NumBd,
+ XEmacPs_Bd * BdSetPtr)
+{
+ LONG Status;
+ (void) BdSetPtr;
+ Xil_AssertNonvoid(RingPtr != NULL);
+ Xil_AssertNonvoid(BdSetPtr != NULL);
+
+ /* Enough BDs in the free state for the request? */
+ if (RingPtr->PreCnt < NumBd) {
+ Status = (LONG)(XST_FAILURE);
+ } else {
+ /* Set the return argument and move FreeHead backward */
+ XEMACPS_RING_SEEKBACK(RingPtr, (RingPtr->FreeHead), NumBd);
+ RingPtr->FreeCnt += NumBd;
+ RingPtr->PreCnt -= NumBd;
+ Status = (LONG)(XST_SUCCESS);
+ }
+ return Status;
+}
+
+
+/*****************************************************************************/
+/**
+ * Enqueue a set of BDs to hardware that were previously allocated by
+ * XEmacPs_BdRingAlloc(). Once this function returns, the argument BD set goes
+ * under hardware control. Any changes made to these BDs after this point will
+ * corrupt the BD list leading to data corruption and system instability.
+ *
+ * The set will be rejected if the last BD of the set does not mark the end of
+ * a packet (see XEmacPs_BdSetLast()).
+ *
+ * @param RingPtr is a pointer to the instance to be worked on.
+ * @param NumBd is the number of BDs in the set.
+ * @param BdSetPtr is the first BD of the set to commit to hardware.
+ *
+ * @return
+ * - XST_SUCCESS if the set of BDs was accepted and enqueued to hardware.
+ * - XST_FAILURE if the set of BDs was rejected because the last BD of the set
+ * did not have its "last" bit set.
+ * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with
+ * XEmacPs_BdRingAlloc().
+ *
+ * @note This function should not be preempted by another XEmacPs_Bd function
+ * call that modifies the BD space. It is the caller's responsibility to
+ * provide a mutual exclusion mechanism.
+ *
+ *****************************************************************************/
+LONG XEmacPs_BdRingToHw(XEmacPs_BdRing * RingPtr, u32 NumBd,
+ XEmacPs_Bd * BdSetPtr)
+{
+ XEmacPs_Bd *CurBdPtr;
+ u32 i;
+ LONG Status;
+ /* if no bds to process, simply return. */
+ if (0U == NumBd){
+ Status = (LONG)(XST_SUCCESS);
+ } else {
+ /* Make sure we are in sync with XEmacPs_BdRingAlloc() */
+ if ((RingPtr->PreCnt < NumBd) || (RingPtr->PreHead != BdSetPtr)) {
+ Status = (LONG)(XST_DMA_SG_LIST_ERROR);
+ } else {
+ CurBdPtr = BdSetPtr;
+ for (i = 0U; i < NumBd; i++) {
+ CurBdPtr = (XEmacPs_Bd *)((void *)XEmacPs_BdRingNext(RingPtr, CurBdPtr));
+ }
+ /* Adjust ring pointers & counters */
+ XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->PreHead, NumBd);
+ RingPtr->PreCnt -= NumBd;
+ RingPtr->HwTail = CurBdPtr;
+ RingPtr->HwCnt += NumBd;
+
+ Status = (LONG)(XST_SUCCESS);
+ }
+ }
+ return Status;
+}
+
+
+/*****************************************************************************/
+/**
+ * Returns a set of BD(s) that have been processed by hardware. The returned
+ * BDs may be examined to determine the outcome of the DMA transaction(s).
+ * Once the BDs have been examined, the user must call XEmacPs_BdRingFree()
+ * in the same order which they were retrieved here. Example:
+ *
+ *
+ * NumBd = XEmacPs_BdRingFromHwTx(MyRingPtr, MaxBd, &MyBdSet),
+ * if (NumBd == 0)
+ * {
+ * * hardware has nothing ready for us yet*
+ * }
+ *
+ * CurBd = MyBdSet,
+ * for (i=0; i
+ *
+ * A more advanced use of this function may allocate multiple sets of BDs.
+ * They must be retrieved from hardware and freed in the correct sequence:
+ *
+ * * Legal *
+ * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1),
+ * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1),
+ *
+ * * Legal *
+ * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1),
+ * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd2, &MySet2),
+ * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1),
+ * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2),
+ *
+ * * Not legal *
+ * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1),
+ * XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd2, &MySet2),
+ * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2),
+ * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1),
+ *
+ *
+ * If hardware has only partially completed a packet spanning multiple BDs,
+ * then none of the BDs for that packet will be included in the results.
+ *
+ * @param RingPtr is a pointer to the instance to be worked on.
+ * @param BdLimit is the maximum number of BDs to return in the set.
+ * @param BdSetPtr is an output parameter, it points to the first BD available
+ * for examination.
+ *
+ * @return
+ * The number of BDs processed by hardware. A value of 0 indicates that no
+ * data is available. No more than BdLimit BDs will be returned.
+ *
+ * @note Treat BDs returned by this function as read-only.
+ *
+ * @note This function should not be preempted by another XEmacPs_Bd function
+ * call that modifies the BD space. It is the caller's responsibility to
+ * provide a mutual exclusion mechanism.
+ *
+ *****************************************************************************/
+u32 XEmacPs_BdRingFromHwTx(XEmacPs_BdRing * RingPtr, u32 BdLimit,
+ XEmacPs_Bd ** BdSetPtr)
+{
+ XEmacPs_Bd *CurBdPtr;
+ u32 BdStr = 0U;
+ u32 BdCount;
+ u32 BdPartialCount;
+ u32 Sop = 0U;
+ u32 Status;
+ u32 BdLimitLoc = BdLimit;
+ CurBdPtr = RingPtr->HwHead;
+ BdCount = 0U;
+ BdPartialCount = 0U;
+
+ /* If no BDs in work group, then there's nothing to search */
+ if (RingPtr->HwCnt == 0x00000000U) {
+ *BdSetPtr = NULL;
+ Status = 0U;
+ } else {
+
+ if (BdLimitLoc > RingPtr->HwCnt){
+ BdLimitLoc = RingPtr->HwCnt;
+ }
+ /* Starting at HwHead, keep moving forward in the list until:
+ * - A BD is encountered with its new/used bit set which means
+ * hardware has not completed processing of that BD.
+ * - RingPtr->HwTail is reached and RingPtr->HwCnt is reached.
+ * - The number of requested BDs has been processed
+ */
+ while (BdCount < BdLimitLoc) {
+ /* Read the status */
+ if(CurBdPtr != NULL){
+ BdStr = XEmacPs_BdRead(CurBdPtr, XEMACPS_BD_STAT_OFFSET);
+ }
+
+ if ((Sop == 0x00000000U) && ((BdStr & XEMACPS_TXBUF_USED_MASK)!=0x00000000U)){
+ Sop = 1U;
+ }
+ if (Sop == 0x00000001U) {
+ BdCount++;
+ BdPartialCount++;
+ }
+
+ /* hardware has processed this BD so check the "last" bit.
+ * If it is clear, then there are more BDs for the current
+ * packet. Keep a count of these partial packet BDs.
+ */
+ if ((Sop == 0x00000001U) && ((BdStr & XEMACPS_TXBUF_LAST_MASK)!=0x00000000U)) {
+ Sop = 0U;
+ BdPartialCount = 0U;
+ }
+
+ /* Move on to next BD in work group */
+ CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr);
+ }
+
+ /* Subtract off any partial packet BDs found */
+ BdCount -= BdPartialCount;
+
+ /* If BdCount is non-zero then BDs were found to return. Set return
+ * parameters, update pointers and counters, return success
+ */
+ if (BdCount > 0x00000000U) {
+ *BdSetPtr = RingPtr->HwHead;
+ RingPtr->HwCnt -= BdCount;
+ RingPtr->PostCnt += BdCount;
+ XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount);
+ Status = (BdCount);
+ } else {
+ *BdSetPtr = NULL;
+ Status = 0U;
+ }
+ }
+ return Status;
+}
+
+
+/*****************************************************************************/
+/**
+ * Returns a set of BD(s) that have been processed by hardware. The returned
+ * BDs may be examined to determine the outcome of the DMA transaction(s).
+ * Once the BDs have been examined, the user must call XEmacPs_BdRingFree()
+ * in the same order which they were retrieved here. Example:
+ *
+ *
+ * NumBd = XEmacPs_BdRingFromHwRx(MyRingPtr, MaxBd, &MyBdSet),
+ *
+ * if (NumBd == 0)
+ * {
+ * *hardware has nothing ready for us yet*
+ * }
+ *
+ * CurBd = MyBdSet,
+ * for (i=0; i
+ *
+ * A more advanced use of this function may allocate multiple sets of BDs.
+ * They must be retrieved from hardware and freed in the correct sequence:
+ *
+ * * Legal *
+ * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1),
+ * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1),
+ *
+ * * Legal *
+ * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1),
+ * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd2, &MySet2),
+ * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1),
+ * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2),
+ *
+ * * Not legal *
+ * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1),
+ * XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd2, &MySet2),
+ * XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2),
+ * XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1),
+ *
+ *
+ * If hardware has only partially completed a packet spanning multiple BDs,
+ * then none of the BDs for that packet will be included in the results.
+ *
+ * @param RingPtr is a pointer to the instance to be worked on.
+ * @param BdLimit is the maximum number of BDs to return in the set.
+ * @param BdSetPtr is an output parameter, it points to the first BD available
+ * for examination.
+ *
+ * @return
+ * The number of BDs processed by hardware. A value of 0 indicates that no
+ * data is available. No more than BdLimit BDs will be returned.
+ *
+ * @note Treat BDs returned by this function as read-only.
+ *
+ * @note This function should not be preempted by another XEmacPs_Bd function
+ * call that modifies the BD space. It is the caller's responsibility to
+ * provide a mutual exclusion mechanism.
+ *
+ *****************************************************************************/
+u32 XEmacPs_BdRingFromHwRx(XEmacPs_BdRing * RingPtr, u32 BdLimit,
+ XEmacPs_Bd ** BdSetPtr)
+{
+ XEmacPs_Bd *CurBdPtr;
+ u32 BdStr = 0U;
+ u32 BdCount;
+ u32 BdPartialCount;
+ u32 Status;
+
+ CurBdPtr = RingPtr->HwHead;
+ BdCount = 0U;
+ BdPartialCount = 0U;
+
+ /* If no BDs in work group, then there's nothing to search */
+ if (RingPtr->HwCnt == 0x00000000U) {
+ *BdSetPtr = NULL;
+ Status = 0U;
+ } else {
+
+ /* Starting at HwHead, keep moving forward in the list until:
+ * - A BD is encountered with its new/used bit set which means
+ * hardware has completed processing of that BD.
+ * - RingPtr->HwTail is reached and RingPtr->HwCnt is reached.
+ * - The number of requested BDs has been processed
+ */
+ while (BdCount < BdLimit) {
+
+ /* Read the status */
+ if(CurBdPtr!=NULL){
+ BdStr = XEmacPs_BdRead(CurBdPtr, XEMACPS_BD_STAT_OFFSET);
+ }
+ if ((!(XEmacPs_BdIsRxNew(CurBdPtr)))==TRUE) {
+ break;
+ }
+
+ BdCount++;
+
+ /* hardware has processed this BD so check the "last" bit. If
+ * it is clear, then there are more BDs for the current packet.
+ * Keep a count of these partial packet BDs.
+ */
+ if ((BdStr & XEMACPS_RXBUF_EOF_MASK)!=0x00000000U) {
+ BdPartialCount = 0U;
+ } else {
+ BdPartialCount++;
+ }
+
+ /* Move on to next BD in work group */
+ CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr);
+ }
+
+ /* Subtract off any partial packet BDs found */
+ BdCount -= BdPartialCount;
+
+ /* If BdCount is non-zero then BDs were found to return. Set return
+ * parameters, update pointers and counters, return success
+ */
+ if (BdCount > 0x00000000U) {
+ *BdSetPtr = RingPtr->HwHead;
+ RingPtr->HwCnt -= BdCount;
+ RingPtr->PostCnt += BdCount;
+ XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount);
+ Status = (BdCount);
+ }
+ else {
+ *BdSetPtr = NULL;
+ Status = 0U;
+ }
+}
+ return Status;
+}
+
+
+/*****************************************************************************/
+/**
+ * Frees a set of BDs that had been previously retrieved with
+ * XEmacPs_BdRingFromHw().
+ *
+ * @param RingPtr is a pointer to the instance to be worked on.
+ * @param NumBd is the number of BDs to free.
+ * @param BdSetPtr is the head of a list of BDs returned by
+ * XEmacPs_BdRingFromHw().
+ *
+ * @return
+ * - XST_SUCCESS if the set of BDs was freed.
+ * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with
+ * XEmacPs_BdRingFromHw().
+ *
+ * @note This function should not be preempted by another XEmacPs_Bd function
+ * call that modifies the BD space. It is the caller's responsibility to
+ * provide a mutual exclusion mechanism.
+ *
+ *****************************************************************************/
+LONG XEmacPs_BdRingFree(XEmacPs_BdRing * RingPtr, u32 NumBd,
+ XEmacPs_Bd * BdSetPtr)
+{
+ LONG Status;
+ /* if no bds to process, simply return. */
+ if (0x00000000U == NumBd){
+ Status = (LONG)(XST_SUCCESS);
+ } else {
+ /* Make sure we are in sync with XEmacPs_BdRingFromHw() */
+ if ((RingPtr->PostCnt < NumBd) || (RingPtr->PostHead != BdSetPtr)) {
+ Status = (LONG)(XST_DMA_SG_LIST_ERROR);
+ } else {
+ /* Update pointers and counters */
+ RingPtr->FreeCnt += NumBd;
+ RingPtr->PostCnt -= NumBd;
+ XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->PostHead, NumBd);
+ Status = (LONG)(XST_SUCCESS);
+ }
+ }
+ return Status;
+}
+
+
+/*****************************************************************************/
+/**
+ * Check the internal data structures of the BD ring for the provided channel.
+ * The following checks are made:
+ *
+ * - Is the BD ring linked correctly in physical address space.
+ * - Do the internal pointers point to BDs in the ring.
+ * - Do the internal counters add up.
+ *
+ * The channel should be stopped prior to calling this function.
+ *
+ * @param RingPtr is a pointer to the instance to be worked on.
+ * @param Direction is either XEMACPS_SEND or XEMACPS_RECV that indicates
+ * which direction.
+ *
+ * @return
+ * - XST_SUCCESS if the set of BDs was freed.
+ * - XST_DMA_SG_NO_LIST if the list has not been created.
+ * - XST_IS_STARTED if the channel is not stopped.
+ * - XST_DMA_SG_LIST_ERROR if a problem is found with the internal data
+ * structures. If this value is returned, the channel should be reset to
+ * avoid data corruption or system instability.
+ *
+ * @note This function should not be preempted by another XEmacPs_Bd function
+ * call that modifies the BD space. It is the caller's responsibility to
+ * provide a mutual exclusion mechanism.
+ *
+ *****************************************************************************/
+LONG XEmacPs_BdRingCheck(XEmacPs_BdRing * RingPtr, u8 Direction)
+{
+ UINTPTR AddrV, AddrP;
+ u32 i;
+
+ if ((Direction != (u8)XEMACPS_SEND) && (Direction != (u8)XEMACPS_RECV)) {
+ return (LONG)(XST_INVALID_PARAM);
+ }
+
+ /* Is the list created */
+ if (RingPtr->AllCnt == 0x00000000U) {
+ return (LONG)(XST_DMA_SG_NO_LIST);
+ }
+
+ /* Can't check if channel is running */
+ if (RingPtr->RunState == (u32)XST_DMA_SG_IS_STARTED) {
+ return (LONG)(XST_IS_STARTED);
+ }
+
+ /* RunState doesn't make sense */
+ if (RingPtr->RunState != (u32)XST_DMA_SG_IS_STOPPED) {
+ return (LONG)(XST_DMA_SG_LIST_ERROR);
+ }
+
+ /* Verify internal pointers point to correct memory space */
+ AddrV = (UINTPTR) RingPtr->FreeHead;
+ if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
+ return (LONG)(XST_DMA_SG_LIST_ERROR);
+ }
+
+ AddrV = (UINTPTR) RingPtr->PreHead;
+ if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
+ return (LONG)(XST_DMA_SG_LIST_ERROR);
+ }
+
+ AddrV = (UINTPTR) RingPtr->HwHead;
+ if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
+ return (LONG)(XST_DMA_SG_LIST_ERROR);
+ }
+
+ AddrV = (UINTPTR) RingPtr->HwTail;
+ if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
+ return (LONG)(XST_DMA_SG_LIST_ERROR);
+ }
+
+ AddrV = (UINTPTR) RingPtr->PostHead;
+ if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) {
+ return (LONG)(XST_DMA_SG_LIST_ERROR);
+ }
+
+ /* Verify internal counters add up */
+ if ((RingPtr->HwCnt + RingPtr->PreCnt + RingPtr->FreeCnt +
+ RingPtr->PostCnt) != RingPtr->AllCnt) {
+ return (LONG)(XST_DMA_SG_LIST_ERROR);
+ }
+
+ /* Verify BDs are linked correctly */
+ AddrV = RingPtr->BaseBdAddr;
+ AddrP = RingPtr->PhysBaseAddr + RingPtr->Separation;
+
+ for (i = 1U; i < RingPtr->AllCnt; i++) {
+ /* Check BDA for this BD. It should point to next physical addr */
+ if (XEmacPs_BdRead(AddrV, XEMACPS_BD_ADDR_OFFSET) != AddrP) {
+ return (LONG)(XST_DMA_SG_LIST_ERROR);
+ }
+
+ /* Move on to next BD */
+ AddrV += RingPtr->Separation;
+ AddrP += RingPtr->Separation;
+ }
+
+ /* Last BD should have wrap bit set */
+ if (XEMACPS_SEND == Direction) {
+ if ((!XEmacPs_BdIsTxWrap(AddrV))==TRUE) {
+ return (LONG)(XST_DMA_SG_LIST_ERROR);
+ }
+ }
+ else { /* XEMACPS_RECV */
+ if ((!XEmacPs_BdIsRxWrap(AddrV))==TRUE) {
+ return (LONG)(XST_DMA_SG_LIST_ERROR);
+ }
+ }
+
+ /* No problems found */
+ return (LONG)(XST_SUCCESS);
+}
+
+/*****************************************************************************/
+/**
+ * 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)
+ *
+ *****************************************************************************/
+static void XEmacPs_BdSetRxWrap(UINTPTR BdPtr)
+{
+ u32 DataValueRx;
+ u32 *TempPtr;
+
+ BdPtr += (u32)(XEMACPS_BD_ADDR_OFFSET);
+ TempPtr = (u32 *)BdPtr;
+ if(TempPtr != NULL) {
+ DataValueRx = *TempPtr;
+ DataValueRx |= XEMACPS_RXBUF_WRAP_MASK;
+ *TempPtr = DataValueRx;
+ }
+}
+
+/*****************************************************************************/
+/**
+ * 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)
+ *
+ *****************************************************************************/
+static void XEmacPs_BdSetTxWrap(UINTPTR BdPtr)
+{
+ u32 DataValueTx;
+ u32 *TempPtr;
+
+ BdPtr += (u32)(XEMACPS_BD_STAT_OFFSET);
+ TempPtr = (u32 *)BdPtr;
+ if(TempPtr != NULL) {
+ DataValueTx = *TempPtr;
+ DataValueTx |= XEMACPS_TXBUF_WRAP_MASK;
+ *TempPtr = DataValueTx;
+ }
+}
+
+/*****************************************************************************/
+/**
+ * Reset BD ring head and tail pointers.
+ *
+ * @param RingPtr is the instance to be worked on.
+ * @param virtaddrloc is the virtual base address of the user memory region.
+ *
+ * @note
+ * Should be called after XEmacPs_Stop()
+ *
+ * @note
+ * C-style signature:
+ * void XEmacPs_BdRingPtrReset(XEmacPs_BdRing * RingPtr, void *virtaddrloc)
+ *
+ *****************************************************************************/
+void XEmacPs_BdRingPtrReset(XEmacPs_BdRing * RingPtr, void *virtaddrloc)
+{
+ RingPtr->FreeHead = virtaddrloc;
+ RingPtr->PreHead = virtaddrloc;
+ RingPtr->HwHead = virtaddrloc;
+ RingPtr->HwTail = virtaddrloc;
+ RingPtr->PostHead = virtaddrloc;
+}
+
+/** @} */
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_bdring.h b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_bdring.h
new file mode 100644
index 0000000000..9d7331d6d9
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_bdring.h
@@ -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.
+*
+*
+* 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.
+*
+*
+*
+******************************************************************************/
+
+#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 */
+/** @} */
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_control.c b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_control.c
new file mode 100644
index 0000000000..b9620c208b
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_control.c
@@ -0,0 +1,1133 @@
+/******************************************************************************
+* Copyright (C) 2009 - 2020 Xilinx, Inc. All rights reserved.
+* SPDX-License-Identifier: MIT
+******************************************************************************/
+
+/*****************************************************************************/
+/**
+ *
+ * @file xemacps_control.c
+* @addtogroup emacps_v3_11
+* @{
+ *
+ * Functions in this file implement general purpose command and control related
+ * functionality. See xemacps.h for a detailed description of the driver.
+ *
+ *
+ * MODIFICATION HISTORY:
+ *
+ * Ver Who Date Changes
+ * ----- ---- -------- -------------------------------------------------------
+ * 1.00a wsy 01/10/10 First release
+ * 1.02a asa 11/05/12 Added a new API for deleting an entry from the HASH
+ * register. Added a new API for setting the BURST length
+ * in DMACR register.
+ * 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.0 hk 02/20/15 Added support for jumbo frames.
+ * 3.2 hk 02/22/16 Added SGMII support for Zynq Ultrascale+ MPSoC.
+ *
+ *****************************************************************************/
+
+/***************************** Include Files *********************************/
+
+#include "xemacps.h"
+
+/************************** Constant Definitions *****************************/
+
+
+/**************************** Type Definitions *******************************/
+
+
+/***************** Macros (Inline Functions) Definitions *********************/
+
+
+/************************** Function Prototypes ******************************/
+
+
+/************************** Variable Definitions *****************************/
+
+
+/*****************************************************************************/
+/**
+ * Set the MAC address for this driver/device. The address is a 48-bit value.
+ * The device must be stopped before calling this function.
+ *
+ * @param InstancePtr is a pointer to the instance to be worked on.
+ * @param AddressPtr is a pointer to a 6-byte MAC address.
+ * @param Index is a index to which MAC (1-4) address.
+ *
+ * @return
+ * - XST_SUCCESS if the MAC address was set successfully
+ * - XST_DEVICE_IS_STARTED if the device has not yet been stopped
+ *
+ *****************************************************************************/
+LONG XEmacPs_SetMacAddress(XEmacPs *InstancePtr, void *AddressPtr, u8 Index)
+{
+ u32 MacAddr;
+ u8 *Aptr = (u8 *)(void *)AddressPtr;
+ u8 IndexLoc = Index;
+ LONG Status;
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(Aptr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
+ Xil_AssertNonvoid((IndexLoc <= (u8)XEMACPS_MAX_MAC_ADDR) && (IndexLoc > 0x00U));
+
+ /* Be sure device has been stopped */
+ if (InstancePtr->IsStarted == (u32)XIL_COMPONENT_IS_STARTED) {
+ Status = (LONG)(XST_DEVICE_IS_STARTED);
+ }
+ else{
+ /* Index ranges 1 to 4, for offset calculation is 0 to 3. */
+ IndexLoc--;
+
+ /* Set the MAC bits [31:0] in BOT */
+ MacAddr = *(Aptr);
+ MacAddr |= ((u32)(*(Aptr+1)) << 8U);
+ MacAddr |= ((u32)(*(Aptr+2)) << 16U);
+ MacAddr |= ((u32)(*(Aptr+3)) << 24U);
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ ((u32)XEMACPS_LADDR1L_OFFSET + ((u32)IndexLoc * (u32)8)), MacAddr);
+
+ /* There are reserved bits in TOP so don't affect them */
+ MacAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ ((u32)XEMACPS_LADDR1H_OFFSET + ((u32)IndexLoc * (u32)8)));
+
+ MacAddr &= (u32)(~XEMACPS_LADDR_MACH_MASK);
+
+ /* Set MAC bits [47:32] in TOP */
+ MacAddr |= (u32)(*(Aptr+4));
+ MacAddr |= (u32)(*(Aptr+5)) << 8U;
+
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ ((u32)XEMACPS_LADDR1H_OFFSET + ((u32)IndexLoc * (u32)8)), MacAddr);
+
+ Status = (LONG)(XST_SUCCESS);
+ }
+ return Status;
+}
+
+
+/*****************************************************************************/
+/**
+ * Get the MAC address for this driver/device.
+ *
+ * @param InstancePtr is a pointer to the instance to be worked on.
+ * @param AddressPtr is an output parameter, and is a pointer to a buffer into
+ * which the current MAC address will be copied.
+ * @param Index is a index to which MAC (1-4) address.
+ *
+ *****************************************************************************/
+void XEmacPs_GetMacAddress(XEmacPs *InstancePtr, void *AddressPtr, u8 Index)
+{
+ u32 MacAddr;
+ u8 *Aptr = (u8 *)(void *)AddressPtr;
+ u8 IndexLoc = Index;
+ Xil_AssertVoid(InstancePtr != NULL);
+ Xil_AssertVoid(Aptr != NULL);
+ Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
+ Xil_AssertVoid((IndexLoc <= (u8)XEMACPS_MAX_MAC_ADDR) && (IndexLoc > 0x00U));
+
+ /* Index ranges 1 to 4, for offset calculation is 0 to 3. */
+ IndexLoc--;
+
+ MacAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ ((u32)XEMACPS_LADDR1L_OFFSET + ((u32)IndexLoc * (u32)8)));
+ *Aptr = (u8) MacAddr;
+ *(Aptr+1) = (u8) (MacAddr >> 8U);
+ *(Aptr+2) = (u8) (MacAddr >> 16U);
+ *(Aptr+3) = (u8) (MacAddr >> 24U);
+
+ /* Read MAC bits [47:32] in TOP */
+ MacAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ ((u32)XEMACPS_LADDR1H_OFFSET + ((u32)IndexLoc * (u32)8)));
+ *(Aptr+4) = (u8) MacAddr;
+ *(Aptr+5) = (u8) (MacAddr >> 8U);
+}
+
+
+/*****************************************************************************/
+/**
+ * Set 48-bit MAC addresses in hash table.
+ * The device must be stopped before calling this function.
+ *
+ * The hash address register is 64 bits long and takes up two locations in
+ * the memory map. The least significant bits are stored in hash register
+ * bottom and the most significant bits in hash register top.
+ *
+ * The unicast hash enable and the multicast hash enable bits in the network
+ * configuration register enable the reception of hash matched frames. The
+ * destination address is reduced to a 6 bit index into the 64 bit hash
+ * register using the following hash function. The hash function is an XOR
+ * of every sixth bit of the destination address.
+ *
+ *
+ * hash_index[05] = da[05]^da[11]^da[17]^da[23]^da[29]^da[35]^da[41]^da[47]
+ * hash_index[04] = da[04]^da[10]^da[16]^da[22]^da[28]^da[34]^da[40]^da[46]
+ * hash_index[03] = da[03]^da[09]^da[15]^da[21]^da[27]^da[33]^da[39]^da[45]
+ * hash_index[02] = da[02]^da[08]^da[14]^da[20]^da[26]^da[32]^da[38]^da[44]
+ * hash_index[01] = da[01]^da[07]^da[13]^da[19]^da[25]^da[31]^da[37]^da[43]
+ * hash_index[00] = da[00]^da[06]^da[12]^da[18]^da[24]^da[30]^da[36]^da[42]
+ *
+ *
+ * da[0] represents the least significant bit of the first byte received,
+ * that is, the multicast/unicast indicator, and da[47] represents the most
+ * significant bit of the last byte received.
+ *
+ * If the hash index points to a bit that is set in the hash register then
+ * the frame will be matched according to whether the frame is multicast
+ * or unicast.
+ *
+ * A multicast match will be signaled if the multicast hash enable bit is
+ * set, da[0] is logic 1 and the hash index points to a bit set in the hash
+ * register.
+ *
+ * A unicast match will be signaled if the unicast hash enable bit is set,
+ * da[0] is logic 0 and the hash index points to a bit set in the hash
+ * register.
+ *
+ * To receive all multicast frames, the hash register should be set with
+ * all ones and the multicast hash enable bit should be set in the network
+ * configuration register.
+ *
+ *
+ * @param InstancePtr is a pointer to the instance to be worked on.
+ * @param AddressPtr is a pointer to a 6-byte MAC address.
+ *
+ * @return
+ * - XST_SUCCESS if the HASH MAC address was set successfully
+ * - XST_DEVICE_IS_STARTED if the device has not yet been stopped
+ * - XST_INVALID_PARAM if the HASH MAC address passed in does not meet
+ * requirement after calculation
+ *
+ * @note
+ * Having Aptr be unsigned type prevents the following operations from sign
+ * extending.
+ *****************************************************************************/
+LONG XEmacPs_SetHash(XEmacPs *InstancePtr, void *AddressPtr)
+{
+ u32 HashAddr;
+ u8 *Aptr = (u8 *)(void *)AddressPtr;
+ u8 Temp1, Temp2, Temp3, Temp4, Temp5, Temp6, Temp7, Temp8;
+ u32 Result;
+ LONG Status;
+
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(AddressPtr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
+
+ /* Be sure device has been stopped */
+ if (InstancePtr->IsStarted == (u32)XIL_COMPONENT_IS_STARTED) {
+ Status = (LONG)(XST_DEVICE_IS_STARTED);
+ } else {
+ Temp1 = (*(Aptr+0)) & 0x3FU;
+ Temp2 = ((*(Aptr+0) >> 6U) & 0x03U) | ((*(Aptr+1) & 0x0FU) << 2U);
+
+ Temp3 = ((*(Aptr+1) >> 4U) & 0x0FU) | ((*(Aptr+2) & 0x3U) << 4U);
+ Temp4 = ((*(Aptr+2) >> 2U) & 0x3FU);
+ Temp5 = (*(Aptr+3)) & 0x3FU;
+ Temp6 = ((*(Aptr+3) >> 6U) & 0x03U) | ((*(Aptr+4) & 0x0FU) << 2U);
+ Temp7 = ((*(Aptr+4) >> 4U) & 0x0FU) | ((*(Aptr+5) & 0x03U) << 4U);
+ Temp8 = ((*(Aptr+5) >> 2U) & 0x3FU);
+
+ Result = (u32)((u32)Temp1 ^ (u32)Temp2 ^ (u32)Temp3 ^ (u32)Temp4 ^
+ (u32)Temp5 ^ (u32)Temp6 ^ (u32)Temp7 ^ (u32)Temp8);
+
+ if (Result >= (u32)XEMACPS_MAX_HASH_BITS) {
+ Status = (LONG)(XST_INVALID_PARAM);
+ } else {
+
+ if (Result < (u32)32) {
+ HashAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_HASHL_OFFSET);
+ HashAddr |= (u32)(0x00000001U << Result);
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_HASHL_OFFSET, HashAddr);
+ } else {
+ HashAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_HASHH_OFFSET);
+ HashAddr |= (u32)(0x00000001U << (u32)(Result - (u32)32));
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_HASHH_OFFSET, HashAddr);
+ }
+ Status = (LONG)(XST_SUCCESS);
+ }
+ }
+ return Status;
+}
+
+/*****************************************************************************/
+/**
+ * Delete 48-bit MAC addresses in hash table.
+ * The device must be stopped before calling this function.
+ *
+ * @param InstancePtr is a pointer to the instance to be worked on.
+ * @param AddressPtr is a pointer to a 6-byte MAC address.
+ *
+ * @return
+ * - XST_SUCCESS if the HASH MAC address was deleted successfully
+ * - XST_DEVICE_IS_STARTED if the device has not yet been stopped
+ * - XST_INVALID_PARAM if the HASH MAC address passed in does not meet
+ * requirement after calculation
+ *
+ * @note
+ * Having Aptr be unsigned type prevents the following operations from sign
+ * extending.
+ *****************************************************************************/
+LONG XEmacPs_DeleteHash(XEmacPs *InstancePtr, void *AddressPtr)
+{
+ u32 HashAddr;
+ u8 *Aptr = (u8 *)(void *)AddressPtr;
+ u8 Temp1, Temp2, Temp3, Temp4, Temp5, Temp6, Temp7, Temp8;
+ u32 Result;
+ LONG Status;
+
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(Aptr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
+
+ /* Be sure device has been stopped */
+ if (InstancePtr->IsStarted == (u32)XIL_COMPONENT_IS_STARTED) {
+ Status = (LONG)(XST_DEVICE_IS_STARTED);
+ } else {
+ Temp1 = (*(Aptr+0)) & 0x3FU;
+ Temp2 = ((*(Aptr+0) >> 6U) & 0x03U) | ((*(Aptr+1) & 0x0FU) << 2U);
+ Temp3 = ((*(Aptr+1) >> 4U) & 0x0FU) | ((*(Aptr+2) & 0x03U) << 4U);
+ Temp4 = ((*(Aptr+2) >> 2U) & 0x3FU);
+ Temp5 = (*(Aptr+3)) & 0x3FU;
+ Temp6 = ((*(Aptr+3) >> 6U) & 0x03U) | ((*(Aptr+4) & 0x0FU) << 2U);
+ Temp7 = ((*(Aptr+4) >> 4U) & 0x0FU) | ((*(Aptr+5) & 0x03U) << 4U);
+ Temp8 = ((*(Aptr+5) >> 2U) & 0x3FU);
+
+ Result = (u32)((u32)Temp1 ^ (u32)Temp2 ^ (u32)Temp3 ^ (u32)Temp4 ^
+ (u32)Temp5 ^ (u32)Temp6 ^ (u32)Temp7 ^ (u32)Temp8);
+
+ if (Result >= (u32)(XEMACPS_MAX_HASH_BITS)) {
+ Status = (LONG)(XST_INVALID_PARAM);
+ } else {
+ if (Result < (u32)32) {
+ HashAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_HASHL_OFFSET);
+ HashAddr &= (u32)(~(0x00000001U << Result));
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_HASHL_OFFSET, HashAddr);
+ } else {
+ HashAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_HASHH_OFFSET);
+ HashAddr &= (u32)(~(0x00000001U << (u32)(Result - (u32)32)));
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_HASHH_OFFSET, HashAddr);
+ }
+ Status = (LONG)(XST_SUCCESS);
+ }
+ }
+ return Status;
+}
+/*****************************************************************************/
+/**
+ * Clear the Hash registers for the mac address pointed by AddressPtr.
+ *
+ * @param InstancePtr is a pointer to the instance to be worked on.
+ *
+ *****************************************************************************/
+void XEmacPs_ClearHash(XEmacPs *InstancePtr)
+{
+ Xil_AssertVoid(InstancePtr != NULL);
+ Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
+
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_HASHL_OFFSET, 0x0U);
+
+ /* write bits [63:32] in TOP */
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_HASHH_OFFSET, 0x0U);
+}
+
+
+/*****************************************************************************/
+/**
+ * Get the Hash address for this driver/device.
+ *
+ * @param InstancePtr is a pointer to the instance to be worked on.
+ * @param AddressPtr is an output parameter, and is a pointer to a buffer into
+ * which the current HASH MAC address will be copied.
+ *
+ *****************************************************************************/
+void XEmacPs_GetHash(XEmacPs *InstancePtr, void *AddressPtr)
+{
+ u32 *Aptr = (u32 *)(void *)AddressPtr;
+
+ Xil_AssertVoid(InstancePtr != NULL);
+ Xil_AssertVoid(AddressPtr != NULL);
+ Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
+
+ *(Aptr+0) = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_HASHL_OFFSET);
+
+ /* Read Hash bits [63:32] in TOP */
+ *(Aptr+1) = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_HASHH_OFFSET);
+}
+
+
+/*****************************************************************************/
+/**
+ * Set the Type ID match for this driver/device. The register is a 32-bit
+ * value. The device must be stopped before calling this function.
+ *
+ * @param InstancePtr is a pointer to the instance to be worked on.
+ * @param Id_Check is type ID to be configured.
+ * @param Index is a index to which Type ID (1-4).
+ *
+ * @return
+ * - XST_SUCCESS if the MAC address was set successfully
+ * - XST_DEVICE_IS_STARTED if the device has not yet been stopped
+ *
+ *****************************************************************************/
+LONG XEmacPs_SetTypeIdCheck(XEmacPs *InstancePtr, u32 Id_Check, u8 Index)
+{
+ u8 IndexLoc = Index;
+ LONG Status;
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
+ Xil_AssertNonvoid((IndexLoc <= (u8)XEMACPS_MAX_TYPE_ID) && (IndexLoc > 0x00U));
+
+ /* Be sure device has been stopped */
+ if (InstancePtr->IsStarted == (u32)XIL_COMPONENT_IS_STARTED) {
+ Status = (LONG)(XST_DEVICE_IS_STARTED);
+ } else {
+
+ /* Index ranges 1 to 4, for offset calculation is 0 to 3. */
+ IndexLoc--;
+
+ /* Set the ID bits in MATCHx register */
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ ((u32)XEMACPS_MATCH1_OFFSET + ((u32)IndexLoc * (u32)4)), Id_Check);
+
+ Status = (LONG)(XST_SUCCESS);
+ }
+ return Status;
+}
+
+/*****************************************************************************/
+/**
+ * Set options for the driver/device. The driver should be stopped with
+ * XEmacPs_Stop() before changing options.
+ *
+ * @param InstancePtr is a pointer to the instance to be worked on.
+ * @param Options are the options to set. Multiple options can be set by OR'ing
+ * XTE_*_OPTIONS constants together. Options not specified are not
+ * affected.
+ *
+ * @return
+ * - XST_SUCCESS if the options were set successfully
+ * - XST_DEVICE_IS_STARTED if the device has not yet been stopped
+ *
+ * @note
+ * See xemacps.h for a description of the available options.
+ *
+ *****************************************************************************/
+LONG XEmacPs_SetOptions(XEmacPs *InstancePtr, u32 Options)
+{
+ u32 Reg; /* Generic register contents */
+ u32 RegNetCfg; /* Reflects original contents of NET_CONFIG */
+ u32 RegNewNetCfg; /* Reflects new contents of NET_CONFIG */
+ LONG Status;
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
+
+ /* Be sure device has been stopped */
+ if (InstancePtr->IsStarted == (u32)XIL_COMPONENT_IS_STARTED) {
+ Status = (LONG)(XST_DEVICE_IS_STARTED);
+ } else {
+
+ /* Many of these options will change the NET_CONFIG registers.
+ * To reduce the amount of IO to the device, group these options here
+ * and change them all at once.
+ */
+
+ /* Grab current register contents */
+ RegNetCfg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCFG_OFFSET);
+ RegNewNetCfg = RegNetCfg;
+
+ /*
+ * It is configured to max 1536.
+ */
+ if ((Options & XEMACPS_FRAME1536_OPTION) != 0x00000000U) {
+ RegNewNetCfg |= (XEMACPS_NWCFG_1536RXEN_MASK);
+ }
+
+ /* Turn on VLAN packet only, only VLAN tagged will be accepted */
+ if ((Options & XEMACPS_VLAN_OPTION) != 0x00000000U) {
+ RegNewNetCfg |= XEMACPS_NWCFG_NVLANDISC_MASK;
+ }
+
+ /* Turn on FCS stripping on receive packets */
+ if ((Options & XEMACPS_FCS_STRIP_OPTION) != 0x00000000U) {
+ RegNewNetCfg |= XEMACPS_NWCFG_FCSREM_MASK;
+ }
+
+ /* Turn on length/type field checking on receive packets */
+ if ((Options & XEMACPS_LENTYPE_ERR_OPTION) != 0x00000000U) {
+ RegNewNetCfg |= XEMACPS_NWCFG_LENERRDSCRD_MASK;
+ }
+
+ /* Turn on flow control */
+ if ((Options & XEMACPS_FLOW_CONTROL_OPTION) != 0x00000000U) {
+ RegNewNetCfg |= XEMACPS_NWCFG_PAUSEEN_MASK;
+ }
+
+ /* Turn on promiscuous frame filtering (all frames are received) */
+ if ((Options & XEMACPS_PROMISC_OPTION) != 0x00000000U) {
+ RegNewNetCfg |= XEMACPS_NWCFG_COPYALLEN_MASK;
+ }
+
+ /* Allow broadcast address reception */
+ if ((Options & XEMACPS_BROADCAST_OPTION) != 0x00000000U) {
+ RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_BCASTDI_MASK);
+ }
+
+ /* Allow multicast address filtering */
+ if ((Options & XEMACPS_MULTICAST_OPTION) != 0x00000000U) {
+ RegNewNetCfg |= XEMACPS_NWCFG_MCASTHASHEN_MASK;
+ }
+
+ /* enable RX checksum offload */
+ if ((Options & XEMACPS_RX_CHKSUM_ENABLE_OPTION) != 0x00000000U) {
+ RegNewNetCfg |= XEMACPS_NWCFG_RXCHKSUMEN_MASK;
+ }
+
+ /* Enable jumbo frames */
+ if (((Options & XEMACPS_JUMBO_ENABLE_OPTION) != 0x00000000U) &&
+ (InstancePtr->Version > 2)) {
+ RegNewNetCfg |= XEMACPS_NWCFG_JUMBO_MASK;
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_JUMBOMAXLEN_OFFSET, XEMACPS_RX_BUF_SIZE_JUMBO);
+ Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_DMACR_OFFSET);
+ Reg &= ~XEMACPS_DMACR_RXBUF_MASK;
+ Reg |= (((((u32)XEMACPS_RX_BUF_SIZE_JUMBO / (u32)XEMACPS_RX_BUF_UNIT) +
+ (((((u32)XEMACPS_RX_BUF_SIZE_JUMBO %
+ (u32)XEMACPS_RX_BUF_UNIT))!=(u32)0) ? 1U : 0U)) <<
+ (u32)(XEMACPS_DMACR_RXBUF_SHIFT)) &
+ (u32)(XEMACPS_DMACR_RXBUF_MASK));
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_DMACR_OFFSET, Reg);
+ InstancePtr->MaxMtuSize = XEMACPS_MTU_JUMBO;
+ InstancePtr->MaxFrameSize = XEMACPS_MTU_JUMBO +
+ XEMACPS_HDR_SIZE + XEMACPS_TRL_SIZE;
+ InstancePtr->MaxVlanFrameSize = InstancePtr->MaxFrameSize +
+ XEMACPS_HDR_VLAN_SIZE;
+ InstancePtr->RxBufMask = XEMACPS_RXBUF_LEN_JUMBO_MASK;
+ }
+
+ if (((Options & XEMACPS_SGMII_ENABLE_OPTION) != 0x00000000U) &&
+ (InstancePtr->Version > 2)) {
+ RegNewNetCfg |= (XEMACPS_NWCFG_SGMIIEN_MASK |
+ XEMACPS_NWCFG_PCSSEL_MASK);
+ }
+
+ /* Officially change the NET_CONFIG registers if it needs to be
+ * modified.
+ */
+ if (RegNetCfg != RegNewNetCfg) {
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCFG_OFFSET, RegNewNetCfg);
+ }
+
+ /* Enable TX checksum offload */
+ if ((Options & XEMACPS_TX_CHKSUM_ENABLE_OPTION) != 0x00000000U) {
+ Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_DMACR_OFFSET);
+ Reg |= XEMACPS_DMACR_TCPCKSUM_MASK;
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_DMACR_OFFSET, Reg);
+ }
+
+ /* Enable transmitter */
+ if ((Options & XEMACPS_TRANSMITTER_ENABLE_OPTION) != 0x00000000U) {
+ Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET);
+ Reg |= XEMACPS_NWCTRL_TXEN_MASK;
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET, Reg);
+ }
+
+ /* Enable receiver */
+ if ((Options & XEMACPS_RECEIVER_ENABLE_OPTION) != 0x00000000U) {
+ Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET);
+ Reg |= XEMACPS_NWCTRL_RXEN_MASK;
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET, Reg);
+ }
+
+ /* The remaining options not handled here are managed elsewhere in the
+ * driver. No register modifications are needed at this time. Reflecting
+ * the option in InstancePtr->Options is good enough for now.
+ */
+
+ /* Set options word to its new value */
+ InstancePtr->Options |= Options;
+
+ Status = (LONG)(XST_SUCCESS);
+ }
+ return Status;
+}
+
+
+/*****************************************************************************/
+/**
+ * Clear options for the driver/device
+ *
+ * @param InstancePtr is a pointer to the instance to be worked on.
+ * @param Options are the options to clear. Multiple options can be cleared by
+ * OR'ing XEMACPS_*_OPTIONS constants together. Options not specified
+ * are not affected.
+ *
+ * @return
+ * - XST_SUCCESS if the options were set successfully
+ * - XST_DEVICE_IS_STARTED if the device has not yet been stopped
+ *
+ * @note
+ * See xemacps.h for a description of the available options.
+ *
+ *****************************************************************************/
+LONG XEmacPs_ClearOptions(XEmacPs *InstancePtr, u32 Options)
+{
+ u32 Reg; /* Generic */
+ u32 RegNetCfg; /* Reflects original contents of NET_CONFIG */
+ u32 RegNewNetCfg; /* Reflects new contents of NET_CONFIG */
+ LONG Status;
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
+
+ /* Be sure device has been stopped */
+ if (InstancePtr->IsStarted == (u32)XIL_COMPONENT_IS_STARTED) {
+ Status = (LONG)(XST_DEVICE_IS_STARTED);
+ } else {
+
+ /* Many of these options will change the NET_CONFIG registers.
+ * To reduce the amount of IO to the device, group these options here
+ * and change them all at once.
+ */
+
+ /* Grab current register contents */
+ RegNetCfg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCFG_OFFSET);
+ RegNewNetCfg = RegNetCfg;
+
+ /* There is only RX configuration!?
+ * It is configured in two different length, up to 1536 and 10240 bytes
+ */
+ if ((Options & XEMACPS_FRAME1536_OPTION) != 0x00000000U) {
+ RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_1536RXEN_MASK);
+ }
+
+ /* Turn off VLAN packet only */
+ if ((Options & XEMACPS_VLAN_OPTION) != 0x00000000U) {
+ RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_NVLANDISC_MASK);
+ }
+
+ /* Turn off FCS stripping on receive packets */
+ if ((Options & XEMACPS_FCS_STRIP_OPTION) != 0x00000000U) {
+ RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_FCSREM_MASK);
+ }
+
+ /* Turn off length/type field checking on receive packets */
+ if ((Options & XEMACPS_LENTYPE_ERR_OPTION) != 0x00000000U) {
+ RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_LENERRDSCRD_MASK);
+ }
+
+ /* Turn off flow control */
+ if ((Options & XEMACPS_FLOW_CONTROL_OPTION) != 0x00000000U) {
+ RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_PAUSEEN_MASK);
+ }
+
+ /* Turn off promiscuous frame filtering (all frames are received) */
+ if ((Options & XEMACPS_PROMISC_OPTION) != 0x00000000U) {
+ RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_COPYALLEN_MASK);
+ }
+
+ /* Disallow broadcast address filtering => broadcast reception */
+ if ((Options & XEMACPS_BROADCAST_OPTION) != 0x00000000U) {
+ RegNewNetCfg |= XEMACPS_NWCFG_BCASTDI_MASK;
+ }
+
+ /* Disallow multicast address filtering */
+ if ((Options & XEMACPS_MULTICAST_OPTION) != 0x00000000U) {
+ RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_MCASTHASHEN_MASK);
+ }
+
+ /* Disable RX checksum offload */
+ if ((Options & XEMACPS_RX_CHKSUM_ENABLE_OPTION) != 0x00000000U) {
+ RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_RXCHKSUMEN_MASK);
+ }
+
+ /* Disable jumbo frames */
+ if (((Options & XEMACPS_JUMBO_ENABLE_OPTION) != 0x00000000U) &&
+ (InstancePtr->Version > 2)) {
+ RegNewNetCfg &= (u32)(~XEMACPS_NWCFG_JUMBO_MASK);
+ Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_DMACR_OFFSET);
+ Reg &= ~XEMACPS_DMACR_RXBUF_MASK;
+ Reg |= (((((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));
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_DMACR_OFFSET, Reg);
+ 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;
+ }
+
+ if (((Options & XEMACPS_SGMII_ENABLE_OPTION) != 0x00000000U) &&
+ (InstancePtr->Version > 2)) {
+ RegNewNetCfg &= (u32)(~(XEMACPS_NWCFG_SGMIIEN_MASK |
+ XEMACPS_NWCFG_PCSSEL_MASK));
+ }
+
+ /* Officially change the NET_CONFIG registers if it needs to be
+ * modified.
+ */
+ if (RegNetCfg != RegNewNetCfg) {
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCFG_OFFSET, RegNewNetCfg);
+ }
+
+ /* Disable TX checksum offload */
+ if ((Options & XEMACPS_TX_CHKSUM_ENABLE_OPTION) != 0x00000000U) {
+ Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_DMACR_OFFSET);
+ Reg &= (u32)(~XEMACPS_DMACR_TCPCKSUM_MASK);
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_DMACR_OFFSET, Reg);
+ }
+
+ /* Disable transmitter */
+ if ((Options & XEMACPS_TRANSMITTER_ENABLE_OPTION) != 0x00000000U) {
+ Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET);
+ Reg &= (u32)(~XEMACPS_NWCTRL_TXEN_MASK);
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET, Reg);
+ }
+
+ /* Disable receiver */
+ if ((Options & XEMACPS_RECEIVER_ENABLE_OPTION) != 0x00000000U) {
+ Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET);
+ Reg &= (u32)(~XEMACPS_NWCTRL_RXEN_MASK);
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET, Reg);
+ }
+
+ /* The remaining options not handled here are managed elsewhere in the
+ * driver. No register modifications are needed at this time. Reflecting
+ * option in InstancePtr->Options is good enough for now.
+ */
+
+ /* Set options word to its new value */
+ InstancePtr->Options &= ~Options;
+
+ Status = (LONG)(XST_SUCCESS);
+ }
+ return Status;
+}
+
+
+/*****************************************************************************/
+/**
+ * Get current option settings
+ *
+ * @param InstancePtr is a pointer to the instance to be worked on.
+ *
+ * @return
+ * A bitmask of XTE_*_OPTION constants. Any bit set to 1 is to be interpreted
+ * as a set option.
+ *
+ * @note
+ * See xemacps.h for a description of the available options.
+ *
+ *****************************************************************************/
+u32 XEmacPs_GetOptions(XEmacPs *InstancePtr)
+{
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
+
+ return (InstancePtr->Options);
+}
+
+
+/*****************************************************************************/
+/**
+ * Send a pause packet
+ *
+ * @param InstancePtr is a pointer to the instance to be worked on.
+ *
+ * @return
+ * - XST_SUCCESS if pause frame transmission was initiated
+ * - XST_DEVICE_IS_STOPPED if the device has not been started.
+ *
+ *****************************************************************************/
+LONG XEmacPs_SendPausePacket(XEmacPs *InstancePtr)
+{
+ u32 Reg;
+ LONG Status;
+
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
+
+ /* Make sure device is ready for this operation */
+ if (InstancePtr->IsStarted != (u32)XIL_COMPONENT_IS_STARTED) {
+ Status = (LONG)(XST_DEVICE_IS_STOPPED);
+ } else {
+ /* Send flow control frame */
+ Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET);
+ Reg |= XEMACPS_NWCTRL_PAUSETX_MASK;
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCTRL_OFFSET, Reg);
+ Status = (LONG)(XST_SUCCESS);
+ }
+ return Status;
+}
+
+/*****************************************************************************/
+/**
+ * XEmacPs_GetOperatingSpeed gets the current operating link speed. This may
+ * be the value set by XEmacPs_SetOperatingSpeed() or a hardware default.
+ *
+ * @param InstancePtr references the TEMAC channel on which to operate.
+ *
+ * @return XEmacPs_GetOperatingSpeed returns the link speed in units of
+ * megabits per second.
+ *
+ * @note
+ *
+ *****************************************************************************/
+u16 XEmacPs_GetOperatingSpeed(XEmacPs *InstancePtr)
+{
+ u32 Reg;
+ u16 Status;
+
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
+
+ Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCFG_OFFSET);
+
+ if ((Reg & XEMACPS_NWCFG_1000_MASK) != 0x00000000U) {
+ Status = (u16)(1000);
+ } else {
+ if ((Reg & XEMACPS_NWCFG_100_MASK) != 0x00000000U) {
+ Status = (u16)(100);
+ } else {
+ Status = (u16)(10);
+ }
+ }
+ return Status;
+}
+
+
+/*****************************************************************************/
+/**
+ * XEmacPs_SetOperatingSpeed sets the current operating link speed. For any
+ * traffic to be passed, this speed must match the current MII/GMII/SGMII/RGMII
+ * link speed.
+ *
+ * @param InstancePtr references the TEMAC channel on which to operate.
+ * @param Speed is the speed to set in units of Mbps. Valid values are 10, 100,
+ * or 1000. XEmacPs_SetOperatingSpeed ignores invalid values.
+ *
+ * @note
+ *
+ *****************************************************************************/
+void XEmacPs_SetOperatingSpeed(XEmacPs *InstancePtr, u16 Speed)
+{
+ u32 Reg;
+ Xil_AssertVoid(InstancePtr != NULL);
+ Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
+ Xil_AssertVoid((Speed == (u16)10) || (Speed == (u16)100) || (Speed == (u16)1000));
+
+ Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCFG_OFFSET);
+ Reg &= (u32)(~(XEMACPS_NWCFG_1000_MASK | XEMACPS_NWCFG_100_MASK));
+
+ switch (Speed) {
+ case (u16)10:
+ break;
+
+ case (u16)100:
+ Reg |= XEMACPS_NWCFG_100_MASK;
+ break;
+
+ case (u16)1000:
+ Reg |= XEMACPS_NWCFG_1000_MASK;
+ break;
+ }
+
+ /* Set register and return */
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCFG_OFFSET, Reg);
+}
+
+
+/*****************************************************************************/
+/**
+ * Set the MDIO clock divisor.
+ *
+ * Calculating the divisor:
+ *
+ *
+ * f[HOSTCLK]
+ * f[MDC] = -----------------
+ * (1 + Divisor) * 2
+ *
+ *
+ * where f[HOSTCLK] is the bus clock frequency in MHz, and f[MDC] is the
+ * MDIO clock frequency in MHz to the PHY. Typically, f[MDC] should not
+ * exceed 2.5 MHz. Some PHYs can tolerate faster speeds which means faster
+ * access. Here is the table to show values to generate MDC,
+ *
+ *
+ * 000 : divide pclk by 8 (pclk up to 20 MHz)
+ * 001 : divide pclk by 16 (pclk up to 40 MHz)
+ * 010 : divide pclk by 32 (pclk up to 80 MHz)
+ * 011 : divide pclk by 48 (pclk up to 120 MHz)
+ * 100 : divide pclk by 64 (pclk up to 160 MHz)
+ * 101 : divide pclk by 96 (pclk up to 240 MHz)
+ * 110 : divide pclk by 128 (pclk up to 320 MHz)
+ * 111 : divide pclk by 224 (pclk up to 540 MHz)
+ *
+ *
+ * @param InstancePtr is a pointer to the instance to be worked on.
+ * @param Divisor is the divisor to set. Range is 0b000 to 0b111.
+ *
+ *****************************************************************************/
+void XEmacPs_SetMdioDivisor(XEmacPs *InstancePtr, XEmacPs_MdcDiv Divisor)
+{
+ u32 Reg;
+ Xil_AssertVoid(InstancePtr != NULL);
+ Xil_AssertVoid(InstancePtr->IsReady == (u32)XIL_COMPONENT_IS_READY);
+ Xil_AssertVoid(Divisor <= (XEmacPs_MdcDiv)0x7); /* only last three bits are valid */
+
+ Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCFG_OFFSET);
+ /* clear these three bits, could be done with mask */
+ Reg &= (u32)(~XEMACPS_NWCFG_MDCCLKDIV_MASK);
+
+ Reg |= ((u32)Divisor << XEMACPS_NWCFG_MDC_SHIFT_MASK);
+
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWCFG_OFFSET, Reg);
+}
+
+
+/*****************************************************************************/
+/**
+* Read the current value of the PHY register indicated by the PhyAddress and
+* the RegisterNum parameters. The MAC provides the driver with the ability to
+* talk to a PHY that adheres to the Media Independent Interface (MII) as
+* defined in the IEEE 802.3 standard.
+*
+* Prior to PHY access with this function, the user should have setup the MDIO
+* clock with XEmacPs_SetMdioDivisor().
+*
+* @param InstancePtr is a pointer to the XEmacPs instance to be worked on.
+* @param PhyAddress is the address of the PHY to be read (supports multiple
+* PHYs)
+* @param RegisterNum is the register number, 0-31, of the specific PHY register
+* to read
+* @param PhyDataPtr is an output parameter, and points to a 16-bit buffer into
+* which the current value of the register will be copied.
+*
+* @return
+*
+* - XST_SUCCESS if the PHY was read from successfully
+* - XST_EMAC_MII_BUSY if there is another PHY operation in progress
+*
+* @note
+*
+* This function is not thread-safe. The user must provide mutually exclusive
+* access to this function if there are to be multiple threads that can call it.
+*
+* There is the possibility that this function will not return if the hardware
+* is broken (i.e., it never sets the status bit indicating that the read is
+* done). If this is of concern to the user, the user should provide a mechanism
+* suitable to their needs for recovery.
+*
+* For the duration of this function, all host interface reads and writes are
+* blocked to the current XEmacPs instance.
+*
+******************************************************************************/
+LONG XEmacPs_PhyRead(XEmacPs *InstancePtr, u32 PhyAddress,
+ u32 RegisterNum, u16 *PhyDataPtr)
+{
+ u32 Mgtcr;
+ volatile u32 Ipisr;
+ u32 IpReadTemp;
+ LONG Status;
+
+ Xil_AssertNonvoid(InstancePtr != NULL);
+
+ /* Make sure no other PHY operation is currently in progress */
+ if ((!(XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWSR_OFFSET) &
+ XEMACPS_NWSR_MDIOIDLE_MASK))==TRUE) {
+ Status = (LONG)(XST_EMAC_MII_BUSY);
+ } else {
+
+ /* Construct Mgtcr mask for the operation */
+ Mgtcr = XEMACPS_PHYMNTNC_OP_MASK | XEMACPS_PHYMNTNC_OP_R_MASK |
+ (PhyAddress << XEMACPS_PHYMNTNC_PHAD_SHFT_MSK) |
+ (RegisterNum << XEMACPS_PHYMNTNC_PREG_SHFT_MSK);
+
+ /* Write Mgtcr and wait for completion */
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_PHYMNTNC_OFFSET, Mgtcr);
+
+ do {
+ Ipisr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWSR_OFFSET);
+ IpReadTemp = Ipisr;
+ } while ((IpReadTemp & XEMACPS_NWSR_MDIOIDLE_MASK) == 0x00000000U);
+
+ /* Read data */
+ *PhyDataPtr = (u16)XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_PHYMNTNC_OFFSET);
+ Status = (LONG)(XST_SUCCESS);
+ }
+ return Status;
+}
+
+
+/*****************************************************************************/
+/**
+* Write data to the specified PHY register. The Ethernet driver does not
+* require the device to be stopped before writing to the PHY. Although it is
+* probably a good idea to stop the device, it is the responsibility of the
+* application to deem this necessary. The MAC provides the driver with the
+* ability to talk to a PHY that adheres to the Media Independent Interface
+* (MII) as defined in the IEEE 802.3 standard.
+*
+* Prior to PHY access with this function, the user should have setup the MDIO
+* clock with XEmacPs_SetMdioDivisor().
+*
+* @param InstancePtr is a pointer to the XEmacPs instance to be worked on.
+* @param PhyAddress is the address of the PHY to be written (supports multiple
+* PHYs)
+* @param RegisterNum is the register number, 0-31, of the specific PHY register
+* to write
+* @param PhyData is the 16-bit value that will be written to the register
+*
+* @return
+*
+* - XST_SUCCESS if the PHY was written to successfully. Since there is no error
+* status from the MAC on a write, the user should read the PHY to verify the
+* write was successful.
+* - XST_EMAC_MII_BUSY if there is another PHY operation in progress
+*
+* @note
+*
+* This function is not thread-safe. The user must provide mutually exclusive
+* access to this function if there are to be multiple threads that can call it.
+*
+* There is the possibility that this function will not return if the hardware
+* is broken (i.e., it never sets the status bit indicating that the write is
+* done). If this is of concern to the user, the user should provide a mechanism
+* suitable to their needs for recovery.
+*
+* For the duration of this function, all host interface reads and writes are
+* blocked to the current XEmacPs instance.
+*
+******************************************************************************/
+LONG XEmacPs_PhyWrite(XEmacPs *InstancePtr, u32 PhyAddress,
+ u32 RegisterNum, u16 PhyData)
+{
+ u32 Mgtcr;
+ volatile u32 Ipisr;
+ u32 IpWriteTemp;
+ LONG Status;
+
+ Xil_AssertNonvoid(InstancePtr != NULL);
+
+ /* Make sure no other PHY operation is currently in progress */
+ if ((!(XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWSR_OFFSET) &
+ XEMACPS_NWSR_MDIOIDLE_MASK))==TRUE) {
+ Status = (LONG)(XST_EMAC_MII_BUSY);
+ } else {
+ /* Construct Mgtcr mask for the operation */
+ Mgtcr = XEMACPS_PHYMNTNC_OP_MASK | XEMACPS_PHYMNTNC_OP_W_MASK |
+ (PhyAddress << XEMACPS_PHYMNTNC_PHAD_SHFT_MSK) |
+ (RegisterNum << XEMACPS_PHYMNTNC_PREG_SHFT_MSK) | (u32)PhyData;
+
+ /* Write Mgtcr and wait for completion */
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_PHYMNTNC_OFFSET, Mgtcr);
+
+ do {
+ Ipisr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_NWSR_OFFSET);
+ IpWriteTemp = Ipisr;
+ } while ((IpWriteTemp & XEMACPS_NWSR_MDIOIDLE_MASK) == 0x00000000U);
+
+ Status = (LONG)(XST_SUCCESS);
+ }
+ return Status;
+}
+
+/*****************************************************************************/
+/**
+* API to update the Burst length in the DMACR register.
+*
+* @param InstancePtr is a pointer to the XEmacPs instance to be worked on.
+* @param BLength is the length in bytes for the dma burst.
+*
+* @return None
+*
+******************************************************************************/
+void XEmacPs_DMABLengthUpdate(XEmacPs *InstancePtr, s32 BLength)
+{
+ u32 Reg;
+ u32 RegUpdateVal = 0;
+
+ Xil_AssertVoid(InstancePtr != NULL);
+ Xil_AssertVoid((BLength == XEMACPS_SINGLE_BURST) ||
+ (BLength == XEMACPS_4BYTE_BURST) ||
+ (BLength == XEMACPS_8BYTE_BURST) ||
+ (BLength == XEMACPS_16BYTE_BURST));
+
+ switch (BLength) {
+ case XEMACPS_SINGLE_BURST:
+ RegUpdateVal = XEMACPS_DMACR_SINGLE_AHB_BURST;
+ break;
+
+ case XEMACPS_4BYTE_BURST:
+ RegUpdateVal = XEMACPS_DMACR_INCR4_AHB_BURST;
+ break;
+
+ case XEMACPS_8BYTE_BURST:
+ RegUpdateVal = XEMACPS_DMACR_INCR8_AHB_BURST;
+ break;
+
+ case XEMACPS_16BYTE_BURST:
+ RegUpdateVal = XEMACPS_DMACR_INCR16_AHB_BURST;
+ break;
+ }
+ Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress,
+ XEMACPS_DMACR_OFFSET);
+
+ Reg &= (u32)(~XEMACPS_DMACR_BLENGTH_MASK);
+ Reg |= RegUpdateVal;
+ XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_DMACR_OFFSET,
+ Reg);
+}
+/** @} */
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_g.c b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_g.c
new file mode 100644
index 0000000000..7f725231af
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_g.c
@@ -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
+ }
+};
+
+
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_hw.c b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_hw.c
new file mode 100644
index 0000000000..3fa614b553
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_hw.c
@@ -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
+*
+*
+* 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.
+*
+*
+******************************************************************************/
+
+/***************************** 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);
+}
+/** @} */
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_hw.h b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_hw.h
new file mode 100644
index 0000000000..362acfdb7f
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_hw.h
@@ -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
+*
+*
+* 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
+*
+*
+******************************************************************************/
+
+#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 */
+/** @} */
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_intr.c b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_intr.c
new file mode 100644
index 0000000000..cd9335ace6
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_intr.c
@@ -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.
+*
+*
+* 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
+*
+******************************************************************************/
+
+/***************************** 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);
+ }
+
+}
+/** @} */
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_sinit.c b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_sinit.c
new file mode 100644
index 0000000000..a16201e939
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/emacps_v3_11/xemacps_sinit.c
@@ -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.
+*
+*
+* 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.
+*
+*
+******************************************************************************/
+
+/***************************** 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);
+}
+/** @} */
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/sleep.h b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/sleep.h
index b49a864dc6..eca569e5b4 100644
--- a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/sleep.h
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/sleep.h
@@ -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
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/SConscript b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/SConscript
new file mode 100644
index 0000000000..8e5fc7069e
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/SConscript
@@ -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')
\ No newline at end of file
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/netif/xadapter.h b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/netif/xadapter.h
new file mode 100644
index 0000000000..aaff03e647
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/netif/xadapter.h
@@ -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
+
+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
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/netif/xemacpsif.h b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/netif/xemacpsif.h
new file mode 100644
index 0000000000..796cdd7f66
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/netif/xemacpsif.h
@@ -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__ */
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/netif/xpqueue.h b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/netif/xpqueue.h
new file mode 100644
index 0000000000..132f02fb38
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/netif/xpqueue.h
@@ -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
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/netif/xtopology.h b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/netif/xtopology.h
new file mode 100644
index 0000000000..f3474cba7c
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/netif/xtopology.h
@@ -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
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xadapter.c b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xadapter.c
new file mode 100644
index 0000000000..a9ed329d58
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xadapter.c
@@ -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
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemac_ieee_reg.h b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemac_ieee_reg.h
new file mode 100644
index 0000000000..4c240a9b7c
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemac_ieee_reg.h
@@ -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_ */
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemacpsif.c b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemacpsif.c
new file mode 100644
index 0000000000..d2aeaba3da
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemacpsif.c
@@ -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
+#include
+
+#include
+#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);
+}
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemacpsif_dma.c b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemacpsif_dma.c
new file mode 100644
index 0000000000..e52f6da6bb
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemacpsif_dma.c
@@ -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
+
+#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);
+}
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemacpsif_hw.c b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemacpsif_hw.c
new file mode 100644
index 0000000000..a1bef1faa1
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemacpsif_hw.c
@@ -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
+}
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemacpsif_hw.h b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemacpsif_hw.h
new file mode 100644
index 0000000000..64f7771494
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemacpsif_hw.h
@@ -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
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemacpsif_physpeed.c b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemacpsif_physpeed.c
new file mode 100644
index 0000000000..9113e3fecb
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xemacpsif_physpeed.c
@@ -0,0 +1,1152 @@
+/*
+ * 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.
+ *
+ */
+
+/*****************************************************************************
+* This file xemacpsif_physpeed.c implements functionalities to:
+* - Detect the available PHYs connected to a MAC
+* - Negotiate speed
+* - Configure speed
+* - Configure the SLCR registers for the negotiated speed
+*
+* In a typical use case, users of the APIs implemented in this file need to
+* do the following.
+* - Call the API detect_phy. It probes for the available PHYs connected to a MAC.
+* The MACs can be Emac0 (XPAR_XEMACPS_0_BASEADDR, 0xE000B000) or Emac1
+* (XPAR_XEMACPS_0_BASEADDR, 0xE000C000). It populates an array to notify
+* about the detected PHYs. The array phymapemac0 is used for Emac0 and
+* phymapemac1 is for Emac1.
+* - The users need to parse the corresponding arrays, phymapemac0 or phymapemac1
+* to know the available PHYs for a MAC. The users then need to call
+* phy_setup_emacps to setup the PHYs for proper speed setting. The API
+* phy_setup_emacps should be called with the PHY address for which the speed
+* needs to be negotiated or configured. In a specific use case, if 2 PHYs are
+* connected to Emac0 with addresses of 7 and 11, then users get these address
+* details from phymapemac0 (after calling detect_phy) and then call
+* phy_setup_emacps twice, with ab address of 7 and 11.
+* - Points to note: The MAC can operate at only one speed. If a MAC is connected
+* to multiple PHYs, then all PHYs must negotiate and configured for the same
+* speed.
+* - This file implements static functions to set proper SLCR clocks. As stated
+* above, all PHYs connected to a PHY must operate at same speed and the SLCR
+* clock will be setup accordingly.
+*
+* This file implements the following PHY types.
+* - The standard RGMII.
+* - It provides support for GMII to RGMII converter Xilinx IP. This Xilinx IP
+* sits on the MDIO bus with a predefined PHY address. This IP exposes register
+* that needs to be programmed with the negotiated speed.
+* For example, in a typical design, the Emac0 or Emac1 exposes GMII interface.
+* The user can then use the Xilinx IP that converts GMII to RGMII.
+* The external PHY (most typically Marvell 88E1116R) negotiates for speed
+* with the remote PHY. The implementation in this file then programs the
+* Xilinx IP with this negotiated speed. The Xilinx IP has a predefined IP
+* address exposed through xparameters.h
+* - The SGMII and 1000 BaseX PHY interfaces.
+* If the PHY interface is SGMII or 1000 BaseX a separate "get_IEEE_phy_speed"
+* is used which is different from standard RGMII "get_IEEE_phy_speed".
+* The 1000 BaseX always operates at 1000 Mbps. The SGMII interface can
+* negotiate speed accordingly.
+* For SGMII or 1000 BaseX interfaces, the detect_phy should not be called.
+* The phy addresses for these interfaces are fixed at the design time.
+*
+* Point to note:
+* A MAC can not be connected to PHYs where there is a mix between
+* SGMII or 1000 Basex or GMII/MII/RGMII.
+* In a typical multiple PHY designs, it is expected that the PHYs connected
+* will be RGMII or GMII.
+*
+* The users can choose not to negotiate speed from lwip settings GUI.
+* If they opt to choose a particular PHY speed, then the PHY will hard code
+* the speed to operate only at the corresponding speed. It will not advertise
+* any other speeds. It is users responsibility to ensure that the remote PHY
+* supports the speed programmed through the lwip gui.
+*
+* The following combination of MDIO/PHY are supported:
+* - Multiple PHYs connected to the MDIO bus of a MAC. If Emac0 MDIO is connected
+* to single/multiple PHYs, it is supported. Similarly Emac1 MDIO connected to
+* single/multiple PHYs is supported.
+* - A design where both the interfaces are present and are connected to their own
+* MDIO bus is supported.
+*
+* The following MDIO/PHY setup is not supported:
+* - A design has both the MACs present. MDIO bus is available only for one MAC
+* (Emac0 or Emac1). This MDIO bus has multiple PHYs available for both the
+* MACs. The negotiated speed for PHYs sitting on the MDIO bus of one MAC will
+* not be see for the other MAC and hence the speed/SLCR settings of the other
+* MAC cannot be programmed. Hence this kind of design will not work for
+* this implementation.
+*
+********************************************************************************/
+
+#include "netif/xemacpsif.h"
+#include "lwipopts.h"
+#include "xparameters_ps.h"
+#include "xparameters.h"
+#include "xemac_ieee_reg.h"
+
+#if defined (__aarch64__)
+#include "bspconfig.h"
+#include "xil_smc.h"
+#endif
+
+#define CONFIG_LINKSPEED_AUTODETECT 1
+
+#define PHY_DETECT_REG 1
+#define PHY_IDENTIFIER_1_REG 2
+#define PHY_IDENTIFIER_2_REG 3
+#define PHY_DETECT_MASK 0x1808
+#define PHY_MARVELL_IDENTIFIER 0x0141
+#define PHY_TI_IDENTIFIER 0x2000
+#define PHY_REALTEK_IDENTIFIER 0x001c
+#define PHY_XILINX_PCS_PMA_ID1 0x0174
+#define PHY_XILINX_PCS_PMA_ID2 0x0C00
+
+#define XEMACPS_GMII2RGMII_SPEED1000_FD 0x140
+#define XEMACPS_GMII2RGMII_SPEED100_FD 0x2100
+#define XEMACPS_GMII2RGMII_SPEED10_FD 0x100
+#define XEMACPS_GMII2RGMII_REG_NUM 0x10
+
+#define PHY_REGCR 0x0D
+#define PHY_ADDAR 0x0E
+#define PHY_RGMIIDCTL 0x86
+#define PHY_RGMIICTL 0x32
+#define PHY_STS 0x11
+#define PHY_TI_CR 0x10
+#define PHY_TI_CFG4 0x31
+
+#define MICREL_PHY_IDENTIFIER 0x22
+#define MICREL_PHY_KSZ9031_MODEL 0x220
+
+#define PHY_REGCR_ADDR 0x001F
+#define PHY_REGCR_DATA 0x401F
+#define PHY_TI_CRVAL 0x5048
+#define PHY_TI_CFG4RESVDBIT7 0x80
+
+/* Frequency setting */
+#define SLCR_LOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x4)
+#define SLCR_UNLOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x8)
+#define SLCR_GEM0_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x140)
+#define SLCR_GEM1_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x144)
+#define SLCR_GEM_SRCSEL_EMIO 0x40
+#define SLCR_LOCK_KEY_VALUE 0x767B
+#define SLCR_UNLOCK_KEY_VALUE 0xDF0D
+#define SLCR_ADDR_GEM_RST_CTRL (XPS_SYS_CTRL_BASEADDR + 0x214)
+#define EMACPS_SLCR_DIV_MASK 0xFC0FC0FF
+
+#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
+
+#ifdef PCM_PMA_CORE_PRESENT
+#define IEEE_CTRL_RESET 0x9140
+#define IEEE_CTRL_ISOLATE_DISABLE 0xFBFF
+#endif
+
+u32_t phymapemac0[32];
+u32_t phymapemac1[32];
+
+#if defined (PCM_PMA_CORE_PRESENT) || defined (CONFIG_LINKSPEED_AUTODETECT)
+static u32_t get_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr);
+#endif
+static void SetUpSLCRDivisors(u32_t mac_baseaddr, s32_t speed);
+#if defined (CONFIG_LINKSPEED1000) || defined (CONFIG_LINKSPEED100) \
+ || defined (CONFIG_LINKSPEED10)
+static u32_t configure_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr, u32_t speed);
+#endif
+
+#ifdef PCM_PMA_CORE_PRESENT
+u32_t phy_setup_emacps (XEmacPs *xemacpsp, u32_t phy_addr)
+{
+ u32_t link_speed;
+ u16_t regval;
+ u16_t phy_id;
+
+ if(phy_addr == 0) {
+ for (phy_addr = 31; phy_addr > 0; phy_addr--) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_IDENTIFIER_1_REG,
+ &phy_id);
+
+ if (phy_id == PHY_XILINX_PCS_PMA_ID1) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_IDENTIFIER_2_REG,
+ &phy_id);
+ if (phy_id == PHY_XILINX_PCS_PMA_ID2) {
+ /* Found a valid PHY address */
+ LWIP_DEBUGF(NETIF_DEBUG, ("XEmacPs detect_phy: PHY detected at address %d.\r\n",
+ phy_addr));
+ break;
+ }
+ }
+ }
+ }
+
+ link_speed = get_IEEE_phy_speed(xemacpsp, phy_addr);
+ if (link_speed == 1000)
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000);
+ else if (link_speed == 100)
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100);
+ else
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10);
+
+ xil_printf("link speed for phy address %d: %d\r\n", phy_addr, link_speed);
+ return link_speed;
+}
+
+static u32_t get_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
+{
+ u16_t temp;
+ u16_t control;
+ u16_t status;
+ u16_t partner_capabilities;
+
+ xil_printf("Start PHY autonegotiation \r\n");
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
+ control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
+ control &= IEEE_CTRL_ISOLATE_DISABLE;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
+
+ xil_printf("Waiting for PHY to complete autonegotiation.\r\n");
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+ while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
+ sleep(1);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET,
+ &status);
+ }
+ xil_printf("autonegotiation complete \r\n");
+
+#if XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT == 1
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 1);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_1_REG_OFFSET, &temp);
+ if ((temp & 0x0020) == 0x0020) {
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
+ return 1000;
+ }
+ else {
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
+ xil_printf("Link error, temp = %x\r\n", temp);
+ return 0;
+ }
+#elif XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT == 1
+ xil_printf("Waiting for Link to be up; Polling for SGMII core Reg \r\n");
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_1_REG_OFFSET, &temp);
+ while(!(temp & 0x8000)) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_PARTNER_ABILITIES_1_REG_OFFSET, &temp);
+ }
+ if((temp & 0x0C00) == 0x0800) {
+ return 1000;
+ }
+ else if((temp & 0x0C00) == 0x0400) {
+ return 100;
+ }
+ else if((temp & 0x0C00) == 0x0000) {
+ return 10;
+ } else {
+ xil_printf("get_IEEE_phy_speed(): Invalid speed bit value, Defaulting to Speed = 10 Mbps\r\n");
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &temp);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, 0x0100);
+ return 10;
+ }
+#endif
+
+}
+
+#else /*PCM_PMA_CORE_PRESENT not defined, GMII/RGMII case*/
+void detect_phy(XEmacPs *xemacpsp)
+{
+ u16_t phy_reg;
+ u32_t phy_addr;
+ u32_t emacnum;
+
+ if (xemacpsp->Config.BaseAddress == XPAR_XEMACPS_0_BASEADDR)
+ emacnum = 0;
+ else
+ emacnum = 1;
+ for (phy_addr = 31; phy_addr > 0; phy_addr--) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_DETECT_REG,
+ &phy_reg);
+
+ if ((phy_reg != 0xFFFF) &&
+ ((phy_reg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) {
+ /* Found a valid PHY address */
+ LWIP_DEBUGF(NETIF_DEBUG, ("XEmacPs detect_phy: PHY detected at address %d.\r\n",
+ phy_addr));
+ if (emacnum == 0)
+ phymapemac0[phy_addr] = TRUE;
+ else
+ phymapemac1[phy_addr] = TRUE;
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_IDENTIFIER_1_REG,
+ &phy_reg);
+ if ((phy_reg != PHY_MARVELL_IDENTIFIER) &&
+ (phy_reg != PHY_TI_IDENTIFIER) &&
+ (phy_reg != PHY_REALTEK_IDENTIFIER)) {
+ xil_printf("WARNING: Not a Marvell or TI or Realtek Ethernet PHY. Please verify the initialization sequence\r\n");
+ }
+ }
+ }
+}
+
+u32_t phy_setup_emacps (XEmacPs *xemacpsp, u32_t phy_addr)
+{
+ u32_t link_speed;
+ u32_t conv_present = 0;
+ u32_t convspeeddupsetting = 0;
+ u32_t convphyaddr = 0;
+
+#ifdef XPAR_GMII2RGMIICON_0N_ETH0_ADDR
+ convphyaddr = XPAR_GMII2RGMIICON_0N_ETH0_ADDR;
+ conv_present = 1;
+#endif
+#ifdef XPAR_GMII2RGMIICON_0N_ETH1_ADDR
+ convphyaddr = XPAR_GMII2RGMIICON_0N_ETH1_ADDR;
+ conv_present = 1;
+#endif
+
+#ifdef CONFIG_LINKSPEED_AUTODETECT
+ link_speed = get_IEEE_phy_speed(xemacpsp, phy_addr);
+ if (link_speed == 1000) {
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000);
+ convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED1000_FD;
+ } else if (link_speed == 100) {
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100);
+ convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED100_FD;
+ } else if (link_speed != XST_FAILURE){
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10);
+ convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED10_FD;
+ } else {
+ xil_printf("Phy setup error \r\n");
+ return XST_FAILURE;
+ }
+#elif defined(CONFIG_LINKSPEED1000)
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,1000);
+ link_speed = 1000;
+ configure_IEEE_phy_speed(xemacpsp, phy_addr, link_speed);
+ convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED1000_FD;
+ sleep(1);
+#elif defined(CONFIG_LINKSPEED100)
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,100);
+ link_speed = 100;
+ configure_IEEE_phy_speed(xemacpsp, phy_addr, link_speed);
+ convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED100_FD;
+ sleep(1);
+#elif defined(CONFIG_LINKSPEED10)
+ SetUpSLCRDivisors(xemacpsp->Config.BaseAddress,10);
+ link_speed = 10;
+ configure_IEEE_phy_speed(xemacpsp, phy_addr, link_speed);
+ convspeeddupsetting = XEMACPS_GMII2RGMII_SPEED10_FD;
+ sleep(1);
+#endif
+ if (conv_present) {
+ XEmacPs_PhyWrite(xemacpsp, convphyaddr,
+ XEMACPS_GMII2RGMII_REG_NUM, convspeeddupsetting);
+ }
+
+ xil_printf("link speed for phy address %d: %d\r\n", phy_addr, link_speed);
+ return link_speed;
+}
+
+#if defined CONFIG_LINKSPEED_AUTODETECT
+static u32_t get_phy_speed_ksz9031(XEmacPs *xemacpsp, u32_t phy_addr)
+{
+ static int phy_init_flag = 0;
+ u16_t temp;
+ u16_t control;
+ u16_t status;
+ u16_t status_speed;
+ u32_t timeout_counter = 0;
+
+ xil_printf("Start PHY autonegotiation \r\n");
+
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
+ control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);
+
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
+ control |= IEEE_ASYMMETRIC_PAUSE_MASK;
+ control |= IEEE_PAUSE_MASK;
+ control |= ADVERTISE_100;
+ control |= ADVERTISE_10;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
+ &control);
+ control |= ADVERTISE_1000;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
+ control);
+
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG, &control);
+
+ control |= (7 << 12); /* max number of gigabit attempts */
+ control |= (1 << 11); /* enable downshift */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
+ control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
+ control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control |= IEEE_CTRL_RESET_MASK;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
+
+ while (1) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ if (control & IEEE_CTRL_RESET_MASK)
+ continue;
+ else
+ break;
+ }
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+
+ xil_printf("Waiting for PHY to complete autonegotiation.\r\n");
+
+ while (!(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE)) {
+ sleep(1);
+ XEmacPs_PhyRead(xemacpsp, phy_addr,
+ IEEE_COPPER_SPECIFIC_STATUS_REG_2, &temp);
+ timeout_counter++;
+ if ((phy_init_flag == 0) && (timeout_counter > 1))
+ {
+ phy_init_flag = 1;
+ return XST_FAILURE;
+ }
+ if (timeout_counter == 30) {
+ xil_printf("Auto negotiation error \r\n");
+ return XST_FAILURE;
+ }
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+ }
+ xil_printf("autonegotiation complete \r\n");
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, 0x1f, &status_speed);
+
+ if ((status_speed & 0x40) == 0x40) /* 1000Mbps */
+ return 1000;
+ else if ((status_speed & 0x20) == 0x20) /* 100Mbps */
+ return 100;
+ else if ((status_speed & 0x10) == 0x10) /* 10Mbps */
+ return 10;
+ else
+ return 0;
+ return XST_SUCCESS;
+}
+
+static u32_t get_TI_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
+{
+ u16_t control;
+ u16_t status;
+ u16_t status_speed;
+ u32_t timeout_counter = 0;
+ u32_t phyregtemp;
+ int i;
+ u32_t RetStatus;
+ static int phy_init_flag = 0;
+
+ xil_printf("Start PHY autonegotiation \r\n");
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, 0x1F, (u16_t *)&phyregtemp);
+ phyregtemp |= 0x4000;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, 0x1F, phyregtemp);
+ RetStatus = XEmacPs_PhyRead(xemacpsp, phy_addr, 0x1F, (u16_t *)&phyregtemp);
+ if (RetStatus != XST_SUCCESS) {
+ xil_printf("Error during sw reset \n\r");
+ return XST_FAILURE;
+ }
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, 0, (u16_t *)&phyregtemp);
+ phyregtemp |= 0x8000;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, 0, phyregtemp);
+
+ /*
+ * Delay
+ */
+ for(i=0;i<1000000000;i++);
+
+ RetStatus = XEmacPs_PhyRead(xemacpsp, phy_addr, 0, (u16_t *)&phyregtemp);
+ if (RetStatus != XST_SUCCESS) {
+ xil_printf("Error during reset \n\r");
+ return XST_FAILURE;
+ }
+
+ /* FIFO depth */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_TI_CR, PHY_TI_CRVAL);
+ RetStatus = XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_TI_CR, (u16_t *)&phyregtemp);
+ if (RetStatus != XST_SUCCESS) {
+ xil_printf("Error writing to 0x10 \n\r");
+ return XST_FAILURE;
+ }
+
+ /* TX/RX tuning */
+ /* Write to PHY_RGMIIDCTL */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_ADDR);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_ADDAR, PHY_RGMIIDCTL);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_DATA);
+ RetStatus = XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_ADDAR, 0xA8);
+ if (RetStatus != XST_SUCCESS) {
+ xil_printf("Error in tuning");
+ return XST_FAILURE;
+ }
+
+ /* Read PHY_RGMIIDCTL */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_ADDR);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_ADDAR, PHY_RGMIIDCTL);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_DATA);
+ RetStatus = XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_ADDAR, (u16_t *)&phyregtemp);
+ if (RetStatus != XST_SUCCESS) {
+ xil_printf("Error in tuning");
+ return XST_FAILURE;
+ }
+
+ /* Write PHY_RGMIICTL */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_ADDR);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_ADDAR, PHY_RGMIICTL);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_DATA);
+ RetStatus = XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_ADDAR, 0xD3);
+ if (RetStatus != XST_SUCCESS) {
+ xil_printf("Error in tuning");
+ return XST_FAILURE;
+ }
+
+ /* Read PHY_RGMIICTL */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_ADDR);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_ADDAR, PHY_RGMIICTL);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_DATA);
+ RetStatus = XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_ADDAR, (u16_t *)&phyregtemp);
+ if (RetStatus != XST_SUCCESS) {
+ xil_printf("Error in tuning");
+ return XST_FAILURE;
+ }
+
+ /* SW workaround for unstable link when RX_CTRL is not STRAP MODE 3 or 4 */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_ADDR);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_ADDAR, PHY_TI_CFG4);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_DATA);
+ RetStatus = XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_ADDAR, (u16_t *)&phyregtemp);
+ phyregtemp &= ~(PHY_TI_CFG4RESVDBIT7);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_ADDR);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_ADDAR, PHY_TI_CFG4);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_REGCR, PHY_REGCR_DATA);
+ RetStatus = XEmacPs_PhyWrite(xemacpsp, phy_addr, PHY_ADDAR, phyregtemp);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
+ control |= IEEE_ASYMMETRIC_PAUSE_MASK;
+ control |= IEEE_PAUSE_MASK;
+ control |= ADVERTISE_100;
+ control |= ADVERTISE_10;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
+ &control);
+ control |= ADVERTISE_1000;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
+ control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
+ control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+
+ xil_printf("Waiting for PHY to complete autonegotiation.\r\n");
+
+ while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
+ sleep(1);
+ timeout_counter++;
+ if ((phy_init_flag == 0) && (timeout_counter > 1))
+ {
+ phy_init_flag = 1;
+ return XST_FAILURE;
+ }
+ if (timeout_counter == 30) {
+ xil_printf("Auto negotiation error \r\n");
+ return XST_FAILURE;
+ }
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+ }
+ xil_printf("autonegotiation complete \r\n");
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_STS, &status_speed);
+ if ((status_speed & 0xC000) == 0x8000) {
+ return 1000;
+ } else if ((status_speed & 0xC000) == 0x4000) {
+ return 100;
+ } else {
+ return 10;
+ }
+
+ return XST_SUCCESS;
+}
+
+static u32_t get_Marvell_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
+{
+ u16_t temp;
+ u16_t control;
+ u16_t status;
+ u16_t status_speed;
+ u32_t timeout_counter = 0;
+ u32_t temp_speed;
+ static int phy_init_flag = 0;
+
+ xil_printf("Start PHY autonegotiation \r\n");
+
+ XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
+ control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);
+
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
+ control |= IEEE_ASYMMETRIC_PAUSE_MASK;
+ control |= IEEE_PAUSE_MASK;
+ control |= ADVERTISE_100;
+ control |= ADVERTISE_10;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
+ &control);
+ control |= ADVERTISE_1000;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
+ control);
+
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
+ &control);
+ control |= (7 << 12); /* max number of gigabit attempts */
+ control |= (1 << 11); /* enable downshift */
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_COPPER_SPECIFIC_CONTROL_REG,
+ control);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
+ control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control |= IEEE_CTRL_RESET_MASK;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
+
+ while (1) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ if (control & IEEE_CTRL_RESET_MASK)
+ continue;
+ else
+ break;
+ }
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+
+ xil_printf("Waiting for PHY to complete autonegotiation.\r\n");
+
+ while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
+ sleep(1);
+ XEmacPs_PhyRead(xemacpsp, phy_addr,
+ IEEE_COPPER_SPECIFIC_STATUS_REG_2, &temp);
+ timeout_counter++;
+ if ((phy_init_flag == 0) && (timeout_counter > 1))
+ {
+ phy_init_flag = 1;
+ return XST_FAILURE;
+ }
+ if (timeout_counter == 30) {
+ xil_printf("Auto negotiation error \r\n");
+ return XST_FAILURE;
+ }
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+ }
+ xil_printf("autonegotiation complete \r\n");
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr,IEEE_SPECIFIC_STATUS_REG,
+ &status_speed);
+ if (status_speed & 0x400) {
+ temp_speed = status_speed & IEEE_SPEED_MASK;
+
+ if (temp_speed == IEEE_SPEED_1000)
+ return 1000;
+ else if(temp_speed == IEEE_SPEED_100)
+ return 100;
+ else
+ return 10;
+ }
+
+ return XST_SUCCESS;
+}
+
+static u32_t get_Realtek_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
+{
+ u16_t control;
+ u16_t status;
+ u16_t status_speed;
+ u32_t timeout_counter = 0;
+ u32_t temp_speed;
+ static int phy_init_flag = 0;
+
+ xil_printf("Start PHY autonegotiation \r\n");
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &control);
+ control |= IEEE_ASYMMETRIC_PAUSE_MASK;
+ control |= IEEE_PAUSE_MASK;
+ control |= ADVERTISE_100;
+ control |= ADVERTISE_10;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
+ &control);
+ control |= ADVERTISE_1000;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET,
+ control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE;
+ control |= IEEE_STAT_AUTONEGOTIATE_RESTART;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control |= IEEE_CTRL_RESET_MASK;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, control);
+
+ while (1) {
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ if (control & IEEE_CTRL_RESET_MASK)
+ continue;
+ else
+ break;
+ }
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+
+ xil_printf("Waiting for PHY to complete autonegotiation.\r\n");
+
+ while ( !(status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) {
+ sleep(1);
+ timeout_counter++;
+ if ((phy_init_flag == 0) && (timeout_counter > 1))
+ {
+ phy_init_flag = 1;
+ return XST_FAILURE;
+ }
+ if (timeout_counter == 30) {
+ xil_printf("Auto negotiation error \r\n");
+ return XST_FAILURE;
+ }
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_STATUS_REG_OFFSET, &status);
+ }
+ xil_printf("autonegotiation complete \r\n");
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr,IEEE_SPECIFIC_STATUS_REG,
+ &status_speed);
+ if (status_speed & 0x400) {
+ temp_speed = status_speed & IEEE_SPEED_MASK;
+
+ if (temp_speed == IEEE_SPEED_1000)
+ return 1000;
+ else if(temp_speed == IEEE_SPEED_100)
+ return 100;
+ else
+ return 10;
+ }
+
+ return XST_FAILURE;
+}
+
+static u32_t get_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr)
+{
+ u16_t phy_identity;
+ u32_t RetStatus;
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, PHY_IDENTIFIER_1_REG,
+ &phy_identity);
+ if(phy_identity == MICREL_PHY_IDENTIFIER){
+ RetStatus = get_phy_speed_ksz9031(xemacpsp, phy_addr);
+ } else if (phy_identity == PHY_TI_IDENTIFIER) {
+ RetStatus = get_TI_phy_speed(xemacpsp, phy_addr);
+ } else if (phy_identity == PHY_REALTEK_IDENTIFIER) {
+ RetStatus = get_Realtek_phy_speed(xemacpsp, phy_addr);
+ } else {
+ RetStatus = get_Marvell_phy_speed(xemacpsp, phy_addr);
+ }
+
+ return RetStatus;
+}
+#endif
+
+#if defined (CONFIG_LINKSPEED1000) || defined (CONFIG_LINKSPEED100) \
+ || defined (CONFIG_LINKSPEED10)
+static u32_t configure_IEEE_phy_speed(XEmacPs *xemacpsp, u32_t phy_addr, u32_t speed)
+{
+ u16_t control;
+ u16_t autonereg;
+
+ XEmacPs_PhyWrite(xemacpsp,phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 2);
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, &control);
+ control |= IEEE_RGMII_TXRX_CLOCK_DELAYED_MASK;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_MAC, control);
+
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_PAGE_ADDRESS_REGISTER, 0);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
+ autonereg |= IEEE_ASYMMETRIC_PAUSE_MASK;
+ autonereg |= IEEE_PAUSE_MASK;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
+
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET, &control);
+ control &= ~IEEE_CTRL_LINKSPEED_1000M;
+ control &= ~IEEE_CTRL_LINKSPEED_100M;
+ control &= ~IEEE_CTRL_LINKSPEED_10M;
+
+ if (speed == 1000) {
+ control |= IEEE_CTRL_LINKSPEED_1000M;
+
+ /* Don't advertise PHY speed of 100 Mbps */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
+ autonereg &= (~ADVERTISE_100);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
+
+ /* Don't advertise PHY speed of 10 Mbps */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
+ autonereg &= (~ADVERTISE_10);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
+
+ /* Advertise PHY speed of 1000 Mbps */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, &autonereg);
+ autonereg |= ADVERTISE_1000;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, autonereg);
+ }
+
+ else if (speed == 100) {
+ control |= IEEE_CTRL_LINKSPEED_100M;
+
+ /* Don't advertise PHY speed of 1000 Mbps */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, &autonereg);
+ autonereg &= (~ADVERTISE_1000);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, autonereg);
+
+ /* Don't advertise PHY speed of 10 Mbps */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
+ autonereg &= (~ADVERTISE_10);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
+
+ /* Advertise PHY speed of 100 Mbps */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
+ autonereg |= ADVERTISE_100;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
+ }
+
+ else if (speed == 10) {
+ control |= IEEE_CTRL_LINKSPEED_10M;
+
+ /* Don't advertise PHY speed of 1000 Mbps */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, &autonereg);
+ autonereg &= (~ADVERTISE_1000);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_1000_ADVERTISE_REG_OFFSET, autonereg);
+
+ /* Don't advertise PHY speed of 100 Mbps */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
+ autonereg &= (~ADVERTISE_100);
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
+
+ /* Advertise PHY speed of 10 Mbps */
+ XEmacPs_PhyRead(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, &autonereg);
+ autonereg |= ADVERTISE_10;
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_AUTONEGO_ADVERTISE_REG, autonereg);
+ }
+
+ XEmacPs_PhyWrite(xemacpsp, phy_addr, IEEE_CONTROL_REG_OFFSET,
+ control | IEEE_CTRL_RESET_MASK);
+ {
+ volatile s32_t wait;
+ for (wait=0; wait < 100000; wait++);
+ }
+ return 0;
+}
+#endif
+#endif /*PCM_PMA_CORE_PRESENT*/
+
+static void SetUpSLCRDivisors(u32_t mac_baseaddr, s32_t speed)
+{
+ volatile u32_t slcrBaseAddress;
+ u32_t SlcrDiv0 = 0;
+ u32_t SlcrDiv1 = 0;
+ u32_t SlcrTxClkCntrl;
+ u32_t gigeversion;
+ volatile u32_t CrlApbBaseAddr;
+ u32_t CrlApbDiv0 = 0;
+ u32_t CrlApbDiv1 = 0;
+ u32_t CrlApbGemCtrl;
+#if EL1_NONSECURE
+ u32_t ClkId;
+#endif
+
+ gigeversion = ((Xil_In32(mac_baseaddr + 0xFC)) >> 16) & 0xFFF;
+ if (gigeversion == 2) {
+
+ *(volatile u32_t *)(SLCR_UNLOCK_ADDR) = SLCR_UNLOCK_KEY_VALUE;
+
+ if (mac_baseaddr == ZYNQ_EMACPS_0_BASEADDR) {
+ slcrBaseAddress = SLCR_GEM0_CLK_CTRL_ADDR;
+ } else {
+ slcrBaseAddress = SLCR_GEM1_CLK_CTRL_ADDR;
+ }
+
+ if((*(volatile u32_t *)(UINTPTR)(slcrBaseAddress)) &
+ SLCR_GEM_SRCSEL_EMIO) {
+ return;
+ }
+
+ if (speed == 1000) {
+ if (mac_baseaddr == XPAR_XEMACPS_0_BASEADDR) {
+#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0
+ SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0;
+ SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1;
+#endif
+ } else {
+#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0
+ SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0;
+ SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV1;
+#endif
+ }
+ } else if (speed == 100) {
+ if (mac_baseaddr == XPAR_XEMACPS_0_BASEADDR) {
+#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0
+ SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0;
+ SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1;
+#endif
+ } else {
+#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0
+ SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV0;
+ SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_100MBPS_DIV1;
+#endif
+ }
+ } else {
+ if (mac_baseaddr == XPAR_XEMACPS_0_BASEADDR) {
+#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0
+ SlcrDiv0 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0;
+ SlcrDiv1 = XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV1;
+#endif
+ } else {
+#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0
+ SlcrDiv0 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV0;
+ SlcrDiv1 = XPAR_PS7_ETHERNET_1_ENET_SLCR_10MBPS_DIV1;
+#endif
+ }
+ }
+
+ if (SlcrDiv0 != 0 && SlcrDiv1 != 0) {
+ SlcrTxClkCntrl = *(volatile u32_t *)(UINTPTR)(slcrBaseAddress);
+ SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK;
+ SlcrTxClkCntrl |= (SlcrDiv1 << 20);
+ SlcrTxClkCntrl |= (SlcrDiv0 << 8);
+ *(volatile u32_t *)(UINTPTR)(slcrBaseAddress) = SlcrTxClkCntrl;
+ *(volatile u32_t *)(SLCR_LOCK_ADDR) = SLCR_LOCK_KEY_VALUE;
+ } else {
+ xil_printf("Clock Divisors incorrect - Please check\r\n");
+ }
+ } else if (gigeversion == GEM_VERSION_ZYNQMP) {
+ /* Setup divisors in CRL_APB for Zynq Ultrascale+ MPSoC */
+ if (mac_baseaddr == ZYNQMP_EMACPS_0_BASEADDR) {
+ CrlApbBaseAddr = CRL_APB_GEM0_REF_CTRL;
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_1_BASEADDR) {
+ CrlApbBaseAddr = CRL_APB_GEM1_REF_CTRL;
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_2_BASEADDR) {
+ CrlApbBaseAddr = CRL_APB_GEM2_REF_CTRL;
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_3_BASEADDR) {
+ CrlApbBaseAddr = CRL_APB_GEM3_REF_CTRL;
+ }
+
+ if (speed == 1000) {
+ if (mac_baseaddr == ZYNQMP_EMACPS_0_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1;
+#endif
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_1_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_1_ENET_SLCR_1000MBPS_DIV1;
+#endif
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_2_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_2_ENET_SLCR_1000MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_2_ENET_SLCR_1000MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_2_ENET_SLCR_1000MBPS_DIV1;
+#endif
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_3_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_3_ENET_SLCR_1000MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_3_ENET_SLCR_1000MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_3_ENET_SLCR_1000MBPS_DIV1;
+#endif
+ }
+ } else if (speed == 100) {
+ if (mac_baseaddr == ZYNQMP_EMACPS_0_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_0_ENET_SLCR_100MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_0_ENET_SLCR_100MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_0_ENET_SLCR_100MBPS_DIV1;
+#endif
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_1_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_1_ENET_SLCR_100MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_1_ENET_SLCR_100MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_1_ENET_SLCR_100MBPS_DIV1;
+#endif
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_2_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_2_ENET_SLCR_100MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_2_ENET_SLCR_100MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_2_ENET_SLCR_100MBPS_DIV1;
+#endif
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_3_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_3_ENET_SLCR_100MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_3_ENET_SLCR_100MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_3_ENET_SLCR_100MBPS_DIV1;
+#endif
+ }
+ } else {
+ if (mac_baseaddr == ZYNQMP_EMACPS_0_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_0_ENET_SLCR_10MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_0_ENET_SLCR_10MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_0_ENET_SLCR_10MBPS_DIV1;
+#endif
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_1_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_1_ENET_SLCR_10MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_1_ENET_SLCR_10MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_1_ENET_SLCR_10MBPS_DIV1;
+#endif
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_2_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_2_ENET_SLCR_10MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_2_ENET_SLCR_10MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_2_ENET_SLCR_10MBPS_DIV1;
+#endif
+ } else if (mac_baseaddr == ZYNQMP_EMACPS_3_BASEADDR) {
+#ifdef XPAR_PSU_ETHERNET_3_ENET_SLCR_10MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSU_ETHERNET_3_ENET_SLCR_10MBPS_DIV0;
+ CrlApbDiv1 = XPAR_PSU_ETHERNET_3_ENET_SLCR_10MBPS_DIV1;
+#endif
+ }
+ }
+
+ if (CrlApbDiv0 != 0 && CrlApbDiv1 != 0) {
+ #if EL1_NONSECURE
+ XSmc_OutVar RegRead;
+ RegRead = Xil_Smc(MMIO_READ_SMC_FID, (u64)(CrlApbBaseAddr),
+ 0, 0, 0, 0, 0, 0);
+ CrlApbGemCtrl = RegRead.Arg0 >> 32;
+ #else
+ CrlApbGemCtrl = *(volatile u32_t *)(UINTPTR)(CrlApbBaseAddr);
+ #endif
+ CrlApbGemCtrl &= ~CRL_APB_GEM_DIV0_MASK;
+ CrlApbGemCtrl |= CrlApbDiv0 << CRL_APB_GEM_DIV0_SHIFT;
+ CrlApbGemCtrl &= ~CRL_APB_GEM_DIV1_MASK;
+ CrlApbGemCtrl |= CrlApbDiv1 << CRL_APB_GEM_DIV1_SHIFT;
+ #if EL1_NONSECURE
+ Xil_Smc(MMIO_WRITE_SMC_FID, (u64)(CrlApbBaseAddr) | ((u64)(0xFFFFFFFF) << 32),
+ (u64)CrlApbGemCtrl, 0, 0, 0, 0, 0);
+ do {
+ RegRead = Xil_Smc(MMIO_READ_SMC_FID, (u64)(CrlApbBaseAddr),
+ 0, 0, 0, 0, 0, 0);
+ } while((RegRead.Arg0 >> 32) != CrlApbGemCtrl);
+ #else
+ *(volatile u32_t *)(UINTPTR)(CrlApbBaseAddr) = CrlApbGemCtrl;
+ #endif
+ } else {
+ xil_printf("Clock Divisors incorrect - Please check\r\n");
+ }
+ } else if (gigeversion == GEM_VERSION_VERSAL) {
+ /* Setup divisors in CRL for Versal */
+ if (mac_baseaddr == VERSAL_EMACPS_0_BASEADDR) {
+ CrlApbBaseAddr = VERSAL_CRL_GEM0_REF_CTRL;
+#if EL1_NONSECURE
+ ClkId = CLK_GEM0_REF;
+#endif
+ } else if (mac_baseaddr == VERSAL_EMACPS_1_BASEADDR) {
+ CrlApbBaseAddr = VERSAL_CRL_GEM1_REF_CTRL;
+#if EL1_NONSECURE
+ ClkId = CLK_GEM1_REF;
+#endif
+ }
+
+ if (speed == 1000) {
+ if (mac_baseaddr == VERSAL_EMACPS_0_BASEADDR) {
+#ifdef XPAR_PSV_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSV_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0;
+#endif
+ } else if (mac_baseaddr == VERSAL_EMACPS_1_BASEADDR) {
+#ifdef XPAR_PSV_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSV_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0;
+#endif
+ }
+ } else if (speed == 100) {
+ if (mac_baseaddr == VERSAL_EMACPS_0_BASEADDR) {
+#ifdef XPAR_PSV_ETHERNET_0_ENET_SLCR_100MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSV_ETHERNET_0_ENET_SLCR_100MBPS_DIV0;
+#endif
+ } else if (mac_baseaddr == VERSAL_EMACPS_1_BASEADDR) {
+#ifdef XPAR_PSV_ETHERNET_1_ENET_SLCR_100MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSV_ETHERNET_1_ENET_SLCR_100MBPS_DIV0;
+#endif
+ }
+ } else {
+ if (mac_baseaddr == VERSAL_EMACPS_0_BASEADDR) {
+#ifdef XPAR_PSV_ETHERNET_0_ENET_SLCR_10MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSV_ETHERNET_0_ENET_SLCR_10MBPS_DIV0;
+#endif
+ } else if (mac_baseaddr == VERSAL_EMACPS_1_BASEADDR) {
+#ifdef XPAR_PSV_ETHERNET_1_ENET_SLCR_10MBPS_DIV0
+ CrlApbDiv0 = XPAR_PSV_ETHERNET_1_ENET_SLCR_10MBPS_DIV0;
+#endif
+ }
+ }
+
+ if (CrlApbDiv0 != 0) {
+#if EL1_NONSECURE
+ Xil_Smc(PM_SET_DIVIDER_SMC_FID, (((u64)CrlApbDiv0 << 32) | ClkId), 0, 0, 0, 0, 0, 0);
+#else
+ CrlApbGemCtrl = Xil_In32((UINTPTR)CrlApbBaseAddr);
+ CrlApbGemCtrl &= ~VERSAL_CRL_GEM_DIV_MASK;
+ CrlApbGemCtrl |= CrlApbDiv0 << VERSAL_CRL_APB_GEM_DIV_SHIFT;
+
+ Xil_Out32((UINTPTR)CrlApbBaseAddr, CrlApbGemCtrl);
+#endif
+ } else {
+ xil_printf("Clock Divisors incorrect - Please check\r\n");
+ }
+ }
+
+ return;
+}
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xlwipconfig.h b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xlwipconfig.h
new file mode 100644
index 0000000000..fd114dd5fb
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xlwipconfig.h
@@ -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
+ *
+ */
+#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
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xpqueue.c b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xpqueue.c
new file mode 100644
index 0000000000..b5a773e29b
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xpqueue.c
@@ -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
+
+#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;
+}
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xtopology_g.c b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xtopology_g.c
new file mode 100644
index 0000000000..9d6fb85f03
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xemacpsif/xtopology_g.c
@@ -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;
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xil_types.h b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xil_types.h
index 3970866971..107f0bd724 100644
--- a/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xil_types.h
+++ b/bsp/zynqmp-r5-axu4ev/drivers/Zynq_HAL_Driver/xil_types.h
@@ -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.
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/drv_eth.c b/bsp/zynqmp-r5-axu4ev/drivers/drv_eth.c
new file mode 100644
index 0000000000..758fc138df
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/drv_eth.c
@@ -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
+#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
+
+#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 = ð_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(ð_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);
\ No newline at end of file
diff --git a/bsp/zynqmp-r5-axu4ev/drivers/drv_eth.h b/bsp/zynqmp-r5-axu4ev/drivers/drv_eth.h
new file mode 100644
index 0000000000..3d1a5d37cf
--- /dev/null
+++ b/bsp/zynqmp-r5-axu4ev/drivers/drv_eth.h
@@ -0,0 +1,13 @@
+#ifndef __DRV_ETH_H__
+#define __DRV_ETH_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/bsp/zynqmp-r5-axu4ev/rtconfig.h b/bsp/zynqmp-r5-axu4ev/rtconfig.h
index 95d92ea09d..03ced833bc 100644
--- a/bsp/zynqmp-r5-axu4ev/rtconfig.h
+++ b/bsp/zynqmp-r5-axu4ev/rtconfig.h
@@ -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 */
diff --git a/libcpu/arm/zynqmp-r5/cache.c b/libcpu/arm/zynqmp-r5/cache.c
index d6e7cd2d6d..ed0efa4824 100644
--- a/libcpu/arm/zynqmp-r5/cache.c
+++ b/libcpu/arm/zynqmp-r5/cache.c
@@ -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
#include
@@ -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)
diff --git a/libcpu/arm/zynqmp-r5/start_gcc.S b/libcpu/arm/zynqmp-r5/start_gcc.S
index faea0022be..7e99c9e82b 100644
--- a/libcpu/arm/zynqmp-r5/start_gcc.S
+++ b/libcpu/arm/zynqmp-r5/start_gcc.S
@@ -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
diff --git a/libcpu/arm/zynqmp-r5/xil_mmu.h b/libcpu/arm/zynqmp-r5/xil_mmu.h
new file mode 100644
index 0000000000..99e019c6f5
--- /dev/null
+++ b/libcpu/arm/zynqmp-r5/xil_mmu.h
@@ -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.
+*
+*
+*
+*
+* MODIFICATION HISTORY:
+*
+* Ver Who Date Changes
+* ----- ---- -------- ---------------------------------------------------
+* 5.0 pkp 2/12/15 Initial version
+*
+*
+* @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 */
diff --git a/libcpu/arm/zynqmp-r5/xil_mpu.c b/libcpu/arm/zynqmp-r5/xil_mpu.c
new file mode 100644
index 0000000000..7115bbb0a6
--- /dev/null
+++ b/libcpu/arm/zynqmp-r5/xil_mpu.c
@@ -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.
+*
+*
+* 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().
+*
+*
+*
+******************************************************************************/
+
+/***************************** 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
+#define DBG_TAG "xil_mpu"
+#define DBG_LVL DBG_INFO
+#include
+
+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;
+}
diff --git a/libcpu/arm/zynqmp-r5/xil_mpu.h b/libcpu/arm/zynqmp-r5/xil_mpu.h
new file mode 100644
index 0000000000..1afa6f76f7
--- /dev/null
+++ b/libcpu/arm/zynqmp-r5/xil_mpu.h
@@ -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.
+*
+* @{
+*
+* 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.
+*
+*
+
+*
+*
+******************************************************************************/
+
+#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".
+*/