diff --git a/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet.mdd b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet.mdd new file mode 100755 index 00000000..24f0b94e --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet.mdd @@ -0,0 +1,48 @@ +############################################################################### +# +# Copyright (C) 2010 - 2014 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. +# +# Use of the Software is limited solely to applications: +# (a) running on a Xilinx device, or +# (b) that interact with a Xilinx device through a bus or interconnect. +# +# 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 +# XILINX 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. +# +# Except as contained in this notice, the name of the Xilinx shall not be used +# in advertising or otherwise to promote the sale, use or other dealings in +# this Software without prior written authorization from Xilinx. +# +# MODIFICATION HISTORY: +# +# 05/12/10 asa First Release +# 02/01/13 srt Added support for IPI designs (CR 698249) +# +############################################################################### + +OPTION psf_version = 2.1; + +BEGIN driver axiethernet + + OPTION supported_peripherals = (axi_ethernet_v[3-9]_[0-9][1-9]_[a-z] axi_ethernet_v[3-9]_[0-9] axi_ethernet_buffer); + OPTION driver_state = ACTIVE; + OPTION copyfiles = all; + OPTION VERSION = 5.0; + OPTION NAME = axiethernet; + +END driver diff --git a/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet.tcl b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet.tcl new file mode 100755 index 00000000..6daa1bae --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet.tcl @@ -0,0 +1,700 @@ +############################################################################### +# +# Copyright (C) 2010 - 2014 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. +# +# Use of the Software is limited solely to applications: +# (a) running on a Xilinx device, or +# (b) that interact with a Xilinx device through a bus or interconnect. +# +# 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 +# XILINX 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. +# +# Except as contained in this notice, the name of the Xilinx shall not be used +# in advertising or otherwise to promote the sale, use or other dealings in +# this Software without prior written authorization from Xilinx. +# +# MODIFICATION HISTORY: +# +# 05/12/10 asa First Release based on the LL TEMAC driver tcl +# 01/07/13 srt Added C_PHYADDR configuration parameter to support SGMII mode +# 02/03/13 srt Added support for IPI designs (CR 698249) +# 02/14/13 srt Added support for Zynq (CR 681136) +# 04/24/13 srt Modified parameter *_SGMII_PHYADDR to *_PHYADDR, the config +# parameter C_PHYADDR applies to SGMII/1000BaseX modes of +# operation (CR 704195) +# 08/06/13 srt Added support to handle multiple instances of AxiEthernet +# FIFO interface (CR 721141) +# 06/08/14 adk Modified the driver tcl to handle the open/close of files +# properly (CR 810643) +# 29/10/14 adk Added support for generating parameters for SGMII/1000BaseX modes +# When IP is configured with the PCS/PMA core (CR 828796) +# 8/1/15 adk Fixed TCL errors when axiethernet is configured with the +# Axi stream fifo (CR 835605). +# +############################################################################### +#uses "xillib.tcl" + +set periph_config_params 0 +set periph_ninstances 0 + +proc init_periph_config_struct { deviceid } { + global periph_config_params + set periph_config_params($deviceid) [list] +} + +proc get_periph_config_struct_fields { deviceid } { + global periph_config_params + return $periph_config_params($deviceid) +} +proc add_field_to_periph_config_struct { deviceid fieldval } { + global periph_config_params + lappend periph_config_params($deviceid) $fieldval +} +proc display_avb_warning_if_applicable { periph } { + set avb_param_val "" + set avb_param_val [::hsi::utils::get_param_value $periph C_AVB] + if { $avb_param_val == 1 } { + puts "*******************************************************************************\r\n" + puts "WARNING: Audio Video Bridging (AVB) functionality is ENABLED in the AXI Ethernet core." + puts "The AXI Ethernet driver does not support AVB functionality." + puts "Please refer to the System Integration section of the Ethernet AVB User Guide" + puts "http://www.xilinx.com/support/documentation/ip_documentation/eth_avb_endpoint_ug492.pdf for information on AXI-Ethernet AVB Driver integration.\r\n" + puts "*******************************************************************************\r\n" + } +} + +# ------------------------------------------------------------------ +# Given an Axi Ethernet peripheral, generate all the stuff required in +# the system include file. +# +# Given an Axi Ethernet which is an initiator on a +# Axi4 Stream interface, traverse the Axi4 Stream to the target side, +# figure out the peripheral type that is connected and +# put in appropriate defines. The peripheral on the other side +# can be AXI DMA or AXI Streaming FIFO. +# +# ------------------------------------------------------------------ +proc xdefine_axiethernet_include_file {drv_handle file_name drv_string} { + global periph_ninstances + + # Open include file + set file_handle [::hsi::utils::open_include_file $file_name] + + # Get all peripherals connected to this driver + set periphs [::hsi::utils::get_common_driver_ips $drv_handle] + + # ---------------------------------------------- + # PART 1 - AXI Ethernet related parameters + # ---------------------------------------------- + + # Handle NUM_INSTANCES + set periph_ninstances 0 + puts $file_handle "/* Definitions for driver [string toupper [get_property NAME $drv_handle]] */" + foreach periph $periphs { + init_periph_config_struct $periph_ninstances + incr periph_ninstances 1 + } + puts $file_handle "\#define [::hsi::utils::get_driver_param_name $drv_string NUM_INSTANCES] $periph_ninstances" + + close $file_handle + # Now print all useful parameters for all peripherals + set device_id 0 + foreach periph $periphs { + #puts $file_handle "" + + ::hsi::utils::define_include_file $drv_handle "xparameters.h" "XAxiEthernet" "NUM_INSTANCES" "DEVICE_ID" "C_BASEADDR" "C_HIGHADDR" "C_TYPE" "C_TXCSUM" "C_RXCSUM" "C_PHY_TYPE" "C_TXVLAN_TRAN" "C_RXVLAN_TRAN" "C_TXVLAN_TAG" "C_RXVLAN_TAG" "C_TXVLAN_STRP" "C_RXVLAN_STRP" "C_MCAST_EXTEND" "C_STATS" "C_AVB" "C_PHYADDR" + + set file_handle [::hsi::utils::open_include_file $file_name] + # Create canonical definitions + xdefine_temac_params_canonical $file_handle $periph $device_id + + # Interrupt ID (canonical) + xdefine_temac_interrupt $file_handle $periph $device_id + + generate_sgmii_params $drv_handle "xparameters.h" + + display_avb_warning_if_applicable $periph + + incr device_id + puts $file_handle "\n" + close $file_handle + + } + # ------------------------------------------------------- + # PART 2 -- AXIFIFO/AXIDMA Connection related parameters + # ------------------------------------------------------- + set file_handle [::hsi::utils::open_include_file $file_name] + xdefine_axi_target_params $periphs $file_handle + + puts $file_handle "\n/******************************************************************/\n" + close $file_handle +} +# ------------------------------------------------------------------ +# Main generate function - called by the tools +# ------------------------------------------------------------------ +proc generate {drv_handle} { + + xdefine_axiethernet_include_file $drv_handle "xparameters.h" "XAxiEthernet" + xdefine_axiethernet_config_file "xaxiethernet_g.c" "XAxiEthernet" +} + +# --------------------------------------------------------------------------- +# Given each AXI4 Stream peripheral which is an initiator on a AXI4 +# Stream interface, traverse to the target side, figure out the peripheral +# type that is connected and put in appropriate defines. +# The peripheral on the other side can be AXI DMA or AXi Streaming FIFO. +# +# NOTE: This procedure assumes that each AXI4 Stream on each peripheral +# corresponds to a unique device id in the system and populates +# the global device config params structure accordingly. +# --------------------------------------------------------------------------- +proc xdefine_axi_target_params {periphs file_handle} { + + global periph_ninstances + + # + # First dump some enumerations on AXI_TYPE + # + puts $file_handle "/* AxiEthernet TYPE Enumerations */" + puts $file_handle "#define XPAR_AXI_FIFO 1" + puts $file_handle "#define XPAR_AXI_DMA 2" + puts $file_handle "" + + set device_id 0 + set validentry 0 + + # Get unique list of p2p peripherals + foreach periph $periphs { + set p2p_periphs [list] + set periph_name [string toupper [get_property NAME $periph]] + # Get all point2point buses for periph + set p2p_busifs_i [get_intf_pins -of_objects $periph -filter "TYPE==INITIATOR"] + + puts $file_handle "" + puts $file_handle "/* Canonical Axi parameters for $periph_name */" + + # Add p2p periphs + foreach p2p_busif $p2p_busifs_i { + + set busif_name [string toupper [get_property NAME $p2p_busif]] + set conn_busif_handle [::hsi::utils::get_connected_intf $periph $busif_name] + if { [string compare -nocase $conn_busif_handle ""] == 0} { + continue + } else { + # if there is a single match, we know if it is FIFO or DMA + # no need for further iterations + set conn_busif_name [get_property NAME $conn_busif_handle] + set target_periph [get_cells -of_objects $conn_busif_handle] + set target_periph_type [get_property IP_NAME $target_periph] + if { [string compare -nocase $target_periph_type "tri_mode_ethernet_mac"] == 0 } { + continue + } + set tartget_per_name [get_property NAME $target_periph] + set target_periph_name [string toupper [get_property NAME $target_periph]] + set canonical_tag [string toupper [format "AXIETHERNET_%d" $device_id ]] + set validentry 1 + break + } + } + if {$validentry == 1} { + if {$target_periph_type == "axi_fifo_mm_s"} { + # + # Handle the connection type (FIFO in this case) + # + set canonical_name [format "XPAR_%s_CONNECTED_TYPE" $canonical_tag] + puts $file_handle "#define $canonical_name XPAR_AXI_FIFO" + add_field_to_periph_config_struct $device_id $canonical_name + + set axi_fifo_baseaddr [get_property CONFIG.C_BASEADDR $target_periph] + set canonical_name [format "XPAR_%s_CONNECTED_BASEADDR" $canonical_tag] + puts $file_handle [format "#define $canonical_name %s" $axi_fifo_baseaddr] + add_field_to_periph_config_struct $device_id $canonical_name + # FIFO Interrupts Handling + set int_pin [get_pins -of_objects [get_cells $tartget_per_name] INTERRUPT] + set intc_periph_type [::hsi::utils::get_connected_intr_cntrl $tartget_per_name $int_pin] + set intc_name [get_property IP_NAME $intc_periph_type] + if { $intc_name != [format "ps7_scugic"] } { + set int_id [::hsi::utils::get_port_intr_id [get_cells $tartget_per_name] $int_pin] + set canonical_name [format "XPAR_%s_CONNECTED_FIFO_INTR" $canonical_tag] + puts $file_handle [format "#define $canonical_name %d" $int_id] + add_field_to_periph_config_struct $device_id $canonical_name + puts $file_handle [format "#define XPAR_%s_CONNECTED_DMARX_INTR 0xFF" $canonical_tag] + puts $file_handle [format "#define XPAR_%s_CONNECTED_DMATX_INTR 0xFF" $canonical_tag] + add_field_to_periph_config_struct $device_id 0xFF + add_field_to_periph_config_struct $device_id 0xFF + } else { + set canonical_name [format "XPAR_%s_CONNECTED_FIFO_INTR" $canonical_tag] + set temp [string toupper $int_pin] + puts $file_handle [format "#define $canonical_name XPAR_FABRIC_%s_%s_INTR" $target_periph_name $temp] + add_field_to_periph_config_struct $device_id $canonical_name + puts $file_handle [format "#define XPAR_%s_CONNECTED_DMARX_INTR 0xFF" $canonical_tag] + puts $file_handle [format "#define XPAR_%s_CONNECTED_DMATX_INTR 0xFF" $canonical_tag] + add_field_to_periph_config_struct $device_id 0xFF + add_field_to_periph_config_struct $device_id 0xFF + } + } + if {$target_periph_type == "axi_dma"} { + set axi_dma_baseaddr [get_property CONFIG.C_BASEADDR $target_periph] + # Handle base address and connection type + set canonical_name [format "XPAR_%s_CONNECTED_TYPE" $canonical_tag] + puts $file_handle "#define $canonical_name XPAR_AXI_DMA" + add_field_to_periph_config_struct $device_id $canonical_name + set canonical_name [format "XPAR_%s_CONNECTED_BASEADDR" $canonical_tag] + puts $file_handle [format "#define $canonical_name %s" $axi_dma_baseaddr] + add_field_to_periph_config_struct $device_id $canonical_name + + puts $file_handle [format "#define XPAR_%s_CONNECTED_FIFO_INTR 0xFF" $canonical_tag] + add_field_to_periph_config_struct $device_id 0xFF + set dmarx_signal [format "s2mm_introut"] + set dmatx_signal [format "mm2s_introut"] + xdefine_dma_interrupts $file_handle $target_periph $device_id $canonical_tag $dmarx_signal $dmatx_signal + } + incr device_id + + } + + if {$validentry !=1} { + puts "*******************************************************************************\r\n" + puts "The target Peripheral(Axi DMA or AXI FIFO) is not connected properly to the AXI Ethernet core." + puts "*******************************************************************************\r\n" + } + } +} +# ------------------------------------------------------------------ +# This procedure creates XPARs that are canonical/normalized for the +# hardware design parameters. It also adds these to the Config table. +# ------------------------------------------------------------------ +proc xdefine_temac_params_canonical {file_handle periph device_id} { + + puts $file_handle "\n/* Canonical definitions for peripheral [string toupper [get_property NAME $periph]] */" + + set canonical_tag [string toupper [format "XPAR_AXIETHERNET_%d" $device_id]] + + # Handle device ID + set canonical_name [format "%s_DEVICE_ID" $canonical_tag] + puts $file_handle "\#define $canonical_name $device_id" + add_field_to_periph_config_struct $device_id $canonical_name + + # Handle BASEADDR specially + set canonical_name [format "%s_BASEADDR" $canonical_tag] + puts $file_handle "\#define $canonical_name [::hsi::utils::get_param_value $periph C_BASEADDR]" + add_field_to_periph_config_struct $device_id $canonical_name + + # Handle HIGHADDR specially + set canonical_name [format "%s_HIGHADDR" $canonical_tag] + puts $file_handle "\#define $canonical_name [::hsi::utils::get_param_value $periph C_HIGHADDR]" + + set canonical_name [format "%s_TEMAC_TYPE" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_TYPE] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_TXCSUM" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_TXCSUM] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_RXCSUM" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_RXCSUM] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_PHY_TYPE" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_PHY_TYPE] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_TXVLAN_TRAN" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_TXVLAN_TRAN] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_RXVLAN_TRAN" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_RXVLAN_TRAN] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_TXVLAN_TAG" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_TXVLAN_TAG] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_RXVLAN_TAG" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_RXVLAN_TAG] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_TXVLAN_STRP" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_TXVLAN_STRP] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_RXVLAN_STRP" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_RXVLAN_STRP] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_MCAST_EXTEND" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_MCAST_EXTEND] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_STATS" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_STATS] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + + set canonical_name [format "%s_AVB" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_AVB] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + set canonical_name [format "%s_ENABLE_SGMII_OVER_LVDS" $canonical_tag] + set value [::hsi::utils::get_param_value $periph C_ENABLE_LVDS] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + add_field_to_periph_config_struct $device_id $canonical_name + set canonical_name [format "%s_PHYADDR" $canonical_tag] + set phyaddr [::hsi::utils::get_param_value $periph C_PHYADDR] + set value [::hsi::utils::convert_binary_to_decimal $phyaddr] + if {[llength $value] == 0} { + set value 0 + } + puts $file_handle "\#define $canonical_name $value" + +} + +# ------------------------------------------------------------------ +# Create configuration C file as required by Xilinx drivers +# Use the config field list technique +# ------------------------------------------------------------------ +proc xdefine_axiethernet_config_file {file_name drv_string} { + global periph_ninstances + + set filename [file join "src" $file_name] + file delete $filename + set config_file [open $filename w] + ::hsi::utils::write_c_header $config_file "Driver configuration" + puts $config_file "\#include \"xparameters.h\"" + puts $config_file "\#include \"[string tolower $drv_string].h\"" + puts $config_file "\n/*" + puts $config_file "* The configuration table for devices" + puts $config_file "*/\n" + puts $config_file [format "%s_Config %s_ConfigTable\[\] =" $drv_string $drv_string] + puts $config_file "\{" + + set start_comma "" + for {set i 0} {$i < $periph_ninstances} {incr i} { + + puts $config_file [format "%s\t\{" $start_comma] + set comma "" + foreach field [get_periph_config_struct_fields $i] { + puts -nonewline $config_file [format "%s\t\t%s" $comma $field] + set comma ",\n" + } + + puts -nonewline $config_file "\n\t\}" + set start_comma ",\n" + } + puts $config_file "\n\};\n" + close $config_file +} + +# ------------------------------------------------------------------ +# Find the two LocalLink DMA interrupts (RX and TX), and define +# the canonical constants in xparameters.h and the config table +# ------------------------------------------------------------------ +proc xdefine_dma_interrupts {file_handle target_periph deviceid canonical_tag dmarx_signal dmatx_signal} { + + set target_periph_name [string toupper [get_property NAME $target_periph]] + + # First get the interrupt ports on this AXI peripheral + set interrupt_port [get_pins -of_objects $target_periph -filter {TYPE==INTERRUPT&&DIRECTION==O}] + if {$interrupt_port == ""} { + puts "Info: There are no AXIDMA Interrupt ports" + puts $file_handle [format "#define XPAR_%s_CONNECTED_DMARX_INTR 0xFF" $canonical_tag] + add_field_to_periph_config_struct $deviceid 0xFF + puts $file_handle [format "#define XPAR_%s_CONNECTED_DMATX_INTR 0xFF" $canonical_tag] + add_field_to_periph_config_struct $deviceid 0xFF + return + } + # For each interrupt port, find out the ordinal of the interrupt line + # as connected to an interrupt controller + set addentry 0 + set dmarx "null" + set dmatx "null" + foreach intr_port $interrupt_port { + set interrupt_signal_name [get_property NAME $intr_port] + set intc_port [get_pins -of_objects $target_periph -filter {TYPE==INTERRUPT&&DIRECTION==O}] + + # Make sure the interrupt signal was connected in this design. We assume + # at least one is. (could be a bug if user just wants polled mode) + if { $intc_port != "" } { + set found_intc "" + foreach intr_sink $intc_port { + set pname_type [::hsi::utils::get_connected_intr_cntrl $target_periph $intr_sink] + if {$pname_type != "chipscope_ila"} { + set special [get_property IP_TYPE $pname_type] + if {[string compare -nocase $special "INTERRUPT_CNTLR"] == 0} { + set found_intc $intr_sink + } + } + } + + if {$found_intc == ""} { + puts "Info: DMA interrupt not connected to intc\n" + puts "Info: There are no AXIDMA Interrupt ports" + puts $file_handle [format "#define XPAR_%s_CONNECTED_DMARX_INTR 0xFF" $canonical_tag] + add_field_to_periph_config_struct $deviceid 0xFF + puts $file_handle [format "#define XPAR_%s_CONNECTED_DMATX_INTR 0xFF" $canonical_tag] + add_field_to_periph_config_struct $deviceid 0xFF + return + } + set intc_periph [get_cells -of_objects $found_intc] + set intc_periph_type [get_property IP_NAME $pname_type] + set intc_name [string toupper [get_property NAME $pname_type]] + } else { + puts "Info: $target_periph_name interrupt signal $interrupt_signal_name not connected" + continue + } + } + + # A bit of ugliness here. The only way to figure the ordinal is to + # iterate over the interrupt lines again and see if a particular signal + # matches the original interrupt signal we were tracking. + # If it does, put out the XPAR + if { $intc_periph_type != [format "ps7_scugic"] } { + set rx_int_id [::hsi::utils::get_port_intr_id $target_periph $dmarx_signal] + set canonical_name [format "XPAR_%s_CONNECTED_DMARX_INTR" $canonical_tag] + puts $file_handle [format "#define $canonical_name %d" $rx_int_id] + add_field_to_periph_config_struct $deviceid $canonical_name + set tx_int_id [::hsi::utils::get_port_intr_id $target_periph $dmatx_signal] + set canonical_name [format "XPAR_%s_CONNECTED_DMATX_INTR" $canonical_tag] + puts $file_handle [format "#define $canonical_name %d" $tx_int_id] + add_field_to_periph_config_struct $deviceid $canonical_name + } else { + set addentry 2 + } + + + # Now add to the config table in the proper order (RX first, then TX + + if { $intc_periph_type == [format "ps7_scugic"] } { + set canonical_name [format "XPAR_%s_CONNECTED_DMARX_INTR" $canonical_tag] + puts $file_handle [format "#define $canonical_name XPAR_FABRIC_%s_S2MM_INTROUT_INTR" $target_periph_name] + add_field_to_periph_config_struct $deviceid $canonical_name + set canonical_name [format "XPAR_%s_CONNECTED_DMATX_INTR" $canonical_tag] + puts $file_handle [format "#define $canonical_name XPAR_FABRIC_%s_MM2S_INTROUT_INTR" $target_periph_name] + add_field_to_periph_config_struct $deviceid $canonical_name + } + + if { $addentry == 1} { + # for some reason, only one DMA interrupt was connected (probably a bug), + # but fill in a dummy entry for the other (may be the wrong direction!) + puts "WARNING: only one SDMA interrupt line connected for $target_periph_name" + } +} + +# ------------------------------------------------------------------------------------ +# This procedure re-forms the AXI Ethernet interrupt ID XPAR constant and adds it to +# the driver config table. This Tcl needs to be careful of the order of the +# config table entries +# ------------------------------------------------------------------------------------ +proc xdefine_temac_interrupt {file_handle periph device_id} { + + #set mhs_handle [xget_hw_parent_handle $periph] + set periph_name [string toupper [get_property NAME $periph]] + + # set up the canonical constant name + set canonical_name [format "XPAR_AXIETHERNET_%d_INTR" $device_id] + + # + # In order to reform the XPAR for the interrupt ID, we need to hunt + # for the interrupt ID based on the interrupt signal name of the TEMAC + # + # First get the interrupt ports on this peripheral + set interrupt_port [::hsi::get_pins -of_objects $periph -filter {TYPE==INTERRUPT&&DIRECTION==O}] + if {$interrupt_port == ""} { + puts "Info: There are no AXI Ethernet Interrupt ports" + # No interrupts were connected, so add dummy entry to the config structure + puts $file_handle [format "#define $canonical_name 0xFF"] + add_field_to_periph_config_struct $device_id 0xFF + } + + set addentry 0 + # For each interrupt port, find out the ordinal of the interrupt line + # as connected to an interrupt controller + set interrupt_signal_name [get_property NAME $interrupt_port] + #set interrupt_signal [xget_hw_value $interrupt_port] + set intc_prt [::hsi::utils::get_sink_pins [get_pins -of_objects [get_cells $periph] INTERRUPT]] + + # Make sure the interrupt signal was connected in this design. We assume + # at least one is. (could be a bug if user just wants polled mode) + if { $intc_prt != "" } { + set intc_periph [::hsi::utils::get_connected_intr_cntrl $periph [get_pins -of_objects [get_cells $periph] INTERRUPT] ] + if {$intc_periph == ""} { + puts "Info: Axi Ethernet interrupt not connected to intc\n" + # No interrupts were connected, so add dummy entry to the config structure + puts $file_handle [format "#define $canonical_name 0xFF"] + add_field_to_periph_config_struct $device_id 0xFF + return + } + + set intc_periph_type [get_property IP_NAME $intc_periph] + set intc_name [string toupper [get_property NAME $intc_periph]] + } else { + puts "Info: $periph_name interrupt signal $interrupt_signal_name not connected" + # No interrupts were connected, so add dummy entry to the config structure + puts $file_handle [format "#define $canonical_name 0xFF"] + add_field_to_periph_config_struct $device_id 0xFF + return + } + + # A bit of ugliness here. The only way to figure the ordinal is to + # iterate over the interrupt lines again and see if a particular signal + # matches the original interrupt signal we were tracking. + + if { $intc_periph_type != [format "ps7_scugic"] } { + set ethernet_int_signal_name [get_pins -of_objects $periph INTERRUPT] + set int_id [::hsi::utils::get_port_intr_id $periph $ethernet_int_signal_name] + puts $file_handle "\#define $canonical_name $int_id" + add_field_to_periph_config_struct $device_id $canonical_name + set addentry 1 + } else { + puts $file_handle [format "#define $canonical_name XPAR_FABRIC_%s_INTERRUPT_INTR" $periph_name] + add_field_to_periph_config_struct $device_id $canonical_name + set addentry 1 + } + + if { $addentry == 0 } { + # No interrupts were connected, so add dummy entry to the config structure + puts $file_handle [format "#define $canonical_name 0xFF"] + add_field_to_periph_config_struct $device_id 0xFF + } +} + +proc generate_sgmii_params {drv_handle file_name} { + set file_handle [::hsi::utils::open_include_file $file_name] + set ips [get_cells "*"] + + foreach ip $ips { + set periph [get_property IP_NAME $ip] + if { [string compare -nocase $periph "gig_ethernet_pcs_pma"] == 0} { + set PhyStandard [get_property CONFIG.Standard $ip] + } + } + + foreach ip $ips { + set periph [get_property IP_NAME $ip] + if { [string compare -nocase $periph "axi_ethernet_buffer"] == 0} { + set phya [is_gige_pcs_pma_ip_present $ip] + if { $phya == 0} { + close $file_handle + return 0 + } + if { $PhyStandard == "1000BASEX" } { + puts $file_handle "/* Definitions related to PCS PMA PL IP*/" + puts $file_handle "\#define XPAR_GIGE_PCS_PMA_1000BASEX_CORE_PRESENT 1" + puts $file_handle "\#define XPAR_PCSPMA_1000BASEX_PHYADDR $phya" + puts $file_handle "\n/******************************************************************/\n" + } else { + puts $file_handle "/* Definitions related to PCS PMA PL IP*/" + puts $file_handle "\#define XPAR_GIGE_PCS_PMA_SGMII_CORE_PRESENT 1" + puts $file_handle "\#define XPAR_PCSPMA_SGMII_PHYADDR $phya" + puts $file_handle "\n/******************************************************************/\n" + + } + } + } + close $file_handle +} + +proc is_gige_pcs_pma_ip_present {slave} { + set port_value 0 + set phy_addr 0 + set ipconv 0 + + set ips [get_cells "*"] + set enetipinstance_name [get_property IP_NAME $slave] + + foreach ip $ips { + set periph [get_property IP_NAME $ip] + if { [string compare -nocase $periph "gig_ethernet_pcs_pma"] == 0} { + set sgmii_param [get_property CONFIG.c_is_sgmii $ip] + set PhyStandarrd [get_property CONFIG.Standard $ip] + if {$sgmii_param == true || $PhyStandarrd == "1000BASEX"} { + set ipconv $ip + } + break + } + } + + if { $ipconv != 0 } { + set port_value [get_pins -of_objects [get_nets -of_objects [get_pins -of_objects $ipconv gmii_txd]]] + if { $port_value != 0 } { + if { [string compare -nocase $enetipinstance_name "axi_ethernet_buffer"] == 0} { + set phyaddr [::hsi::utils::get_param_value $ipconv C_PHYADDR] + set phy_addr [::hsi::utils::convert_binary_to_decimal $phyaddr] + if {[llength $phy_addr] == 0} { + set phy_addr 0 + } + } + } + } + return $phy_addr +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_fifo_intr_header.h b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_fifo_intr_header.h new file mode 100644 index 00000000..7e37c1c8 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_fifo_intr_header.h @@ -0,0 +1,47 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2014 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ + +#include "xstatus.h" +#include "xil_types.h" +#include "xparameters.h" + +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC XIntc +#else +#define INTC XScuGic +#endif + +int AxiEthernetFifoIntrExample(INTC * IntcInstancePtr, + XAxiEthernet * AxiEthernetInstancePtr, + XLlFifo * FifoInstancePtr, + u16 AxiEthernetDeviceId, u16 FifoDeviceId, + u16 AxiEthernetIntrId, u16 FifoIntrId); diff --git a/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_header.h b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_header.h new file mode 100644 index 00000000..17e8b6cf --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_header.h @@ -0,0 +1,36 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2014 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ + +#include "xstatus.h" +#include "xil_types.h" + +int AxiEthernetPolledExample(u16 AxiEthernetDeviceId, u16 FifoDeviceId); diff --git a/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_intr_header.h b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_intr_header.h new file mode 100644 index 00000000..44d3e645 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_intr_header.h @@ -0,0 +1,49 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2014 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ + +#include "xstatus.h" +#include "xil_types.h" + +#include "xparameters.h" + +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC XIntc +#else +#define INTC XScuGic +#endif + +int AxiEthernetSgDmaIntrExample(INTC * IntcInstancePtr, + XAxiEthernet * AxiEthernetInstancePtr, + XAxiDma * DmaInstancePtr, + u16 AxiEthernetDeviceId, + u16 AxiDmaDeviceId, u16 AxiEthernetIntrId, + u16 DmaRxIntrId, u16 DmaTxIntrId); diff --git a/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_tapp.tcl b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_tapp.tcl new file mode 100755 index 00000000..f292cd7e --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/data/axiethernet_tapp.tcl @@ -0,0 +1,416 @@ +############################################################################### +# +# Copyright (C) 2010 - 2014 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. +# +# Use of the Software is limited solely to applications: +# (a) running on a Xilinx device, or +# (b) that interact with a Xilinx device through a bus or interconnect. +# +# 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 +# XILINX 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. +# +# Except as contained in this notice, the name of the Xilinx shall not be used +# in advertising or otherwise to promote the sale, use or other dealings in +# this Software without prior written authorization from Xilinx. +# +# MODIFICATION HISTORY: +# +# Ver Who Date Changes +# -------- ------ -------- ---------------------------------------------------- +# 1.00.a asa 05/12/10 First Release +# 4.0 adk 10/12/13 Updated as per the New Tcl API's +# 4.1 adk 21/4/14 Fixed the CR:780537 Modified the get_dma_info proc +# logic as appropriate(In case of multiple dma's in the +# system some connected to ethernet some not). +# +############################################################################### + +# ----------------------------------------------------------------- +# Software Project Types (swproj): +# 0 : MemoryTest - Calls basic memorytest routines from common driver dir +# 1 : PeripheralTest - Calls any existing polled_example and/or selftest +# ----------------------------------------------------------------- + +# ----------------------------------------------------------------- +# TCL Procedures: +# ----------------------------------------------------------------- + +proc gen_include_files {swproj mhsinst} { + if {$swproj == 0} { + return "" + } + if {$swproj == 1} { + set ifintr [::hsi::utils::is_ip_interrupting_current_proc $mhsinst] + set dmaType [get_dma_type $mhsinst] + + if {$ifintr == 1} { + set inc_file_lines {xaxiethernet.h xaxiethernet_example.h} + + if {$dmaType == 1} { + append inc_file_lines " xllfifo.h" + append inc_file_lines " axiethernet_header.h" + append inc_file_lines " axiethernet_fifo_intr_header.h" + } + if {$dmaType == 3} { + append inc_file_lines " xaxidma.h" + append inc_file_lines " axiethernet_intr_header.h" + } + } else { + if {$dmaType == 1} { + set inc_file_lines {xaxiethernet.h xaxiethernet_example.h axiethernet_header.h} + } else { + return "" + } + } + + return $inc_file_lines + } +} + +proc gen_src_files {swproj mhsinst} { + if {$swproj == 0} { + return "" + } + if {$swproj == 1} { + set ifintr [::hsi::utils::is_ip_interrupting_current_proc $mhsinst] + set dmaType [get_dma_type $mhsinst] + + if {$ifintr == 1} { + if {$dmaType == 1} { + set inc_file_lines {examples/xaxiethernet_example.h examples/xaxiethernet_example_polled.c examples/xaxiethernet_example_util.c examples/xaxiethernet_example_intr_fifo.c data/axiethernet_header.h data/axiethernet_fifo_intr_header.h} + } elseif {$dmaType == 3} { + set inc_file_lines {examples/xaxiethernet_example.h examples/xaxiethernet_example_util.c examples/xaxiethernet_example_intr_sgdma.c data/axiethernet_intr_header.h} + } + } else { + if {$dmaType == 1} { + set inc_file_lines {examples/xaxiethernet_example.h examples/xaxiethernet_example_polled.c examples/xaxiethernet_example_util.c data/axiethernet_header.h} + } else { + return "" + } + } + return $inc_file_lines + } +} + +proc gen_testfunc_def {swproj mhsinst} { + return "" +} + +proc gen_init_code {swproj mhsinst} { + if {$swproj == 0} { + return "" + } + if {$swproj == 1} { + + set ipname [get_property NAME $mhsinst] + set ifintr [::hsi::utils::is_ip_interrupting_current_proc $mhsinst] + + if {$ifintr == 1} { + set dmaType [get_dma_type $mhsinst] + set decl " static XAxiEthernet ${ipname}_AxiEthernet;" + + # FIFO + if {$dmaType == 1} { + set fifo_ipname [get_fifo_info $mhsinst "name"] + + append decl " + static XLlFifo ${fifo_ipname}_AxiFifo; + +" + } + + # DMA + if {$dmaType == 3} { + append decl " + static XAxiDma ${ipname}_AxiDma; + +" + } + + set inc_file_lines $decl + return $inc_file_lines + } + } + + return "" +} + + +proc gen_testfunc_call {swproj mhsinst} { + + if {$swproj == 0} { + return "" + } + + set ipname [get_property NAME $mhsinst] + set deviceid [::hsi::utils::get_ip_param_name $mhsinst "DEVICE_ID"] + set stdout [get_property CONFIG.STDOUT [get_os]] + if { $stdout == "" || $stdout == "none" } { + set hasStdout 0 + } else { + set hasStdout 1 + } + set dma [get_dma_type $mhsinst] + set ifintr [::hsi::utils::is_ip_interrupting_current_proc $mhsinst] + + set fifo_deviceid [get_fifo_info $mhsinst "id"] + set fifo_ipname [get_fifo_info $mhsinst "name"] + + set dma_deviceid [get_dma_info $mhsinst "id"] + set dma_ipname [get_dma_info $mhsinst "name"] + + if {$ifintr == 1} { + set intr_pin_name [get_pins -of_objects [get_cells $ipname] INTERRUPT] + set intcname [::hsi::utils::get_connected_intr_cntrl $ipname $intr_pin_name] + set intcvar intc + set proc [get_property IP_NAME [get_cells [get_sw_processor]]] + } + + + if { $dma == 1 } { + set type "Fifo" + } + if { $dma == 3 } { + set type "SgDma" + } + + set testfunc_call "" + + # BEGIN: FIFO + if { $dma == 1 } { + append testfunc_call " + + { + int Status; +" + + if {${hasStdout} == 1} { + append testfunc_call " + print(\"\\r\\n Running AxiEthernetPolledExample() for ${ipname}...\\r\\n\"); +" + } + + append testfunc_call " + Status = AxiEthernetPolledExample( ${deviceid}, + ${fifo_deviceid} ); +" + + if {${hasStdout} == 1} { + append testfunc_call " + if (Status == 0) { + print(\"AxiEthernetPolledExample PASSED\\r\\n\"); + } + else { + print(\"AxiEthernetPolledExample FAILED\\r\\n\"); + } +" + } + + append testfunc_call " + } +" + } + # END: FIFO + + # BEGIN: DMA + if { $dma == 3 } { + append testfunc_call " + /* AxiEthernetPolledExample does not support AXI DMA */ +" + } + # END: DMA + + # BEGIN: INTERRUPT + if { ${ifintr} == 1 } { + + # AXIETHERNET + if { + $proc == "microblaze" + } then { + set intr_id "XPAR_${intcname}_${ipname}_${intr_pin_name}_INTR" + } else { + set intr_id "XPAR_FABRIC_${ipname}_${intr_pin_name}_INTR" + } + set intr_id [string toupper $intr_id] + + + # BEGIN: FIFO & INTERRUPT + if {$dma == 1} { + # AXIFIFO + if { + $proc == "microblaze" + } then { + set fifo_intr_id "XPAR_${intcname}_${fifo_ipname}_${intr_pin_name}_INTR" + } else { + set fifo_intr_id "XPAR_FABRIC_${fifo_ipname}_${intr_pin_name}_INTR" + } + + set fifo_intr_id [string toupper $fifo_intr_id] + + append testfunc_call " + { + int Status; +" + + if {${hasStdout} == 1} { + append testfunc_call " + print(\"\\r\\nRunning AxiEthernet${type}IntrExample() for ${ipname}...\\r\\n\"); +" + } + + append testfunc_call " + Status = AxiEthernet${type}IntrExample(&${intcvar}, &${ipname}_AxiEthernet, + &${fifo_ipname}_AxiFifo, + ${deviceid}, + ${fifo_deviceid}, + ${intr_id}, + ${fifo_intr_id}); +" + + if {${hasStdout} == 1} { + append testfunc_call " + if(Status == 0) { + print(\"AxiEthernet Interrupt Test PASSED.\\r\\n\"); + } + else { + print(\"AxiEthernet Interrupt Test FAILED.\\r\\n\"); + } +" + } + + append testfunc_call " + } +" + } + # END: FIFO & INTERRUPT + + # BEGIN: DMA & INTERRUPT + if {$dma == 3} { + # DMA + set dmaDriverInst "${ipname}_AxiDma" + set dmaRxIntrId "XPAR_AXIETHERNET_0_CONNECTED_DMARX_INTR" + set dmaTxIntrId "XPAR_AXIETHERNET_0_CONNECTED_DMATX_INTR" + + append testfunc_call " + { + int Status; +" + + if {${hasStdout} == 1} { + append testfunc_call " + print(\"\\r\\nRunning AxiEthernet${type}IntrExample() for ${ipname}...\\r\\n\"); +" + } + + append testfunc_call " + Status = AxiEthernet${type}IntrExample(&${intcvar}, &${ipname}_AxiEthernet, + &${dmaDriverInst}, + ${deviceid}, + ${dma_deviceid}, + ${intr_id}, + ${dmaRxIntrId}, + ${dmaTxIntrId}); +" + + if {${hasStdout} == 1} { + append testfunc_call " + if (Status == 0) { + print(\"AxiEthernet Interrupt Test PASSED.\\r\\n\"); + } + else { + print(\"AxiEthernet Interrupt Test FAILED.\\r\\n\"); + } +" + } + + append testfunc_call " + }" + } + # END: DMA & INTERRUPT + } + # END: INTERRUPT + + return $testfunc_call +} + +proc get_fifo_info {mhsHandle type} { + + set ipinst_list [get_cells $mhsHandle "*"] + + foreach ipinst $ipinst_list { + set coreName [get_property IP_NAME $ipinst] + set instName [get_property NAME $ipinst] + + if {[string compare -nocase $coreName "axi_fifo_mm_s"] == 0} { + + if {[string compare -nocase $type "id"] == 0} { + set deviceid [::hsi::utils::get_ip_param_name $ipinst "DEVICE_ID"] + return $deviceid + } + if {[string compare -nocase $type "name"] == 0} { + return $instName + } + } + } +} + +proc get_dma_info {mhsinst type} { + set ipinst_list [get_cells $mhsinst "*"] + + set p2p_busifs_i [get_intf_pins -of_objects $mhsinst -filter "TYPE==INITIATOR"] + # Add p2p periphs + foreach p2p_busif $p2p_busifs_i { + set busif_name [string toupper [get_property NAME $p2p_busif]] + set conn_busif_handle [::hsi::utils::get_connected_intf $mhsinst $busif_name] + if { [string compare -nocase $conn_busif_handle ""] == 0} { + continue + } else { + # if there is a single match, we know if it is FIFO or DMA + # no need for further iterations + set conn_busif_name [get_property NAME $conn_busif_handle] + set target_periph [get_cells -of_objects $conn_busif_handle] + set target_periph_type [get_property IP_NAME $target_periph] + if { [string compare -nocase $target_periph_type "tri_mode_ethernet_mac"] == 0 } { + continue + } + set target_periph_name [string toupper [get_property NAME $target_periph]] + set instName [get_property NAME $target_periph] + if {[string compare -nocase $target_periph_type "axi_dma"] == 0} { + if {[string compare -nocase $type "id"] == 0} { + set deviceid [::hsi::utils::get_ip_param_name $target_periph "DEVICE_ID"] + return $deviceid + } + if {[string compare -nocase $type "name"] == 0} { + return $instName + } + } + } + } +} + +proc get_dma_type {mhsinst} { + + set dma_deviceid [get_dma_info $mhsinst "id"] + + if { $dma_deviceid != "" } { + set dma 3 + } else { + set dma 1 + } + return $dma +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/data/dependencies.props b/XilinxProcessorIPLib/drivers/axiethernet/data/dependencies.props new file mode 100644 index 00000000..edba046f --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/data/dependencies.props @@ -0,0 +1,5 @@ +xaxiethernet_example_polled.c=xemacps_example_util.c,xaxiethernet_example_util.c,xaxiethernet_example.h +xaxiethernet_example_intr_sgdma.c=xemacps_example_util.c,xaxiethernet_example_util.c,xaxiethernet_example.h +xaxiethernet_example_intr_fifo.c=xemacps_example_util.c,xaxiethernet_example_util.c,xaxiethernet_example.h +xaxiethernet_example_extmulticast.c=xemacps_example_util.c,xaxiethernet_example_util.c,xaxiethernet_example.h +xaxiethernet_example_extvlan.c=xemacps_example_util.c,xaxiethernet_example_util.c,xaxiethernet_example.h \ No newline at end of file diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb.c new file mode 100644 index 00000000..f436ff17 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb.c @@ -0,0 +1,742 @@ +/****************************************************************************** +* +* Copyright (C) 2008 - 2014 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xavb.c +* +* The top level c file for the AVB driver. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a mbr 09/19/08 First release +* 1.01a mbr 06/24/09 PTP frame format updates for IEEE802.1 AS draft 5-0 +* 2_02a mbr 09/16/09 Updates for programmable PTP timers +* 2_04a kag 07/23/10 PTP frame format updates for IEEE802.1 AS draft 6-7 +* 3_01a kag 08/29/11 Added new APIs to update the RX Filter Control Reg. +* Fix for CR:572539. Updated bit map for Rx Filter +* control reg. +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_io.h" +#include "xil_assert.h" +#include "xenv.h" +#include "xavb_hw.h" +#include "xavb.h" +#include "xparameters.h" +#include "stdio.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Variable Definitions *****************************/ + +extern XAvb_Config XAvb_ConfigTable[]; +extern volatile u8 EchoPTPFramesReceived; + +/************************** Function Prototypes ******************************/ +static void XAvb_StubHandler(void *CallBackRef, u32 TimestampsUncertain); + +/*****************************************************************************/ + +/* + * Mandatory Device Driver Functions + */ + +/****************************************************************************/ +/** +* +* A function to initialise variables in the data structure records +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param ConfigPtr is the Configuration Pointer +* @param EffectiveAddress is the base address of the Configuration Pointer +* +* @return +* - XST_SUCCESS if initialization was successful +* - XST_DEVICE_NOT_FOUND if device configuration information was not found +* for a device with the supplied device ID.* +* @note None. +* +*****************************************************************************/ +XStatus XAvb_CfgInitialize(XAvb *InstancePtr, + XAvb_Config *ConfigPtr, + u32 EffectiveAddress) { + + Xil_AssertNonvoid(InstancePtr != NULL); + + /** The component is not yet ready to use */ + InstancePtr->IsReady = 0; + + /** Clear instance memory */ + memset(InstancePtr, 0, sizeof(XAvb)); + memcpy(&InstancePtr->Config, ConfigPtr, sizeof(XAvb_Config)); + + /** + * Lookup the device configuration in the temporary CROM table. Use this + * configuration info down below when initializing this component. + */ + if (ConfigPtr == NULL) { + return XST_DEVICE_NOT_FOUND; + } + + /** + * Populate Base Address field using the base address value in the + * configuration structure. + */ + InstancePtr->Config.BaseAddress = EffectiveAddress; + + /** + * Indicate the component is now ready to use. + */ + InstancePtr->IsReady = XIL_COMPONENT_IS_READY; + + /** + * Set the callback handler to a stub + */ + InstancePtr->GMDiscHandler = XAvb_StubHandler; + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function resets all of the AVB device driver functions to the start-up +* (reset) defaults. +* +* @param InstancePtr is a pointer to the Xavb instance to be worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XAvb_Reset(XAvb * InstancePtr) +{ + /** Assert bad arguments and conditions */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /** + * Perform a Software Reset of the AVB Core. + * This will reset both the transmitter and receiver paths. + * The RTC counter is not reset here. + */ + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_SW_RESET_OFFSET, + XAVB_SW_RESET_TX_AND_RX_PATHS); + + /** + * Set IEEE specification default values in the device's data structure + */ + xil_printf("\r\n*** XAvb_Reset() : Call XAvb_BecomeRtcMaster() *** \r\n"); + XAvb_BecomeRtcMaster(InstancePtr,0); + XAvb_ChangePeerASCapability(InstancePtr, 0); + + InstancePtr->PtpIsRunning = 0; + InstancePtr->PtpRecords.LinkDelay = 0; + InstancePtr->SignallingFrameData.SyncIntervalDuration = + XAvb_ConvertLogMeanToDuration(XAVB_DEFAULT_LOG_MEAN_SYNC_INTERVAL); + InstancePtr->SignallingFrameData.LinkDelayIntervalDuration = + XAvb_ConvertLogMeanToDuration(XAVB_DEFAULT_LOG_MEAN_PDELAY_REQ_INTERVAL); + InstancePtr->SignallingFrameData.AnnounceIntervalDuration = + XAvb_ConvertLogMeanToDuration(XAVB_DEFAULT_LOG_MEAN_ANNOUNCE_INTERVAL); + + InstancePtr->latestMDSyncReceive.SyncIntervalDuration = + XAvb_ConvertLogMeanToDuration(XAVB_DEFAULT_LOG_MEAN_SYNC_INTERVAL); + + /** Update logMeanMessageInterval in the pre-loaded TX SYNC message buffer */ + XAvb_UpdateLogMeanMessageInterval(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_SYNC_OFFSET, + InstancePtr->SignallingFrameData.SyncIntervalDuration); + /** Update logMeanMessageInterval in the pre-loaded TX FOLLOW_UP message buffer */ + XAvb_UpdateLogMeanMessageInterval(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_FOLLOW_UP_OFFSET, + InstancePtr->SignallingFrameData.SyncIntervalDuration); + + /** Update logMeanMessageInterval in the pre-loaded TX PDELAYREQ message buffer */ + XAvb_UpdateLogMeanMessageInterval(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYREQ_OFFSET, + InstancePtr->SignallingFrameData.LinkDelayIntervalDuration); + + /** Update logMeanMessageInterval in the pre-loaded TX ANNOUNCE message buffer */ + XAvb_UpdateLogMeanMessageInterval(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + InstancePtr->SignallingFrameData.AnnounceIntervalDuration); + + /** + * Initialise other driver variables in the device's data structure + */ + InstancePtr->PtpCounters.RxPtpHardPointer = 0; + InstancePtr->PtpCounters.RxPtpSoftPointer = 0xFF; + InstancePtr->PtpCounters.CounterSyncInterval = 0; + InstancePtr->PtpCounters.CounterLinkDelayInterval = 0; + InstancePtr->PtpCounters.CounterAnnounceInterval = 0; + InstancePtr->PtpCounters.CounterSyncEvents = 0; + InstancePtr->StateMachineData.lostResponses = 0; + InstancePtr->StateMachineData.rcvdPDelayResp = 0; + InstancePtr->StateMachineData.rcvdPDelayRespFollowUp = 0; +#ifdef DEBUG_XAVB_LEVEL1 + xil_printf("\r\n** XAvb_Reset(): PTP Driver Reset **"); +#endif +} + + +/* + * Device Specific Driver Functions + */ + + +/*****************************************************************************/ +/** +* +* This function will start the PTP drivers running. +* +* @param InstancePtr is a pointer to the Xavb instance to be worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XAvb_Start(XAvb * InstancePtr) +{ + /** Assert bad arguments and conditions */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /** Re-run the BMCA algorithm with the current PTP buffer Announce Packet */ + XAvb_DecodeTxAnnounceFrame(InstancePtr); + + /** Set to PTP running in the PTP data structure */ + InstancePtr->PtpIsRunning = 1; + + /** Assume that the Peer is not AS capable until it replies to a pDelay_Req + * frame */ + XAvb_ChangePeerASCapability(InstancePtr, 0); + +#ifdef DEBUG_XAVB_LEVEL1 + xil_printf("\r\n** XAvb_Start(): Starting PTP **"); +#endif +} + + +/*****************************************************************************/ +/** +* +* This function will stop the PTP drivers from running. +* +* @param InstancePtr is a pointer to the Xavb instance to be worked on. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XAvb_Stop(XAvb * InstancePtr) +{ + /** Assert bad arguments and conditions */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + +#ifdef DEBUG_XAVB_LEVEL1 + xil_printf("\r\n** XAvb_Stop(): PTP STOPPED **"); +#endif + XAvb_Reset(InstancePtr); +} + + +/****************************************************************************/ +/** +* +* The Interrupt subroutine for the "interruptPtpTimer" signal. This interrupt +* fires reguarly on a 1/128 second period (based on the RTC). +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_PtpTimerInterruptHandler(XAvb * InstancePtr) { + + /** Clear Interrupt */ + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_CLEAR_INT_OFFSET, + XAVB_RTC_CLEAR_INT_MASK); + + /** If PTP functions are marked as not running, then take no further action */ + if (InstancePtr->PtpIsRunning == 1) { + + /** If the Link Partner is not AS capable, then take no further action */ + if (InstancePtr->PeerASCapable == 1) { + + + /** If a Master, then initiate Sync Frames and Announce frames at the + * correct intervals + */ + if (InstancePtr->CurrentBmc.IAmTheRtcMaster == 1) { + + /** Master will initiate a Sync Frame when the SyncIntervalDuration + * expires (SyncIntervalDuration is used to count/time the duration) + * - unless a Signalling frame has told us not to send Sync Frames + */ + if ((InstancePtr->SignallingFrameData.SyncIntervalDuration != XAVB_PKT_TYPE_DISABLED) && + (InstancePtr->PtpCounters.CounterSyncInterval >= + (InstancePtr->SignallingFrameData.SyncIntervalDuration-1))) { + + XAvb_MasterSendSync(InstancePtr); + InstancePtr->PtpCounters.CounterSyncInterval = 0; + + /** Following a Sync Frame, a Follow Up frame should always be sent + */ + XAvb_MasterSendFollowUp(InstancePtr); + + + } else { + InstancePtr->PtpCounters.CounterSyncInterval + = InstancePtr->PtpCounters.CounterSyncInterval + 1; + } + + /** Master will initiate an Announce Frame when the + * AnnounceIntervalDuration expires (CounterAnnounceInterval is used + * to count/time the duration) + * - unless a Signalling frame has told us not to send Announce Frames + */ + if ((InstancePtr->SignallingFrameData.AnnounceIntervalDuration != XAVB_PKT_TYPE_DISABLED) && + (InstancePtr->PtpCounters.CounterAnnounceInterval >= + (InstancePtr->SignallingFrameData.AnnounceIntervalDuration-1))) { + + XAvb_MasterSendAnnounce(InstancePtr); + InstancePtr->PtpCounters.CounterAnnounceInterval = 0; + + } else { + InstancePtr->PtpCounters.CounterAnnounceInterval + = InstancePtr->PtpCounters.CounterAnnounceInterval + 1; + } + + /** If a Slave, monitor Announce/Sync Packet reception from the Master */ + } else { + + /** Timeout for Announce Packet reception: XAVB_ANNOUNCE_RECEIPT_TIMEOUT + * The AnnounceIntervalDuration is stored with the GrandMaster BMCA data + * as it is captured from the last Announce frame that was received. + */ + if (InstancePtr->PtpCounters.CounterAnnounceInterval >= + ((InstancePtr->CurrentBmc.AnnounceIntervalDuration-1) * + XAVB_ANNOUNCE_RECEIPT_TIMEOUT) ) { + +#ifdef XAVB_DEBUG_LEVEL1 + xil_printf("XAVB_ANNOUNCE_RECEIPT_TIMEOUT: Becoming GM! CounterAnnounceInterval = %d\r\n", InstancePtr->PtpCounters.CounterAnnounceInterval); +#endif + + InstancePtr->PtpCounters.CounterAnnounceInterval = 0; + + /** No Announce received from GM for timeout interval: we become the master */ + xil_printf("\r\n*** Announce timeout : Call XAvb_BecomeRtcMaster() *** \r\n"); + XAvb_BecomeRtcMaster(InstancePtr,0); + + } else { + InstancePtr->PtpCounters.CounterAnnounceInterval + = InstancePtr->PtpCounters.CounterAnnounceInterval + 1; + } + + /** Timeout for Sync Packet reception: XAVB_SYNC_RECEIPT_TIMEOUT * + * The SyncIntervalDuration is stored with the Received Sync data + * as it is captured from the last Sync frame that was received. + */ + if( InstancePtr->PtpCounters.CounterSyncInterval >= + ((InstancePtr->latestMDSyncReceive.SyncIntervalDuration-1) * + XAVB_SYNC_RECEIPT_TIMEOUT) ) { + +#ifdef XAVB_DEBUG_LEVEL1 + xil_printf("\r\nXAVB_SYNC_RECEIPT_TIMEOUT: Becoming GM! CounterSyncInterval = %d\r\n", InstancePtr->PtpCounters.CounterSyncInterval); + xil_printf("\r\nXAVB_SYNC_RECEIPT_TIMEOUT: SyncIntervalDuration = %d\r\n", InstancePtr->SignallingFrameData.SyncIntervalDuration); +#endif + + InstancePtr->PtpCounters.CounterSyncInterval = 0; + + + /** No Syncs received from GM for timeout interval: we become + * the master */ + xil_printf("\r\n*** Sync Timeout : Call XAvb_BecomeRtcMaster() *** \r\n"); + XAvb_BecomeRtcMaster(InstancePtr,0); + + } else { + InstancePtr->PtpCounters.CounterSyncInterval + = InstancePtr->PtpCounters.CounterSyncInterval + 1; + } + } + } + + /** Both Master and Slave will initiate a link delay measurement when the + * LinkDelayIntervalDuration expires (LinkDelayIntervalDuration is used to + * count/time the duration) + * - unless a Signalling frame has told us not to send PdelayReq Frames + */ + if ((InstancePtr->SignallingFrameData.LinkDelayIntervalDuration != XAVB_PKT_TYPE_DISABLED) && + (InstancePtr->PtpCounters.CounterLinkDelayInterval >= + (InstancePtr->SignallingFrameData.LinkDelayIntervalDuration-1))) { + + /** Check to see if we've received PDelayResp and + * PDelayRespFollowUp messages since the last PDelayReq was + * sent */ + if( InstancePtr->StateMachineData.rcvdPDelayResp && + InstancePtr->StateMachineData.rcvdPDelayRespFollowUp ) { + + InstancePtr->StateMachineData.lostResponses = 0; + } else { + InstancePtr->StateMachineData.lostResponses++; + } + + if( InstancePtr->StateMachineData.lostResponses >= XAVB_ALLOWED_LOST_RESPONSES ) { + /** the peer is no longer ASCapable */ + XAvb_ChangePeerASCapability(InstancePtr, 0); + + xil_printf("\r\n** XAvb_PtpTimerInterruptHandler(): The peer is no longer ASCapable **"); + xil_printf("\r\n** XAvb_PtpTimerInterruptHandler(): StateMachineData.lostResponses >= %d **", + XAVB_ALLOWED_LOST_RESPONSES); + + /** avoid potential overflow */ + InstancePtr->StateMachineData.lostResponses = XAVB_ALLOWED_LOST_RESPONSES; + } + + XAvb_SendPDelayReq(InstancePtr); + + InstancePtr->StateMachineData.rcvdPDelayResp = 0; + InstancePtr->StateMachineData.rcvdPDelayRespFollowUp = 0; + InstancePtr->PtpCounters.CounterLinkDelayInterval = 0; + + } else { + InstancePtr->PtpCounters.CounterLinkDelayInterval + = InstancePtr->PtpCounters.CounterLinkDelayInterval + 1; + } + + } /** end of 'if (InstancePtr->PtpIsRunning == 1)' */ + +} + + +/****************************************************************************/ +/** +* +* The Interrupt subroutine for the "interrupt_ptp_rx" signal. This interrupt +* fires whenever a PTP frame has been received. The main function is to +* identify, decode, and act on the type of PTP frame received. +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_PtpRxInterruptHandler(XAvb * InstancePtr) { +#ifdef DEBUG_XAVB_LEVEL1 + u32 x = 0; +#endif + u32 MessageType = 0; + u32 PtpFrameBaseAddr = 0; + + /** RxPtpHardPointer indicates the bin location of the last frame to be + * received and written into the Rx PTP buffer in hardware. This read will + * also clear the interrupt.*/ + InstancePtr->PtpCounters.RxPtpHardPointer + = (XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_PTP_RX_CONTROL_OFFSET) + & XAVB_PTP_RX_PACKET_FIELD_MASK) >> 8; + + /** If PTP functions are marked as not running, then take no further action */ + if (InstancePtr->PtpIsRunning == 1) { + + + /** RxPtpSoftPointer indicates the bin location of the last frame to be + * processed in software. */ + while ( (InstancePtr->PtpCounters.RxPtpSoftPointer & 0xF) + != (InstancePtr->PtpCounters.RxPtpHardPointer & 0xF) ) { + + /** decode the rx'd frames until RxPtpHardPointer = RxPtpSoftPointer */ + InstancePtr->PtpCounters.RxPtpSoftPointer + = InstancePtr->PtpCounters.RxPtpSoftPointer + 1; + + /** Set the base address of the current PTP frame in the Buffer */ + PtpFrameBaseAddr = XAVB_PTP_RX_BASE_OFFSET + + ((InstancePtr->PtpCounters.RxPtpSoftPointer & 0xF) + << 8); + + + /** Perform very basic sanity checking of the frame : is it a PTP? */ + if (XAvb_IsRxFramePTP(InstancePtr, PtpFrameBaseAddr) == 1) { + + + /** Determine which PTP frame was received. */ + MessageType = (XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_TYPE_OFFSET) + & 0x000F0000 ) >> 16; + + + /** Now act on the received frame */ + switch (MessageType) { + + /** Sync Frame + * ---------- */ + case XAVB_PTP_TYPE_SYNC: + XAvb_DecodeRxSync(InstancePtr, PtpFrameBaseAddr); + break; + + /** Follow Up Frame + * --------------- */ + case XAVB_PTP_TYPE_FOLLOW_UP: + XAvb_DecodeRxFollowUp(InstancePtr, PtpFrameBaseAddr); + break; + + /** PDelayReq Frame + * --------------- */ + case XAVB_PTP_TYPE_PDELAYREQ: + /** Send a send PDelayResp frame after receiving a PDelayReq Frame */ + XAvb_SendPDelayResp(InstancePtr, PtpFrameBaseAddr); + + /** Send a send PDelayRespFollowUp frame after a PDelayResp Frame */ + XAvb_SendPDelayRespFollowUp(InstancePtr); + + break; + + /** PDelayResp Frame + * ---------------- */ + case XAVB_PTP_TYPE_PDELAYRESP: + XAvb_DecodeRxPDelayResp(InstancePtr, PtpFrameBaseAddr); + break; + + /** PDelayRespFollowUp Frame + * ------------------------ */ + case XAVB_PTP_TYPE_PDELAYRESP_FOLLOW_UP: + EchoPTPFramesReceived = 1; + XAvb_DecodeRxPDelayRespFollowUp(InstancePtr, PtpFrameBaseAddr); + break; + + /** Announce Frame + * -------------- */ + case XAVB_PTP_TYPE_ANNOUNCE: + XAvb_DecodeRxAnnounceFrame(InstancePtr, + PtpFrameBaseAddr); + break; + + /** Signaling Frame + * -------------- */ + case XAVB_PTP_TYPE_SIGNALING: + XAvb_DecodeRxSignaling(InstancePtr, PtpFrameBaseAddr); + break; + + /** Unknown Frame + * -------------- */ + default: +#ifdef DEBUG_XAVB_LEVEL1 + xil_printf("\r\nXAvb_PtpRxInterruptHandler()"); + xil_printf("\r\n** Unknown PTP Frame Rx'd **"); + xil_printf("\r\nMessage Type is %x", MessageType); + xil_printf("\r\n-------Unknown Frame -------"); + for (x = 0; x < 0x100; x = x + 4) { + xil_printf("\r\n %x %x", x, + (XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + x))); + } +#endif + break; + } + } + } + + } else { /* InstancePtr->PtpIsRunning != 1 */ + + /** PTP is not running so just consume the packets so they are not left in the + * queue and cause problems when we actually start */ + + /** RxPtpSoftPointer indicates the bin location of the last frame to be + * processed in software. */ + while ( (InstancePtr->PtpCounters.RxPtpSoftPointer & 0xF) + != (InstancePtr->PtpCounters.RxPtpHardPointer & 0xF) ) { + + /** decode the rx'd frames until RxPtpHardPointer = RxPtpSoftPointer */ + InstancePtr->PtpCounters.RxPtpSoftPointer + = InstancePtr->PtpCounters.RxPtpSoftPointer + 1; + } + } + +} + +/**************************************************************************** +* +* This function provides a stub handler such that if the application does not +* define a handler this function will be called. +* +* @param CallBackRef has no purpose but is necessary to match the +* interface for a handler. +* @param TimestampsUncertain has no purpose but is necessary to match the +* interface for a handler. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +static void XAvb_StubHandler(void *CallBackRef, u32 TimestampsUncertain) +{ + /* + * Assert occurs always since this is a stub and should never be called + */ + Xil_AssertVoidAlways(); +} + +/****************************************************************************/ +/** +* +* A function to set the VLAN PCP field for either SR A or B traffic in the +* RX Filtering Control Register - such that AV traffic is correctly filtered +* by the RX Splitter. +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @param VlanPriority contains the 3-bit value to be written to the register +* in the correct bit positions as defined in the address map +* +* @param SrClass is '0' if VLAN Priority (PCP) A is to be updated and is +* '1' if VLAN Priority (PCP) B is to be updated +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_SetupRxFilterControlPcp(XAvb * InstancePtr, + u32 VlanPriority, + u8 SrClass) { + u32 LocalData = 0; + + LocalData = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RX_FILTER_CONTROL); + + if (SrClass == 0x0) { + LocalData = LocalData | (VlanPriority & XAVB_RX_AV_VLAN_PRIORITY_A_MASK); + } else { + LocalData = LocalData | (VlanPriority & XAVB_RX_AV_VLAN_PRIORITY_B_MASK); + } + + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_RX_FILTER_CONTROL, + LocalData); +} + +/****************************************************************************/ +/** +* +* A function to set the VLAN VID field for either SR A or B traffic in the +* RX Filtering Control Register - such that AV traffic is correctly filtered +* by the RX Splitter. +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @param VlanVid contains the 12-bit value to be written to the register +* in the correct bit positions as defined in the address map +* +* @param SrClass is '0' if VLAN VID A is to be updated and is +* '1' if VLAN VID B is to be updated +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_SetupRxFilterControlVid(XAvb * InstancePtr, + u32 VlanVid, + u8 SrClass) { + u32 LocalData = 0; + + LocalData = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RX_FILTER_CONTROL); + + if (SrClass == 0x0) { + LocalData = LocalData | (VlanVid & XAVB_RX_AV_VLAN_VID_A_MASK); + } else { + LocalData = LocalData | (VlanVid & XAVB_RX_AV_VLAN_VID_B_MASK); + } + + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_RX_FILTER_CONTROL, + LocalData); +} + + +/****************************************************************************/ +/** +* +* A function to set the VLAN Match Mode field for the RX Filtering Control +* Register - such that AV traffic is correctly filtered by the RX Splitter. +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @param VlanMatchMode contains the 1-bit value to be written to the register +* in the correct bit position as defined in the address map +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_SetupRxFilterControlMatchMode(XAvb * InstancePtr, + u32 VlanMatchMode) { + u32 LocalData = 0; + + LocalData = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RX_FILTER_CONTROL); + + LocalData = LocalData | (VlanMatchMode & XAVB_RX_AV_VLAN_MATCH_MODE_MASK); + + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_RX_FILTER_CONTROL, + LocalData); +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb.h b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb.h new file mode 100644 index 00000000..249c5453 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb.h @@ -0,0 +1,668 @@ +/****************************************************************************** +* +* Copyright (C) 2008 - 2014 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xavb.h +* +* This header file contains the identifiers and basic driver functions (or +* macros) that can be used to access the device. Other driver functions +* are defined in xavb.h. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a mbr 09/19/08 First release +* 1.01a mbr 06/24/09 PTP frame format updates for IEEE802.1 AS draft 5-0 +* 2_02a mbr 09/16/09 Updates for programmable PTP timers +* 2_04a kag 07/23/10 PTP frame format updates for IEEE802.1 AS draft 6-7 +* 3_01a kag 08/29/11 Added new APIs to update the RX Filter Control Reg. +* Fix for CR:572539. Updated bit map for Rx Filter +* control reg. +* 4_0 asa 03/06/14 Fix for CR 740863. The value of XAVB_CLOCK_LOCK_THRESHOLD +* is increased to 1000ns (1 us) to make it more +* meningful and reasonable. +* +*+* +******************************************************************************/ + +#ifndef XAVB_H /* prevent circular inclusions */ +#define XAVB_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/***************************** Include Files *********************************/ + +#include "xavb_hw.h" +#include "xstatus.h" +#include "stdio.h" + +/************************** Constant Definitions *****************************/ + +/** @name Define the Debug Level Verbosity for print messages for this driver + * @{ + */ +#undef DEBUG_XAVB_LEVEL1 /* Basic messages and PTP frame reception messages */ +#undef DEBUG_XAVB_LEVEL2 /* PTP Calculation messages */ +#undef DEBUG_XAVB_LEVEL3 /* PTP frame transmission messages */ + +/** @name MAC Latency Definitions + * @{ + */ +#define XAVB_TX_MAC_LATENCY_IN_NS 80 +#define XAVB_RX_MAC_LATENCY_IN_NS 80 +/* @} */ + + +/** @name PTP Buffer Storage Definitions + * @{ + */ +#define XAVB_PTP_TX_SYNC 0x0 +#define XAVB_PTP_TX_FOLLOW_UP 0x1 +#define XAVB_PTP_TX_PDELAYREQ 0x2 +#define XAVB_PTP_TX_PDELAYRESP 0x3 +#define XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP 0x4 +#define XAVB_PTP_TX_ANNOUNCE 0x5 +#define XAVB_PTP_TX_SIGNALING 0x6 +/* @} */ + + +/** @name PTP Packet Message Type Definitions + * @{ + */ +#define XAVB_PTP_TYPE_SYNC 0x0 +#define XAVB_PTP_TYPE_FOLLOW_UP 0x8 +#define XAVB_PTP_TYPE_PDELAYREQ 0x2 +#define XAVB_PTP_TYPE_PDELAYRESP 0x3 +#define XAVB_PTP_TYPE_PDELAYRESP_FOLLOW_UP 0xA +#define XAVB_PTP_TYPE_ANNOUNCE 0xB +#define XAVB_PTP_TYPE_SIGNALING 0xC +/* @} */ + + +/** @name Common PTP Frame Structure Definitions. + * @{ + */ +#define XAVB_PTP_PKT_CAPTURED_TIMESTAMP_OFFSET 0x000000FC +/* @} */ + + +/** @name General Tx PTP Frame Structure Definitions. + * @{ + */ +#define XAVB_PTP_TX_PKT_SA_UPPER_OFFSET 0x0000000C +#define XAVB_PTP_TX_PKT_SA_LOWER_OFFSET 0x00000010 +#define XAVB_PTP_TX_PKT_TYPE_OFFSET 0x00000014 +#define XAVB_PTP_TX_PKT_CORRECTION_FIELD_OFFSET 0x00000020 +#define XAVB_PTP_TX_PKT_PORTID_UPPER_OFFSET 0x00000028 +#define XAVB_PTP_TX_PKT_PORTID_MID_OFFSET 0x0000002C +#define XAVB_PTP_TX_PKT_PORTID_LOWER_OFFSET 0x00000030 +#define XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET 0x00000034 +#define XAVB_PTP_TX_PKT_TIMESTAMP_UPPER_OFFSET 0x00000038 +#define XAVB_PTP_TX_PKT_TIMESTAMP_MID_OFFSET 0x0000003C +#define XAVB_PTP_TX_PKT_TIMESTAMP_LOWER_OFFSET 0x00000040 /* upper 2 bytes */ +#define XAVB_PTP_TX_PKT_REQ_PORTID_UPPER_OFFSET 0x00000040 /* lower 2 bytes */ +#define XAVB_PTP_TX_PKT_REQ_PORTID_MID_OFFSET 0x00000044 +#define XAVB_PTP_TX_PKT_REQ_PORTID_LOWER_OFFSET 0x00000048 +/* @} */ + +/** @name Tx Announce PTP Frame Structure Definitions. + * @{ + */ +#define XAVB_PTP_TX_PKT_ANNOUNCE_CURR_UTCOFF_OFFSET 0x00000040 +#define XAVB_PTP_TX_PKT_ANNOUNCE_QUAL_LOW_PRI2_GMID_HI_OFFSET 0x00000048 +#define XAVB_PTP_TX_PKT_ANNOUNCE_GMID_MID_OFFSET 0x0000004C +#define XAVB_PTP_TX_PKT_ANNOUNCE_GMID_LOW_STEPSREMOVED_HI_OFFSET 0x00000050 +#define XAVB_PTP_TX_PKT_ANNOUNCE_STEPSREMOVED_LOW_TIMESRC_OFFSET 0x00000054 +#define XAVB_PTP_TX_PKT_ANNOUNCE_TLVLEN_PATHSEQ_START_OFFSET 0x00000058 +/* @} */ + +/** @name PTP frame constant definitions + * @{ + * + * Constant value for the control field and LogMeanMessageInterval field for + * pDelayResp and pDelayRespFollowUp PTP frames (defined in IEEE802.1 AS) + */ +#define XAVB_PDELAY_LOG_MEAN_MESSAGE_INT 0x7F050000 +/* @} */ + + +/** @name Default LogMeanInterval values +* @{ +*/ +#define XAVB_DEFAULT_LOG_MEAN_SYNC_INTERVAL (-3) /** 2^(-3) = 125ms */ +#define XAVB_DEFAULT_LOG_MEAN_PDELAY_REQ_INTERVAL 0 /** 128/128 = 2^(0) = 1 s */ +#define XAVB_DEFAULT_LOG_MEAN_ANNOUNCE_INTERVAL 0 /** 128/128 = 2^(0) = 1 s */ +#define XAVB_PKT_TYPE_DISABLED 0xffff + +#define XAVB_MAX_SUPPORTED_LOG_MEAN_INTERVAL 8 /** 32768/128 = 256 s */ +#define XAVB_MIN_SUPPORTED_LOG_MEAN_INTERVAL (-7) /** 1/128 s */ +/* @} */ + +/** @name Announce / Sync Timeout values +* @{ +*/ +/** XAVB_ANNOUNCE_RECEIPT_TIMEOUT is the number of announce + * intervals without the receipt of an Announce message from + * the GM that are allowed before the GM is assumed to be no + * longer present and BMCA should be run again + */ +#define XAVB_ANNOUNCE_RECEIPT_TIMEOUT 2 + +/** XAVB_SYNC_RECEIPT_TIMEOUT is the number of sync intervals + * without the receipt of an Sync message from the GM that are + * allowed before the GM is assumed to be no longer present and + * BMCA should be run again + */ +#define XAVB_SYNC_RECEIPT_TIMEOUT 3 +/* @} */ + + +/** @name AS Network Requirements +* @{ +*/ +/** XAVB_NEIGHBOR_PROP_DELAY_THRESH is the maximum allowed delay (in nanosecs) + * across a full duplex link for which the AVB protocol is allowed to function. + * Although this parameter is defined in the IEEE spec, no default is defined. + */ +#define XAVB_NEIGHBOR_PROP_DELAY_THRESH 5000 + +/** XAVB_ALLOWED_LOST_RESPONSES is the number of Pdelay_Req + * messages for which a valid response is not received, above + * which the Peer should no longer be considered ASCapable + */ +#define XAVB_ALLOWED_LOST_RESPONSES 3 + +/* @} */ + + +/** @name General Rx PTP Frame Structure Definitions. + * @{ + */ +#define XAVB_PTP_RX_PKT_SA_UPPER_OFFSET 0x00000004 +#define XAVB_PTP_RX_PKT_SA_LOWER_OFFSET 0x00000008 +#define XAVB_PTP_RX_PKT_TYPE_OFFSET 0x0000000C +#define XAVB_PTP_RX_PKT_CORRECTION_FIELD_OFFSET 0x00000018 +#define XAVB_PTP_RX_PKT_PORTID_UPPER_OFFSET 0x00000020 +#define XAVB_PTP_RX_PKT_PORTID_MID_OFFSET 0x00000024 +#define XAVB_PTP_RX_PKT_PORTID_LOWER_OFFSET 0x00000028 +#define XAVB_PTP_RX_PKT_SEQUENCEID_OFFSET 0x0000002C +#define XAVB_PTP_RX_PKT_TIMESTAMP_UPPER_OFFSET 0x00000030 +#define XAVB_PTP_RX_PKT_TIMESTAMP_MID_OFFSET 0x00000034 +#define XAVB_PTP_RX_PKT_TIMESTAMP_LOWER_OFFSET 0x00000038 /* upper 2 bytes */ +#define XAVB_PTP_RX_PKT_REQ_PORTID_UPPER_OFFSET 0x00000038 /* lower 2 bytes */ +#define XAVB_PTP_RX_PKT_REQ_PORTID_MID_OFFSET 0x0000003C +#define XAVB_PTP_RX_PKT_REQ_PORTID_LOWER_OFFSET 0x00000040 +/* @} */ + + +/** @name Rx Announce PTP Frame Structure Definitions. + * @{ + */ +#define XAVB_PTP_RX_PKT_ANNOUNCE_PRI1_QUAL_HI_OFFSET 0x0000003C +#define XAVB_PTP_RX_PKT_ANNOUNCE_QUAL_LOW_PRI2_GMID_HI_OFFSET 0x00000040 +#define XAVB_PTP_RX_PKT_ANNOUNCE_GMID_MID_OFFSET 0x00000044 +#define XAVB_PTP_RX_PKT_ANNOUNCE_GMID_LOW_STEPSREMOVED_HI_OFFSET 0x00000048 +#define XAVB_PTP_RX_PKT_ANNOUNCE_STEPSREMOVED_LOW_TIMESRC_OFFSET 0x0000004C +/* @} */ + + +/** @name Rx Signalling PTP Frame Structure Definitions. + * @{ + */ +#define XAVB_PTP_RX_PKT_SIGNALING_DELAY_INTERVAL_OFFSET 0x00000044 +/* @} */ + +/** @name Standard PTP Frame Field Definitions (from IEEE802.1AS specification). + * @{ + */ +#define XAVB_PTP_ETHERTYPE 0x88F7 +#define XAVB_PTP_VERSION_PTP 2 +/* @} */ + + +/** @name Real Time Clock Definitions. + * @{ + */ +#define XAVB_ONE_SECOND 1000000000 /**< Value in ns */ +#define XAVB_PERIOD_8KHZ 125000 /**< Value in ns */ +/* @} */ + +/** @name Real Time Clock Locked Definitions. + * @{ + * If the Slave error is > this threshold then define PTP to be + * unlocked and link not asCapable. + * @note: This threshold is not specified in IEEE 802.1as. + */ +#define XAVB_CLOCK_LOCK_THRESHOLD 1000 /**< Value in ns */ +/* @} */ + +/** @name RTC Increment Value Update Definitions + * @{ + * Define how often to re-calculate the RTC Increment This value + * indicates how many good Sync/FollowUp message pairs + * are received before the re-calculation is performed. + */ +#define XAVB_NUM_SYNC_FU_PAIR_CALC_RTC_INCREMENT 2 +/* @} */ + +/**************************** Type Definitions *******************************/ + +/** + * Callback function. The first argument is a callback reference passed in by + * the upper layer when setting the callback functions, and passed back to the + * upper layer when the callback is invoked. + * The second argument is a '1' if a Grandmaster Discontinuity event has occurred + * otherwise it is '0'. + */ +typedef void (*XAvb_Handler)(void *CallBackRef, u32 TimestampsUncertain); + +/** + * This typedef contains configuration information for a device. + */ +typedef struct { + u16 DeviceId; /**< Unique ID of device */ + u32 BaseAddress; /**< Register base address */ +} XAvb_Config; + + +/** + * This typedef defines the format for a data structure which stores the Port + * Identity information from received Announce packets + */ +typedef struct +{ + u32 ClockIdentityUpper; /**< Upper 4 bytes of ClockIdentity */ + u32 ClockIdentityLower; /**< Lower 4 bytes of ClockIdentity*/ + u16 PortNumber; /**< PortNumber associated with ClockIdentity*/ +} XAvb_PortIdentity; + +/** + * This typedef defines the format for a data structure which stores the Clock + * Identity information from received Announce packets + */ +typedef struct +{ + u32 ClockIdentityUpper; /**< Upper 4 bytes of ClockIdentity */ + u32 ClockIdentityLower; /**< Lower 4 bytes of ClockIdentity*/ +} XAvb_ClockIdentity; + +/** + * This typedef defines the quality of a clock + */ +typedef struct +{ + u8 clockClass; /**< Announce message: clockClass */ + u8 clockAccuracy; /**< Announce message: clockAccuracy */ + u16 offsetScaledLogVariance; /**< Announce message: offsetScaledLogVariance*/ +} XAvb_ClockQuality; + +/** + * This typedef defines the format for a data structure which stores the relevant + * fields which are captured from Announce Packets. + */ +typedef struct +{ + XAvb_PortIdentity SourcePortIdentity; /**< Announce message: sourcePortIdentity */ + XAvb_ClockIdentity GrandmasterIdentity; /**< Announce message: grandmasterIdentity */ + u16 stepsRemoved; /**< Announce message: stepsRemoved */ + XAvb_ClockQuality ClockQuality; /**< Announce message: grandmasterClockQuality */ + u8 GrandmasterPriority1; /**< Announce message: grandmasterPriority1*/ + u8 GrandmasterPriority2; /**< Announce message: grandmasterPriority2*/ + u8 IAmTheRtcMaster; /**< Boolean: 1 = grandmaster, 0 = slave*/ + u16 tlvLengthField; /**< Announce message: lengthField (for TLV)*/ + char logMessageInterval; /**< Announce message: logMessageInterval. + * NOTE: 8-bit signed integer */ + u16 AnnounceIntervalDuration; /**< Announce Interval in units of 1/128 secs */ +} XAvb_BmcData; + + +/** + * This typedef defines the format for a data structure which stores information + * relating to the 1588 based PTP timing calculations + */ +typedef struct +{ + u32 Nanosec; /**< ns value for sync frame tx request */ + u32 SlaveSyncTimestamp; /**< The timestamp taken of a rx'd sync */ + u32 MasterCorrectionField; /**< Correction Field from rx'd follow-up */ + u32 PDelayTimestampT1; /**< T1 :PDelayReq Frame transmission */ + u32 PDelayTimestampT2; /**< T2 :PDelayReq rx'd at link partner */ + u32 PDelayTimestampT3; /**< T3 :PDelayResp Frame reception */ + u32 PDelayTimestampT4; /**< T4 :PDelayResp tx'd by link partner */ + u32 LinkDelay; /**< Last calculated value of Link Delay */ + u32 NewSlaveTime; /**< RTC ns at slave for last rx'd sync */ + u32 NewMasterTime; /**< RTC ns at master for last tx'd sync */ + u32 OldSlaveTime; /**< Stored RTC slave ns for past sync rx */ + u32 OldMasterTime; /**< Stored RTC master ns for past sync tx*/ + u32 NsOffsetForPDelayResp; /**< RTC ns offset at PDelayResp tx time */ +} XAvb_PtpStruct; + + +/** + * This typedef defines the format for a data structure which stores the last + * used sequence ID for all of the PTP timing frames. + */ +typedef struct +{ + u16 SyncSequenceId; /**< SequenceId of the latest RX'd Sync message */ + u16 FollowUpSequenceId; /**< SequenceId of the latest RX'd FollowUp message */ + u16 PDelayReqSequenceId; /**< SequenceId of the latest TX'd PDelayReq message */ + u16 PDelayRespSequenceId; /**< SequenceId of the latest RX'd PDelayResp message */ + u16 PDelayFollowUpSequenceId; /**< SequenceId of the latest RX'd PDelayRespFollowUp message */ + u16 OldSyncSequenceId; /**< SequenceId of the previous RX'd Sync message used + * for XAvb_UpdateRtcIncrement() calculations */ + u16 NewSyncSequenceId; /**< SequenceId of the current RX'd Sync message used + * for XAvb_UpdateRtcIncrement() calculations */ +} XAvb_SequenceIdStruct; + + +/** + * The Signalling frame defines the delays to be used between Sync Frames, Link + * Delay measurements and Announce Frame events + */ +typedef struct +{ + u16 SyncIntervalDuration; /**< Sync Interval in units of 1/128 seconds */ + u16 LinkDelayIntervalDuration; /**< Link Delay Interval in units of 1/128 seconds */ + u16 AnnounceIntervalDuration; /**< Announce Interval in units of 1/128 seconds */ +} XAvb_SignallingFrameData; + + +/** + * This typedef defines the various counters which have to maintained for the + * PTP operation. + */ +typedef struct +{ + u8 RxPtpHardPointer; /**< The Rx PTP Buffer last written to */ + u8 RxPtpSoftPointer; /**< The current software pointer to Rx Buffer */ + u16 CounterSyncInterval; /**< To count units of 1/128 seconds */ + u16 CounterLinkDelayInterval; /**< To count units of 1/128 seconds */ + u16 CounterAnnounceInterval; /**< To count units of 1/128 seconds */ + u8 CounterSyncEvents; /**< To count the number of Sync Events */ +} XAvb_Counters; + +/** Keep track of state machine data to make sure we're fully + * compliant with the spec + */ +typedef struct +{ + u8 lostResponses; /**< Keep track of the state machine errors */ + u8 rcvdPDelayResp; /**< Received a valid PDelayResp packet since PDelayReq was sent */ + u8 rcvdPDelayRespFollowUp; /**< Received a valid PDelayFollowUp packet since PDelayResp was received */ + XAvb_PortIdentity respPortIdentity; /**< sourcePortIdentity of the last PDelayResp packet received */ + XAvb_PortIdentity respReqPortIdentity; /**< requestingPortIdentity of the last PDelayResp packet received */ +} XAvb_StateMachineData; + + +/** This struct captures information from RX'd Sync/FollowUp message pairs in a format similiar + * to the MDSyncReceive structure described in the IEEE P802.1AS specification. + */ +typedef struct +{ + /** The logMessageInterval is the value of the logMessageInterval of the time-synchronization + * event message received by this port. It is the logSyncInterval of the upstream MasterPort + * that sent the event message.*/ + u8 logMessageInterval; + + /** Convert logMessageInterval into a value we can relate to our 1/128 ns clk pulse */ + u16 SyncIntervalDuration; + +} XAvb_MDSyncReceive; + + +/** + * The XAvb driver instance data. The user is required to allocate a + * variable of this type for every AVB device in the system. A pointer + * to a variable of this type is then passed to the driver API functions. + */ +typedef struct { + /** hardware configuration */ + XAvb_Config Config; + + /** Device is initialized and ready */ + u32 IsReady; + + /** Is AVB enabled */ + u32 AVBIsEnabled; + + /** The PTP algorithm can be started and stopped as requested */ + u32 PtpIsRunning; + + /** The peer must be AS capable before we start full blown PTP */ + u32 PeerASCapable; + + /** Current PTP Slave Error is less than XAVB_CLOCK_LOCK_THRESHOLD nsec */ + u32 PTPLocked; + + /** Store the info from the latest RX'd Sync/Follow message pair */ + XAvb_MDSyncReceive latestMDSyncReceive; + + /** Contains the local port Identity information */ + XAvb_PortIdentity portIdLocal; + + /** Create a data structure for the Best Master Clock Algorithm (BMCA) */ + XAvb_BmcData CurrentBmc; + + /** Create a data structure for the Precise Timing Protocol (PTP) */ + XAvb_PtpStruct PtpRecords; + + /** Create a data structure to record the PTP frames Sequence ID values */ + XAvb_SequenceIdStruct SequenceIdRecords; + + /** Create a data structure to store the Signalling frame information */ + XAvb_SignallingFrameData SignallingFrameData; + + /** Create a data structure to store various PTP counters/timers */ + XAvb_Counters PtpCounters; + + /** Create a data structure to store state machine flags */ + XAvb_StateMachineData StateMachineData; + + /** Callback Handler for a GrandMaster discontinuity event */ + XAvb_Handler GMDiscHandler; + /** Callback ref for a GrandMaster discontinuity event */ + void *GMDiscCallBackRef; + +} XAvb; + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +/* + * Functions in xavb.c + */ +XStatus XAvb_CfgInitialize(XAvb *InstancePtr, \ + XAvb_Config *ConfigPtr, \ + u32 EffectiveAddress); + +XAvb_Config *XAvb_LookupConfig(u16 DeviceId); + +void XAvb_Reset(XAvb * InstancePtr); + +void XAvb_Start(XAvb * InstancePtr); + +void XAvb_Stop(XAvb * InstancePtr); + +void XAvb_PtpTimerInterruptHandler(XAvb * InstancePtr); + +void XAvb_PtpRxInterruptHandler(XAvb * InstancePtr); + +void XAvb_SetupRxFilterControlPcp(XAvb * InstancePtr, \ + u32 VlanPriority, \ + u8 SrClass); + +void XAvb_SetupRxFilterControlVid(XAvb * InstancePtr, \ + u32 VlanVid, \ + u8 SrClass); + +void XAvb_SetupRxFilterControlMatchMode(XAvb * InstancePtr, \ + u32 VlanMatchMode); + +/* + * Functions in xavb_ptp_packets.c + */ +u32 XAvb_ReorderWord(u32 Data); +u32 XAvb_CompareClockIdentity(u32 BaseAddress, \ + XAvb_ClockIdentity Identity1, \ + XAvb_ClockIdentity Identity2); + +u32 XAvb_ComparePortIdentity(u32 BaseAddress, \ + XAvb_PortIdentity Identity1, \ + XAvb_PortIdentity Identity2); + +void XAvb_WriteToMultipleTxPtpFrames(u32 BaseAddress, \ + u32 Address, \ + u32 Data, \ + u32 DataBitEnable, \ + u8 BufferEnable); + +u32 XAvb_IncSequenceId(u32 BaseAddress, \ + u32 PTPFrameBaseAddress); + +void XAvb_GetPortIdentity(u32 BaseAddress, \ + u32 PtpFrameBaseAddr, \ + u32 PortIdOffset, \ + XAvb_PortIdentity *portID); + +void XAvb_WaitOnTxPtpQueue(XAvb * InstancePtr); + +void XAvb_MasterSendAnnounce(XAvb * InstancePtr); + +void XAvb_MasterSendSync(XAvb * InstancePtr); + +void XAvb_MasterSendFollowUp(XAvb * InstancePtr); + +void XAvb_SendPDelayReq(XAvb * InstancePtr); + +void XAvb_SendPDelayResp(XAvb * InstancePtr, \ + u32 PtpFrameBaseAddr); + +void XAvb_SendPDelayRespFollowUp(XAvb * InstancePtr); + +u32 XAvb_IsRxFramePTP(XAvb * InstancePtr, \ + u32 PtpFrameBaseAddr); + +void XAvb_DecodeRxSync(XAvb * InstancePtr, \ + u32 PtpFrameBaseAddr); + +void XAvb_DecodeRxFollowUp(XAvb * InstancePtr, \ + u32 PtpFrameBaseAddr); + +void XAvb_DecodeRxPDelayResp(XAvb * InstancePtr, \ + u32 PtpFrameBaseAddr); + +void XAvb_DecodeRxPDelayRespFollowUp(XAvb * InstancePtr, \ + u32 PtpFrameBaseAddr); + +void XAvb_DecodeRxSignaling(XAvb * InstancePtr, \ + u32 PtpFrameBaseAddr); + +u16 XAvb_UpdateIntervalDuration(u16 currentIntervalDuration, \ + char logMeanVal); + +u16 XAvb_ConvertLogMeanToDuration(char logMeanVal); + +char XAvb_ConvertDurationToLogMean(u16 fractionalVal); + +void XAvb_UpdateLogMeanMessageInterval(u32 BaseAddress, \ + u32 PtpFrameBaseAddr, \ + u16 intervalDuration); + +void XAvb_SetupSourcePortIdentity(XAvb * InstancePtr, \ + XAvb_PortIdentity systemIdentity); + +/* + * Functions in xavb_ptp_bmca.c + */ +void XAvb_DecodeTxAnnounceFrame(XAvb * InstancePtr); + +void XAvb_DecodeRxAnnounceFrame(XAvb * InstancePtr, \ + u32 PtpFrameBaseAddr); + +void XAvb_ReadAnnounceFrame(u32 BaseAddress, \ + u32 PtpFrameBaseAddr, \ + XAvb_BmcData* AnnounceFrame); + +void XAvb_ReadAnnounceReceiptTimeout(u32 BaseAddress, \ + u32 PtpFrameBaseAddr, \ + XAvb_BmcData * AnnounceFrame); + +void XAvb_UpdateBmcRecords(XAvb_BmcData* NewMaster, \ + XAvb_BmcData* CurrentBmc); + +u32 XAvb_BestMasterClockAlgorithm(XAvb_BmcData* AnnounceFrame, \ + XAvb_BmcData* CurrentBmc); + +void XAvb_BecomeRtcMaster(XAvb * InstancePtr, u8 txAnnounceHasWon); + +void XAvb_BecomeRtcSlave(XAvb * InstancePtr); + +void XAvb_ChangePTPLockStatus(XAvb * InstancePtr, u8 locked); + +void XAvb_ChangePeerASCapability(XAvb *InstancePtr, u8 capable); + +void XAvb_SetGMDiscontinuityHandler(XAvb *InstancePtr, \ + XAvb_Handler FuncPtr, \ + void *CallBackRef); + +/* + * Functions in xavb_rtc_sync.c + */ +u32 XAvb_CaptureNanoSec(u32 BaseAddress, \ + u32 PtpFrameBaseAddr); + +void XAvb_CalcDelay(XAvb * InstancePtr); + +void XAvb_CalcRtcOffset(XAvb * InstancePtr, \ + u32 PtpFrameBaseAddr); + +void XAvb_UpdateRtcIncrement(XAvb * InstancePtr); + +void XAvb_Adjust8kClock(u32 BaseAddress, \ + u32 NewOffset); + + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_example.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_example.c new file mode 100644 index 00000000..ded52272 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_example.c @@ -0,0 +1,654 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2014 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xavb_example.c +* +* This file implements a simple example to show the usage of Audio Video +* Bridging (AVB) functionality of Axi Ethernet IP in loopback mode. +* The example uses the PTP Timer and the PTP Rx interrupts. A PDelay_Req packet +* is sent and is received back (as we are in loopback mode). . +* After this loop backed PDelay_Req packet is received, a PDelay_Resp and +* PDelay_RespFollowUp packets are sent. These packets are also received. +* Since the source port identity of the received packets matches with our +* systems's own source port identity there is no further processing done. +* +* @note +* +* This code assumes the processor type is Microblaze, Xilinx interrupt +* controller (XIntc) is used in the system , and that no operating +* system is used. +* +* It also assumes that all the relevant AVB interrupts are properly +* connected to the Intc module. +* +* The Ethernet AVB Endpoint functionality should be enabled in the Xilinx +* Axi Ethernet core for this example to work. +* +* The Axi Ethernet is used with a GMII interface. The example initializes +* the GMII interface with 1000 Mbps speed. +* +* IMPORTANT NOTE: +* The user must define the macro XAVB_CLOCK_LOCK_THRESHOLD in xavb.h to +* an appropriate value as relevant for the corresponding use case. Presently +* it is defined to 1000 ns which is typical for telecom industry. +* This macro is used to compare against the slave error as calculated everytime +* after receiving 2 successive sync/followup frames. Slave error is the +* difference between master time duration and slave time duration as calculated +* for the time gap (the time it takes to receive two successive sync/follow up +* frames). If slave error is greater than the value defined in +* XAVB_CLOCK_LOCK_THRESHOLD, then master and slave clocks are unlocked. This +* means the node running this SW assumes that the peer is no more capable of +* processing 802.1as frames. The node running the SW then waits till it successful +* calculates the path delay (which essentially means the peer is again capable +* of processing 802.1as frames. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ------- -------- ----------------------------------------------------- +* 1.00a kag/asa 08/25/10 First release +* 3.00a asa 04/10/12 Disabled enabling of promiscuous mode. This is +* required for AxiEthernet cores with version v3_01_a +* onwards because of a change in the AVB implementation. +* 4.0 asa 03/06/14 Fix for CR 740863. Added a #warning message for +* users of this example to take note of the fact that +* we have just used a typical value for XAVB_CLOCK_LOCK_THRESHOLD +* and users may want to change it as per their requirements. +* +*+*******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xil_types.h" +#include "xintc.h" +#include "xil_exception.h" +#include "xavb_hw.h" +#include "xavb.h" +#include "xil_cache.h" +#include "xaxiethernet.h" /* defines Axi Ethernet APIs */ + +/************************** Constant Definitions *****************************/ +/** + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define AXIETHERNET_DEVICE_ID XPAR_AXIETHERNET_0_DEVICE_ID + +#define AVB_PTP_RX_INTERRUPT_ID \ +XPAR_INTC_0_AXIETHERNET_0_AV_INTERRUPT_PTP_RX_VEC_ID /* + * AVB PTP Received + * Frame Interrupt ID + */ +#define AVB_PTP_INTERRUPT_ID \ +XPAR_INTC_0_AXIETHERNET_0_AV_INTERRUPT_10MS_VEC_ID /* AVB PTP Timer + * Interrupt ID + */ + +/* + * Other constants used in this file. + */ + +#define PHY_DETECT_REG 1 +#define PHY_DETECT_MASK 0x1808 + + +#define PHY_R0_RESET 0x8000 +#define PHY_R0_LOOPBACK 0x4000 +#define PHY_R0_DFT_SPD_1000 0x0040 + +/* + * The source MAC address used in this example. This will also form + * a part of source port identity field in the PTP messages + */ +#define ETH_SYSTEM_ADDRESS_EUI48_HIGH 0x000A35 +#define ETH_SYSTEM_ADDRESS_EUI48_LOW 0x010203 + +/******************************************************************************/ +#warning The threshold or tolerance limit for slave error is currently set to \ + 1000 ns. This can be configured through the macro \ + XAVB_CLOCK_LOCK_THRESHOLD in xavb.h. Slave error is the difference \ + between measured master time duration and slave time duration over \ + two sync-frame intervals. If slave error exceeds the configured \ + threshold, the master and slave clocks are unlocked. For usage of the \ + macro XAVB_CLOCK_LOCK_THRESHOLD refer to the function \ + XAvb_UpdateRtcIncrement in file xavb_rtc_sync.c +/******************************************************************************/ + +/************************** Function Prototypes ******************************/ + +static int AvbSetupInterruptSystem(XAvb *InstancePtr); +static int AvbConfigHW(XAxiEthernet *AxiEthernetInstancePtr,XAvb *InstancePtr); +void AvbGMDiscontinuityHandler(void *CallBackRef, u32 TimestampsUncertain); +static int AvbConfigureGmii(XAxiEthernet *InstancePtr, XAvb *AvbInstancePtr); +static int AvbEnterPhyLoopBack(XAxiEthernet *InstancePtr); +static void AvbUtilPhyDelay(unsigned int Seconds); +static void AvbEnablePTPInterrupts(void); +static void AvbUtilPrintMessage(char *Message); + + +static XAxiEthernet AxiEthernetInstance; /* Instance of Axi Ethernet driver */ +static XAvb Avb; /* Instance of AVB driver */ +static XIntc InterruptController; /* Instance of INTC driver */ + +static XAvb_Config AvbConfigStruct; +volatile u8 EchoPTPFramesReceived = 0; + +/*****************************************************************************/ +/** +* +* This is the main function for the AVB example. +* +* @param None. +* +* @return - XST_SUCCESS to indicate success. +* - XST_FAILURE to indicate failure +* +* @note This example will be in a infinte loop if the HW is not working +* properly and if the interrupts are not received. +* +****************************************************************************/ +int main() +{ + + int Status; + XAxiEthernet_Config *AxiEtherCfgPtr; + XAvb_PortIdentity SystemIdentity; + u32 WriteData; + +#if XPAR_MICROBLAZE_USE_ICACHE + Xil_ICacheInvalidate(); + Xil_ICacheEnable(); +#endif + +#if XPAR_MICROBLAZE_USE_DCACHE + Xil_DCacheInvalidate(); + Xil_DCacheEnable(); +#endif + + AvbUtilPrintMessage("\r\n--- Entering main() ---"); + + /* + * Initialize Axi Ethernet Driver. + */ + AxiEtherCfgPtr = XAxiEthernet_LookupConfig(AXIETHERNET_DEVICE_ID); + Status = XAxiEthernet_CfgInitialize(&AxiEthernetInstance, + AxiEtherCfgPtr, + AxiEtherCfgPtr->BaseAddress); + if (Status != XST_SUCCESS) { + AvbUtilPrintMessage("Failed initializing config for Axi Ethernet\r\n"); + AvbUtilPrintMessage("--- Exiting main() ---\r\n"); + return XST_FAILURE; + } + + /* + * Initialize the AVB Config structure. + */ + AvbConfigStruct.DeviceId = AxiEtherCfgPtr->DeviceId; + AvbConfigStruct.BaseAddress = AxiEtherCfgPtr->BaseAddress; + Status = XAvb_CfgInitialize(&Avb, &AvbConfigStruct, AvbConfigStruct.BaseAddress); + if (Status != XST_SUCCESS) { + AvbUtilPrintMessage("Failed initializing config for AVB\r\n"); + AvbUtilPrintMessage("--- Exiting main() ---\r\n"); + return XST_FAILURE; + } + + /* + * Setup the handler for the AVB that will be called if the PTP drivers + * identify a possible discontinuity in GrandMaster time. + */ + XAvb_SetGMDiscontinuityHandler(&Avb, AvbGMDiscontinuityHandler, &Avb); + + /* + * Reset and initialize the AVB driver. + */ + XAvb_Reset(&Avb); + + /* + * Perform configuration on the Axi Ethernet and Ethernet AVB Endpoint + * cores + */ + Status = AvbConfigHW(&AxiEthernetInstance, &Avb); + if (Status != XST_SUCCESS) { + AvbUtilPrintMessage("Failed initializing Axi Ethernet and AVB\r\n"); + AvbUtilPrintMessage("--- Exiting main() ---\r\n"); + return XST_FAILURE; + } + + + /* + * Initialize Interrupt Controller + */ + Status = AvbSetupInterruptSystem(&Avb); + if (Status != XST_SUCCESS) { + AvbUtilPrintMessage("Failed initializing INTC system\r\n"); + AvbUtilPrintMessage("--- Exiting main() ---\r\n"); + return XST_FAILURE; + } + + /* + * Setup the Source Address and Source Port Identity fields in all + * TX PTP Buffers + */ + SystemIdentity.ClockIdentityUpper = (ETH_SYSTEM_ADDRESS_EUI48_HIGH + << 8) | 0xFF; + SystemIdentity.ClockIdentityLower = (0xFE << 24) | + (ETH_SYSTEM_ADDRESS_EUI48_LOW); + SystemIdentity.PortNumber = 1; + + /* + * Write the SA to all default TX PTP buffers + */ + WriteData = (XAvb_ReorderWord(SystemIdentity.ClockIdentityUpper)) << 16; + XAvb_WriteToMultipleTxPtpFrames(Avb.Config.BaseAddress, + XAVB_PTP_TX_PKT_SA_UPPER_OFFSET, + (WriteData & 0xFFFF0000) , + 0xFFFF0000, + 0x7F); + + WriteData = (SystemIdentity.ClockIdentityUpper << 16); + WriteData = (WriteData & 0xFF000000); + WriteData = (WriteData | (SystemIdentity.ClockIdentityLower & 0x00FFFFFF)); + WriteData = XAvb_ReorderWord(WriteData); + XAvb_WriteToMultipleTxPtpFrames(Avb.Config.BaseAddress, + XAVB_PTP_TX_PKT_SA_LOWER_OFFSET, + WriteData, + 0xFFFFFFFF, + 0x7F); + + /* + * Write sourceportidentity to all default TX PTP buffers + */ + XAvb_SetupSourcePortIdentity(&Avb,SystemIdentity); + + + /* + * Start AVB and enable the PTP interrupts. + */ + XAvb_Start(&Avb); + AvbEnablePTPInterrupts(); + + + while(1) { + if(EchoPTPFramesReceived) { + AvbUtilPrintMessage("\r\nExample passed\r\n"); + AvbUtilPrintMessage("--- Exiting main() ---\r\n"); + break; + } + } + return XST_SUCCESS; +} + + +/*****************************************************************************/ +/** +* +* This function configures Axi Ethernet core and AVB module. +* +* @param AxiEthernetInstancePtr is a pointer to the Axi Ethernet driver +* instance +* @param AvbInstancePtr is a pointer to the AVB instance. +* +* @return -XST_SUCCESS to indicate success +* -XST_FAILURE to indicate failure. +* +* @note None. +* +******************************************************************************/ +static int AvbConfigHW(XAxiEthernet *AxiEthernetInstancePtr, XAvb *AvbInstancePtr) +{ + u32 ReadData; + int Status; + + /* + * Configure MDIO Master in Axi Ethernet - MUST be done before + * any MDIO accesses + */ + XAxiEthernet_WriteReg(AxiEthernetInstancePtr->Config.BaseAddress, + XAE_MDIO_MC_OFFSET,0x0000005D); + + /* + * Disable Axi Ethernet Flow Control + */ + XAxiEthernet_WriteReg(AxiEthernetInstancePtr->Config.BaseAddress, + XAE_FCC_OFFSET,0x0); + + /* + * Initialise Axi Ethernet by enabling Tx and Rx with VLAN capability + */ + XAxiEthernet_WriteReg(AxiEthernetInstancePtr->Config.BaseAddress, + XAE_TC_OFFSET,XAE_TC_TX_MASK | XAE_TC_VLAN_MASK); + XAxiEthernet_WriteReg(AxiEthernetInstancePtr->Config.BaseAddress, + XAE_RCW1_OFFSET, XAE_RCW1_RX_MASK | XAE_RCW1_VLAN_MASK); + + /* + * Initialise RTC reference clock for nominal frequency 125MHz - + * (see xavb_hw.h for value) + */ + XAvb_WriteReg(AvbInstancePtr->Config.BaseAddress, + XAVB_RTC_INCREMENT_OFFSET, + XAVB_RTC_INCREMENT_NOMINAL_RATE); + + Status = AvbConfigureGmii(AxiEthernetInstancePtr,AvbInstancePtr); + return Status; +} + +/*****************************************************************************/ +/** +* +* This function configures the GMII interface and Axi Ethernet registers for +* 1000 Mbps speed configuration. +* +* @param InstancePtr is a pointer to the Axi Ethernet driver instance +* @param AvbInstancePtr is a pointer to the AVB instance. +* +* @return - XST_SUCCESS if successful. +* - XST_FAILURE, in case of failure... +* +* @note None. +* +******************************************************************************/ +static int AvbConfigureGmii(XAxiEthernet *InstancePtr, XAvb *AvbInstancePtr) +{ + u32 EmmcReg; + int Status; + + /* + * Set PHY to loopback. + */ + Status = AvbEnterPhyLoopBack(InstancePtr); + if(Status != XST_SUCCESS) { + XAvb_Stop(AvbInstancePtr); + return XST_FAILURE; + } + + /* + * Get the current contents of the EMAC config register and + * zero out speed bits + */ + EmmcReg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_EMMC_OFFSET); + EmmcReg = EmmcReg & (~XAE_EMMC_LINKSPEED_MASK); + EmmcReg |= XAE_EMMC_LINKSPD_1000; + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_EMMC_OFFSET,EmmcReg); + + /* + * Setting the operating speed of the MAC needs a delay. There + * doesn't seem to be register to poll, so please consider this + * during your application design. + */ + AvbUtilPhyDelay(1); + return XST_SUCCESS; + +} + +/******************************************************************************/ +/** +* +* This function sets the PHY to loopback mode. This works with the marvell PHY +* common on Xilinx evaluation boards. This sets the PHY speed to 1000 Mbps. +* +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* +* @return - XST_SUCCESS if successful. +* - XST_FAILURE, in case of failure.. +* +* @note None. +* +******************************************************************************/ +static int AvbEnterPhyLoopBack(XAxiEthernet *InstancePtr) +{ + u16 PhyReg0; + signed int PhyAddr; + u16 PhyReg; + + for (PhyAddr = 31; PhyAddr >= 0; PhyAddr--) { + XAxiEthernet_PhyRead(&AxiEthernetInstance, PhyAddr, + PHY_DETECT_REG, &PhyReg); + if ((PhyReg != 0xFFFF) && ((PhyReg & PHY_DETECT_MASK) + == PHY_DETECT_MASK)) { + /* Found a valid PHY address */ + break; + } + } + + if(PhyAddr == 0) + return XST_FAILURE; + /* + * Clear the PHY of any existing bits by zeroing this out + */ + PhyReg0 = 0; + PhyReg0 |= PHY_R0_DFT_SPD_1000; + + /* + * Set the speed and put the PHY in reset, then put the PHY in loopback + */ + XAxiEthernet_PhyWrite(&AxiEthernetInstance, PhyAddr, 0, + PhyReg0 | PHY_R0_RESET); + AvbUtilPhyDelay(1); + XAxiEthernet_PhyRead(&AxiEthernetInstance, PhyAddr, 0,&PhyReg0); + XAxiEthernet_PhyWrite(&AxiEthernetInstance, PhyAddr, 0, + PhyReg0 | PHY_R0_LOOPBACK); + AvbUtilPhyDelay(1); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function sets up the interrupt system so interrupts can occur for the +* AVB design. +* +* @param InstancePtr contains a pointer to the instance of the AVB +* component which is going to be connected to the interrupt +* controller. +* +* @return - XST_SUCCESS if successful. +* - XST_FAILURE, in case of failure.. +* +* @note None. +* +****************************************************************************/ +static int AvbSetupInterruptSystem(XAvb *InstancePtr) +{ + int Status; + + /* + * Initialize the interrupt controller driver so that it can be used. + * XPAR_INTC_0_DEVICE_ID specifies the XINTC device ID that is + * generated in xparameters.h + */ + Status = XIntc_Initialize(&InterruptController, XPAR_INTC_0_DEVICE_ID); + + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + /* + * Connect the Ethernet AVB Endpoint's 10 ms interrupt + */ + Status = XIntc_Connect(&InterruptController, + AVB_PTP_INTERRUPT_ID, + (XInterruptHandler)XAvb_PtpTimerInterruptHandler, + InstancePtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Connect the Ethernet AVB Endpoint's PTP Rx interrupt + */ + Status = XIntc_Connect(&InterruptController, + AVB_PTP_RX_INTERRUPT_ID, + (XInterruptHandler)XAvb_PtpRxInterruptHandler, + InstancePtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Start the interrupt controller so interrupts are enabled for all + * devices that cause interrupts. + */ + Status = XIntc_Start(&InterruptController, XIN_REAL_MODE); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable interrupt on Microblaze + */ + Xil_ExceptionInit(); + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler)XIntc_InterruptHandler, + (void *)&InterruptController); + Xil_ExceptionEnable(); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function enables the PTP Timer interrupt and PTP Rx interrupt in the +* INTC module. +* +* @param None +* +* @return None +* +* @note None. +* +******************************************************************************/ +static void AvbEnablePTPInterrupts(void) +{ + XIntc_Enable(&InterruptController, AVB_PTP_RX_INTERRUPT_ID); + XIntc_Enable(&InterruptController, AVB_PTP_INTERRUPT_ID); + return; +} + +/****************************************************************************/ +/** +* +* This function is the handler which will be called if the PTP drivers +* identify a possible discontinuity in GrandMaster time. +* +* This handler provides an example of how to handle this situation - +* but this function is application specific. +* +* +* @param CallBackRef contains a callback reference from the driver, in +* this case it is the instance pointer for the AVB driver. +* @param TimestampsUncertain - a value of 1 indicates that there is a +* possible discontinuity in GrandMaster time. A value of 0 +* indicates that Timestamps are no longer uncertain. +* +* @return None. +* +* @note This Handler ned to be defined otherwise the XAvb_StubHandler +* will generate an error +* +****************************************************************************/ +void AvbGMDiscontinuityHandler(void *CallBackRef, u32 TimestampsUncertain) +{ + + xil_printf("\r\nGMDiscontinuityHandler: Timestamps are now %s\r\n", + TimestampsUncertain ? "uncertain" : "certain"); + +} + + +/******************************************************************************/ +/** +* +* For Microblaze we use an assembly loop that is roughly the same regardless of +* optimization level, although caches and memory access time can make the delay +* vary. Just keep in mind that after resetting or updating the PHY modes, +* the PHY typically needs time to recover. +* +* @return None +* +* @note None +* +******************************************************************************/ +static void AvbUtilPhyDelay(unsigned int Seconds) +{ + static int WarningFlag = 0; + + /* If MB caches are disabled or do not exist, this delay loop could + * take minutes instead of seconds (e.g., 30x longer). Print a warning + * message for the user (once). If only MB had a built-in timer! + */ + if (((mfmsr() & 0x20) == 0) && (!WarningFlag)) { + WarningFlag = 1; + } + +#define ITERS_PER_SEC (XPAR_CPU_CORE_CLOCK_FREQ_HZ / 6) + asm volatile ("\n" + "1: \n\t" + "addik r7, r0, %0 \n\t" + "2: \n\t" + "addik r7, r7, -1 \n\t" + "bneid r7, 2b \n\t" + "or r0, r0, r0 \n\t" + "bneid %1, 1b \n\t" + "addik %1, %1, -1 \n\t" + :: "i"(ITERS_PER_SEC), "d" (Seconds)); + +} + +/******************************************************************************/ +/** +* +* This function is called by example code to display a console message +* +* @param Message is the text explaining the error +* +* @return None +* +* @note None +* +******************************************************************************/ +static void AvbUtilPrintMessage(char *Message) +{ +#ifdef STDOUT_BASEADDRESS + xil_printf("%s\r\n", Message); +#endif +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_hw.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_hw.c new file mode 100644 index 00000000..387a7e1b --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_hw.c @@ -0,0 +1,164 @@ +/****************************************************************************** +* +* Copyright (C) 2008 - 2014 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ + +/*****************************************************************************/ +/** +* +* @file xavb_hw.c +* +* The xavb_hw driver. Functions in this file are the minimum required functions +* for this driver. See xavb_hw.h for a detailed description of the driver. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a mbr 09/19/08 First release +* 1.01a mbr 06/24/09 PTP frame format updates for IEEE802.1 AS draft 5-0 +* 2_02a mbr 09/16/09 Updates for programmable PTP timers +* 2_04a kag 07/23/10 PTP frame format updates for IEEE802.1 AS draft 6-7 +* 3_01a kag 08/29/11 Added new APIs to update the RX Filter Control Reg. +* Fix for CR:572539. Updated bit map for Rx Filter +* control reg. +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_io.h" +#include "xavb_hw.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Variable Definitions *****************************/ + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ + +/****************************************************************************/ +/** +* +* This function reads the given Ethernet Statistic Register +* +* @param BaseAddress is the base address of the device +* @param CounterID is the Statistic Counter to be read +* @param Value a pointer to the read value of the 64-bit value of the counter +* and it is updated by this function +* +* @return None. +* +* @note The CounterID's defined here are the same as the Statistic Counter +* Addresses as used with the TEMAC core. Since each counter is 8-bytes +* wide, we must multiply these Counter ID's by 8 (or a left shift of 3) +* when mapping this into the PLB memory map. The 64-bit counter value +* is read as two separate 32-bit accesses. +* +*****************************************************************************/ +void XAvbMac_ReadStats(u32 BaseAddress, + u32 CounterId, + XAvb_Uint64* Value) +{ + Value->Upper = Xil_In32(BaseAddress + ((CounterId & 0x00ff) << 3) + 0x4); + Value->Lower = Xil_In32(BaseAddress + ((CounterId & 0x00ff) << 3)); +} + + +/****************************************************************************/ +/** +* +* This function reads the current Real Time Counter (RTC) value +* +* @param BaseAddress is the base address of the device +* @param RtcValue is a pointer to a struct in which to store the value read +* from the RTC (The RTC 48-bit seconds field and the 32-bit ns field +* of this struct are updated). +* +* @return None +* +* @note This is provided as a basic function since the ns field MUST be read +* before the seconds/epoch registers (reading the ns samples the entire +* RTC in hardware). +* +*****************************************************************************/ +void XAvb_ReadRtc(u32 BaseAddress, + XAvb_RtcFormat* RtcValue) +{ + RtcValue->NanoSeconds = + Xil_In32(BaseAddress + XAVB_RTC_NANOSEC_VALUE_OFFSET) + & XAVB_RTC_NS_MASK; + + RtcValue->SecondsLower = + Xil_In32(BaseAddress + XAVB_RTC_SEC_LOWER_VALUE_OFFSET) + & XAVB_RTC_SEC_LOWER_MASK; + + RtcValue->SecondsUpper = + Xil_In32(BaseAddress + XAVB_RTC_SEC_UPPER_VALUE_OFFSET) + & XAVB_RTC_SEC_UPPER_MASK; +} + + +/****************************************************************************/ +/** +* +* This function writes to the Real Time Counter (RTC) Offset Registers +* +* @param BaseAddress is the base address of the device +* @param RtcValue is the nanoseconds and seconds offset values that should +* be written to the RTC. +* +* @return None +* +* @note This is provided as a basic function since the ns field MUST be +* written after the seconds/epoch offset registers (writing to the ns +* offset registers samples the entire RTC offset in hardware). +* +*****************************************************************************/ +void XAvb_WriteRtcOffset(u32 BaseAddress, XAvb_RtcFormat* RtcValue) +{ + Xil_Out32((BaseAddress + XAVB_RTC_SEC_UPPER_OFFSET), + (RtcValue->SecondsUpper & XAVB_RTC_SEC_UPPER_MASK)); + + Xil_Out32((BaseAddress + XAVB_RTC_SEC_LOWER_OFFSET), + (RtcValue->SecondsLower & XAVB_RTC_SEC_LOWER_MASK)); + + Xil_Out32((BaseAddress + XAVB_RTC_NANOSEC_OFFSET), + (RtcValue->NanoSeconds & XAVB_RTC_NS_MASK)); +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_hw.h b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_hw.h new file mode 100644 index 00000000..1494a75b --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_hw.h @@ -0,0 +1,504 @@ +/****************************************************************************** +* +* Copyright (C) 2008 - 2014 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xavb_hw.h +* +* This header file contains the identifiers and basic driver functions (or +* macros) that can be used to access the device. Other driver functions +* are defined in xavb.h. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a mbr 09/19/08 First release +* 1.01a mbr 06/24/09 PTP frame format updates for IEEE802.1 AS draft 5-0 +* 2_02a mbr 09/16/09 Updates for programmable PTP timers +* 2_04a kag 07/23/10 PTP frame format updates for IEEE802.1 AS draft 6-7 +* 3_01a kag 08/29/11 Added new APIs to update the RX Filter Control Reg. +* Fix for CR:572539. Updated bit map for Rx Filter +* control reg. +* 3_01a asa 04/10/12 The AVB core is now brought inside the AxiEthernet +* core. Because of this there are changes in the +* register map. +* +*+* +******************************************************************************/ + +#ifndef XAVB_HW_H /* prevent circular inclusions */ +#define XAVB_HW_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_io.h" + +/************************** Constant Definitions *****************************/ + +/** @name Register offsets for the Tri-Mode Ethernet MAC. Each register is 32 + * bits. The MAC is addressable through the Ethernet AVB Endpoint core. + * @{ + */ +#define XAVB_MAC_RX_REG0_OFFSET 0x00000400 /**< MAC Rx Config Register 0 */ +#define XAVB_MAC_RX_REG1_OFFSET 0x00000404 /**< MAC Rx Config Register 1 */ +#define XAVB_MAC_TX_REG_OFFSET 0x00000408 /**< MAC Tx Config Register */ +#define XAVB_MAC_FC_REG_OFFSET 0x0000040c /**< MAC Flow Control Register */ +#define XAVB_MAC_SPD_REG_OFFSET 0x00000410 /**< MAC Speed Control Register */ +//#define XAVB_MAC_MGMT_REG_OFFSET 0x0000050C /**< MAC MDIO Management Register*/ +/* @} */ + +/** @name Register offsets for the Ethernet Audio Video Endpoint. Each register + * is 32 bits. + * @{ + */ +#define XAVB_PTP_TX_CONTROL_OFFSET 0x00012000 /**< Tx PTP Control Reg */ +#define XAVB_PTP_RX_CONTROL_OFFSET 0x00012004 /**< Rx PTP Control Reg */ +#define XAVB_RX_FILTER_CONTROL 0x00012008 /**< Rx Filter Control Reg */ +#define XAVB_TX_SENDSLOPE 0x0001200C /**< Tx rate sendSlope Reg */ +#define XAVB_TX_IDLESLOPE 0x00012010 /**< Tx rate idleSlope Reg */ +#define XAVB_TX_HILIMIT 0x00012014 /**< Tx rate hiLimit Reg */ +#define XAVB_TX_LOLIMIT 0x00012018 /**< Tx rate loLimit Reg */ +#define XAVB_RTC_NANOSEC_OFFSET 0x00012800 /**< RTC ns offset Reg */ +#define XAVB_RTC_SEC_LOWER_OFFSET 0x00012808 /**< RTC sec[31:0] offset */ +#define XAVB_RTC_SEC_UPPER_OFFSET 0x0001280C /**< RTC sec[47:32] offset */ +#define XAVB_RTC_INCREMENT_OFFSET 0x00012810 /**< RTC Increment Reg */ +#define XAVB_RTC_NANOSEC_VALUE_OFFSET 0x00012814 /**< RTC ns value Reg */ +#define XAVB_RTC_SEC_LOWER_VALUE_OFFSET 0x00012818 /**< RTC sec[31:0] value */ +#define XAVB_RTC_SEC_UPPER_VALUE_OFFSET 0x0001281C /**< RTC sec[47:32] value */ +#define XAVB_RTC_CLEAR_INT_OFFSET 0x00012820 /**< RTC Interrupt Clear */ +#define XAVB_RTC_8K_OFFSET_OFFSET 0x00012824 /**< RTC 8k phase offset */ +#define XAVB_SW_RESET_OFFSET 0x00012828 /**< S/W Reset Reg */ +/* @} */ + +/** @name Packet base address offsets for the Ethernet Audio Video Endpoint Tx + * Precise Timing Protocol (PTP) frame buffer. Each PTP frames is + * stored in 256-byte chunks of BRAM. This BRAM can store 8 PTP frames + * of which only 6 are currently in use. + * @{ + */ +#define XAVB_PTP_TX_SYNC_OFFSET 0x00011000 +#define XAVB_PTP_TX_FOLLOW_UP_OFFSET 0x00011100 +#define XAVB_PTP_TX_PDELAYREQ_OFFSET 0x00011200 +#define XAVB_PTP_TX_PDELAYRESP_OFFSET 0x00011300 +#define XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP_OFFSET 0x00011400 +#define XAVB_PTP_TX_ANNOUNCE_OFFSET 0x00011500 +/* @} */ + +/** @name Base address offset for the Ethernet Audio Video Endpoint Rx + * Precise Timing Protocol (PTP) frame buffer. These PTP frames are + * stored in 256-byte chunks of BRAM. This BRAM can store 16 PTP frames. + * @{ + */ +#define XAVB_PTP_RX_BASE_OFFSET 0x00010000 +/* @} */ + +/** @name AVB Tx PTP Control Register + * @{ + */ +#define XAVB_PTP_TX_SEND_SYNC_FRAME_MASK 0x00000001 +#define XAVB_PTP_TX_SEND_FOLLOWUP_FRAME_MASK 0x00000002 +#define XAVB_PTP_TX_SEND_PDELAYREQ_FRAME_MASK 0x00000004 +#define XAVB_PTP_TX_SEND_PDELAYRESP_FRAME_MASK 0x00000008 +#define XAVB_PTP_TX_SEND_PDELAYRESPFOLLOWUP_FRAME_MASK 0x00000010 +#define XAVB_PTP_TX_SEND_ANNOUNCE_FRAME_MASK 0x00000020 +#define XAVB_PTP_TX_SEND_FRAME6_BIT_MASK 0x00000040 +#define XAVB_PTP_TX_SEND_FRAME7_BIT_MASK 0x00000080 +#define XAVB_PTP_TX_WAIT_SYNC_FRAME_MASK 0x00000100 +#define XAVB_PTP_TX_WAIT_FOLLOWUP_FRAME_MASK 0x00000200 +#define XAVB_PTP_TX_WAIT_PDELAYREQ_FRAME_MASK 0x00000400 +#define XAVB_PTP_TX_WAIT_PDELAYRESP_FRAME_MASK 0x00000800 +#define XAVB_PTP_TX_WAIT_PDELAYRESPFOLLOWUP_FRAME_MASK 0x00001000 +#define XAVB_PTP_TX_WAIT_ANNOUNCE_FRAME_MASK 0x00002000 +#define XAVB_PTP_TX_WAIT_FRAME6_BIT_MASK 0x00004000 +#define XAVB_PTP_TX_WAIT_FRAME7_BIT_MASK 0x00008000 +#define XAVB_PTP_TX_WAIT_ALL_FRAMES_MASK 0x0000FF00 +#define XAVB_PTP_TX_PACKET_FIELD_MASK 0x00070000 + +/* @} */ + +/** @name AVB Rx PTP Control Register + * @{ + */ +#define XAVB_PTP_RX_CLEAR_BIT_MASK 0x00000001 +#define XAVB_PTP_RX_PACKET_FIELD_MASK 0x00000F00 +/* @} */ + +/** @name AVB Rx Filter Control Register + * @{ + */ +#define XAVB_RX_AV_VLAN_PRIORITY_A_MASK 0x00000007 +#define XAVB_RX_AV_VLAN_VID_A_MASK 0x00007FF8 +#define XAVB_RX_AV_VLAN_MATCH_MODE_MASK 0x00008000 +#define XAVB_RX_AV_VLAN_PRIORITY_B_MASK 0x00070000 +#define XAVB_RX_AV_VLAN_VID_B_MASK 0x7FF80000 +#define XAVB_RX_LEGACY_PROMISCUOUS_MODE_MASK 0x80000000 +/* @} */ + +/** @name AVB Tx rate control sendSlope + * @{ + */ +#define XAVB_TX_SENDSLOPE_MASK 0X000FFFFF +/* @} */ + +/** @name AVB Tx rate control idleSlope + * @{ + */ +#define XAVB_TX_IDLESLOPE_MASK 0X000FFFFF +/* @} */ + +/** @name AVB Tx rate control hiLimit + * @{ + */ +#define XAVB_TX_HILIMIT_MASK 0X01FFFFFF +/* @} */ + +/** @name AVB Tx rate control loLimit + * @{ + */ +#define XAVB_TX_LOLIMIT_MASK 0X01FFFFFF +/* @} */ + +/** @name RTC field Registers + * @{ + */ +#define XAVB_RTC_NS_MASK 0x3FFFFFFF +#define XAVB_RTC_SEC_LOWER_MASK 0xFFFFFFFF +#define XAVB_RTC_SEC_UPPER_MASK 0x0000FFFF +/* @} */ + +/** @name RTC Increment Register + * @{ + */ +#define XAVB_RTC_INCREMENT_VALUE_MASK 0x03FFFFFF +/** This value assumes a 125MHz rtc_clock */ +#define XAVB_RTC_INCREMENT_NOMINAL_RATE 0x00800000 +/** Add some rails so that recovery is possible after a + * string of bad pDelay values. The RTC should be able to lock + * to within 100ppm of the slowest allowable clock (25 MHz). + * This equates to +/-4ps. Let's arbitrarily set the rails to + * 400ppm (+/-16ps) just in case someone decides to use a + * particularly bad oscillator. The lowest 20 bits of + * NewIncrement are fractions of a nanosecond, which equates + * to +/- 0x04189 */ +#define XAVB_RTC_400PPM_OFFSET 0x00004189 +/* @} */ + +/** @name RTC Interrupt Clear Register + * @{ + */ +#define XAVB_RTC_INCREMENT_VALUE_MASK 0x03FFFFFF +/* @} */ + + +/** @name RTC Interrupt Clear Register + * @{ + */ +#define XAVB_RTC_CLEAR_INT_MASK 0x00000000 +/* @} */ + + +/** @name RTC 8k phase offset Register + * @{ + */ +#define XAVB_RTC_8K_PHASE_OFFSET_MASK 0x3FFFFFFF +/* @} */ + +/** @name S/W Reset Register + * @{ + */ +#define XAVB_SW_RESET_TX_AND_RX_PATHS 0x00000003 +/* @} */ + + +/** @name AVB MAC MDIO register address space. + * @{ + */ +#define XAVB_MAC_MDIO_BASE_OFFSET 0x00006000 +/* @} */ + + +/** @name MDIO valid data mask (MDIO registers are all 16-bits). + * @{ + */ +#define XAVB_MAC_MDIO_DATA_MASK 0x0000FFFF +/* @} */ + + +/** @name MAC Statistic Counter names and CounterID. + * @{ + */ +#define XAVB_STATS_BYTES_TRANSMITTED 0x00000000 +#define XAVB_STATS_BYTES_RECEIVED 0x00000001 +#define XAVB_STATS_UNDERSIZED_FRAMES_RECEIVED 0x00000002 +#define XAVB_STATS_FRAGMENT_FRAMES_RECEIVED 0x00000003 +#define XAVB_STATS_64_BYTE_FRAMES_RECEIVED_OK 0x00000004 +#define XAVB_STATS_65_TO_127_BYTE_FRAMES_RECEIVED_OK 0x00000005 +#define XAVB_STATS_128_TO_255_BYTE_FRAMES_RECEIVED_OK 0x00000006 +#define XAVB_STATS_256_TO_511_BYTE_FRAMES_RECEIVED_OK 0x00000007 +#define XAVB_STATS_512_TO_1023_BYTE_FRAMES_RECEIVED_OK 0x00000008 +#define XAVB_STATS_1024_TO_1518_BYTE_FRAMES_RECEIVED_OK 0x00000009 +#define XAVB_STATS_OVERSIZED_FRAMES_RECEIVED_OK 0x0000000A +#define XAVB_STATS_64_BYTE_FRAMES_TRANSMITTED_OK 0x0000000B +#define XAVB_STATS_65_TO_127_BYTE_FRAMES_TRANSMITTED_OK 0x0000000C +#define XAVB_STATS_128_TO_255_BYTE_FRAMES_TRANSMITTED_OK 0x0000000D +#define XAVB_STATS_256_TO_511_BYTE_FRAMES_TRANSMITTED_OK 0x0000000E +#define XAVB_STATS_512_TO_1023_BYTE_FRAMES_TRANSMITTED_OK 0x0000000F +#define XAVB_STATS_1024_TO_1518_BYTE_FRAMES_TRANSMITTED_OK 0x00000010 +#define XAVB_STATS_OVERSIZE_FRAMES_TRANSMITTED_OK 0x00000011 +#define XAVB_STATS_FRAMES_RECEIVED_OK 0x00000012 +#define XAVB_STATS_FCS_ERRORS 0x00000013 +#define XAVB_STATS_BROADCAST_FRAMES_RECEIVED_OK 0x00000014 +#define XAVB_STATS_MULTICAST_FRAMES_RECEIVED_OK 0x00000015 +#define XAVB_STATS_CONTROL_FRAMES_RECEIVED_OK 0x00000016 +#define XAVB_STATS_LENGTH_TYPE_OUT_OF_RANGE 0x00000017 +#define XAVB_STATS_VLAN_TAGGED_FRAMES_RECEIVED_OK 0x00000018 +#define XAVB_STATS_PAUSE_FRAMES_RECEIVED_OK 0x00000019 +#define XAVB_STATS_CONTROL_FRAMES_WITH_UNSUPPORTED_OPCODE 0x0000001A +#define XAVB_STATS_FRAMES_TRANSMITTED 0x0000001B +#define XAVB_STATS_BROADCAST_FRAMES_TRANSMITTED 0x0000001C +#define XAVB_STATS_MULTICAST_FRAMES_TRANSMITTED 0x0000001D +#define XAVB_STATS_UNDERRUN_ERRORS 0x0000001E +#define XAVB_STATS_CONTROL_FRAMES_TRANSMITTED_OK 0x0000001F +#define XAVB_STATS_VLAN_TAGGED_FRAMES_TRANSMITTED_OK 0x00000020 +#define XAVB_STATS_PAUSE_FRAMES_TRANSMITTED_OK 0x00000021 +#define XAVB_STATS_SINGLE_COLLISION_FRAMES 0x00000022 +#define XAVB_STATS_MULTI_COLLISION_FRAMES 0x00000023 +#define XAVB_STATS_DEFERRAL_FRAMES 0x00000024 +#define XAVB_STATS_LATE_COLLISION_FRAMES 0x00000025 +#define XAVB_STATS_EXCESS_COLLISION_FRAMES 0x00000026 +#define XAVB_STATS_EXCESS_DEFERRAL_FRAMES 0x00000027 +#define XAVB_STATS_CARRIER_SENSE_ERRORS 0x00000028 +#define XAVB_STATS_ALIGNMENT_ERRORS 0x00000029 +/* @} */ + + +/**************************** Type Definitions *******************************/ + +/** + * This typedef defines the format for the Real Time Clock (RTC). The RTC + * contains a 48-bit seconds field (split into upper and lower sections) and + * a 32-bit nano-seconds field. + */ +typedef struct +{ + u16 SecondsUpper; /**< Upper 16-bits of seconds field */ + u32 SecondsLower; /**< Lower 32-bits of seconds field */ + u32 NanoSeconds; /**< 32-bit nanoseconds field */ +} XAvb_RtcFormat; + +/** + * This typedef descibes a 64-bit un-signed integer in terms of 2 u32s + */ +typedef struct +{ + u32 Upper; /**< Upper 32 bits */ + u32 Lower; /**< Lower 32 bits */ +} XAvb_Uint64; + +/***************** Macros (Inline Functions) Definitions *********************/ + +/****************************************************************************/ +/** +* +* This macro reads from the given AVB core 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 None. +* +*****************************************************************************/ +#define XAvb_ReadReg(BaseAddress, RegOffset) \ + Xil_In32((BaseAddress) + (RegOffset)) + + +/****************************************************************************/ +/** +* +* This macro writes to the given AVB core 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 None. +* +*****************************************************************************/ +#define XAvb_WriteReg(BaseAddress, RegOffset, Data) \ + Xil_Out32((BaseAddress) + (RegOffset), (Data)) + + +/****************************************************************************/ +/** +* +* This macro reads from the given PTP frame buffer. +* +* @param BaseAddress is the base address of the device +* @param PtpPacketBaseAddress is the base address of the frame in the PTP +* BRAM packet buffer + @param PtpPacketOffset is the offset address within the PTP frame +* +* @return The 32-bit value of the register +* +* @note None. +* +*****************************************************************************/ +#define XAvb_ReadPtpBuffer(BaseAddress, PtpPacketBaseAddress, PtpPacketOffset)\ + Xil_In32(BaseAddress + PtpPacketBaseAddress + PtpPacketOffset) + + +/****************************************************************************/ +/** +* +* This macro writes to the given PTP frame buffer. +* +* @param BaseAddress is the base address of the device +* @param PtpPacketBaseAddress is the base address of the frame in the PTP +* packet buffer + @param PtpPacketOffset is the offset address within the PTP frame +* @param Data is the 32-bit value to write to the register +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +#define XAvb_WritePtpBuffer(BaseAddress, PtpPacketBaseAddress, \ + PtpPacketOffset, Data) \ + Xil_Out32(BaseAddress + PtpPacketBaseAddress + PtpPacketOffset, (Data)) + + +/****************************************************************************/ +/** +* +* This macro reads from the given TEMAC Configuration 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 None. +* +*****************************************************************************/ +#define XAvbMac_ReadConfig(BaseAddress, RegOffset) \ + Xil_In32((BaseAddress) + (RegOffset)) + + +/****************************************************************************/ +/** +* +* This macro writes to the given TEMAC Configuration 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 None. +* +*****************************************************************************/ +#define XAvbMac_WriteConfig(BaseAddress, RegOffset, Data) \ + Xil_Out32((BaseAddress) + (RegOffset), (Data)) + + +/****************************************************************************/ +/** +* +* This macro reads from the given MDIO Register using the TEMAC +* +* @param BaseAddress is the base address of the device +* @param Phyad is the Physical Address of the PHY +* @param Regad is the Address of the MDIO register within the addressed PHY +* +* @return The 32-bit value of the register (upper 16-bits will be all 0's) +* +* @note None. +* +*****************************************************************************/ +#define XAvbMac_ReadMdio(BaseAddress, Phyad, Regad) \ + Xil_In32((BaseAddress) + XAVB_MAC_MDIO_BASE_OFFSET \ + + (((Phyad) & 0x1F) << 8) \ + + (((Regad) & 0x1F) << 3)) + + +/****************************************************************************/ +/** +* +* This macro writes to the given MDIO Register using the TEMAC +* +* @param BaseAddress is the base address of the device +* @param Phyad is the Physical Address of the PHY +* @param Regad is the Address of the MDIO register within the addressed PHY +* @param Data is the 32-bit value to write +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +#define XAvbMac_WriteMdio(BaseAddress, Phyad, Regad, Data) \ + Xil_Out32(BaseAddress + XAVB_MAC_MDIO_BASE_OFFSET \ + + (((Phyad) & 0x1F) << 8) \ + + (((Regad) & 0x1F) << 3), \ + (Data & XAVB_MAC_MDIO_DATA_MASK)) + + +/************************** Function Prototypes ******************************/ + +/* + * Functions in xavb_hw.c + */ +void XAvbMac_ReadStats(u32 BaseAddress, u32 CounterId, XAvb_Uint64* Value); +void XAvb_ReadRtc(u32 BaseAddress, XAvb_RtcFormat* RtcValue); +void XAvb_WriteRtcOffset(u32 BaseAddress, XAvb_RtcFormat* RtcValue); + + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_ptp_bmca.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_ptp_bmca.c new file mode 100644 index 00000000..3d487dea --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_ptp_bmca.c @@ -0,0 +1,819 @@ +/****************************************************************************** +* +* Copyright (C) 2008 - 2014 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xavb_ptp_bmca.c +* +* The XAvb driver. Functions in this file all relate to the Best Master Clock +* Algorithm (BMCA) which is performed on the AVB network to select a network +* Grand Master Clock. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a mbr 09/19/08 First release +* 1.01a mbr 06/24/09 PTP frame format updates for IEEE802.1 AS draft 5-0 +* 2_02a mbr 09/16/09 Updates for programmable PTP timers +* 2_04a kag 07/23/10 PTP frame format updates for IEEE802.1 AS draft 6-7 +* 3_01a kag 08/29/11 Added new APIs to update the RX Filter Control Reg. +* Fix for CR:572539. Updated bit map for Rx Filter +* control reg. +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_assert.h" +#include "xavb_hw.h" +#include "xavb.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Variable Definitions *****************************/ + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ + +/****************************************************************************/ +/** +* +* A New Announce Packet has been written to this device to transmit. We need to +* decode it and rerun the Best Master Clock Algorithm (BMCA) +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. But an updated True/False decision as to whether this device +* should operate as a clock master or a slave is written into the +* CurrentBmc data structure. +* +* @note None. +* +*****************************************************************************/ +void XAvb_DecodeTxAnnounceFrame(XAvb * InstancePtr) { + + u32 NewMaster = 0; + XAvb_BmcData TxAnnounceFrame; + + + /** Read the attributes for the new Announce frame in the Tx PTP buffer */ + XAvb_ReadAnnounceFrame(InstancePtr->Config.BaseAddress, + (XAVB_PTP_TX_ANNOUNCE_OFFSET + 8), + &TxAnnounceFrame); + + /** Compare the clock attributes between then new Announce frame and the + * current master */ + NewMaster = XAvb_BestMasterClockAlgorithm(&TxAnnounceFrame, + &InstancePtr->CurrentBmc); + + + if ((NewMaster == 1) | (InstancePtr->CurrentBmc.IAmTheRtcMaster == 1)) { + /** Update records with the NEW best master */ + XAvb_UpdateBmcRecords(&TxAnnounceFrame, + &InstancePtr->CurrentBmc); + +#ifdef DEBUG_XAVB_LEVEL1 + xil_printf("\r\nXAvb_DecodeTxAnnounceFrame()"); + xil_printf("\r\n* BMC : I am the MASTER"); + xil_printf("\r\n-----------------------"); + xil_printf("\r\nLocal Announce Frame"); + xil_printf("\r\n-----------------------"); + xil_printf("\r\nGM ID upper %x", + InstancePtr->CurrentBmc.GrandmasterIdentity.ClockIdentityUpper); + + xil_printf("\r\nGM ID lower %x", + InstancePtr->CurrentBmc.GrandmasterIdentity.ClockIdentityLower); + + xil_printf("\r\nPriority1 %x", + InstancePtr->CurrentBmc.GrandmasterPriority1); + + xil_printf("\r\nclockClass %x", + InstancePtr->CurrentBmc.ClockQuality.clockClass); + + xil_printf("\r\nPriority2 %x", + InstancePtr->CurrentBmc.GrandmasterPriority2); +#endif + + /** Our new Tx Announce Packet has won - so this device must be the + * master */ + xil_printf("\r\n*** XAvb_DecodeTxAnnounceFrame() : Call XAvb_BecomeRtcMaster() *** \r\n"); + XAvb_BecomeRtcMaster(InstancePtr,1); + + } + +} + + +/****************************************************************************/ +/** +* +* A New Announce Packet has been received. We need to decode it and rerun the +* Best Master Clock Algorithm (BMCA) +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* +* @return None. But an updated True/False decision as to whether this device +* should operate as a clock master or a slave is written into the +* CurrentBmc data structure. +* +* @note None. +* +*****************************************************************************/ +void XAvb_DecodeRxAnnounceFrame(XAvb * InstancePtr, + u32 PtpFrameBaseAddr) { + + u32 NewMaster = 0; + XAvb_BmcData RxAnnounceFrame; + + /** Read the attributes for the new Announce frame received */ + XAvb_ReadAnnounceFrame(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + &RxAnnounceFrame); + + /** If the received packet's clockIdentity matches our + * clockIdentity, ignore the packet */ + if( XAvb_ComparePortIdentity(InstancePtr->Config.BaseAddress, + InstancePtr->portIdLocal, + RxAnnounceFrame.SourcePortIdentity) ) { + xil_printf("Got an announce from myself.. ignoring\r\n"); + return; + } + + /** If the received packet's stepsRemoved field is >= 255, + * ignore the packet */ + if( RxAnnounceFrame.stepsRemoved >= 255 ) { + xil_printf("Got an announce with stepsRemoved > 255.. ignoring\r\n"); + return; + } + + /** If the Announce packet's GMID matches that of our current GM + * record, then update its records based on the current packet, + * just in case something (such as priority) has changed. */ + if( XAvb_CompareClockIdentity(InstancePtr->Config.BaseAddress, + RxAnnounceFrame.GrandmasterIdentity, + InstancePtr->CurrentBmc.GrandmasterIdentity) ) { + + /** update timeout information */ + InstancePtr->PtpCounters.CounterAnnounceInterval = 0; + + XAvb_UpdateBmcRecords(&RxAnnounceFrame, + &InstancePtr->CurrentBmc); + /** Compare against this device's information to see if we should be GM */ + XAvb_DecodeTxAnnounceFrame(InstancePtr); + + } else if( InstancePtr->CurrentBmc.IAmTheRtcMaster ) { + + /** run BMCA on this announce to see if it is better than me */ + NewMaster = XAvb_BestMasterClockAlgorithm(&RxAnnounceFrame, + &InstancePtr->CurrentBmc); + + if (NewMaster == 1) { + /** Update records with the NEW best master */ + XAvb_UpdateBmcRecords(&RxAnnounceFrame, + &InstancePtr->CurrentBmc); + + /** Capture the Announce Receipt Timeout Interval. + * Reset the announce receipt timeout interval to use the new value. + */ + XAvb_ReadAnnounceReceiptTimeout(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + &RxAnnounceFrame); + + InstancePtr->CurrentBmc.AnnounceIntervalDuration = + XAvb_ConvertLogMeanToDuration(RxAnnounceFrame.logMessageInterval); + + +#ifdef DEBUG_XAVB_LEVEL1 + xil_printf("\r\r\nXAvb_DecodeRxAnnounceFrame()"); + xil_printf("\r\n-----------------------"); + xil_printf("\r\nWinning Announce Frame"); + xil_printf("\r\n-----------------------"); + + xil_printf("\r\nGM ID upper %x", + InstancePtr->CurrentBmc.GrandmasterIdentity.ClockIdentityUpper); + + xil_printf("\r\nGM ID lower %x", + InstancePtr->CurrentBmc.GrandmasterIdentity.ClockIdentityLower); + + xil_printf("\r\nPriority1 %x", + InstancePtr->CurrentBmc.GrandmasterPriority1); + + xil_printf("\r\nclockClass %x", + InstancePtr->CurrentBmc.ClockQuality.clockClass); + + xil_printf("\r\nPriority2 %x", + InstancePtr->CurrentBmc.GrandmasterPriority2); +#endif + + /** New Rx Announce Packet has won - so this device cannot be a master */ + xil_printf("\r\n* XAvb_DecodeRxAnnounceFrame()::BMC : I am a SLAVE"); + XAvb_BecomeRtcSlave(InstancePtr); + } + } +} + + +/****************************************************************************/ +/** +* +* A New Announce Packet is to be analyzed. This function will read in the +* packet, decode it, and extract the relevent information fields to the +* "AnnounceFrame" data pointer. +* +* @param BaseAddress is the base address of the device +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* @param AnnounceFrame is a pointer to a suitable data structure, designed to +* record the useful fields from the received Announce Packet +* +* @return The AnnounceFrame data structure is updated. +* +* @note None. +* +*****************************************************************************/ +void XAvb_ReadAnnounceFrame(u32 BaseAddress, + u32 PtpFrameBaseAddr, + XAvb_BmcData * AnnounceFrame) { + + u32 ReadWord; + + AnnounceFrame->SourcePortIdentity.ClockIdentityLower = 0; + AnnounceFrame->SourcePortIdentity.ClockIdentityUpper = 0; + + /** Get the Source Port Identity of the port sending the Announce Packet */ + XAvb_GetPortIdentity(BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_PORTID_UPPER_OFFSET, &AnnounceFrame->SourcePortIdentity); + + + /** Read priority1 and top half of ClockQuality */ + ReadWord = XAvb_ReorderWord(XAvb_ReadPtpBuffer(BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_ANNOUNCE_PRI1_QUAL_HI_OFFSET)); + AnnounceFrame->GrandmasterPriority1 = (ReadWord >> 16); + AnnounceFrame->ClockQuality.clockClass = (ReadWord >> 8); + AnnounceFrame->ClockQuality.clockAccuracy = ReadWord; + + + /** Read bottom half of ClockQuality, priority2, and top byte of GMID */ + ReadWord = XAvb_ReorderWord(XAvb_ReadPtpBuffer(BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_ANNOUNCE_QUAL_LOW_PRI2_GMID_HI_OFFSET)); + AnnounceFrame->ClockQuality.offsetScaledLogVariance = (ReadWord >> 16); + AnnounceFrame->GrandmasterPriority2 = (ReadWord >> 8); + AnnounceFrame->GrandmasterIdentity.ClockIdentityUpper = (ReadWord << 24); + + /** Read bytes 4-7 of GMID */ + ReadWord = XAvb_ReorderWord(XAvb_ReadPtpBuffer(BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_ANNOUNCE_GMID_MID_OFFSET)); + AnnounceFrame->GrandmasterIdentity.ClockIdentityUpper |= (ReadWord >> 8); + AnnounceFrame->GrandmasterIdentity.ClockIdentityLower = (ReadWord << 24); + + /** Read bytes 1-3 of GMID and high byte of stepsRemoved */ + ReadWord = XAvb_ReorderWord(XAvb_ReadPtpBuffer(BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_ANNOUNCE_GMID_LOW_STEPSREMOVED_HI_OFFSET)); + AnnounceFrame->GrandmasterIdentity.ClockIdentityLower |= (ReadWord >> 8); + AnnounceFrame->stepsRemoved = (ReadWord << 8); + + /** Read low byte of stepsRemoved */ + ReadWord = XAvb_ReorderWord(XAvb_ReadPtpBuffer(BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_ANNOUNCE_STEPSREMOVED_LOW_TIMESRC_OFFSET)); + AnnounceFrame->stepsRemoved |= (ReadWord >> 24); + +} + +/****************************************************************************/ +/** +* +* This function reads the logMessageinteval from an RX PTP Buffer and updates +* the AnnounceFrame struct with the value read. +* +* @param BaseAddress is the base address of the device +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* @param AnnounceFrame is a pointer to a suitable data structure, designed to +* record the useful fields from the received Announce Packet +* +* @return The AnnounceFrame data structure is updated. +* +* @note None. +* +*****************************************************************************/ +void XAvb_ReadAnnounceReceiptTimeout(u32 BaseAddress, + u32 PtpFrameBaseAddr, + XAvb_BmcData * AnnounceFrame) { + + u32 ReadWord; + u8 logMessageInterval; + + ReadWord = XAvb_ReorderWord((XAvb_ReadPtpBuffer(BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_SEQUENCEID_OFFSET)) & + 0xFF000000); + + logMessageInterval = ReadWord; + + /* Implicit convert from unsigned (u8) to signed (char) */ + AnnounceFrame->logMessageInterval = logMessageInterval; + +} + +/****************************************************************************/ +/** +* +* This function will accept the data pointer to the current BMCA records, accept +* a pointer to an equivalent data structure for the new Announce Packet. The +* Best Master Clock Algorithm (BMCA) is then performed on these two data +* structures by comparing the data fields +* +* @param CurrentBmc is a pointer to a suitable data structure, designed to +* record the current fields from the current Grand Master's Announce +* Packet. +* @param AnnounceFrame is a pointer to a suitable data structure, designed to +* record the useful fields from the received Announce Packet +* +* @return An updated True/False decision as to whether there is to be a change +* of Grand Master in the network. +* +* @note None. +* +*****************************************************************************/ +u32 XAvb_BestMasterClockAlgorithm(XAvb_BmcData * AnnounceFrame, + XAvb_BmcData * CurrentBmc) { + + u32 NewMaster = 0; + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("*** Performing BMCA ***\r\n"); +#endif + + /** Priority1 takes precedence over all over priorites */ + if (AnnounceFrame->GrandmasterPriority1 < CurrentBmc->GrandmasterPriority1) { + /** we have found a better master! */ + NewMaster = 1; + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: Found new GM on priority1: AnnPri1 (%d) < BmcPri1 (%d)\r\n", + AnnounceFrame->GrandmasterPriority1, + CurrentBmc->GrandmasterPriority1); +#endif + + } else if (AnnounceFrame->GrandmasterPriority1 == + CurrentBmc->GrandmasterPriority1) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: priority1 equal moving on: (%d)\r\n", + AnnounceFrame->GrandmasterPriority1); +#endif + + /** convert structs to u32 values for easy comparison */ + u32 AnnClockQualityInteger; + u32 BmcClockQualityInteger; + AnnClockQualityInteger = (AnnounceFrame->ClockQuality.clockClass << 24) | + (AnnounceFrame->ClockQuality.clockAccuracy << 16) | + (AnnounceFrame->ClockQuality.offsetScaledLogVariance); + BmcClockQualityInteger = (CurrentBmc->ClockQuality.clockClass << 24) | + (CurrentBmc->ClockQuality.clockAccuracy << 16) | + (CurrentBmc->ClockQuality.offsetScaledLogVariance); + + /** ClockQuality has the next priority */ + if (AnnClockQualityInteger < BmcClockQualityInteger ) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: Found new GM on clockQuality: Ann (0x%08x) < Bmc (0x%08x)\r\n", + AnnClockQualityInteger, + BmcClockQualityInteger); +#endif + + /** we have found a better master! */ + NewMaster = 1; + + } else if ( AnnClockQualityInteger == BmcClockQualityInteger ) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: clockQuality equal moving on: (0x%08x)\r\n", + AnnClockQualityInteger); +#endif + + /** Priority2 provides fine grained ordering amongst otherwise equal + * clocks */ + if (AnnounceFrame->GrandmasterPriority2 < + CurrentBmc->GrandmasterPriority2) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: Found new GM on priority2: AnnPri1 (%d) < BmcPri1 (%d)\r\n", + AnnounceFrame->GrandmasterPriority2, + CurrentBmc->GrandmasterPriority2); +#endif + + /** we have found a better master! */ + NewMaster = 1; + + /** Next compare the Clock Identities */ + } else if (AnnounceFrame->GrandmasterPriority2 + == CurrentBmc->GrandmasterPriority2) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: priority2 equal moving on: (%d)\r\n", + AnnounceFrame->GrandmasterPriority2); +#endif + + if (AnnounceFrame->GrandmasterIdentity.ClockIdentityUpper < + CurrentBmc->GrandmasterIdentity.ClockIdentityUpper) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: Found new GM on GMIDClockIDUp: Ann (0x%08x) < Bmc (0x%08x)\r\n", + AnnounceFrame->GrandmasterIdentity.ClockIdentityUpper, + CurrentBmc->GrandmasterIdentity.ClockIdentityUpper); +#endif + + /** we have found a better master! */ + NewMaster = 1; + + } else if (AnnounceFrame->GrandmasterIdentity.ClockIdentityUpper + == CurrentBmc->GrandmasterIdentity.ClockIdentityUpper) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: GMIDclockIDUp equal moving on: (0x%08x)\r\n", + AnnounceFrame->GrandmasterIdentity.ClockIdentityUpper); +#endif + + if (AnnounceFrame->GrandmasterIdentity.ClockIdentityLower < + CurrentBmc->GrandmasterIdentity.ClockIdentityLower) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: Found new GM on GMIDClockIDLow: Ann (0x%08x) < Bmc (0x%08x)\r\n", + AnnounceFrame->GrandmasterIdentity.ClockIdentityLower, + CurrentBmc->GrandmasterIdentity.ClockIdentityLower); +#endif + + /** we have found a better master! */ + NewMaster = 1; + + /** Next compare stepsRemoved */ + } else if( AnnounceFrame->GrandmasterIdentity.ClockIdentityLower + == CurrentBmc->GrandmasterIdentity.ClockIdentityLower ) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: GMIDclockIDLo equal moving on: (0x%08x)\r\n", + AnnounceFrame->GrandmasterIdentity.ClockIdentityLower); +#endif + + if( AnnounceFrame->stepsRemoved < CurrentBmc->stepsRemoved ) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: Found new GM on stepsRemoved: Ann (%d) < Bmc (%d)\r\n", + AnnounceFrame->stepsRemoved, + CurrentBmc->stepsRemoved); +#endif + + /** we have found a better master! */ + NewMaster = 1; + + /** Next compare SourcePortIdentity */ + } else if( AnnounceFrame->stepsRemoved == CurrentBmc->stepsRemoved ) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: stepsRemoved equal moving on: (%d)\r\n", + AnnounceFrame->stepsRemoved); +#endif + + if( AnnounceFrame->SourcePortIdentity.ClockIdentityUpper < + CurrentBmc->SourcePortIdentity.ClockIdentityUpper) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: Found new GM on sourceIDClockIDupper: Ann (0x%08x) < Bmc (0x%08x)\r\n", + AnnounceFrame->SourcePortIdentity.ClockIdentityUpper, + CurrentBmc->SourcePortIdentity.ClockIdentityUpper); +#endif + + /** we have found a better master! */ + NewMaster = 1; + + } else if( AnnounceFrame->SourcePortIdentity.ClockIdentityUpper + == CurrentBmc->SourcePortIdentity.ClockIdentityUpper ) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: sourceIDportUp equal moving on: (0x%08x)\r\n", + CurrentBmc->SourcePortIdentity.ClockIdentityUpper); +#endif + + if( AnnounceFrame->SourcePortIdentity.ClockIdentityLower < + CurrentBmc->SourcePortIdentity.ClockIdentityLower ) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: Found new GM on sourceIDClockIDlow: Ann (0x%08x) < Bmc (0x%08x)\r\n", + AnnounceFrame->SourcePortIdentity.ClockIdentityLower, + CurrentBmc->SourcePortIdentity.ClockIdentityLower); +#endif + + /** we have found a better master! */ + NewMaster = 1; + + /** If all else fails, the SourcePortIdentity Port Number must + * act as the tie-breaker */ + } else if( AnnounceFrame->SourcePortIdentity.PortNumber < + CurrentBmc->SourcePortIdentity.PortNumber ) { + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("BMCA: Found new GM on sourceIDportNum: AnnPort (0x%08x) < BmcPort (0x%08x)\r\n", + AnnounceFrame->SourcePortIdentity.PortNumber, + CurrentBmc->SourcePortIdentity.PortNumber); +#endif + + /** A new master has won on the tie-break! */ + NewMaster = 1; + } + } + } + } + } + } + } + } + +#ifdef XAVB_DEBUG_LEVEL2 + xil_printf("*** END BMCA ***\r\n"); +#endif + + return NewMaster; + +} + + +/****************************************************************************/ +/** +* +* This function will accept the data pointer to the current BMCA records, accept +* an equivalent pointer to a new (winning) Grand Masters Announce Packet +* information. The CurrentBmc data structure is then updated with the +* information from the NewMaster. +* +* @param NewMaster is a pointer to a suitable data structure which has recorded +* the relevent Announce Packet fields of the new (winning) Grand Master. +* @param CurrentBmc is a pointer to a suitable data structure which has +* recorded the current fields of the current Grand Master's Announce +* Packet. +* +* @return The CurrentBmc data structure is updated. +* +* @note None. +* +*****************************************************************************/ +void XAvb_UpdateBmcRecords(XAvb_BmcData* NewMaster, + XAvb_BmcData* CurrentBmc) { + + CurrentBmc->SourcePortIdentity.ClockIdentityUpper = + NewMaster->SourcePortIdentity.ClockIdentityUpper; + + CurrentBmc->SourcePortIdentity.ClockIdentityLower = + NewMaster->SourcePortIdentity.ClockIdentityLower; + + CurrentBmc->SourcePortIdentity.PortNumber = + NewMaster->SourcePortIdentity.PortNumber; + + CurrentBmc->GrandmasterIdentity.ClockIdentityUpper = + NewMaster->GrandmasterIdentity.ClockIdentityUpper; + + CurrentBmc->GrandmasterIdentity.ClockIdentityLower = + NewMaster->GrandmasterIdentity.ClockIdentityLower; + + + CurrentBmc->stepsRemoved = NewMaster->stepsRemoved; + CurrentBmc->ClockQuality = NewMaster->ClockQuality; + CurrentBmc->GrandmasterPriority1 = NewMaster->GrandmasterPriority1; + CurrentBmc->GrandmasterPriority2 = NewMaster->GrandmasterPriority2; + +} + + +/****************************************************************************/ +/** +* +* This function will make any adjustments needed when the node becomes the Grand +* Master, including resetting the RTC to its nominal value +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @param txAnnounceHasWon indicates that this function has been called from +* the function XAvb_DecodeTxAnnounceFrame(). Is this is set then this +* function has no need to repeat actions that have been already performed. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_BecomeRtcMaster(XAvb *InstancePtr, + u8 txAnnounceHasWon) { + + XAvb_BmcData deviceData; + + if (txAnnounceHasWon == 0) { + /** + * Update the BMCA records to this device's information + */ + + /** Read the attributes in the Tx PTP buffer */ + XAvb_ReadAnnounceFrame(InstancePtr->Config.BaseAddress, + (XAVB_PTP_TX_ANNOUNCE_OFFSET + 8), + &deviceData); + + /** Update records */ + XAvb_UpdateBmcRecords(&deviceData, + &InstancePtr->CurrentBmc); + } + + /** reset the RTC to a nominal value */ + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_INCREMENT_OFFSET, + XAVB_RTC_INCREMENT_NOMINAL_RATE); + + /** set timestamp uncertainty if new status */ + if( !InstancePtr->CurrentBmc.IAmTheRtcMaster ) { + xil_printf("\r\n*** I am now the Grand Master ***"); + xil_printf("\r\nNOTICE: timestamps are now certain\r\n"); + InstancePtr->GMDiscHandler(InstancePtr->GMDiscCallBackRef, + 0); + } + + /** inform the rest of the system */ + InstancePtr->CurrentBmc.IAmTheRtcMaster = 1; + +} + +/****************************************************************************/ +/** +* +* This function will make any adjustments needed when the node becomes a PTP slave +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_BecomeRtcSlave(XAvb *InstancePtr) { + + /** set timestamp uncertainty if new status */ + if( InstancePtr->CurrentBmc.IAmTheRtcMaster ) { + xil_printf("\r\n*** I am now a PTP slave ***"); + xil_printf("\r\nNOTICE: timestamps are now uncertain\r\n"); + InstancePtr->GMDiscHandler(InstancePtr->GMDiscCallBackRef, + 1); + } + + /* Reset the syncReceiptTimeoutTimeInterval counter as this has now changed purpose + */ + InstancePtr->PtpCounters.CounterSyncInterval = 0; + + /* inform the rest of the system */ + InstancePtr->CurrentBmc.IAmTheRtcMaster = 0; + + +} + +/****************************************************************************/ +/** +* +* Operations needed when PTP locks or unlocks +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param locked is 1 if changing to locked status, zero if unlocked +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_ChangePTPLockStatus(XAvb *InstancePtr, u8 locked) { + u32 lockedOld; + u32 tu = 0; + + lockedOld = InstancePtr->PTPLocked; + + /** set status variable */ + InstancePtr->PTPLocked = locked; + + /** set timestamp uncertainty if necessary */ + if( InstancePtr->PTPLocked != lockedOld ) { + XAvb_ChangePeerASCapability(InstancePtr, locked); + +#ifdef XAVB_DEBUG_LEVEL2 + if (locked == 0) { + xil_printf("\r\nXAvb_ChangePTPLockStatus():The peer is no longer ASCapable "); + xil_printf("\r\nXAvb_ChangePTPLockStatus():locked = %d\r\n",locked); + } +#endif + + tu = InstancePtr->PTPLocked ? 0 : 1; + xil_printf("\r\nXAvb_ChangePTPLockStatus()::"); + xil_printf("\r\nNOTICE: timestamps are now %s\r\n", tu ? "uncertain" : "certain"); + InstancePtr->GMDiscHandler(InstancePtr->GMDiscCallBackRef, + tu); + } + +} + +/****************************************************************************/ +/** +* +* Operations needed when the peer's AS capability changes +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param capable is 1 if the peer is ASCapable, 0 otherwise +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_ChangePeerASCapability(XAvb *InstancePtr, u8 capable) { + u32 capableOld; + + capableOld = InstancePtr->PeerASCapable; + + /* set status variable */ + InstancePtr->PeerASCapable = capable; + + if( capable != capableOld ) { + if( capable ) { + xil_printf("\r\nThe Peer is now AS Capable\r\n"); + } else { + xil_printf("\r\nThe Peer is no longer AS Capable\r\n"); + } + } + +} + +/****************************************************************************/ +/** +* +* This function sets the handler that will be called when a GM discontinuity +* event is identified by the driver. The purpose of the handler is to allow +* application specific processing to be performed. +* +* @param InstancePtr is a pointer to the XAvb instance. +* @param FuncPtr is the pointer to the callback function. +* @param CallBackRef is the upper layer callback reference passed back +* 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 (nor should it) +* +*****************************************************************************/ +void XAvb_SetGMDiscontinuityHandler(XAvb *InstancePtr, + XAvb_Handler FuncPtr, void *CallBackRef) +{ + /* + * Assert validates the input arguments + * CallBackRef not checked, no way to know what is valid + */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(FuncPtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + InstancePtr->GMDiscHandler = FuncPtr; + InstancePtr->GMDiscCallBackRef = CallBackRef; +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_ptp_packets.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_ptp_packets.c new file mode 100644 index 00000000..110a3c7d --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_ptp_packets.c @@ -0,0 +1,1742 @@ +/****************************************************************************** +* +* Copyright (C) 2008 - 2014 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xavb_ptp_packets.c +* +* The XAvb driver. Functions in this file all contain functions which decode the +* received Precise Timing Protocol (PTP) frames, or to format and transmit PTP +* frames. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a mbr 09/19/08 First release +* 1.01a mbr 06/24/09 PTP frame format updates for IEEE802.1 AS draft 5-0 +* 2_02a mbr 09/16/09 Updates for programmable PTP timers +* 2_04a kag 07/23/10 PTP frame format updates for IEEE802.1 AS draft 6-7 +* 3_01a kag 08/29/11 Added new APIs to update the RX Filter Control Reg. +* Fix for CR:572539. Updated bit map for Rx Filter +* control reg. +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xavb_hw.h" +#include "xavb.h" +#include "stdlib.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Variable Definitions *****************************/ + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ + +/****************************************************************************/ +/** +* +* A function to compare two ClockIdentity values. +* +* @param BaseAddress is the base address of the device +* @param Identity1 is the first ClockIdentity to be compared +* @param Identity2 is the second ClockIdentity to be compared +* +* @return 1 if the two values are equal, 0 if not equal +* +* @note +* +*****************************************************************************/ +u32 XAvb_CompareClockIdentity(u32 BaseAddress, + XAvb_ClockIdentity Identity1, + XAvb_ClockIdentity Identity2) { + + if( Identity1.ClockIdentityUpper != Identity2.ClockIdentityUpper ) { + /*xil_printf("ID1Upper (0x%08x) != ID2Upper (0x%08x)\r\n", + Identity1.ClockIdentityUpper, + Identity2.ClockIdentityUpper);*/ + return 0; + } + if( Identity1.ClockIdentityLower != Identity2.ClockIdentityLower ) { + /*xil_printf("ID1Lower (0x%08x) != ID2Lower (0x%08x)\r\n", + Identity1.ClockIdentityLower, + Identity2.ClockIdentityLower);*/ + return 0; + } + + /** values are equal */ + return 1; +} + +/****************************************************************************/ +/** +* +* A function to compare two PortIdentity values. +* +* @param BaseAddress is the base address of the device +* @param Identity1 is the first sourcePortIdentity to be compared +* @param Identity2 is the second sourcePortIdentity to be compared +* +* @return 1 if the two values are equal, 0 if not equal +* +* @note None. +* +*****************************************************************************/ +u32 XAvb_ComparePortIdentity(u32 BaseAddress, + XAvb_PortIdentity Identity1, + XAvb_PortIdentity Identity2) { + + if( Identity1.ClockIdentityUpper != Identity2.ClockIdentityUpper ) { + /*xil_printf("ID1Upper (0x%08x) != ID2Upper (0x%08x)\r\n", + Identity1.ClockIdentityUpper, + Identity2.ClockIdentityUpper);*/ + return 0; + } + if( Identity1.ClockIdentityLower != Identity2.ClockIdentityLower ) { + /*xil_printf("ID1Lower (0x%08x) != ID2Lower (0x%08x)\r\n", + Identity1.ClockIdentityLower, + Identity2.ClockIdentityLower);*/ + return 0; + } + if( Identity1.PortNumber != Identity2.PortNumber ) { + /*xil_printf("ID1Port (0x%08x) != ID2Port (0x%08x)\r\n", + Identity1.PortNumber, + Identity2.PortNumber);*/ + return 0; + } + + /** values are equal */ + return 1; +} + +/****************************************************************************/ +/** +* +* A function to extract portIdentity information from a received PTP frame. +* This can be any portIdentity field (header portIdentity, requestingPortIdentity, +* etc.) +* +* @param BaseAddress is the base address of the device +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* @param PortIdOffset is the packet offset of the first byte of the portIdentity +* field to be parsed +* @param portID is the XAvb_PortIdentity struct that the data will be written to. +* +* @return None, but portID will be updated with the portIdentity information +* +* @note None. +* +*****************************************************************************/ +void XAvb_GetPortIdentity(u32 BaseAddress, u32 PtpFrameBaseAddr, + u32 PortIdOffset, XAvb_PortIdentity *portID) { + + u32 ReadWord; + + ReadWord = XAvb_ReorderWord(XAvb_ReadPtpBuffer(BaseAddress, PtpFrameBaseAddr, PortIdOffset)); + + portID->ClockIdentityUpper = (ReadWord << 16); + + ReadWord = XAvb_ReorderWord(XAvb_ReadPtpBuffer(BaseAddress, PtpFrameBaseAddr, PortIdOffset + 4)); + + portID->ClockIdentityUpper |= (ReadWord >> 16); + portID->ClockIdentityLower = (ReadWord << 16); + + ReadWord = XAvb_ReorderWord(XAvb_ReadPtpBuffer(BaseAddress, PtpFrameBaseAddr, PortIdOffset + 8)); + + portID->ClockIdentityLower |= (ReadWord >> 16); + portID->PortNumber = ReadWord; + +} + +/****************************************************************************/ +/** +* +* A function to write common data (eg the Source Address) to all PTP frames +* stored in the Tx PTP Packet buffer +* +* @param BaseAddress is the base address of the device +* @param PtpFieldAddress is the offset address of the relevant field in PTP +* frames. +* @param Data is the common data to be written to all Tx PTP frame templates +* @param DataBitEnable allows only selected bits of the 32-bit Data word to +* be modified. +* @param BufferEnable allows the selected buffer to be seleced: there are 8 +* PTP buffers - these are encoded as one-hot. For example, 0x3F will +* write the selected data to the first 6 buffers only. +* +* @return None. But the Tx PTP Packet Buffer is written to as requested +* +* @note None. +* +*****************************************************************************/ +void XAvb_WriteToMultipleTxPtpFrames(u32 BaseAddress, + u32 PtpFieldAddress, + u32 Data, + u32 DataBitEnable, + u8 BufferEnable) { + u32 PtpBufferPointer = 0; + u32 LocalData = 0; + u32 LocalAddr = 0; + + /** Write to all 8 PTP frame templates */ + for (PtpBufferPointer= 0; PtpBufferPointer < 8; PtpBufferPointer++) { + + /** Only write to selected buffers */ + if ( ((BufferEnable >> PtpBufferPointer) & 0x1) == 0x1) { + + LocalAddr = (PtpBufferPointer<<8) + XAVB_PTP_TX_SYNC_OFFSET; + + /** Read the current value */ + LocalData = XAvb_ReadPtpBuffer(BaseAddress, + LocalAddr, + PtpFieldAddress); + + /** Only change the selected data bits */ + LocalData = LocalData | (Data & DataBitEnable); + + /** Write the updated value */ + XAvb_WritePtpBuffer(BaseAddress, + LocalAddr, + PtpFieldAddress, + LocalData); +#ifdef DEBUG_XAVB_LEVEL3 + xil_printf("\r\nWriteToMultipleTxPtpFrames read/mod(PtpBufferPointer = %x) ", PtpBufferPointer); + xil_printf("\r\n PTPAddress = %x ", LocalAddr); + xil_printf("\r\n PtpFieldAddress = %x ", PtpFieldAddress); + xil_printf("\r\n LocalData = %x ", LocalData); +#endif + } + } +} + + +/****************************************************************************/ +/** +* +* This function switches the bytes in a 4-byte word, swapping the MSB for the +* LSB, and vice-versa. +* +* @param Data is the 4-byte input data word +* +* @return The input data word with the bytes swapped (most significant down to +* least significant +* +* @note None. +* + +*****************************************************************************/ +u32 XAvb_ReorderWord(u32 Data) { + u32 ReOrder = 0; + + ReOrder = (Data & 0x000000FF) << 24; + ReOrder = ReOrder | ((Data & 0x0000FF00) << 8); + ReOrder = ReOrder | ((Data & 0x00FF0000) >> 8); + ReOrder = ReOrder | ((Data & 0xFF000000) >> 24); + return ReOrder; +} + + +/****************************************************************************/ +/** +* +* A function to increment the sequenceId in a PTP frame template +* +* @param BaseAddress is the base address of the device +* @param PtpFrameBaseAddress is the base address of the TX PTP Buffer whose +* SequenceID is to be incremented +* +* @return None. But the relevant TX PTP Packet Buffer is written to with the +* updated SequenceID +* +* @note None. +* +*****************************************************************************/ +u32 XAvb_IncSequenceId(u32 BaseAddress, u32 PtpFrameBaseAddress) { + u32 BufferWord = 0; + u32 SequenceId = 0; + + /** Read the 32-bit BufferWord containing the SequenceId from the PTP buffer */ + BufferWord = XAvb_ReadPtpBuffer(BaseAddress, + PtpFrameBaseAddress, + XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET); + + /** Swap byte order into correct binary and increment the SequenceId */ + SequenceId = XAvb_ReorderWord(BufferWord) + 0x10000; + + /** Swap back the byte order into frame storage order */ + SequenceId = XAvb_ReorderWord(SequenceId); + + /** Write the 32-bit BufferWord variable containing the updated SequenceId */ + XAvb_WritePtpBuffer(BaseAddress, + PtpFrameBaseAddress, + XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET, + SequenceId); + + return SequenceId; + +} + + +/****************************************************************************/ +/** +* +* The software drivers are kept simple by only requesting a single PTP frame to +* be transmitted at a time. This function checks (and if necessary waits) +* until the previously request PTP frame has been transmitted. +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. +** +* @note None. +* +*****************************************************************************/ +void XAvb_WaitOnTxPtpQueue(XAvb * InstancePtr) { + u32 TxPtpType = 0; + + do { + + /** Wait until any queued PTP frame has been transmitted. This is a + * software safety feature, not a hardware restriction */ + TxPtpType = (XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_CONTROL_OFFSET) + & XAVB_PTP_TX_WAIT_ALL_FRAMES_MASK); + + } while(TxPtpType != 0); + +} + + +/****************************************************************************/ +/** +* +* A function to format then request the transmission of a PTP Announce Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. But the relevant Tx PTP Packet Buffer is written to with the +* updated PTP fields, and then the Tx PTP Packet Buffer Control +* Register is written to request the frame transmission. +* +* @note None. +* +*****************************************************************************/ +void XAvb_MasterSendAnnounce(XAvb * InstancePtr) { + u32 Unused = 0; + + + /** Wait until there are no PTP frames to be transmitted */ + XAvb_WaitOnTxPtpQueue(InstancePtr); + + /** Increment the sequenceId */ + Unused = XAvb_IncSequenceId(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET); + +#ifdef DEBUG_XAVB_LEVEL3 + xil_printf("\r\n--------------------------------"); + xil_printf("\r\n---XAvb_MasterSendAnnounce()----"); + xil_printf("\r\n--------------------------------"); + xil_printf("\r\nsequenceId is %x", Unused); + Unused = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_NANOSEC_VALUE_OFFSET); + Unused = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_SEC_LOWER_VALUE_OFFSET); + xil_printf("\r\nSeconds %d", Unused); +#endif + + /** Send the Announce Frame! */ + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_CONTROL_OFFSET, + XAVB_PTP_TX_SEND_ANNOUNCE_FRAME_MASK); +} + + +/****************************************************************************/ +/** +* +* A function to format then request the transmission of a PTP Sync Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. But the relevant Tx PTP Packet Buffer is written to with the +* updated PTP fields, and then the Tx PTP Packet Buffer Control +* Register is written to request the frame transmission. +* +* @note None. +* +*****************************************************************************/ +void XAvb_MasterSendSync(XAvb * InstancePtr) { + u32 Epoch = 0; + u32 Sec = 0; + u32 SequenceId = 0; + u32 BufferWord = 0; + + /** Wait until there are no PTP frames to be transmitted */ + XAvb_WaitOnTxPtpQueue(InstancePtr); + + /** Increment the sequenceId in the Sync frame */ + SequenceId = XAvb_IncSequenceId(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_SYNC_OFFSET); + + /** Read the current RTC Offset values */ + InstancePtr->PtpRecords.Nanosec + = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_NANOSEC_VALUE_OFFSET); + + Sec = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_SEC_LOWER_VALUE_OFFSET); + + Epoch = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_SEC_UPPER_VALUE_OFFSET); + + /** Send the Sync Frame! */ + XAvb_WriteReg(InstancePtr->Config.BaseAddress, XAVB_PTP_TX_CONTROL_OFFSET, + XAVB_PTP_TX_SEND_SYNC_FRAME_MASK); + + + /** Now some pre-work on the Follow-Up Frame + *----------------------------------------- + * + * Write the same sequenceId to the Follow-up frame */ + BufferWord = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET); + + BufferWord = (BufferWord & 0xFFFF0000) | (SequenceId & 0x0000FFFF); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET, + BufferWord); + + + /** Format the Timestamp (RTC) into correct byte positioning. + * Note: this is how the Timestamp is stored in + * the PTP frame itself (transmitted MSB of Epoch first): + * + * |----------------|----------------|----------------|----------------| + * | seconds[23:16] | seconds[31:24] | epoch[7:0] | epoch[15:8] | + * |----------------|----------------|----------------|----------------| + * | nanosec[23:16] | nanosec[31:24] | seconds[7:0] | seconds[15:8] | + * |----------------|----------------|----------------|----------------| + * | 0's | 0's | nanosec[7:0] | nanosec[15:8] | + * |----------------|----------------|----------------|----------------| + */ + + BufferWord = XAvb_ReorderWord((Epoch<<16) | (Sec>>16)); + + /** Write the Timestamp (RTC) to the Follow-up frame */ + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_UPPER_OFFSET, + BufferWord); + + BufferWord = XAvb_ReorderWord((Sec<<16) | + (InstancePtr->PtpRecords.Nanosec>>16)); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_MID_OFFSET, + BufferWord); + + BufferWord = XAvb_ReorderWord(InstancePtr->PtpRecords.Nanosec<<16); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_LOWER_OFFSET, + BufferWord); + +#ifdef DEBUG_XAVB_LEVEL3 + xil_printf("\r\n--------------------------------"); + xil_printf("\r\n-----XAvb_MasterSendSync()------"); + xil_printf("\r\n--------------------------------"); + xil_printf("\r\n--------------RTC---------------"); + xil_printf("\r\nRTC nanosec field is %x", InstancePtr->PtpRecords.Nanosec); + xil_printf("\r\nRTC seconds field is %x", Sec); + xil_printf("\r\nRTC epoch field is %x", Epoch); + xil_printf("\r\n--------------------------------"); + xil_printf("\r\nsequenceId is %x", SequenceId); +#endif + +} + + + +/****************************************************************************/ +/** +* +* A function to format then request the transmission of a PTP Follow-Up Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. But the relevant Tx PTP Packet Buffer is written to with the +* updated PTP fields, and then the Tx PTP Packet Buffer Control +* Register is written to request the frame transmission. +* +* @note None. +* +*****************************************************************************/ +void XAvb_MasterSendFollowUp(XAvb * InstancePtr) { + u32 Timestamp = 0; + u32 NsOffset = 0; + u32 CorrectionField = 0; + u32 BufferWord = 0; + + /** Wait until there are no PTP frames to be transmitted */ + XAvb_WaitOnTxPtpQueue(InstancePtr); + + /** Read the current RTC offset */ + NsOffset = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_NANOSEC_OFFSET); + + /** Read the Timestamp and adjust it for the MAC transmit latency */ + Timestamp = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_SYNC_OFFSET, + XAVB_PTP_PKT_CAPTURED_TIMESTAMP_OFFSET) + + XAVB_TX_MAC_LATENCY_IN_NS; + + /** Adjust the Timestamp with current RTC ns offset */ + Timestamp = Timestamp + NsOffset; + if (Timestamp >= XAVB_ONE_SECOND) { + Timestamp = Timestamp - XAVB_ONE_SECOND; + } + + /** Calculate the Correction Field */ + CorrectionField = Timestamp - InstancePtr->PtpRecords.Nanosec; + if (CorrectionField >= XAVB_ONE_SECOND) { + CorrectionField = CorrectionField + XAVB_ONE_SECOND; + } + + /** Format the Correction Field into correct byte positioning for PTP frame + * storage in the buffer + */ + BufferWord = XAvb_ReorderWord(CorrectionField); + + /** Write the Correction Field to the Follow Up frame */ + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_CORRECTION_FIELD_OFFSET, + BufferWord); + + /** Send the Follow Up Frame! */ + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_CONTROL_OFFSET, + XAVB_PTP_TX_SEND_FOLLOWUP_FRAME_MASK); + +#ifdef DEBUG_XAVB_LEVEL3 + xil_printf("\r\n--------------------------------"); + xil_printf("\r\n---XAvb_MasterSendFollowUp()----"); + xil_printf("\r\n--------------------------------"); + xil_printf("\r\nTimestamp is %x", Timestamp); + xil_printf("\r\nRTC nano seconds field is %x", + InstancePtr->PtpRecords.Nanosec); + xil_printf("\r\nCorrection Field %x", CorrectionField); +#endif + +} + + + +/****************************************************************************/ +/** +* +* A function to format then request the transmission of a PTP PDelay Request +* Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. But the relevant Tx PTP Packet Buffer is written to with the +* updated PTP fields, and then the Tx PTP Packet Buffer Control +* Register is written to request the frame transmission. +* +* @note None. +* +*****************************************************************************/ +void XAvb_SendPDelayReq(XAvb * InstancePtr) { + u32 SequenceId; + + /** Wait until there are no PTP frames to be transmitted */ + XAvb_WaitOnTxPtpQueue(InstancePtr); + + /** Increment the SequenceId */ + SequenceId = XAvb_IncSequenceId(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYREQ_OFFSET) + & 0x0000FFFF; + +#ifdef DEBUG_XAVB_LEVEL3 + xil_printf("\r\n--------------------------------"); + xil_printf("\r\n------XAvb_SendPDelayReq()------"); + xil_printf("\r\n--------------------------------"); + xil_printf("\r\nsequenceId is %x", SequenceId); +#endif + + /** Send the PDelayReq Frame! */ + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_CONTROL_OFFSET, + XAVB_PTP_TX_SEND_PDELAYREQ_FRAME_MASK); + + /** Wait for the frame to be transmitted */ + XAvb_WaitOnTxPtpQueue(InstancePtr); + + /** Capture the Timestamp for Tx of PDelayReq (t1) and adjust it for MAC + * transmit latency */ + InstancePtr->PtpRecords.PDelayTimestampT1 + = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYREQ_OFFSET, + XAVB_PTP_PKT_CAPTURED_TIMESTAMP_OFFSET) + + XAVB_TX_MAC_LATENCY_IN_NS; + + /** Capture the SequenceID of the the PDelayReq */ + InstancePtr->SequenceIdRecords.PDelayReqSequenceId = + XAvb_ReorderWord(XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYREQ_OFFSET, + XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET)) >> 16; +} + + +/****************************************************************************/ +/** +* +* A function to format then request the transmission of a PTP PDelay Response +* Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* +* @return None. But the relevant Tx PTP Packet Buffer is written to with the +* updated PTP fields, and then the Tx PTP Packet Buffer Control +* Register is written to request the frame transmission. +* +* @note None. +* +*****************************************************************************/ +void XAvb_SendPDelayResp(XAvb * InstancePtr, + u32 PtpFrameBaseAddr) { + u32 SequenceId = 0; + u32 TimestampT2 = 0; + u32 BufferWord = 0; + u32 NanoSec = 0; + u32 Seconds = 0; + u32 Epoch = 0; + u32 CopyPortId = 0; + u32 CopyPortId1 = 0; + + /** Wait until there are no PTP frames to be transmitted */ + XAvb_WaitOnTxPtpQueue(InstancePtr); + + /** Format the Timestamp + *--------------------- + * + * Capture the current Synchronised time */ + NanoSec = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_NANOSEC_VALUE_OFFSET); + + Seconds = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_SEC_LOWER_VALUE_OFFSET); + Epoch = XAvb_ReadReg(InstancePtr->Config.BaseAddress, + + XAVB_RTC_SEC_UPPER_VALUE_OFFSET); + + /** Read the current RTC offset */ + InstancePtr->PtpRecords.NsOffsetForPDelayResp = + XAvb_ReadReg(InstancePtr->Config.BaseAddress, XAVB_RTC_NANOSEC_OFFSET); + + /** Read the TimestampT2 for PDelayReq reception and adjust it for MAC + * receive latency */ + TimestampT2 = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_PKT_CAPTURED_TIMESTAMP_OFFSET) + - XAVB_RX_MAC_LATENCY_IN_NS; + + /** The TimestampT2 was captured using syntonised ns time. We need to + * convert this into synchronised time by adding on the current offset */ + TimestampT2 = TimestampT2 + InstancePtr->PtpRecords.NsOffsetForPDelayResp; + + /** Check for ns wrap-around condition */ + if (TimestampT2 >= XAVB_ONE_SECOND) { + TimestampT2 = TimestampT2 - XAVB_ONE_SECOND; + } + + /** Even though we read the RTC value at the beginning of this + * function, there would have been processing delay between the + * actual reception (and timestamping) of the PDelayReq frame and the + * start of this function. During this time, the RTC Seconds + * field could have wrapped around. We need to detect this and if it + * has done, the slave Seconds field would also have incremented (so + * it needs to be set back). + */ + if (NanoSec < TimestampT2) { + /** NanoSec has wrapped since timestamp was taken so decrement the + * Seconds field */ + if (Seconds == 0x00000000) { + Epoch = Epoch - 0x1; + } + Seconds = Seconds - 0x1; + } + + /** Format the Timestamp (t2) into correct byte positioning for PTP frame + * storage, then write the Timestamp (t2) to the PDelayResp frame + */ + BufferWord = XAvb_ReorderWord((Epoch<<16) | (Seconds>>16)); + + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_UPPER_OFFSET, + BufferWord); + + BufferWord = XAvb_ReorderWord((Seconds<<16) | (TimestampT2>>16)); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_MID_OFFSET, + BufferWord); + + BufferWord = XAvb_ReorderWord(TimestampT2<<16); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_LOWER_OFFSET, + BufferWord); + + + /** Format the SequenceId + *---------------------- + * + * Set the SequenceId in the PDelayResp and PDelayRespFollowUp frame to be + * that of the received PDelayReq frame */ + SequenceId = (XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_SEQUENCEID_OFFSET)) + & 0x0000FFFF; + + BufferWord = XAVB_PDELAY_LOG_MEAN_MESSAGE_INT | SequenceId; + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_OFFSET, + XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET, + BufferWord); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET, + BufferWord); + + + /** Format the sourcePortIdentity + *------------------------------ + * + * Copy the sourcePortIdentity field from the PDelayReq into the PDelayResp + * and PDelayRespFollowUp frame + */ + CopyPortId = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_PORTID_UPPER_OFFSET); + + CopyPortId &= 0xffff0000; + CopyPortId1 = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_OFFSET, + XAVB_PTP_TX_PKT_REQ_PORTID_UPPER_OFFSET); + + CopyPortId |= (CopyPortId1 & 0x0000ffff); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_OFFSET, + XAVB_PTP_TX_PKT_REQ_PORTID_UPPER_OFFSET, + CopyPortId); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_REQ_PORTID_UPPER_OFFSET, + CopyPortId); + + CopyPortId = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_PORTID_MID_OFFSET); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_OFFSET, + XAVB_PTP_TX_PKT_REQ_PORTID_MID_OFFSET, + CopyPortId); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_REQ_PORTID_MID_OFFSET, + CopyPortId); + + CopyPortId = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_PORTID_LOWER_OFFSET); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_OFFSET, + XAVB_PTP_TX_PKT_REQ_PORTID_LOWER_OFFSET, + CopyPortId); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_REQ_PORTID_LOWER_OFFSET, + CopyPortId); + + + /** Send the PDelayResp Frame! + *---------------------------*/ + + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_CONTROL_OFFSET, + XAVB_PTP_TX_SEND_PDELAYRESP_FRAME_MASK); + +#ifdef DEBUG_XAVB_LEVEL3 + xil_printf("\r\n--------------------------------"); + xil_printf("\r\n------XAvb_SendPDelayResp()-----"); + xil_printf("\r\n--------------------------------"); + xil_printf("\r\nTimestampT2 is %x", TimestampT2); +#endif + +} + + +/****************************************************************************/ +/** +* +* A function to format then request the transmission of a PTP PDelay Response +* Follow-Up Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. But the relevant Tx PTP Packet Buffer is written to with the +* updated PTP fields, and then the Tx PTP Packet Buffer Control +* Register is written to request the frame transmission. +* +* @note None. +* +*****************************************************************************/ +void XAvb_SendPDelayRespFollowUp(XAvb * InstancePtr) { + u32 TimestampT3 = 0; + u32 BufferWordA = 0; + u32 BufferWordB = 0; + XAvb_RtcFormat Rtc[1]; + + /** Wait until there are no PTP frames to be transmitted */ + XAvb_WaitOnTxPtpQueue(InstancePtr); + + /** Format the Timestamp + *---------------------*/ + + /** Capture the current Synchronised time */ + XAvb_ReadRtc(InstancePtr->Config.BaseAddress, Rtc); + + + /** Read the TimestampT3 for PDelayResp transmission and adjust it for MAC + * transmit latency */ + TimestampT3 = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_OFFSET, + XAVB_PTP_PKT_CAPTURED_TIMESTAMP_OFFSET) + + XAVB_TX_MAC_LATENCY_IN_NS; + + /** The TimestampT3 was captured using syntonised ns time. We need to + * convert this into synchronised time by adding on the ns offset. We + * use the same offset here as for the PDelayResp frame since if a + * ns offset change had been made between PDelayResp and , + * PDelayRespFollowUp, this would result in an error in the link delay + * measurement. */ + TimestampT3 = TimestampT3 + InstancePtr->PtpRecords.NsOffsetForPDelayResp; + + /** Check for ns wrap-around condition */ + if (TimestampT3 >= XAVB_ONE_SECOND) { + TimestampT3 = TimestampT3 - XAVB_ONE_SECOND; + } + + /** Even though we read the RTC value at the beginning of this + * function, there would have been processing delay between the + * actual reception (and timestamping) of the PDelayReq frame and the + * start of this function. During this time, the RTC seconds + * field could have wrapped around. We need to detect this and if it + * has done, the slave seconds field would also have incremented (so + * it needs to be set back). + */ + if (Rtc->NanoSeconds < TimestampT3) { + /** nanosec has wrapped since timestamp was taken so decrement the + * seconds field */ + if (Rtc->SecondsLower == 0x00000000) { + Rtc->SecondsUpper = Rtc->SecondsUpper - 0x1; + } + Rtc->SecondsLower = Rtc->SecondsLower - 0x1; + } + + /** Format the Timestamp (t3) into correct byte positioning for PTP frame + * storage, the write the Timestamp (t3) to the PDelayRespFollowUp frame + */ + BufferWordA = XAvb_ReorderWord((Rtc->SecondsUpper<<16) | + (Rtc->SecondsLower>>16)); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_UPPER_OFFSET, + BufferWordA); + + BufferWordA = XAvb_ReorderWord((Rtc->SecondsLower<<16) | (TimestampT3>>16)); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_MID_OFFSET, + BufferWordA); + + BufferWordA = XAvb_ReorderWord(TimestampT3<<16); + BufferWordB = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_LOWER_OFFSET); + BufferWordA &= 0x0000ffff; + BufferWordA |= (BufferWordB & 0xffff0000); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYRESP_FOLLOW_UP_OFFSET, + XAVB_PTP_TX_PKT_TIMESTAMP_LOWER_OFFSET, + BufferWordA); + + + /** Send the PDelayRespFollowUp Frame! + *----------------------------------- */ + + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_CONTROL_OFFSET, + XAVB_PTP_TX_SEND_PDELAYRESPFOLLOWUP_FRAME_MASK); + +#ifdef DEBUG_XAVB_LEVEL3 + xil_printf("\r\n--------------------------------"); + xil_printf("\r\n--XAvb_SendPDelayRespFollowUp()-"); + xil_printf("\r\n--------------------------------"); + xil_printf("\r\nReading TimestampT3 from address %x", + (InstancePtr->Config.BaseAddress + XAVB_PTP_TX_PDELAYRESP_OFFSET + + XAVB_PTP_PKT_CAPTURED_TIMESTAMP_OFFSET)); + xil_printf("\r\nTimestampT3 is %x", TimestampT3); +#endif + +} + + +/****************************************************************************/ +/** +* +* A function to check that various fields in the received frame contain the +* expected values which define it as a valid AVB PTP frame. If this check does +* not pass then the frame should not be decoded and used. +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* +* @return An updated True/False decision as to whether this received frame +* really is a valid PTP type. +* +* @note None. +* +*****************************************************************************/ +u32 XAvb_IsRxFramePTP(XAvb * InstancePtr, + u32 PtpFrameBaseAddr) { + u32 FrameIsPTP; + u32 FrameField; + + /** Start by assuming that it is a valid PTP frame */ + FrameIsPTP = 1; + + /** Perform a 32-bit read from the relevant position in the frame */ + FrameField = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_TYPE_OFFSET); + + FrameField = XAvb_ReorderWord(FrameField); + + /** Check the Length/Type field for a valid Ethertype */ + if ((FrameField >>16) != XAVB_PTP_ETHERTYPE) { + FrameIsPTP = 0; +#ifdef DEBUG_XAVB_LEVEL1 + xil_printf("\r\nXAvb_IsRxFramePTP(): Bad Ethertype: %x", (FrameField >>16)); +#endif + } + + /** Check the versionPTP */ + if ((FrameField & 0xF) != XAVB_PTP_VERSION_PTP) { + FrameIsPTP = 0; +#ifdef DEBUG_XAVB_LEVEL1 + xil_printf("\r\nXAvb_IsRxFramePTP():Bad versionPTP:%x", (FrameField & 0xF)); +#endif + } + + return FrameIsPTP; + +} + + +/****************************************************************************/ +/** +* +* A function to decode a received PTP Sync Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_DecodeRxSync(XAvb * InstancePtr, + u32 PtpFrameBaseAddr) { + + u32 ReadWord = 0; + XAvb_PortIdentity syncPortID; + + /** Read sourcePortIdentity from packet */ + XAvb_GetPortIdentity(InstancePtr->Config.BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_PORTID_UPPER_OFFSET, &syncPortID); + + /** Only decode if configured for a slave and if SourcePortID is that of the + * RTC Clock Master */ + if ( (InstancePtr->CurrentBmc.IAmTheRtcMaster == 0) && + XAvb_ComparePortIdentity(InstancePtr->Config.BaseAddress, + InstancePtr->CurrentBmc.SourcePortIdentity, + syncPortID) ) { + + /** Reset Sync Interval Counter as we have received a valid Sync */ + InstancePtr->PtpCounters.CounterSyncInterval = 0; + + /** Capture the local Timestamp for receipt of this frame and adjust it for + * MAC receive latency */ + InstancePtr->PtpRecords.SlaveSyncTimestamp + = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_PKT_CAPTURED_TIMESTAMP_OFFSET) + - XAVB_RX_MAC_LATENCY_IN_NS; + + /** Capture the Sync SequenceID */ + ReadWord = XAvb_ReorderWord(XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_SEQUENCEID_OFFSET)); + InstancePtr->SequenceIdRecords.SyncSequenceId = (ReadWord >> 16); + + /** Capture the logMeanMessageInterval and convert into a useful duration + * (NOTE: there is an implicit conversion from u32 to char here) + */ + InstancePtr->latestMDSyncReceive.logMessageInterval = ReadWord & 0x000000ff; + InstancePtr->latestMDSyncReceive.SyncIntervalDuration = + XAvb_ConvertLogMeanToDuration(InstancePtr->latestMDSyncReceive.logMessageInterval); + + /** We don't need to capture the correction field - unless we want to check that it is 0.*/ + + } else { + xil_printf("\r\nXAvb_DecodeRxSync()"); + xil_printf("\r\nSync ignored due to unmatched SourcePortID"); +#ifdef DEBUG_XAVB_LEVEL1 + xil_printf("\r\nInstancePtr->CurrentBmc.SourcePortIdentity.ClockIdentityUpper = %x",InstancePtr->CurrentBmc.SourcePortIdentity.ClockIdentityUpper); + xil_printf("\r\nInstancePtr->CurrentBmc.SourcePortIdentity.ClockIdentityLower = %x",InstancePtr->CurrentBmc.SourcePortIdentity.ClockIdentityLower); + xil_printf("\r\nInstancePtr->CurrentBmc.SourcePortIdentity.PortNumber = %x\r\n",InstancePtr->CurrentBmc.SourcePortIdentity.PortNumber); + xil_printf("\r\nsyncPortID.ClockIdentityUpper = %x",syncPortID.ClockIdentityUpper); + xil_printf("\r\nsyncPortID.ClockIdentityLower = %x",syncPortID.ClockIdentityLower); + xil_printf("\r\nsyncPortID.PortNumber = %x\r\n",syncPortID.PortNumber); +#endif + } +} + + +/****************************************************************************/ +/** +* +* A function to decode a received PTP Follow-up Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_DecodeRxFollowUp(XAvb * InstancePtr, + u32 PtpFrameBaseAddr) { + + XAvb_PortIdentity followUpPortID; + + /** Read sourcePortIdentity from packet */ + XAvb_GetPortIdentity(InstancePtr->Config.BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_PORTID_UPPER_OFFSET, &followUpPortID); + + /** Only decode if configured for a slave and if SA is that of the RTC + * Clock Master */ + if ( (InstancePtr->CurrentBmc.IAmTheRtcMaster == 0) && + XAvb_ComparePortIdentity(InstancePtr->Config.BaseAddress, + InstancePtr->CurrentBmc.SourcePortIdentity, + followUpPortID) ) { + + /** Capture the Follow Up SequenceID */ + InstancePtr->SequenceIdRecords.FollowUpSequenceId + = XAvb_ReorderWord(XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_SEQUENCEID_OFFSET)) + >> 16; + + /** SequenceID in Follow Up Frame should always match that of the + * Sync Frame */ + if (InstancePtr->SequenceIdRecords.FollowUpSequenceId + == InstancePtr->SequenceIdRecords.SyncSequenceId) { + + /** Capture the correction field from follow up frame */ + InstancePtr->PtpRecords.MasterCorrectionField + = XAvb_ReorderWord(XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_CORRECTION_FIELD_OFFSET)); + + /** Perform the Course RTC Offset correction for every Sync / + * FollowUp pair */ + XAvb_CalcRtcOffset(InstancePtr, + PtpFrameBaseAddr); + + /** Every n Sync / FollowUp pairs, we are going to calculate a + * corrected increment rate of RTC */ + if ((InstancePtr->PtpCounters.CounterSyncEvents & 0xF) + == (XAVB_NUM_SYNC_FU_PAIR_CALC_RTC_INCREMENT - 1)) { + + /** Reset the CounterSyncEvents Counter */ + InstancePtr->PtpCounters.CounterSyncEvents = 0x0; + + /** Capture the Sequence ID of the Follow Up frame */ + InstancePtr->SequenceIdRecords.NewSyncSequenceId + = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_SEQUENCEID_OFFSET); + + InstancePtr->SequenceIdRecords.NewSyncSequenceId + = (XAvb_ReorderWord + (InstancePtr->SequenceIdRecords.NewSyncSequenceId) + ) >> 16; + + /** Perform the RTC increment rate adjustment calculation */ + XAvb_UpdateRtcIncrement(InstancePtr); + + /** Sample Sync Frame Time sent (as estimated by the slave) for + * comparison in ten more repetition's time */ + InstancePtr->PtpRecords.OldSlaveTime + = InstancePtr->PtpRecords.NewSlaveTime; + + /** Sample Sync Frame Time sent (as calculated by the master) + * for comparison in ten more repetition's time */ + InstancePtr->PtpRecords.OldMasterTime + = InstancePtr->PtpRecords.NewMasterTime; + + /** Sample the current Follow Up Sequence ID for comparison in + * ten more repetition's time */ + InstancePtr->SequenceIdRecords.OldSyncSequenceId + = InstancePtr->SequenceIdRecords.NewSyncSequenceId; + + } else { + InstancePtr->PtpCounters.CounterSyncEvents + = InstancePtr->PtpCounters.CounterSyncEvents + 1; + } + } else { + xil_printf("SequenceIDs on RxFollowup don't match.\r\n"); + } + } else { + xil_printf("\r\nXAvb_DecodeRxFollowUp()"); + xil_printf("\r\nFollowUp ignored due to unmatched SourcePortID\r\n"); + } +} + + +/****************************************************************************/ +/** +* +* A function to decode a received PDelayResp Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_DecodeRxPDelayResp(XAvb * InstancePtr, + u32 PtpFrameBaseAddr) { + + /** Have we already seen a PDelayResp since the last + * PDelayReq was sent? If so, ignore the packet */ + if( InstancePtr->StateMachineData.rcvdPDelayResp ) { + xil_printf("Error: already saw a PDelayResp since the last PDelayReq was sent\r\n"); + return; + } + + /** Find the ClockIdentity of the Sender */ + XAvb_GetPortIdentity(InstancePtr->Config.BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_PORTID_UPPER_OFFSET, + &InstancePtr->StateMachineData.respPortIdentity); + + /** Is the PDelayResp message from ourself? If so, the Peer + * is most likely a dumb hub and should be considered not + * ASCapable */ + if( XAvb_ComparePortIdentity(InstancePtr->Config.BaseAddress, + InstancePtr->portIdLocal, + InstancePtr->StateMachineData.respPortIdentity) ) { + + XAvb_ChangePeerASCapability(InstancePtr, 0); + + xil_printf("\r\nXAvb_DecodeRxPDelayResp():The peer is no longer ASCapable "); + xil_printf("\r\nXAvb_DecodeRxPDelayResp():Saw a PDelayResp from myself\r\n"); + return; + + } + + /** Capture the requestingPortIdentity */ + XAvb_GetPortIdentity(InstancePtr->Config.BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_REQ_PORTID_UPPER_OFFSET, + &InstancePtr->StateMachineData.respReqPortIdentity); + + /** Capture the PDelayResp SequenceID */ + InstancePtr->SequenceIdRecords.PDelayRespSequenceId = + XAvb_ReorderWord(XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_SEQUENCEID_OFFSET)) >> 16; + + /** Verify that the requestingPortIdentity matches our + * portIdentity */ + if( !XAvb_ComparePortIdentity(InstancePtr->Config.BaseAddress, + InstancePtr->portIdLocal, + InstancePtr->StateMachineData.respReqPortIdentity) ) { + xil_printf("Error: PDelayResp reqPortID doesn't match our portID\r\n"); + return; + } + + /** Only process if the received frame's sequenceId matches + * the sequenceId sent in the last pDelay_Req packet */ + if( (InstancePtr->SequenceIdRecords.PDelayReqSequenceId == + InstancePtr->SequenceIdRecords.PDelayRespSequenceId) ) { + + /** Mark this as a valid PDelayResp packet */ + InstancePtr->StateMachineData.rcvdPDelayResp = 1; + + /** Capture timestamp for receipt time of PDelayReq at Master (t2) */ + InstancePtr->PtpRecords.PDelayTimestampT2 = + XAvb_CaptureNanoSec(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr); + + /** Capture timestamp for receipt time of PDelayResp at Slave (t4) and adjust + * it for MAC receive latency */ + InstancePtr->PtpRecords.PDelayTimestampT4 = + XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_PKT_CAPTURED_TIMESTAMP_OFFSET) + - XAVB_RX_MAC_LATENCY_IN_NS; + } else { + xil_printf("Error: PDelayResp seqID's don't match\r\n"); + } +} + + +/****************************************************************************/ +/** +* +* A function to decode a received PDelayRespFollowUp Packet +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_DecodeRxPDelayRespFollowUp(XAvb * InstancePtr, + u32 PtpFrameBaseAddr) { + + XAvb_PortIdentity portId; + + /** Has a valid PDelayResp packet been received since the + * last PDelayReq packet was sent? */ + if( !InstancePtr->StateMachineData.rcvdPDelayResp ) { + /*xil_printf("Error: Received a PDelayRespFollowUp before receiving a PDelayResp\r\n");*/ + return; + } + + /** Capture the PDelayRespFollowUp SequenceID */ + InstancePtr->SequenceIdRecords.PDelayFollowUpSequenceId = + XAvb_ReorderWord(XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_SEQUENCEID_OFFSET)) >> 16; + + /** Get the sourcePortIdentity of the sender */ + XAvb_GetPortIdentity(InstancePtr->Config.BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_PORTID_UPPER_OFFSET, + &portId); + + /** The sourcePortIdentity of the PDelayRespFollowUp should + * match that of the last PDelayResp packet received */ + if( !XAvb_ComparePortIdentity(InstancePtr->Config.BaseAddress, + portId, + InstancePtr->StateMachineData.respPortIdentity) ) { + xil_printf("Error: sourcePortIdentity of PDelayRespFollowUp doesn't match PDelayResp\r\n"); + return; + } + + /** Get the requestingPortIdentity of the sender */ + XAvb_GetPortIdentity(InstancePtr->Config.BaseAddress, PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_REQ_PORTID_UPPER_OFFSET, + &portId); + + /** The requestingPortIdentity of the PDelayRespFollowUp should + * match that of the last PDelayResp packet received */ + if( !XAvb_ComparePortIdentity(InstancePtr->Config.BaseAddress, + portId, + InstancePtr->StateMachineData.respReqPortIdentity) ) { + xil_printf("Error: reqPortID of PDelayRespFollowUp doesn't match PDelayResp\r\n"); + return; + } + + /** SequenceID of PDelayRespFollowUp Frame should always match that of + * the PDelayResp Frame and the original PDelayReq Frame. */ + if (InstancePtr->SequenceIdRecords.PDelayFollowUpSequenceId == + InstancePtr->SequenceIdRecords.PDelayRespSequenceId) { + + /** Mark this as a valid PDelayRespFollowUp packet */ + InstancePtr->StateMachineData.rcvdPDelayRespFollowUp = 1; + + /** Capture the timestamp for transmit time of PDelayResp at Master + * (t3) */ + InstancePtr->PtpRecords.PDelayTimestampT3 = + XAvb_CaptureNanoSec(InstancePtr->Config.BaseAddress, PtpFrameBaseAddr); + + /** Now we know t1, t2, t3 and t4, calculate the link delay */ + XAvb_CalcDelay(InstancePtr); + + } else { + xil_printf("Error: seqID of PDelayRespFollowUp doesn't match PDelayResp\r\n"); + } +} + +/****************************************************************************/ +/** +* +* A function to decode a received Signalling Packet and modify the TX PTP +* Buffers based on the requested values. +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param PtpFrameBaseAddr is the base address of the received Signaling Packet +* in the Rx PTP Packet Buffer +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_DecodeRxSignaling(XAvb * InstancePtr, u32 PtpFrameBaseAddr) { + + u32 ReadData; + char currentInterval; + + /** Read the requested logMeanMessage durations from the Signalling frame */ + ReadData = XAvb_ReorderWord(XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_SIGNALING_DELAY_INTERVAL_OFFSET)); + + /** update linkDelayInterval */ + currentInterval = (ReadData >> 24); + switch( currentInterval ) { + case (-128): + /** don't change the interval */ + break; + /** currently only support the default value */ + case XAVB_DEFAULT_LOG_MEAN_PDELAY_REQ_INTERVAL: + case 126: + /** set the interval to initial value */ + InstancePtr->SignallingFrameData.LinkDelayIntervalDuration = + XAvb_UpdateIntervalDuration(InstancePtr->SignallingFrameData.LinkDelayIntervalDuration, + XAVB_DEFAULT_LOG_MEAN_PDELAY_REQ_INTERVAL); + + /** Update logMeanMessageInterval in the pre-loaded TX PDELAYREQ message buffer */ + XAvb_UpdateLogMeanMessageInterval(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PDELAYREQ_OFFSET, + InstancePtr->SignallingFrameData.LinkDelayIntervalDuration); + break; + case 127: + /** stop sending pDelay messages */ + InstancePtr->SignallingFrameData.LinkDelayIntervalDuration = XAVB_PKT_TYPE_DISABLED; + break; + default: + xil_printf( "Got a signalling message with an interval (%d) I don't support!\r\n", currentInterval); + } + + /** update timeSyncInterval */ + currentInterval = (ReadData >> 16); + switch( currentInterval ) { + case (-128): + /** don't change the interval */ + break; + case XAVB_DEFAULT_LOG_MEAN_SYNC_INTERVAL: + case 126: + /** set the interval to initial value */ + InstancePtr->SignallingFrameData.SyncIntervalDuration = + XAvb_UpdateIntervalDuration(InstancePtr->SignallingFrameData.SyncIntervalDuration, + XAVB_DEFAULT_LOG_MEAN_SYNC_INTERVAL); + + /** Update logMeanMessageInterval in the pre-loaded TX SYNC message buffer */ + XAvb_UpdateLogMeanMessageInterval(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_SYNC_OFFSET, + InstancePtr->SignallingFrameData.SyncIntervalDuration); + /** Update logMeanMessageInterval in the pre-loaded TX FOLLOW_UP message buffer */ + XAvb_UpdateLogMeanMessageInterval(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_FOLLOW_UP_OFFSET, + InstancePtr->SignallingFrameData.SyncIntervalDuration); + break; + case 127: + /** stop sending sync messages */ + InstancePtr->SignallingFrameData.SyncIntervalDuration = XAVB_PKT_TYPE_DISABLED; + break; + default: + xil_printf( "Got a signalling message with an interval (%d) I don't support!\r\n", currentInterval); + } + + /** update announceInterval */ + currentInterval = (ReadData >> 8); + switch( currentInterval ) { + case (-128): + /** don't change the interval */ + break; + case XAVB_DEFAULT_LOG_MEAN_ANNOUNCE_INTERVAL: + case 126: + /** set the interval to initial value */ + InstancePtr->SignallingFrameData.AnnounceIntervalDuration = + XAvb_UpdateIntervalDuration(InstancePtr->SignallingFrameData.AnnounceIntervalDuration, + XAVB_DEFAULT_LOG_MEAN_ANNOUNCE_INTERVAL); + + /** Update logMeanMessageInterval in the pre-loaded TX ANNOUNCE message buffer */ + XAvb_UpdateLogMeanMessageInterval(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + InstancePtr->SignallingFrameData.AnnounceIntervalDuration); + break; + case 127: + /** stop sending Announce messages */ + InstancePtr->SignallingFrameData.AnnounceIntervalDuration = XAVB_PKT_TYPE_DISABLED; + break; + default: + xil_printf( "Got a signalling message with an interval (%d) I don't support!\r\n", currentInterval); + } +} + + +/****************************************************************************/ +/** +* +* A function to update a PTP message Interval Duration (defined as a +* fraction of 128 seconds). If the endpoint cannot support a requested +* logMeanVal then do not perform the conversion - return the current value. +* +* @param currentIntervalDuration is the Interval Duration to be updated +* @param logMeanVal is the base2 value that is to be converted +* +* @return logMeanVal represented as a fraction of 128 +* +* @note This endpoint only supports logMeanValues >=-7 and <=8. +* +*****************************************************************************/ +u16 XAvb_UpdateIntervalDuration(u16 currentIntervalDuration, + char logMeanVal) { + + if((logMeanVal >= XAVB_MIN_SUPPORTED_LOG_MEAN_INTERVAL) && + (logMeanVal <= XAVB_MAX_SUPPORTED_LOG_MEAN_INTERVAL)) { + + return XAvb_ConvertLogMeanToDuration(logMeanVal); + + } else { + + return currentIntervalDuration; + + } +} + + +/****************************************************************************/ +/** +* +* A function to convert a logMean (power of 2) value into a fraction of 128 +* that is compatible with Signalling data. +* +* @param logMeanVal is the base2 value that is to be converted + +* @return logMeanVal represented as a fraction of 128 +* +* @note None. +* +*****************************************************************************/ +u16 XAvb_ConvertLogMeanToDuration(char logMeanVal) { + + u8 logMeanAbs; + + logMeanAbs = (u8)(abs(logMeanVal)); + + return (logMeanVal < 0) ? + (128 >> logMeanAbs) : + (logMeanVal > 0) ? + (128 << logMeanAbs) : + 128; +} + +/****************************************************************************/ +/** +* +* A function to convert a fraction of 128 value that is compatible with +* Signalling data into a logMean (power of 2) value; +* +* @param fractionalVal is the Signalling data value that is to be converted + +* @return fractionalVal represented as logMean (power of 2) value +* +* @note None. +* +*****************************************************************************/ +char XAvb_ConvertDurationToLogMean(u16 fractionalVal) { + + char logMeanVal = 0; + u8 numShifts = 0; + + /** just in case fractionalVal is not a power of 2, we'll + * only look at the most significant bit + * Count how many shifts it takes for most significant set bit + * to be in the highest (16th) bit location + */ + while( !(fractionalVal & 0x8000) ) { + fractionalVal <<= 1; + numShifts++; + } + + /** logMeanVal = 0 = 2^0 = 128/128 would give us a numShifts + * result of 8, so 8 will be our base + */ + logMeanVal = 8 - numShifts; + + return logMeanVal; +} + +/****************************************************************************/ +/** +* +* A function to update the logMeanMessageInterval field in a PTP packet +* +* @param BaseAddress is the base address of the device +* @param PtpFrameBaseAddr is the base address of the TX PTP Buffer to be updated +* @param intervalDuration is the "fraction of 128" value of the data to be written +* +* @return None. But the relevant Tx PTP Packet Buffer is written to with the +* updated logMeanMessageInterval +* +* @note None. +* +*****************************************************************************/ +void XAvb_UpdateLogMeanMessageInterval(u32 BaseAddress, + u32 PtpFrameBaseAddr, + u16 intervalDuration) { + + u32 ReadVal; + u8 logMean; + + /** Convert intervalDuration to a logMean value */ + logMean = (u8)XAvb_ConvertDurationToLogMean(intervalDuration); + + /** Read the current fields */ + ReadVal = XAvb_ReadPtpBuffer(BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET); + + /** Update just the logMeanMessageInterval field */ + ReadVal = (ReadVal & 0x00ffffff) | (logMean << 24); + + /** Write back */ + XAvb_WritePtpBuffer(BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_TX_PKT_SEQUENCEID_OFFSET, + ReadVal); +} + +/****************************************************************************/ +/** +* +* This function updates the portIdLocal local copy of the sourcePortIdentity +* and writes this value into the TX PTP frame buffer templates. The fields +* that are written are: +* o sourcePortIdentity for all default PTP frames +* o Announce:: grandmasterIdentity +* o Announce:: TLV clockIdentity +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param systemIdentity is the clockIdentity and portNumber for this endpoint +* +* @return None. +* +* @note Announce::TLV. By default the tlvType and length field are set +* up in the BRAM, assuming that N = 1. +* +****************************************************************************/ +void XAvb_SetupSourcePortIdentity(XAvb * InstancePtr, + XAvb_PortIdentity systemIdentity) +{ + u32 BufferWord; + u8 BufferEnable; + u32 DataBitEnable; + u32 ReadWord; + + /* Set up our local copy of the sourcePortIdentity */ + InstancePtr->portIdLocal = systemIdentity; + + /** Write the sourcePortIdentity into the header for all TX PTP buffers + * except the empty default buffer AND write the GMID for TX announce AND + * Write the ClockIdentity into the TX Announce TLV */ + BufferEnable = 0x7F; + + /** (a) Write the upper 2 bytes of the ClockIdentityUpper + * - REM: Swap back the byte order into frame storage order */ + DataBitEnable = 0xFFFF0000; + BufferWord = (systemIdentity.ClockIdentityUpper >> 16); + BufferWord = XAvb_ReorderWord(BufferWord); + + XAvb_WriteToMultipleTxPtpFrames(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PKT_PORTID_UPPER_OFFSET, + BufferWord, + DataBitEnable, + BufferEnable); + + ReadWord = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + XAVB_PTP_TX_PKT_ANNOUNCE_TLVLEN_PATHSEQ_START_OFFSET); + + BufferWord = (ReadWord & 0x0000FFFF) | (BufferWord & 0xFFFF0000); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + XAVB_PTP_TX_PKT_ANNOUNCE_TLVLEN_PATHSEQ_START_OFFSET, + BufferWord); + + /** (b) Write the lower 2 bytes of the ClockIdentityUpper and upper + * 2 bytes of the ClockIdentityLower. + * - REM: Swap back the byte order into frame storage order*/ + BufferWord = ((systemIdentity.ClockIdentityUpper << 16) & 0xFFFF0000) | ((systemIdentity.ClockIdentityLower >> 16) & 0x0000FFFF); + BufferWord = XAvb_ReorderWord(BufferWord); + DataBitEnable = 0xFFFFFFFF; + + XAvb_WriteToMultipleTxPtpFrames(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PKT_PORTID_MID_OFFSET, + BufferWord, + DataBitEnable, + BufferEnable); + + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + (XAVB_PTP_TX_PKT_ANNOUNCE_TLVLEN_PATHSEQ_START_OFFSET + 4), + BufferWord); + + /** (c) Write the lower 2 bytes of the ClockIdentityLower and the portNumber + * - REM: Swap back the byte order into frame storage order*/ + BufferWord = ((systemIdentity.ClockIdentityLower << 16) & 0xFFFF0000) | (systemIdentity.PortNumber & 0x0000FFFF); + BufferWord = XAvb_ReorderWord(BufferWord); + + XAvb_WriteToMultipleTxPtpFrames(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_PKT_PORTID_LOWER_OFFSET, + BufferWord, + DataBitEnable, + BufferEnable); + + BufferWord = (systemIdentity.ClockIdentityLower << 16) & 0xFFFF0000; + BufferWord = XAvb_ReorderWord(BufferWord); + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + (XAVB_PTP_TX_PKT_ANNOUNCE_TLVLEN_PATHSEQ_START_OFFSET + 8), + BufferWord); + + + + /** Write the grandmasterIdentity into the header for the TX Announce PTP buffer */ + /** (a) Write 1 byte of GMID (Upper)*/ + BufferWord = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + XAVB_PTP_TX_PKT_ANNOUNCE_QUAL_LOW_PRI2_GMID_HI_OFFSET); + + BufferWord = (BufferWord & 0x00FFFFFF) | (systemIdentity.ClockIdentityUpper & 0xFF000000); + + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + XAVB_PTP_TX_PKT_ANNOUNCE_QUAL_LOW_PRI2_GMID_HI_OFFSET, + BufferWord); + + /** (b) Write 3 bytes of GMID (Upper) and 1 byte of GMID (Lower)**/ + BufferWord = (systemIdentity.ClockIdentityUpper << 8) | ((systemIdentity.ClockIdentityLower >> 24) & 0x000000FF); + BufferWord = XAvb_ReorderWord(BufferWord); + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + XAVB_PTP_TX_PKT_ANNOUNCE_GMID_MID_OFFSET, + BufferWord); + + /** (c) Write 3 bytes of GMID (Lower) */ + BufferWord = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + XAVB_PTP_TX_PKT_ANNOUNCE_GMID_LOW_STEPSREMOVED_HI_OFFSET); + + BufferWord = ((BufferWord >> 24) & 0x000000FF) | ((systemIdentity.ClockIdentityLower << 8) & 0xFFFFFF00); + BufferWord = XAvb_ReorderWord(BufferWord); + XAvb_WritePtpBuffer(InstancePtr->Config.BaseAddress, + XAVB_PTP_TX_ANNOUNCE_OFFSET, + XAVB_PTP_TX_PKT_ANNOUNCE_GMID_LOW_STEPSREMOVED_HI_OFFSET, + BufferWord); + + +#ifdef DEBUG_XAVB_LEVEL2 + xil_printf("\r\n setupSourcePortIdentity: Writing systemIdentity to buffers %08x", BufferEnable); + xil_printf("\r\n setupSourcePortIdentity: ClockIdentityUpper --> 0x%08x, ClockIdentityLower --> 0x%08x, PortNumber --> 0x%08x", + InstancePtr->portIdLocal.ClockIdentityUpper, + InstancePtr->portIdLocal.ClockIdentityLower, + InstancePtr->portIdLocal.PortNumber); +#endif +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_rtc_sync.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_rtc_sync.c new file mode 100644 index 00000000..3f2dcb10 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/avb/xavb_rtc_sync.c @@ -0,0 +1,640 @@ +/****************************************************************************** +* +* Copyright (C) 2008 - 2014 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/******************************************************************************/ +/*** +* +* @file xavb_rtc_sync.c +* +* The XAvb driver. Functions in this file all contain calculations which are +* essential for the AVB (1588 based) Real Time Clock (RTC) Sychronisation. In +* here are functions to measure the Link Delay (Master and Slave); to measure +* and correct the current RTC error (Slave); to measure and correct the current +* RTC increment rate error. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ----------------------------------------------- +* 1.00a mbr 09/19/08 First release +* 1.01a mbr 06/24/09 PTP frame format updates for IEEE802.1 AS draft 5-0 +* 2_02a mbr 09/16/09 Updates for programmable PTP timers +* 2_04a kag 07/23/10 PTP frame format updates for IEEE802.1 AS draft 6-7 +* 3_01a kag 08/29/11 Added new APIs to update the RX Filter Control Reg. +* Fix for CR:572539. Updated bit map for Rx Filter +* control reg. +* +*+* +******************************************************************************/ + +/****************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xavb_hw.h" +#include "xavb.h" + +/*************************** Constant Definitions *****************************/ + +/***************************** Type Definitions *******************************/ + +/****************** Macros (Inline Functions) Definitions *********************/ + +/*************************** Variable Definitions *****************************/ + +/*************************** Function Prototypes ******************************/ + +/******************************************************************************/ + +/*****************************************************************************/ +/*** +* +* A function to capture the nanosecond timestamp field from a received PTP frame +* +* @param BaseAddress is the base address of the device +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* +* @return The Nanoseconds Timestamp field, captured from an Rx PTP frame +* +* @note None. +* +*****************************************************************************/ +u32 XAvb_CaptureNanoSec(u32 BaseAddress, u32 PtpFrameBaseAddr) { + u32 Timestamp = 0; + u32 BufferWordA = 0; + u32 BufferWordB = 0; + + /** The timestamp is located over several 32-bit Words of the PTP frame buffer + * Read the relevant Words containing the ns timestamp: */ + BufferWordA = XAvb_ReadPtpBuffer(BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_TIMESTAMP_MID_OFFSET); + + BufferWordB = XAvb_ReadPtpBuffer(BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_TIMESTAMP_LOWER_OFFSET); + + /** Now re-arrange the data from the Words to obtain the required ns Timestamp + * in binrary format */ + Timestamp = (XAvb_ReorderWord(BufferWordA)<<16) | + (XAvb_ReorderWord(BufferWordB)>>16); + + return Timestamp; + +} + + +/*****************************************************************************/ +/*** +* +* A function to Measure the Link Delay of the local full-duplex Ethernet link +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XAvb_CalcDelay(XAvb * InstancePtr) { + u32 T4MinusT1 = 0; + u32 T3MinusT2 = 0; + u32 Delay = 0; + + /** Since we are only using the nanoseconds field here we need to account for + * wrap. So we add one second to the T4 and T3 terms to ensure that the + * T4MinusT1 and T3MinusT2 results cannot be negative. These two additional + * seconds then cancel each other out in the T4MinusT1 - T3MinusT2 equation. + */ +#ifdef DEBUG_XAVB_LEVEL2 + xil_printf("\r\nXAvb_CalcDelay()"); + xil_printf("\r\nt1 %x ", InstancePtr->PtpRecords.PDelayTimestampT1); + xil_printf("\r\nt2 %x ", InstancePtr->PtpRecords.PDelayTimestampT2); + xil_printf("\r\nt3 %x ", InstancePtr->PtpRecords.PDelayTimestampT3); + xil_printf("\r\nt4 %x ", InstancePtr->PtpRecords.PDelayTimestampT4); +#endif + + /** If the nanoseconds count has wrapped, add on 1 second to ensure we get the right answer*/ + if (InstancePtr->PtpRecords.PDelayTimestampT4 < InstancePtr->PtpRecords.PDelayTimestampT1) { + T4MinusT1 = (InstancePtr->PtpRecords.PDelayTimestampT4 + XAVB_ONE_SECOND) + - InstancePtr->PtpRecords.PDelayTimestampT1; + } else { + T4MinusT1 = InstancePtr->PtpRecords.PDelayTimestampT4 + - InstancePtr->PtpRecords.PDelayTimestampT1; + } + /** If the nanoseconds count has wrapped, add on 1 second to ensure we get the right answer*/ + if (InstancePtr->PtpRecords.PDelayTimestampT3 < InstancePtr->PtpRecords.PDelayTimestampT2) { + T3MinusT2 = (InstancePtr->PtpRecords.PDelayTimestampT3 + XAVB_ONE_SECOND) + - InstancePtr->PtpRecords.PDelayTimestampT2; + } else { + T3MinusT2 = InstancePtr->PtpRecords.PDelayTimestampT3 + - InstancePtr->PtpRecords.PDelayTimestampT2; + } + + Delay = (T4MinusT1 - T3MinusT2) >> 1; + + /** For now we are simply going to throw out any absurdly large link delays.*/ + if (Delay < XAVB_NEIGHBOR_PROP_DELAY_THRESH ) { + + InstancePtr->PtpRecords.LinkDelay = Delay; + + /** The peer has responded to the pDelay_Req and the measured delay is + * within tolerance: the peer is deemed to be AS capable */ + XAvb_ChangePeerASCapability(InstancePtr, 1); + + } else { + xil_printf("\r\n Bad Link Delay %d ", Delay); +#ifdef DEBUG_XAVB_LEVEL2 + xil_printf("\r\nXAvb_CalcDelay()"); + xil_printf("\r\nt1 %x ", InstancePtr->PtpRecords.PDelayTimestampT1); + xil_printf("\r\nt2 %x ", InstancePtr->PtpRecords.PDelayTimestampT2); + xil_printf("\r\nt3 %x ", InstancePtr->PtpRecords.PDelayTimestampT3); + xil_printf("\r\nt4 %x ", InstancePtr->PtpRecords.PDelayTimestampT4); + xil_printf("\r\nLinkDelay %x ", InstancePtr->PtpRecords.LinkDelay); +#endif + } +} + + +/*****************************************************************************/ +/*** +* +* A function to calculate the Slave Offset from the GrandMaster time +* +* @param InstancePtr is a pointer to the XAvb instance to be worked on +* @param PtpFrameBaseAddr is the base address of the received Announce Packet +* in the Rx PTP Packet Buffer +* +* @return The PtpRecords data structure is updated with the calculated RTC +* Offset value. +* +* @note None. +* +*****************************************************************************/ +void XAvb_CalcRtcOffset (XAvb * InstancePtr, + u32 PtpFrameBaseAddr) { + + u32 MasterNanosec = 0; + u32 MasterSeconds = 0; + u32 MasterEpoch = 0; + + u32 SyncRouteDelay = 0; + u32 MasterNsCorrected = 0; + u32 MasterNsHasWrapped = 0; + + u32 SlaveNsTimestamp = 0; + XAvb_RtcFormat RtcError; + + u32 BufferWordA = 0; + u32 BufferWordB = 0; + + XAvb_RtcFormat SlaveRtc; + + + /** Capture the Slave Time + * ---------------------------- + * We do this immediately to get the slave time ASAP (since processing + * time is uncertain and the RTC does not stand still). */ + XAvb_ReadRtc(InstancePtr->Config.BaseAddress, &SlaveRtc); + + + /** Capture the Master Origin Timestamp (from received FollowUp Frame) + * ---------------------------- */ + MasterNanosec = XAvb_CaptureNanoSec(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr); + + /** read the Words from the PTP frame buffer containing the RTC seconds field + */ + BufferWordA = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_TIMESTAMP_UPPER_OFFSET); + + BufferWordB = XAvb_ReadPtpBuffer(InstancePtr->Config.BaseAddress, + PtpFrameBaseAddr, + XAVB_PTP_RX_PKT_TIMESTAMP_MID_OFFSET); + + /** Now re-arrange the required data from the Words to obtain the required + * seconds field timestamp in binary format */ + MasterSeconds = (XAvb_ReorderWord(BufferWordA) << 16) | + (XAvb_ReorderWord(BufferWordB) >> 16); + + MasterEpoch = XAvb_ReorderWord(BufferWordA) >> 16; + + + + /** Correct the Nanoseconds + * ---------------------------- + * NOTE: we are trying to compare the value of the slave RTC nano- + * seconds field timestamp with the nano-seconds value of the Masters + * RTC nanosecond field at exactly that time. + * + * + * Sync Frame routing delay is equal to the value of the correction + * field (sum of correction fields in Sync and FollowUp frames) plus + * the link delay measurement made by this slave. + */ + SyncRouteDelay = InstancePtr->PtpRecords.MasterCorrectionField + + InstancePtr->PtpRecords.LinkDelay; + + /** MasterNsCorrected time here is the calculated time that the + * master will be at the point in time when the sync frame is received + * (and timestamped) at the slave. This is calculated from the + * originTimeStamp (from the FollowUpframe), plus the Sync Frame + * routing delay. A direct comparison can then be made between master + * and slave. + */ + MasterNsCorrected = MasterNanosec + SyncRouteDelay; + + /** Check for ns wrap-around condition */ + if (MasterNsCorrected >= XAVB_ONE_SECOND) { + MasterNsCorrected = MasterNsCorrected - XAVB_ONE_SECOND; + MasterNsHasWrapped = 1; + } + + + /** Make the Master and Slave comparison and discover the difference! */ + RtcError.NanoSeconds = MasterNsCorrected + - InstancePtr->PtpRecords.SlaveSyncTimestamp; + + /** Check for ns wrap-around condition */ + if (RtcError.NanoSeconds >= XAVB_ONE_SECOND) { + RtcError.NanoSeconds = RtcError.NanoSeconds + XAVB_ONE_SECOND; + } + + + /** Return these comparison figures in the form of a pointer (RTC + * increment rate adjust function also needs to know this information) */ + InstancePtr->PtpRecords.NewSlaveTime + = InstancePtr->PtpRecords.SlaveSyncTimestamp; + + InstancePtr->PtpRecords.NewMasterTime = MasterNsCorrected; + + + /** Adjust the 8k clock logic (if necessary) */ + XAvb_Adjust8kClock(InstancePtr->Config.BaseAddress, RtcError.NanoSeconds); + + + + /** Correct the Seconds and Epoch + * ----------------------------- + * NOTE: we are trying to compare the value of the slave RTC seconds + * field at the exact time when the timestamp was taken with the + * RTC seconds value of the Master at that time. + * + * + * We need to know the value of the slaves synchronised nano-seconds + * field at the time when the timestamp was taken (since timestamps + * use the syntonised time). So we add the current nanosecond field + * offset value: + */ + SlaveNsTimestamp = InstancePtr->PtpRecords.SlaveSyncTimestamp + + XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_NANOSEC_OFFSET); + + /** Check for ns wrap-around condition */ + if (SlaveNsTimestamp >= XAVB_ONE_SECOND) { + SlaveNsTimestamp = SlaveNsTimestamp - XAVB_ONE_SECOND; + } + + /** Even though we read the slave RTC value at the beginning of this + * function, there would have been processing delay between the + * actual reception (and timestamping) of the FollowUp frame and the + * start of this function. During this time, the slave RTC seconds + * field could have wrapped around. We need to detect this and if it + * has done, the slave seconds field would also have incremented (so + * it needs to be set back). + */ + if (SlaveRtc.NanoSeconds < SlaveNsTimestamp) { + /** slave_nanosec has wrapped since timestamp so decrement the + * seconds field */ + if (SlaveRtc.SecondsLower == 0x00000000) { + SlaveRtc.SecondsUpper = SlaveRtc.SecondsUpper - 0x1; + } + SlaveRtc.SecondsLower = SlaveRtc.SecondsLower - 0x1; + } + + + /** If the Master nano seconds field wrapped during the Sync frame + * routing delay, then we need to increment the seconds field. + */ + if (MasterNsHasWrapped == 1) { + if (MasterSeconds == 0xFFFFFFFF) { + MasterEpoch = MasterEpoch + 0x1; + } + MasterSeconds = MasterSeconds + 0x1; + } + + + /** Calculate the slave RTC error: the master time minus the timestamp + * taken by this slave for Sync Frame reception. */ + RtcError.SecondsLower = MasterSeconds - SlaveRtc.SecondsLower; + RtcError.SecondsUpper = MasterEpoch - SlaveRtc.SecondsUpper; + + +#ifdef DEBUG_XAVB_LEVEL2 + if (RtcError.SecondsLower != 0) { + xil_printf("\r\nXAvb_CalcRtcOffset()"); + xil_printf("\r\n-- Seconds Field Correction"); + xil_printf("\r\nSlaveNsTimestamp : %x" , SlaveNsTimestamp); + xil_printf("\r\nslave_ns : %x", SlaveRtc.NanoSeconds); + xil_printf("\r\n--"); + xil_printf("\r\nread slave seconds : %x", + XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_SEC_LOWER_VALUE_OFFSET)); + + xil_printf("\r\ncalc slave secs : %x", SlaveRtc.SecondsLower); + xil_printf("\r\n--"); + xil_printf("\r\nmaster sec wrap : %x" , MasterNsHasWrapped); + xil_printf("\r\ncalc master_secs : %x" , MasterSeconds); + xil_printf("\r\nrtc_sec_error : %x" , RtcError.SecondsLower); + xil_printf("\r\n--"); + } +#endif + + + /** Write the results to the RTC Offset registers + * --------------------------------------------- */ + XAvb_WriteRtcOffset(InstancePtr->Config.BaseAddress, &RtcError); + +} + + +/*****************************************************************************/ +/*** +* +* A function to Adjust the phase offset of the 8k clock +* +* @param InstancePtr->BaseAddress is the base address of the device +* @param NewOffset is the newly calculated RTC Offset value +* +* @return None. But the devices RTC Phase Adjustment Register is updated +* +* @note None. +* +*****************************************************************************/ +void XAvb_Adjust8kClock (u32 BaseAddress, u32 NewOffset) { + + u32 PreviousOffset = 0; + u32 OffsetChange = 0; + u32 ChangeIn8kPeriods = 0; +#ifdef DEBUG_XAVB_LEVEL2 + u32 Clock8kOffset = 0; +#endif + + /** Read the previous offset */ + PreviousOffset = XAvb_ReadReg(BaseAddress, XAVB_RTC_NANOSEC_OFFSET); + + /** Calculate the change in the previous and current RTC ns offset */ + if (PreviousOffset > NewOffset) { + OffsetChange = PreviousOffset - NewOffset; + } else { + OffsetChange = NewOffset - PreviousOffset; + } + + + /** Is the adjustment "large"? "large" is chosen here to be one 8k + * clock period which is a somewhat arbitrary figure */ + if (OffsetChange > XAVB_PERIOD_8KHZ) { + +#ifdef DEBUG_XAVB_LEVEL2 + Clock8kOffset = XAvb_ReadReg(BaseAddress, XAVB_RTC_8K_OFFSET_OFFSET); + xil_printf("\r\nXAvb_Adjust8kClock()"); + xil_printf("\r\nold ns offset: %x" , PreviousOffset); + xil_printf("\r\nold Clk8kOffset: %x", Clock8kOffset); +#endif + + + /** The value XAVB_PERIOD_8KHZ is one 8k clock period in ns. We divide the + * RTC ns offset change by this to get the offset change in a + * multiple of 8k clock periods, the add 1 so that we always round + * up. Then multiply this by XAVB_PERIOD_8KHZ again so that we are always + * phased aligned to the RTC master (only evey adjust in a multiple + * of 8k periods. + */ + ChangeIn8kPeriods = NewOffset / XAVB_PERIOD_8KHZ; + OffsetChange = (ChangeIn8kPeriods + 1) * XAVB_PERIOD_8KHZ; + + /** Write the results to the 8K clock logic Offset register */ + XAvb_WriteReg(BaseAddress, XAVB_RTC_8K_OFFSET_OFFSET, OffsetChange); + +#ifdef DEBUG_XAVB_LEVEL2 + xil_printf("\r\nXAvb_Adjust8kClock()"); + xil_printf("\r\nnew ns offset: %x" , NewOffset); + xil_printf("\r\nnew Clk8kOffset: %x", OffsetChange); +#endif + + } +} + + +/*****************************************************************************/ +/*** +* +* A function to calculate the RTC increment value based on the Slave Error +* +* @return None. But the devices RTC Increment Value Control Register is updated +* +* @note None. +* +*****************************************************************************/ +void XAvb_UpdateRtcIncrement(XAvb * InstancePtr) { + + u32 LoopCount = 31; + u8 SlaveIsFast = 0; + u32 SlaveTimeDuration = 0; + u32 MasterTimeDuration = 0; + u32 SlaveError = 0; + u32 ScaledError = 0; + u32 NormalisedError = 0; + u32 IncrementAdjust = 0; + u32 OldIncrement = 0; + u32 NewIncrement = 0; + + + /** Sanity Check that Sync Frames were n apart. This safeguards the + * calculation against the ethernet cable being pulled out and then + * replaced, etc. */ + if ( ((InstancePtr->SequenceIdRecords.OldSyncSequenceId + + XAVB_NUM_SYNC_FU_PAIR_CALC_RTC_INCREMENT) & 0xFFFF) == + InstancePtr->SequenceIdRecords.NewSyncSequenceId ) { + +#ifdef DEBUG_XAVB_LEVEL2 + xil_printf("\r\nXAvb_UpdateRtcIncrement(): Debug...(a)"); + xil_printf("\r\nNewMasterTime : %x, %d" , InstancePtr->PtpRecords.NewMasterTime, InstancePtr->PtpRecords.NewMasterTime); + xil_printf("\r\nOldMasterTime : %x, %d" , InstancePtr->PtpRecords.OldMasterTime, InstancePtr->PtpRecords.OldMasterTime); + xil_printf("\r\nNewSlaveTime : %x, %d" , InstancePtr->PtpRecords.NewSlaveTime, InstancePtr->PtpRecords.NewSlaveTime); + xil_printf("\r\nOldSlaveTime : %x, %d\r\n" , InstancePtr->PtpRecords.OldSlaveTime, InstancePtr->PtpRecords.OldSlaveTime); +#endif + + /** Measure the time duration, as measured by the RTC master of the + * M sync delay measurment period. */ + MasterTimeDuration = (InstancePtr->PtpRecords.NewMasterTime + - InstancePtr->PtpRecords.OldMasterTime); + + if (MasterTimeDuration >= XAVB_ONE_SECOND) { + MasterTimeDuration = MasterTimeDuration + XAVB_ONE_SECOND; + } + + /** Measure the time duration, as measured by the RTC slave of the + * M sync delay measurment period. */ + SlaveTimeDuration = (InstancePtr->PtpRecords.NewSlaveTime + - InstancePtr->PtpRecords.OldSlaveTime); + + if (SlaveTimeDuration >= XAVB_ONE_SECOND) { + SlaveTimeDuration = SlaveTimeDuration + XAVB_ONE_SECOND; + } + + /** Therefore calculate the slave error (in ns) */ + SlaveError = MasterTimeDuration - SlaveTimeDuration; + + /** If the slave error is zero, skip the remainder of function. + * (Note : a zero error would otherwise get stuck in the while loop + * further down this function). */ + if (SlaveError != 0) { + + + /** Analyse msb of error signal to see which clock is running fastest */ + if (SlaveError & 0x80000000) { + SlaveIsFast = 1; + SlaveError = SlaveTimeDuration - MasterTimeDuration; + } else { + SlaveIsFast = 0; + } + + /** This check is in addition to the checks described in IEEE802.1as. + * If the SlaveError is unexpectedly large, then set asCapable to 0. + */ + if (SlaveError < XAVB_CLOCK_LOCK_THRESHOLD) { + XAvb_ChangePTPLockStatus(InstancePtr, 1); + } else { + XAvb_ChangePTPLockStatus(InstancePtr, 0); + } + + /** SlaveError signal is 32-bits (ns). This can indicate > 4 sec of + * error: this is too large for 100 ms measurement period. So we + * expect upper bits to be zero. + * + * This function will shift the 1st none zero bit of SlaveError up + * to bit 31, so that forthcoming calculation uses maximum accuracy. + * + * This shift is equivalent to a multiply (of the error signal). A + * shift the opposite way (equivalent to a divide) will follow at + * end of full calculation. */ + + while ( !(SlaveError & (0x1 << LoopCount)) ) { + LoopCount = LoopCount - 1; + } + LoopCount = 31 - LoopCount; + ScaledError = (SlaveError << LoopCount); + + + /** Calculate the relative error: can be thought of as a scaled ratio + * of error per time unit */ + NormalisedError = ScaledError / MasterTimeDuration; + + + /** Obtain the current increment value */ + OldIncrement = (XAvb_ReadReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_INCREMENT_OFFSET) + & XAVB_RTC_INCREMENT_VALUE_MASK); + + + /** Calculate the increment adjustment: multiply NormalisedError by + * the increment time unit. Then shift back the other way to + * correct the calculation (restore to ns). */ + IncrementAdjust = (NormalisedError * OldIncrement) >> LoopCount; + + + /** Now calculate the new increment value */ + if (SlaveIsFast) { + NewIncrement = OldIncrement - IncrementAdjust; + } else { + NewIncrement = OldIncrement + IncrementAdjust; + } + + /** Add some rails so that recovery is possible after a + * string of bad pDelay values. The RTC should be able to lock + * to within 100ppm of the slowest allowable clock (25 MHz). + * This equates to +/-4ps. Let's arbitrarily set the rails to + * 400ppm (+/-16ps) just in case someone decides to use a + * particularly bad oscillator. The lowest 20 bits of + * NewIncrement are fractions of a nanosecond, which equates + * to +/- 0x04189 + */ + if( NewIncrement > (XAVB_RTC_INCREMENT_NOMINAL_RATE + XAVB_RTC_400PPM_OFFSET) ) { + xil_printf("\r\nRTC Exceeded 400ppm offset: Railing to 400ppm\r\n"); + NewIncrement = XAVB_RTC_INCREMENT_NOMINAL_RATE + XAVB_RTC_400PPM_OFFSET; + } + if( NewIncrement < (XAVB_RTC_INCREMENT_NOMINAL_RATE - XAVB_RTC_400PPM_OFFSET) ) { + xil_printf("\r\nRTC Exceeded 400ppm offset: Railing to 400ppm\r\n"); + NewIncrement = XAVB_RTC_INCREMENT_NOMINAL_RATE - XAVB_RTC_400PPM_OFFSET; + } + + /** And write the new increment value! */ + XAvb_WriteReg(InstancePtr->Config.BaseAddress, + XAVB_RTC_INCREMENT_OFFSET, + NewIncrement); + +#ifdef DEBUG_XAVB_LEVEL2 + xil_printf("\r\nXAvb_UpdateRtcIncrement(): Debug..."); + xil_printf("\r\nM Time : %x" , MasterTimeDuration); + xil_printf("\r\nS Time : %x" , SlaveTimeDuration); + xil_printf("\r\nErr : %x %x" , SlaveIsFast, SlaveError); + xil_printf("\r\nScaled : %x" , ScaledError); + xil_printf("\r\nNorm : %x" , NormalisedError); + xil_printf("\r\nAdjust : %x" , IncrementAdjust); + xil_printf("\r\nNew Inc: %x" , NewIncrement); +#endif + + } + } else { + + xil_printf("\r\nXAvb_UpdateRtcIncrement()"); + xil_printf("\r\nERROR: Syncs not %d apart - %d\r\n", + XAVB_NUM_SYNC_FU_PAIR_CALC_RTC_INCREMENT, + InstancePtr->SequenceIdRecords.NewSyncSequenceId - + InstancePtr->SequenceIdRecords.OldSyncSequenceId); + } + + if (SlaveError > 0x2700) { + xil_printf("\r\nXAvb_UpdateRtcIncrement(): Large Error over 100ms"); + xil_printf("\r\nM Time : %x" , MasterTimeDuration); + xil_printf("\r\nS Time : %x" , SlaveTimeDuration); + xil_printf("\r\nErr : %x %x" , SlaveIsFast, SlaveError); + xil_printf("\r\nScaled : %x" , ScaledError); + xil_printf("\r\nNorm : %x" , NormalisedError); + xil_printf("\r\nAdjust : %x" , IncrementAdjust); + xil_printf("\r\nNew Inc: %x" , NewIncrement); +} + +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/index.html b/XilinxProcessorIPLib/drivers/axiethernet/examples/index.html new file mode 100755 index 00000000..1f784aa6 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/index.html @@ -0,0 +1,22 @@ + + + + + +
Copyright � 1995-2014 Xilinx, Inc. All rights reserved.
+ + diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example.h b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example.h new file mode 100644 index 00000000..9b077ab2 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example.h @@ -0,0 +1,124 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2014 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xaxiethernet_example.h +* +* Defines common data types, prototypes, and includes the proper headers +* for use with the Axi Ethernet example code residing in this directory. +* +* This file along with xaxiethernet_example_util.c are utilized with the +* specific example code in the other source code files provided. +* +* These examples are designed to be compiled and utilized within the EDK +* standalone BSP development environment. The readme file contains more +* information on build requirements needed by these examples. +* +*+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a asa 4/30/10 First release based on the ll temac driver +* 3.02a srt 4/26/13 Added function prototype for *_ConfigureInternalPhy(). +* +*+* +******************************************************************************/ +#ifndef XAXIETHERNET_EXAMPLE_H +#define XAXIETHERNET_EXAMPLE_H + + +/***************************** Include Files *********************************/ + +#include "xparameters.h" /* defines XPAR values */ +#include "xaxiethernet.h" /* defines Axi Ethernet APIs */ +#include "stdio.h" /* stdio */ + +/************************** Constant Definitions ****************************/ +#define AXIETHERNET_LOOPBACK_SPEED 100 /* 100Mb/s for Mii */ +#define AXIETHERNET_LOOPBACK_SPEED_1G 1000 /* 1000Mb/s for GMii */ +#define AXIETHERNET_PHY_DELAY_SEC 4 /* + * Amount of time to delay waiting on + * PHY to reset. + */ + +#define MAX_MULTICAST_ADDR (1<<23) /* + * Maximum number of multicast ethernet + * mac addresses. + */ + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/**************************** Type Definitions ******************************/ + +/* + * Define an aligned data type for an ethernet frame. This declaration is + * specific to the GNU compiler + */ +typedef unsigned char EthernetFrame[XAE_MAX_JUMBO_FRAME_SIZE] __attribute__ ((aligned(64))); + + +/************************** Function Prototypes *****************************/ + +/* + * Utility functions implemented in xaxiethernet_example_util.c + */ +void AxiEthernetUtilSetupUart(void); +void AxiEthernetUtilFrameHdrFormatMAC(EthernetFrame * FramePtr, + char *DestAddr); +void AxiEthernetUtilFrameHdrFormatType(EthernetFrame * FramePtr, + u16 FrameType); +void AxiEthernetUtilFrameSetPayloadData(EthernetFrame * FramePtr, + int PayloadSize); +void AxiEthernetUtilFrameHdrVlanFormatVid(EthernetFrame * FramePtr, + u32 VlanNumber,u32 Vid); +void AxiEthernetUtilFrameHdrVlanFormatType(EthernetFrame * FramePtr, + u16 FrameType,u32 VlanNumber); +void AxiEthernetUtilFrameSetVlanPayloadData(EthernetFrame * FramePtr, + int PayloadSize,u32 VlanNumber); +int AxiEthernetUtilFrameVerify(EthernetFrame * CheckFrame, + EthernetFrame * ActualFrame); +void AxiEthernetUtilFrameMemClear(EthernetFrame * FramePtr); +int AxiEthernetUtilEnterLoopback(XAxiEthernet * AxiEthernetInstancePtr, + int Speed); +void AxiEthernetUtilErrorTrap(char *Message); +void AxiEthernetUtilPhyDelay(unsigned int Seconds); +int AxiEthernetUtilConfigureInternalPhy(XAxiEthernet *AxiEthernetInstancePtr, + int Speed); + +/************************** Variable Definitions ****************************/ + +extern char AxiEthernetMAC[]; /* Local MAC address */ + +#endif /* XAXIETHERNET_EXAMPLE_H */ diff --git a/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_extmulticast.c b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_extmulticast.c new file mode 100644 index 00000000..5bce008a --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/examples/xaxiethernet_example_extmulticast.c @@ -0,0 +1,1582 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2014 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xaxiethernet_example_extmulticast.c +* +* Implements examples that utilize the AXI Ethernet's interrupt driven DMA +* packet transfer mode to send and receive multicast frames when +* XAE_EXT_MULTICAST_OPTION is enabled. +* +* This example demonstrates: +* +* - How to perform option enable +* - Which interrupt BD word are verified and confirm it is a valid multicast +* frame. +* +* Functional guide to example: +* +* - AxiEthernetSgDmaIntrExtMulticast Example demonstrates the extended +* multicast. The HW must be setup for extended multicast for this +* example to execute. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a asa 4/30/10 First release based on the ll temac driver +* 1.01a asa 12/10/10 Changes made to enable the AXIDMA Tx/Rx ring interrupts +* before allocation of Tx/Rx BDs. +* 3.00a asa 6/25/12 Modifed XAxiDma_BdSetLength API call to support new +* AXI DMA driver version 7.00a. +* 3.00a bss 10/22/12 Added support for Fast Interrupt Handlers. +* 3.01a srt 02/14/13 Added support for Zynq (CR 681136) +* +*+* +******************************************************************************/ + +#warning "This test requires at least 1MB space in RAM." +#warning "Please make sure required resources are available." + +/***************************** Include Files *********************************/ + +#include "xaxiethernet_example.h" +#include "xaxidma.h" +#include "xil_cache.h" +#include "xil_exception.h" + +#ifdef XPAR_INTC_0_DEVICE_ID +#include "xintc.h" +#else +#include "xscugic.h" +#endif + +#ifdef XPAR_XUARTNS550_NUM_INSTANCES +#include "xuartns550_l.h" +#endif + +/*************************** Constant Definitions ****************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#ifndef TESTAPP_GEN +#define AXIETHERNET_DEVICE_ID XPAR_AXIETHERNET_0_DEVICE_ID +#define AXIDMA_DEVICE_ID XPAR_AXIDMA_0_DEVICE_ID +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define AXIETHERNET_IRPT_INTR XPAR_INTC_0_AXIETHERNET_0_VEC_ID +#define DMA_RX_IRPT_INTR XPAR_AXIETHERNET_0_CONNECTED_DMARX_INTR +#define DMA_TX_IRPT_INTR XPAR_AXIETHERNET_0_CONNECTED_DMATX_INTR +#else +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#define AXIETHERNET_IRPT_INTR XPAR_FABRIC_AXIETHERNET_0_VEC_ID +#define DMA_RX_IRPT_INTR XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID +#define DMA_TX_IRPT_INTR XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID +#endif +#endif + +#define RXBD_CNT 128 /* Number of RxBDs to use */ +#define TXBD_CNT 128 /* Number of TxBDs to use */ +#define BD_ALIGNMENT XAXIDMA_BD_MINIMUM_ALIGNMENT/* Byte alignment of + * BDs + */ +#define PAYLOAD_SIZE 1000 /* Payload size used in examples */ +#define BD_RX_STATUS_OFFSET 2 + +/* + * Number of bytes to reserve for BD space for the number of BDs desired + */ +#define RXBD_SPACE_BYTES XAxiDma_BdRingMemCalc(BD_ALIGNMENT, RXBD_CNT) +#define TXBD_SPACE_BYTES XAxiDma_BdRingMemCalc(BD_ALIGNMENT, TXBD_CNT) + + +/*************************** Variable Definitions ****************************/ + +static EthernetFrame TxFrame; /* Transmit buffer */ +static EthernetFrame RxFrame; /* Receive buffer */ + +XAxiEthernet AxiEthernetInstance; +XAxiDma DmaInstance; + +#if XPAR_INTC_0_HAS_FAST == 1 + +/* Variables for Fast Interrupt Handlers */ +XAxiEthernet *AxiEthernetInstancePtr_Fast; +XAxiDma_BdRing *TxRingPtr_Fast; +XAxiDma_BdRing *RxRingPtr_Fast; + +/****** Fast Interrupt Handlers prototypes ******/ + +static void AxiEthernetErrorFastHandler(void) __attribute__ ((fast_interrupt)); + +static void RxIntrFastHandler(void) __attribute__ ((fast_interrupt)); + +static void TxIntrFastHandler(void) __attribute__ ((fast_interrupt)); + +#else + +static void AxiEthernetErrorHandler(XAxiEthernet *AxiEthernet); +static void RxIntrHandler(XAxiDma_BdRing *RxRingPtr); +static void TxIntrHandler(XAxiDma_BdRing *TxRingPtr); + +#endif + +/* + * Aligned memory segments to be used for buffer descriptors + */ +char RxBdSpace[RXBD_SPACE_BYTES] __attribute__ ((aligned(BD_ALIGNMENT))); +char TxBdSpace[TXBD_SPACE_BYTES] __attribute__ ((aligned(BD_ALIGNMENT))); + +/* + * Counters to be incremented by callbacks + */ +static volatile int FramesRx; /* Num of frames that have been received */ +static volatile int FramesTx; /* Num of frames that have been sent */ +static volatile int DeviceErrors; /* Num of errors detected in the device */ + +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC XIntc +#define INTC_HANDLER XIntc_InterruptHandler +#else +#define INTC XScuGic +#define INTC_HANDLER XScuGic_InterruptHandler +#endif + +#ifndef TESTAPP_GEN +static INTC IntcInstance; +#endif + +/* + * Multicast MAC address + */ +char MulticastMAC[6] = { 0x01, 0x00, 0x5E, 0x04, 0x05, 0x06 }; + +/* + * Determine how much space for ALL multicast MAC addresses, there are 2**23 + * per RFC1112. Each bit represents an address. The total number of bytes are + * (2**23)/8=2**20=1MB + */ +u32 McastAddressTable[(MAX_MULTICAST_ADDR>>3)/sizeof(u32)]; + +/*************************** Function Prototypes *****************************/ + +/* + * Examples + */ +int AxiEthernetMcastExample(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr, + u16 AxiEthernetDeviceId, + u16 AxiDmaDeviceId, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, + u16 DmaTxIntrId); + +int AxiEthernetSgDmaIntrExtMulticastExample(XAxiEthernet + *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr); + +/* + * Interrupt setup and Callbacks for examples + */ + +static int AxiEthernetSetupIntrSystem(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, u16 DmaTxIntrId); + +static void AxiEthernetDisableIntrSystem(INTC *IntcInstancePtr, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, u16 DmaTxIntrId); + +/* + * Manage functions for Multicast table in RAM + */ +static int AxiEthernet_AddExtMulticast(void *AddressPtr); +static int AxiEthernet_ClearExtMulticast(void *AddressPtr); +static int AxiEthernet_GetExtMulticast(void *AddressPtr); + +/*****************************************************************************/ +/** +* +* This is the main function for the Axi Ethernet example. This function is not +* included if the example is generated from the TestAppGen test tool. +* +* @param None. +* +* @return - XST_SUCCESS to indicate success. +* - XST_FAILURE to indicate failure +* +* @note None. +* +****************************************************************************/ +#ifndef TESTAPP_GEN +int main(void) +{ + int Status; + +#ifdef XPAR_XUARTNS550_NUM_INSTANCES + XUartNs550_SetBaud(STDIN_BASEADDRESS, XPAR_XUARTNS550_CLOCK_HZ, 9600); + XUartNs550_SetLineControlReg(STDIN_BASEADDRESS, XUN_LCR_8_DATA_BITS); +#endif + +#if XPAR_MICROBLAZE_USE_ICACHE + Xil_ICacheInvalidate(); + Xil_ICacheEnable(); +#endif + +#if XPAR_MICROBLAZE_USE_DCACHE + Xil_DCacheInvalidate(); + Xil_DCacheEnable(); +#endif + + AxiEthernetUtilErrorTrap("\r\n--- Enter main() ---"); + AxiEthernetUtilErrorTrap("This test may take several minutes to finish"); + + /* + * Call the Axi Ethernet multicast example. + */ + Status = AxiEthernetMcastExample(&IntcInstance, + &AxiEthernetInstance, + &DmaInstance, + AXIETHERNET_DEVICE_ID, + AXIDMA_DEVICE_ID, + AXIETHERNET_IRPT_INTR, + DMA_RX_IRPT_INTR, + DMA_TX_IRPT_INTR); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Failed test intr sgdma"); + AxiEthernetUtilErrorTrap("--- Exiting main() ---"); + return XST_FAILURE; + } + + AxiEthernetUtilErrorTrap("Test passed"); + AxiEthernetUtilErrorTrap("--- Exiting main() ---"); + + return XST_SUCCESS; + +} +#endif + +/*****************************************************************************/ +/** +* +* This function demonstrates the usage usage of the Axi Ethernet extended +* multicast feature. It uses AXI DMA core in interrupt mode to transfer Ethernet +* frames. +* +* +* @param IntcInstancePtr is a pointer to the instance of the Intc +* component. +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param DmaInstancePtr is a pointer to the instance of the AXIDMA +* component. +* @param AxiEthernetDeviceId is Device ID of the Axi Ethernet Device , +* typically XPAR_
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a asa 4/30/10 First release based on the ll temac driver +* 1.01a asa 12/10/10 Changes made to enable the AXIDMA Tx/Rx ring interrupts +* before allocation of Tx/Rx BDs. +* 3.00a asa 6/25/12 Modifed XAxiDma_BdSetLength API call to support new +* AXI DMA driver version 7.00a. +* 3.00a bss 10/22/12 Added support for Fast Interrupt Handlers. +* 3.01a srt 02/14/13 Added support for Zynq (CR 681136) +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xaxiethernet_example.h" +#include "xaxidma.h" +#include "xil_cache.h" +#include "xil_exception.h" + +#ifdef XPAR_INTC_0_DEVICE_ID +#include "xintc.h" +#else +#include "xscugic.h" +#endif + +#ifdef XPAR_XUARTNS550_NUM_INSTANCES +#include "xuartns550_l.h" +#endif +/*************************** Constant Definitions ****************************/ +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#ifndef TESTAPP_GEN +#define AXIETHERNET_DEVICE_ID XPAR_AXIETHERNET_0_DEVICE_ID +#define AXIDMA_DEVICE_ID XPAR_AXIDMA_0_DEVICE_ID +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define AXIETHERNET_IRPT_INTR XPAR_INTC_0_AXIETHERNET_0_VEC_ID +#define DMA_RX_IRPT_INTR XPAR_AXIETHERNET_0_CONNECTED_DMARX_INTR +#define DMA_TX_IRPT_INTR XPAR_AXIETHERNET_0_CONNECTED_DMATX_INTR +#else +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#define AXIETHERNET_IRPT_INTR XPAR_FABRIC_AXIETHERNET_0_VEC_ID +#define DMA_RX_IRPT_INTR XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID +#define DMA_TX_IRPT_INTR XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID +#endif +#endif + +#define RXBD_CNT 128 /* Number of RxBDs to use */ +#define TXBD_CNT 128 /* Number of TxBDs to use */ +#define BD_ALIGNMENT XAXIDMA_BD_MINIMUM_ALIGNMENT/* + * Byte alignment + * of BDs + */ +#define PAYLOAD_SIZE 1000 /* Payload size used in examples */ +#define BD_VLAN_TPID_OFFSET 3 /* AXI4-Stream status Word offset from + * the start of app user words in BD. + * TPID is at status word 3, bits + * 31-16 + */ +#define BD_VLAN_VID_OFFSET 4 /* AXI4-Stream status word offset from + * the start of app user words in BD. + * VID is at status word 4, bits + * 31-16 + */ +#define TPID_MASK 0xFFFF0000 /* Mask to extract TPID from + * the AXI4 STream status + * word + */ + +/* + * Number of bytes to reserve for BD space for the number of BDs desired + */ +#define RXBD_SPACE_BYTES XAxiDma_BdRingMemCalc(BD_ALIGNMENT, RXBD_CNT) +#define TXBD_SPACE_BYTES XAxiDma_BdRingMemCalc(BD_ALIGNMENT, TXBD_CNT) + + +/*************************** Variable Definitions ****************************/ + +static EthernetFrame TxFrame; /* Transmit buffer */ +static EthernetFrame RxFrame; /* Receive buffer */ + +XAxiEthernet AxiEthernetInstance; +XAxiDma DmaInstance; + +#if XPAR_INTC_0_HAS_FAST == 1 + +/* Variables for Fast Interrupt Handlers */ +XAxiEthernet *AxiEthernetInstancePtr_Fast; +XAxiDma_BdRing *TxRingPtr_Fast; +XAxiDma_BdRing *RxRingPtr_Fast; + +/****** Fast Interrupt Handlers prototypes ******/ + +static void AxiEthernetErrorFastHandler(void) __attribute__ ((fast_interrupt)); + +static void RxIntrFastHandler(void) __attribute__ ((fast_interrupt)); + +static void TxIntrFastHandler(void) __attribute__ ((fast_interrupt)); + +#else + +static void AxiEthernetErrorHandler(XAxiEthernet *AxiEthernet); +static void RxIntrHandler(XAxiDma_BdRing *RxRingPtr); +static void TxIntrHandler(XAxiDma_BdRing *TxRingPtr); + +#endif + +/* + * Aligned memory segments to be used for buffer descriptors + */ +char RxBdSpace[RXBD_SPACE_BYTES] __attribute__ ((aligned(BD_ALIGNMENT))); +char TxBdSpace[TXBD_SPACE_BYTES] __attribute__ ((aligned(BD_ALIGNMENT))); + +/* + * Counters to be incremented by callbacks + */ +static volatile int FramesRx; /* Num of frames that have been received */ +static volatile int FramesTx; /* Num of frames that have been sent */ +static volatile int DeviceErrors; /* Num of errors detected in the device */ + +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC XIntc +#define INTC_HANDLER XIntc_InterruptHandler +#else +#define INTC XScuGic +#define INTC_HANDLER XScuGic_InterruptHandler +#endif + +#ifndef TESTAPP_GEN +static INTC IntcInstance; +#endif + +/*************************** Function Prototypes *****************************/ + +/* + * Examples + */ +int AxiEthernetExtVlanExample(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr, + u16 AxiEthernetDeviceId, + u16 AxiDmaDeviceId, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, + u16 DmaTxIntrId); +int AxiEthernetSgDmaIntrExtVlanExample(XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr); + +/* + * Interrupt setup and Callbacks for examples + */ + +static int AxiEthernetSetupIntrSystem(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, u16 DmaTxIntrId); + +static void AxiEthernetDisableIntrSystem(INTC *IntcInstancePtr, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, u16 DmaTxIntrId); + + +/*****************************************************************************/ +/** +* +* This is the main function for the Axi Ethernet example. This function is not +* included if the example is generated from the TestAppGen test tool. +* +* @param None. +* +* @return - XST_SUCCESS to indicate success. +* - XST_FAILURE to indicate failure +* +* @note None. +* +****************************************************************************/ +#ifndef TESTAPP_GEN +int main(void) +{ + int Status; + +#ifdef XPAR_XUARTNS550_NUM_INSTANCES + XUartNs550_SetBaud(STDIN_BASEADDRESS, XPAR_XUARTNS550_CLOCK_HZ, 9600); + XUartNs550_SetLineControlReg(STDIN_BASEADDRESS, XUN_LCR_8_DATA_BITS); +#endif + +#if XPAR_MICROBLAZE_USE_ICACHE + Xil_ICacheInvalidate(); + Xil_ICacheEnable(); +#endif + +#if XPAR_MICROBLAZE_USE_DCACHE + Xil_DCacheInvalidate(); + Xil_DCacheEnable(); +#endif + + AxiEthernetUtilErrorTrap("\r\n--- Enter main() ---"); + AxiEthernetUtilErrorTrap("This test may take several minutes to finish"); + + /* + * Call the Axi Ethernet vlan example main function + */ + Status = AxiEthernetExtVlanExample(&IntcInstance, + &AxiEthernetInstance, + &DmaInstance, + AXIETHERNET_DEVICE_ID, + AXIDMA_DEVICE_ID, + AXIETHERNET_IRPT_INTR, + DMA_RX_IRPT_INTR, + DMA_TX_IRPT_INTR); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Failed test intr sgdma"); + AxiEthernetUtilErrorTrap("--- Exiting main() ---"); + return XST_FAILURE; + } + + AxiEthernetUtilErrorTrap("Test passed"); + AxiEthernetUtilErrorTrap("--- Exiting main() ---"); + + return XST_SUCCESS; + +} +#endif + +/*****************************************************************************/ +/** +* +* This function demonstrates the usage usage of the Axi Ethernet by sending +* and receiving frames in interrupt driven SGDMA mode. +* +* +* @param IntcInstancePtr is a pointer to the instance of the Intc +* component. +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param DmaInstancePtr is a pointer to the instance of the AXIDMA +* component. +* @param AxiEthernetDeviceId is Device ID of the Axi Ethernet Device , +* typically XPAR_
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a asa 4/30/10 First release based on the ll temac driver +* 3.00a bss 10/22/12 Added support for Fast Interrupt Handlers. +* 3.01a srt 02/14/13 Added support for Zynq (CR 681136) +* 3.02a srt 08/06/13 Fixed CR 727634 - +* Modified FifoHandler() logic to reflect the bit +* changes in the Interrupt Status Register as per +* the latest AXI FIFO stream IP. +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xaxiethernet_example.h" +#include "xllfifo.h" +#include "xil_cache.h" +#include "xil_exception.h" + +#ifdef XPAR_INTC_0_DEVICE_ID +#include "xintc.h" +#else +#include "xscugic.h" +#endif + +#ifdef XPAR_XUARTNS550_NUM_INSTANCES +#include "xuartns550_l.h" +#endif +/*************************** Constant Definitions ****************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#ifndef TESTAPP_GEN +#define AXIETHERNET_DEVICE_ID XPAR_AXIETHERNET_0_DEVICE_ID +#define FIFO_DEVICE_ID XPAR_AXI_FIFO_0_DEVICE_ID +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define AXIETHERNET_IRPT_INTR XPAR_INTC_0_AXIETHERNET_0_VEC_ID +#define FIFO_IRPT_INTR XPAR_INTC_0_LLFIFO_0_VEC_ID +#else +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#define AXIETHERNET_IRPT_INTR XPAR_FABRIC_AXIETHERNET_0_VEC_ID +#define FIFO_IRPT_INTR XPAR_FABRIC_LLFIFO_0_VEC_ID +#endif +#endif + +#define PAYLOAD_SIZE 100 /* Payload size used in examples */ +/*************************** Variable Definitions ****************************/ + +static EthernetFrame TxFrame; /* Frame used to send with */ +static EthernetFrame RxFrame; /* Frame used to receive data */ +volatile static int DeferRx = 0; + +/* + * Counters setup to be incremented by callbacks + */ +static volatile int FramesRx; /* Number of received frames */ +static volatile int FramesRxInts; /* Number of ints for received + * frames + */ +static volatile int FramesTxInts; /* Number of ints for sent frames */ +static volatile int DeviceErrors; /* Num of errors detected in + * the device + */ +static volatile int FrameDataErrors; /* Num of times frame data check + * failed + */ +XAxiEthernet AxiEthernetInstance; +XLlFifo FifoInstance; + + +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC XIntc +#define INTC_HANDLER XIntc_InterruptHandler +#else +#define INTC XScuGic +#define INTC_HANDLER XScuGic_InterruptHandler +#endif + +#ifndef TESTAPP_GEN +static INTC IntcInstance; +#endif + +#if XPAR_INTC_0_HAS_FAST == 1 + +/* Variables for Fast Interrupt Handlers */ +XAxiEthernet *AxiEthernetInstancePtr_Fast; +XLlFifo *Fifo_Fast; + +/****** Fast Interrupt Handlers prototypes ******/ + +static void AxiEthernetErrorFastHandler(void) __attribute__ ((fast_interrupt)); + +static void FifoFastHandler(void) __attribute__ ((fast_interrupt)); + +#else + +static void AxiEthernetErrorHandler(XAxiEthernet *AxiEthernet); +static void FifoHandler(XLlFifo *Fifo); + +#endif + + +/*************************** Function Prototypes *****************************/ + +/* + * The different examples given in this file + */ +int AxiEthernetFifoIntrExample(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XLlFifo *FifoInstancePtr, + u16 AxiEthernetDeviceId, + u16 FifoDeviceId, u16 AxiEthernetIntrId, + u16 FifoIntrId); +int AxiEthernetSingleFrameIntrExample(XAxiEthernet *AxiEthernetInstancePtr, + XLlFifo *FifoInstancePtr); +int AxiEthernetSingleFrameNonContIntrExample(XAxiEthernet + *AxiEthernetInstancePtr, XLlFifo *FifoInstancePtr); +int AxiEthernetMultipleFramesIntrExample(XAxiEthernet *AxiEthernetInstancePtr, + XLlFifo *FifoInstancePtr); + + +/* + * The Interrupt setup and callbacks + */ +static int AxiEthernetSetupIntrSystem(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XLlFifo *FifoInstancePtr, + u16 AxiEthernetIntrId, u16 FifoIntrId); +static void AxiEthernetDisableIntrSystem(INTC *IntcInstancePtr, + u16 AxiEthernetIntrId, u16 FifoIntrId); + +static void FifoRecvHandler(XLlFifo *Fifo); + +/* + * Utility routines + */ +static int AxiEthernetResetDevice(XAxiEthernet *AxiEthernetInstancePtr, + XLlFifo *FifoInstancePtr); + + +/*****************************************************************************/ +/** +* +* This is the main function for the Axi Ethernet example. This function is not +* included if the example is generated from the TestAppGen test tool. +* +* @param None. +* +* - XST_SUCCESS to indicate success. +* - XST_FAILURE.to indicate failure. +* @note None. +* +****************************************************************************/ +#ifndef TESTAPP_GEN +int main(void) +{ + int Status; + +#ifdef XPAR_XUARTNS550_NUM_INSTANCES + XUartNs550_SetBaud(STDIN_BASEADDRESS, XPAR_XUARTNS550_CLOCK_HZ, 9600); + XUartNs550_SetLineControlReg(STDIN_BASEADDRESS, XUN_LCR_8_DATA_BITS); +#endif +#if XPAR_MICROBLAZE_USE_ICACHE + Xil_ICacheInvalidate(); + Xil_ICacheEnable(); +#endif + +#if XPAR_MICROBLAZE_USE_DCACHE + Xil_DCacheInvalidate(); + Xil_DCacheEnable(); +#endif + + AxiEthernetUtilErrorTrap("\r\n--- Enter main() ---"); + AxiEthernetUtilErrorTrap("This test may take several minutes to finish"); + + + /* + * Call the Axi Ethernet interrupt example , specify the parameters + * generated in xparameters.h + */ + Status = AxiEthernetFifoIntrExample(&IntcInstance, + &AxiEthernetInstance, + &FifoInstance, + AXIETHERNET_DEVICE_ID, + FIFO_DEVICE_ID, + AXIETHERNET_IRPT_INTR, FIFO_IRPT_INTR); + + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Failed test intr fifo"); + } else { + AxiEthernetUtilErrorTrap("Test passed"); + } + + AxiEthernetUtilErrorTrap("--- Exiting main() ---"); + + + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} +#endif + + + +/*****************************************************************************/ +/** +* +* This function demonstrates the usage usage of the Axi Ethernet by sending +* and receiving frames in interrupt driven fifo mode. +* +* +* @param IntcInstancePtr is a pointer to the instance of the Intc +* component. +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* Axi Ethernet component. +* @param FifoInstancePtr is a pointer to the instance of the AXIFIFO +* component. +* @param AxiEthernetDeviceId is Device ID of the Axi Ethernet Device , +* typically XPAR_
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a asa 4/30/10 First release based on the ll temac driver +* 1.01a asa 12/10/10 Added full checksum offload example. +* Changes made to enable the AXIDMA Tx/Rx ring interrupts +* before allocation of Tx/Rx BDs for all examples. +* 3.00a asa 6/25/12 Modifed XAxiDma_BdSetLength API call to support new +* AXI DMA driver version 7.00a. Removed the calls to +* XAxiDma_BdRingStart for the coalesce and checksum +* offload examples. They are not required with the new +* AxiDMA version. +* 3.00a bss 10/22/12 Added support for Fast Interrupt Handlers. +* 3.01a srt 02/14/13 Added support for Zynq (CR 681136). +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xaxiethernet_example.h" +#include "xaxidma.h" +#include "xil_cache.h" +#include "xil_exception.h" +#include "stdio.h" /* stdio */ + +#ifdef XPAR_INTC_0_DEVICE_ID +#include "xintc.h" +#else +#include "xscugic.h" +#endif + +#ifdef XPAR_XUARTNS550_NUM_INSTANCES +#include "xuartns550_l.h" +#endif + +/*************************** Constant Definitions ****************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#ifndef TESTAPP_GEN +#define AXIETHERNET_DEVICE_ID XPAR_AXIETHERNET_0_DEVICE_ID +#define AXIDMA_DEVICE_ID XPAR_AXIDMA_0_DEVICE_ID +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#define AXIETHERNET_IRPT_INTR XPAR_INTC_0_AXIETHERNET_0_VEC_ID +#define DMA_RX_IRPT_INTR XPAR_AXIETHERNET_0_CONNECTED_DMARX_INTR +#define DMA_TX_IRPT_INTR XPAR_AXIETHERNET_0_CONNECTED_DMATX_INTR +#else +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#define AXIETHERNET_IRPT_INTR XPAR_FABRIC_AXIETHERNET_0_VEC_ID +#define DMA_RX_IRPT_INTR XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID +#define DMA_TX_IRPT_INTR XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID +#endif +#endif + +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#else +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#endif + +#define RXBD_CNT 128 /* Number of RxBDs to use */ +#define TXBD_CNT 128 /* Number of TxBDs to use */ +#define BD_ALIGNMENT XAXIDMA_BD_MINIMUM_ALIGNMENT + /* Byte alignment of BDs */ +#define PAYLOAD_SIZE 1000 /* Payload size used in examples */ +#define BD_USR0_OFFSET 0 /* AXI4-Stream Control Word offset from + * the start of app user words in BD. Offset + * 0 means, Control Word 0, used for enabling + * checksum offloading. + */ +#define BD_USR1_OFFSET 1 /* AXI4-Stream Control Word offset from + * the start of app user words in BD. Offset + * 1 means, Control Word 1, used for + * mentioning checksum begin and checksum + * insert points + */ +#define BD_USR2_OFFSET 2 /* AXI4-Stream Control Word offset from + * the start of app user words in BD. Offset + * 2 means, Control Word 2, used for + * mentioning checksum seed. + */ + +#define PARTIAL_CSUM_ENABLE 0x00000001 /* Option for partial csum enable */ +#define FULL_CSUM_ENABLE 0x00000002 /* Option for full csum enable */ +#define TX_CS_INIT_OFFSET 16 /* Offset in the control word where + * byte offset in the ethernet frame + * to start CSUM calculation need to + * be inserted + */ +#define RCV_FRM_NOT_CORRUPTED 0xFFFF /* If the received frame is not + * corrupted, for partial csum + * offloading case, the control + * word 3 would return 0xFFFF + */ + +#define IP_VERSION_4 0x800 /* For IPV4, the Ethernet frame + * type/length field will have a + * value of 0x800 + */ +#define IP_HEADER_VERSION 0x04 /* For IPv4, the version entry in + * IP header is always 4 + */ +#define IP_HEADER_LEN_IN_WORDS 0x05 /* For our case, the header length + * is always 20 bytes (5 words + */ +#define IP_HEADER_LENGTH 20 /* IP header length in bytes. Used + * as offset to kigure out the start + * of TCP header. + */ +#define IP_HEADER_PROTOCOL_TCP 0x6 /* IP header protocol entry. For TCP + * packets, it is 6. + */ +#define IP_HEADER_PROTOCOL_UDP 0x17 /* IP header protocol entry. For UDP + * packets, it is 17. + */ +#define TCP_HEADER_LEN_IN_WORDS 0x5 /* For our case, the header length + * is always 20 bytes (5 words) + */ +#define TCP_HEADER_LENGTH 20 /* IP header length in bytes. Used + * as offset to kigure out the start + * of TCP header. + */ +#define FULL_CSUM_STATUS_MASK 0x00000038 /* Mask to extract full checksum + * status field from AXI4 Stream + * Status Word 2. + */ + +#define FULL_CSUM_VALIDATED 0x00000002 /* If bits 3-5 in AXI4 Status word + * have a value of 0x010, it means + * both IP and TCP checksums have + * been found to be correct. + */ +#define IP_TCP_CSUMS_NOT_CHECKED 0x00000000 +#define IP_CSUM_OK_TCP_NOT_CHECKED 0x00000001 +#define TCP_CSUM_NOT_CHECKED_IP_NOT_OK 0x00000005 +#define IP_CSUM_OK_TCP_NOT_OK 0x00000006 + +#define DUMMY_TCP_PORT_1 0x1111 +#define DUMMY_TCP_PORT_2 0x1112 +/* + * Number of bytes to reserve for BD space for the number of BDs desired + */ +#define RXBD_SPACE_BYTES (XAxiDma_BdRingMemCalc(BD_ALIGNMENT, RXBD_CNT)) +#define TXBD_SPACE_BYTES (XAxiDma_BdRingMemCalc(BD_ALIGNMENT, TXBD_CNT)) + + +/*************************** Variable Definitions ****************************/ + +static EthernetFrame TxFrame; /* Transmit buffer */ +static EthernetFrame RxFrame; /* Receive buffer */ + +XAxiEthernet AxiEthernetInstance; +XAxiDma DmaInstance; + +#if XPAR_INTC_0_HAS_FAST == 1 + +/* Variables for Fast Interrupt Handlers */ +XAxiEthernet *AxiEthernetInstancePtr_Fast; +XAxiDma_BdRing *TxRingPtr_Fast; +XAxiDma_BdRing *RxRingPtr_Fast; + +/****** Fast Interrupt Handlers prototypes ******/ + +static void AxiEthernetErrorFastHandler(void) __attribute__ ((fast_interrupt)); + +static void RxIntrFastHandler(void) __attribute__ ((fast_interrupt)); + +static void TxIntrFastHandler(void) __attribute__ ((fast_interrupt)); + +#else + +static void AxiEthernetErrorHandler(XAxiEthernet *AxiEthernet); +static void RxIntrHandler(XAxiDma_BdRing *RxRingPtr); +static void TxIntrHandler(XAxiDma_BdRing *TxRingPtr); + +#endif + +/* + * Aligned memory segments to be used for buffer descriptors + */ +char RxBdSpace[RXBD_SPACE_BYTES] __attribute__ ((aligned(BD_ALIGNMENT))); +char TxBdSpace[TXBD_SPACE_BYTES] __attribute__ ((aligned(BD_ALIGNMENT))); + +/* + * Counters to be incremented by callbacks + */ +static volatile int FramesRx; /* Num of frames that have been received */ +static volatile int FramesTx; /* Num of frames that have been sent */ +static volatile int DeviceErrors;/* Num of errors detected in the device */ + +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC XIntc +#define INTC_HANDLER XIntc_InterruptHandler +#else +#define INTC XScuGic +#define INTC_HANDLER XScuGic_InterruptHandler +#endif + +#ifndef TESTAPP_GEN +static INTC IntcInstance; +#endif + +/*************************** Function Prototypes *****************************/ + +/* + * Examples + */ +int AxiEthernetSgDmaIntrExample(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr, + u16 AxiEthernetDeviceId, + u16 AxiDmaDeviceId, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, + u16 DmaTxIntrId); +int AxiEthernetSgDmaIntrSingleFrameExample(XAxiEthernet + *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr); +int AxiEthernetSgDmaIntrCoalescingExample(XAxiEthernet + *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr); +int AxiEthernetSgDmaPartialChecksumOffloadExample(XAxiEthernet + *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr); + +int AxiEthernetSgDmaFullChecksumOffloadExample(XAxiEthernet + *AxiEthernetInstancePtr, XAxiDma *DmaInstancePtr); + +/* + * Interrupt setup and Callbacks for examples + */ + +static int AxiEthernetSetupIntrSystem(INTC *IntcInstancePtr, + XAxiEthernet *AxiEthernetInstancePtr, + XAxiDma *DmaInstancePtr, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, + u16 DmaTxIntrId); +static void AxiEthernetDisableIntrSystem(INTC *IntcInstancePtr, + u16 AxiEthernetIntrId, + u16 DmaRxIntrId, u16 DmaTxIntrId); + +void AxiEthernetPHYRegistersDump(XAxiEthernet * AxiEthernetInstancePtr); + +/*****************************************************************************/ +/** +* +* This is the main function for the Axi Ethernet example. This function is not +* included if the example is generated from the TestAppGen test tool. +* +* @param None. +* +* @return - XST_SUCCESS to indicate success. +* - XST_FAILURE to indicate failure +* +* @note None. +* +****************************************************************************/ +#ifndef TESTAPP_GEN +int main(void) +{ + int Status; + +#ifdef XPAR_XUARTNS550_NUM_INSTANCES + XUartNs550_SetBaud(STDIN_BASEADDRESS, XPAR_XUARTNS550_CLOCK_HZ, 9600); + XUartNs550_SetLineControlReg(STDIN_BASEADDRESS, XUN_LCR_8_DATA_BITS); +#endif + +#if XPAR_MICROBLAZE_USE_ICACHE + Xil_ICacheInvalidate(); + Xil_ICacheEnable(); +#endif + +#if XPAR_MICROBLAZE_USE_DCACHE + Xil_DCacheInvalidate(); + Xil_DCacheEnable(); +#endif + AxiEthernetUtilErrorTrap("\r\n--- Enter main() ---"); + AxiEthernetUtilErrorTrap("This test may take several minutes to finish"); + /* + * Call the Axi Ethernet SGDMA interrupt example , specify the + * parameters generated in xparameters.h. + */ + Status = AxiEthernetSgDmaIntrExample(&IntcInstance, + &AxiEthernetInstance, + &DmaInstance, + AXIETHERNET_DEVICE_ID, + AXIDMA_DEVICE_ID, + AXIETHERNET_IRPT_INTR, + DMA_RX_IRPT_INTR, + DMA_TX_IRPT_INTR); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Failed test intr sgdma"); + AxiEthernetUtilErrorTrap("--- Exiting main() ---"); + return XST_FAILURE; + } + + AxiEthernetUtilErrorTrap("Test passed"); + AxiEthernetUtilErrorTrap("--- Exiting main() ---"); + + return XST_SUCCESS; + +} +#endif + + + +/*****************************************************************************/ +/** +* +* This function demonstrates the usage usage of the Axi Ethernet by sending +* and receiving frames in interrupt driven SGDMA mode. +* +* +* @param IntcInstancePtr is a pointer to the instance of the Intc +* component. +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param DmaInstancePtr is a pointer to the instance of the AXIDMA +* component. +* @param AxiEthernetDeviceId is Device ID of the Axi Ethernet Device , +* typically XPAR_
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a asa 4/30/10 First release based on the ll temac driver +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xaxiethernet_example.h" +#include "xllfifo.h" +#include "xil_cache.h" + +#ifdef XPAR_XUARTNS550_NUM_INSTANCES +#include "xuartns550_l.h" +#endif + +/************************** Constant Definitions ****************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#ifndef TESTAPP_GEN +#define AXIETHERNET_DEVICE_ID XPAR_AXIETHERNET_0_DEVICE_ID +#define FIFO_DEVICE_ID XPAR_AXI_FIFO_0_DEVICE_ID +#endif + +/************************** Variable Definitions ****************************/ + +EthernetFrame TxFrame; /* Transmit frame buffer */ +EthernetFrame RxFrame; /* Receive frame buffer */ + +XAxiEthernet AxiEthernetInstance; +XLlFifo FifoInstance; + +/************************** Function Prototypes *****************************/ + +int AxiEthernetPolledExample(u16 AxiEthernetDeviceId, u16 FifoDeviceId); +int AxiEthernetSingleFramePolledExample(); +int AxiEthernetMultipleFramesPolledExample(); + +int AxiEthernetPollForTxStatus(); +int AxiEthernetPollForRxStatus(); +int AxiEthernetResetDevice(); + +/*****************************************************************************/ +/** +* +* This is the main function for the AxiEthernet example. This function is not +* included if the example is generated from the TestAppGen test tool. +* +* @param None. +* +* @return -XST_SUCCESS to indicate success +* -XST_FAILURE to indicate failure +* +* +* @note None. +* +****************************************************************************/ +#ifndef TESTAPP_GEN +int main(void) +{ + int Status; +#ifdef XPAR_XUARTNS550_NUM_INSTANCES + XUartNs550_SetBaud(STDIN_BASEADDRESS, XPAR_XUARTNS550_CLOCK_HZ, 9600); + XUartNs550_SetLineControlReg(STDIN_BASEADDRESS, XUN_LCR_8_DATA_BITS); +#endif +#if XPAR_MICROBLAZE_USE_ICACHE + Xil_ICacheInvalidate(); + Xil_ICacheEnable(); +#endif + +#if XPAR_MICROBLAZE_USE_DCACHE + Xil_DCacheInvalidate(); + Xil_DCacheEnable(); +#endif + + AxiEthernetUtilErrorTrap("\r\n--- Enter main() ---"); + AxiEthernetUtilErrorTrap("This test may take several minutes to finish"); + + /* + * Call the AxiEthernet polled example , specify the Device ID + * generated in xparameters.h + */ + Status = AxiEthernetPolledExample(AXIETHERNET_DEVICE_ID, FIFO_DEVICE_ID); + if (Status != XST_SUCCESS) { + AxiEthernetUtilErrorTrap("Failed test poll mode fifo"); + return XST_FAILURE; + } + + AxiEthernetUtilErrorTrap("Test passed"); + AxiEthernetUtilErrorTrap("--- Exiting main() ---"); + return XST_SUCCESS; + +} +#endif + +/*****************************************************************************/ +/** +* +* This function demonstrates the usage of the Axi Ethernet by sending and +* receiving frames in polled mode. +* +* +* @param AxiEthernetDeviceId is device ID of the AxiEthernet Device , +* typically XPAR_
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a asa 6/30/10 First release based on the ll temac driver +* 3.01a srt 02/03/13 Added support for SGMII mode (CR 676793). +* 02/14/13 Added support for Zynq (CR 681136). +* 3.02a srt 04/24/13 Modified parameter *_SGMII_PHYADDR to *_PHYADDR, the +* config parameter C_PHYADDR applies to SGMII/1000BaseX +* modes of operation and added support for 1000BaseX mode +* (CR 704195). Added function *_ConfigureInternalPhy() +* for this purpose. +* 04/24/13 Added support for RGMII mode. +* 3.02a srt 08/06/13 Fixed CR 717949: +* Configures external Marvel 88E1111 PHY based on the +* axi ethernet physical interface type and allows to +* operate in specific interface mode without changing +* jumpers on the Microblaze board. +* +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xaxiethernet_example.h" +#if !defined (__MICROBLAZE__) && !defined(__PPC__) +#include "sleep.h" +#endif + +/************************** Variable Definitions ****************************/ + +/* + * Local MAC address + */ +char AxiEthernetMAC[6] = { 0x00, 0x0A, 0x35, 0x01, 0x02, 0x03 }; + +/******************************************************************************/ +/** +* +* Set the MAC addresses in the frame. +* +* @param FramePtr is the pointer to the frame. +* @param DestAddr is the Destination MAC address. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void AxiEthernetUtilFrameHdrFormatMAC(EthernetFrame *FramePtr, char *DestAddr) +{ + char *Frame = (char *) FramePtr; + char *SourceAddress = AxiEthernetMAC; + int Index; + + /* + * Destination address + */ + for (Index = 0; Index < XAE_MAC_ADDR_SIZE; Index++) { + *Frame++ = *DestAddr++; + } + + /* + * Source address + */ + for (Index = 0; Index < XAE_MAC_ADDR_SIZE; Index++) { + *Frame++ = *SourceAddress++; + } +} + +/******************************************************************************/ +/** +* +* Set the frame type for the specified frame. +* +* @param FramePtr is the pointer to the frame. +* @param FrameType is the Type to set in frame. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void AxiEthernetUtilFrameHdrFormatType(EthernetFrame *FramePtr, u16 FrameType) +{ + char *Frame = (char *) FramePtr; + + /* + * Increment to type field + */ + Frame = Frame + 12; + + FrameType = Xil_Htons(FrameType); + /* + * Set the type + */ + *(u16 *) Frame = FrameType; +} + +/******************************************************************************/ +/** +* This function places a pattern in the payload section of a frame. The pattern +* is a 8 bit incrementing series of numbers starting with 0. +* Once the pattern reaches 256, then the pattern changes to a 16 bit +* incrementing pattern: +*
+* 0, 1, 2, ... 254, 255, 00, 00, 00, 01, 00, 02, ... +*+* +* @param FramePtr is a pointer to the frame to change. +* @param PayloadSize is the number of bytes in the payload that will be +* set. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void AxiEthernetUtilFrameSetPayloadData(EthernetFrame *FramePtr, + int PayloadSize) +{ + unsigned BytesLeft = PayloadSize; + u8 *Frame; + u16 Counter = 0; + + /* + * Set the frame pointer to the start of the payload area + */ + Frame = (u8 *) FramePtr + XAE_HDR_SIZE; + + /* + * Insert 8 bit incrementing pattern + */ + while (BytesLeft && (Counter < 256)) { + *Frame++ = (u8) Counter++; + BytesLeft--; + } + + /* + * Switch to 16 bit incrementing pattern + */ + while (BytesLeft) { + *Frame++ = (u8) (Counter >> 8); /* high */ + BytesLeft--; + + if (!BytesLeft) + break; + + *Frame++ = (u8) Counter++; /* low */ + BytesLeft--; + } +} + +/******************************************************************************/ +/** +* +* Set the frame VLAN info for the specified frame. +* +* @param FramePtr is the pointer to the frame. +* @param VlanNumber is the VlanValue insertion position to set in frame. +* @param Vid is the 4 bytes Vlan value (TPID, Priority, CFI, VID) +* to be set in frame. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void AxiEthernetUtilFrameHdrVlanFormatVid(EthernetFrame *FramePtr, + u32 VlanNumber, u32 Vid) +{ + char *Frame = (char *) FramePtr; + + /* + * Increment to type field + */ + Frame = Frame + 12 + (VlanNumber * 4); + + Vid = Xil_Htonl(Vid); + + /* + * Set the type + */ + *(u32 *) Frame = Vid; +} + +/******************************************************************************/ +/** +* +* Set the frame type for the specified frame. +* +* @param FramePtr is the pointer to the frame. +* @param FrameType is the Type to set in frame. +* @param VlanNumber is the VLAN friendly adjusted insertion position to +* set in frame. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void AxiEthernetUtilFrameHdrVlanFormatType(EthernetFrame *FramePtr, + u16 FrameType, u32 VlanNumber) +{ + char *Frame = (char *) FramePtr; + + /* + * Increment to type field + */ + Frame = Frame + 12 + (VlanNumber * 4); + + FrameType = Xil_Htons(FrameType); + + /* + * Set the type + */ + *(u16 *) Frame = FrameType; +} + +/******************************************************************************/ +/** +* This function places a pattern in the payload section of a frame. The pattern +* is a 8 bit incrementing series of numbers starting with 0. +* Once the pattern reaches 256, then the pattern changes to a 16 bit +* incrementing pattern: +*
+* 0, 1, 2, ... 254, 255, 00, 00, 00, 01, 00, 02, ... +*+* +* @param FramePtr is a pointer to the frame to change. +* @param PayloadSize is the number of bytes in the payload that will be set. +* @param VlanNumber is the VLAN friendly adjusted insertion position to +* set in frame. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void AxiEthernetUtilFrameSetVlanPayloadData(EthernetFrame *FramePtr, + int PayloadSize, u32 VlanNumber) +{ + unsigned BytesLeft = PayloadSize; + u8 *Frame; + u16 Counter = 0; + + /* + * Set the frame pointer to the start of the payload area + */ + Frame = (u8 *) FramePtr + XAE_HDR_SIZE + (VlanNumber * 4); + + /* + * Insert 8 bit incrementing pattern + */ + while (BytesLeft && (Counter < 256)) { + *Frame++ = (u8) Counter++; + BytesLeft--; + } + + /* + * Switch to 16 bit incrementing pattern + */ + while (BytesLeft) { + *Frame++ = (u8) (Counter >> 8); /* high */ + BytesLeft--; + + if (!BytesLeft) + break; + + *Frame++ = (u8) Counter++; /* low */ + BytesLeft--; + } +} + +/******************************************************************************/ +/** +* This function verifies the frame data against a CheckFrame. +* +* Validation occurs by comparing the ActualFrame to the header of the +* CheckFrame. If the headers match, then the payload of ActualFrame is +* verified for the same pattern Util_FrameSetPayloadData() generates. +* +* @param CheckFrame is a pointer to a frame containing the 14 byte header +* that should be present in the ActualFrame parameter. +* @param ActualFrame is a pointer to a frame to validate. +* +* @return - XST_SUCCESS if successful. +* - XST_FAILURE in case of failure. +* +* @note None. +* +******************************************************************************/ +int AxiEthernetUtilFrameVerify(EthernetFrame * CheckFrame, + EthernetFrame * ActualFrame) +{ + unsigned char *CheckPtr = (unsigned char *) CheckFrame; + unsigned char *ActualPtr = (unsigned char *) ActualFrame; + u16 BytesLeft; + u16 Counter; + int Index; + + + /* + * Compare the headers + */ + for (Index = 0; Index < XAE_HDR_SIZE; Index++) { + if (CheckPtr[Index] != ActualPtr[Index]) { + return XST_FAILURE; + } + } + + Index = 0; + + BytesLeft = *(u16 *) &ActualPtr[12]; + BytesLeft = Xil_Ntohs(BytesLeft); + /* + * Get the length of the payload, do not use VLAN TPID here. + * TPID needs to be verified. + */ + while ((0x8100 == BytesLeft) || (0x88A8 == BytesLeft) || + (0x9100 == BytesLeft) || (0x9200 == BytesLeft)) { + Index++; + BytesLeft = *(u16 *) &ActualPtr[12+(4*Index)]; + BytesLeft = Xil_Ntohs(BytesLeft); + } + + /* + * Validate the payload + */ + Counter = 0; + ActualPtr = &ActualPtr[14+(4*Index)]; + + /* + * Check 8 bit incrementing pattern + */ + while (BytesLeft && (Counter < 256)) { + if (*ActualPtr++ != (u8) Counter++) { + + return XST_FAILURE; + } + BytesLeft--; + } + + /* + * Check 16 bit incrementing pattern + */ + while (BytesLeft) { + if (*ActualPtr++ != (u8) (Counter >> 8)) { /* high */ + return XST_FAILURE; + } + + BytesLeft--; + + if (!BytesLeft) + break; + + if (*ActualPtr++ != (u8) Counter++) { /* low */ + return XST_FAILURE; + } + + BytesLeft--; + } + + return XST_SUCCESS; +} + +/******************************************************************************/ +/** +* This function sets all bytes of a frame to 0. +* +* @param FramePtr is a pointer to the frame itself. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void AxiEthernetUtilFrameMemClear(EthernetFrame * FramePtr) +{ + u32 *Data32Ptr = (u32 *) FramePtr; + u32 WordsLeft = sizeof(EthernetFrame) / sizeof(u32); + + /* + * Frame should be an integral number of words + */ + while (WordsLeft--) { + *Data32Ptr++ = 0; + } +} + +/******************************************************************************/ +/** +* +* This function detects the PHY address by looking for successful MII status +* register contents (PHY register 1). It looks for a PHY that supports +* auto-negotiation and 10Mbps full-duplex and half-duplex. So, this code +* won't work for PHYs that don't support those features, but it's a bit more +* general purpose than matching a specific PHY manufacturer ID. +* +* Note also that on some (older) Xilinx ML4xx boards, PHY address 0 does not +* properly respond to this query. But, since the default is 0 and asssuming +* no other address responds, then it seems to work OK. +* +* @param The Axi Ethernet driver instance +* +* @return The address of the PHY (defaults to 0 if none detected) +* +* @note None. +* +******************************************************************************/ +/* Use MII register 1 (MII status register) to detect PHY */ +#define PHY_DETECT_REG 1 + +/* Mask used to verify certain PHY features (or register contents) + * in the register above: + * 0x1000: 10Mbps full duplex support + * 0x0800: 10Mbps half duplex support + * 0x0008: Auto-negotiation support + */ +#define PHY_DETECT_MASK 0x1808 + +u32 AxiEthernetDetectPHY(XAxiEthernet * AxiEthernetInstancePtr) +{ + u16 PhyReg; + int PhyAddr; + + for (PhyAddr = 31; PhyAddr >= 0; PhyAddr--) { + XAxiEthernet_PhyRead(AxiEthernetInstancePtr, PhyAddr, + PHY_DETECT_REG, &PhyReg); + + if ((PhyReg != 0xFFFF) && + ((PhyReg & PHY_DETECT_MASK) == PHY_DETECT_MASK)) { + /* Found a valid PHY address */ + return PhyAddr; + } + } + + return 0; /* Default to zero */ +} + +/******************************************************************************/ +/** +* Set PHY to loopback mode. This works with the marvell PHY common on ML40x +* evaluation boards +* +* @param Speed is the loopback speed 10, 100, or 1000 Mbit +* +******************************************************************************/ +/* IEEE PHY Specific definitions */ +#define PHY_R0_CTRL_REG 0 +#define PHY_R3_PHY_IDENT_REG 3 + +#define PHY_R0_RESET 0x8000 +#define PHY_R0_LOOPBACK 0x4000 +#define PHY_R0_ANEG_ENABLE 0x1000 +#define PHY_R0_DFT_SPD_MASK 0x2040 +#define PHY_R0_DFT_SPD_10 0x0000 +#define PHY_R0_DFT_SPD_100 0x2000 +#define PHY_R0_DFT_SPD_1000 0x0040 +#define PHY_R0_ISOLATE 0x0400 + +/* Marvel PHY 88E1111 Specific definitions */ +#define PHY_R20_EXTND_CTRL_REG 20 +#define PHY_R27_EXTND_STS_REG 27 + +#define PHY_R20_DFT_SPD_10 0x20 +#define PHY_R20_DFT_SPD_100 0x50 +#define PHY_R20_DFT_SPD_1000 0x60 +#define PHY_R20_RX_DLY 0x80 + +#define PHY_R27_MAC_CONFIG_GMII 0x000F +#define PHY_R27_MAC_CONFIG_MII 0x000F +#define PHY_R27_MAC_CONFIG_RGMII 0x000B +#define PHY_R27_MAC_CONFIG_SGMII 0x0004 + +/* Marvel PHY 88E1116R Specific definitions */ +#define PHY_R22_PAGE_ADDR_REG 22 +#define PHY_PG2_R21_CTRL_REG 21 + +#define PHY_REG21_10 0x0030 +#define PHY_REG21_100 0x2030 +#define PHY_REG21_1000 0x0070 + +/* Marvel PHY flags */ +#define MARVEL_PHY_88E1111_MODEL 0xC0 +#define MARVEL_PHY_88E1116R_MODEL 0x240 +#define PHY_MODEL_NUM_MASK 0x3F0 + +/******************************************************************************/ +/** +* +* This function sets the PHY to loopback mode. This works with the marvell PHY +* common on ML40x evaluation boards. +* +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param Speed is the loopback speed 10, 100, or 1000 Mbit. +* +* @return - XST_SUCCESS if successful. +* - XST_FAILURE, in case of failure.. +* +* @note None. +* +******************************************************************************/ +int AxiEthernetUtilEnterLoopback(XAxiEthernet *AxiEthernetInstancePtr, + int Speed) +{ + u16 PhyReg0; + signed int PhyAddr; + u8 PhyType; + u16 PhyModel; + u16 PhyReg20; /* Extended PHY specific Register (Reg 20) + of Marvell 88E1111 PHY */ + u16 PhyReg21; /* Control Register MAC (Reg 21) + of Marvell 88E1116R PHY */ + + /* Get the Phy Interface */ + PhyType = XAxiEthernet_GetPhysicalInterface(AxiEthernetInstancePtr); + + /* Detect the PHY address */ + if (PhyType != XAE_PHY_TYPE_1000BASE_X) { + PhyAddr = AxiEthernetDetectPHY(AxiEthernetInstancePtr); + } else { + PhyAddr = XPAR_AXIETHERNET_0_PHYADDR; + } + + XAxiEthernet_PhyRead(AxiEthernetInstancePtr, PhyAddr, + PHY_R3_PHY_IDENT_REG, &PhyModel); + PhyModel = PhyModel & PHY_MODEL_NUM_MASK; + + /* Clear the PHY of any existing bits by zeroing this out */ + PhyReg0 = PhyReg20 = PhyReg21 = 0; + + switch (Speed) { + case XAE_SPEED_10_MBPS: + PhyReg0 |= PHY_R0_DFT_SPD_10; + PhyReg20 |= PHY_R20_DFT_SPD_10; + PhyReg21 |= PHY_REG21_10; + break; + + case XAE_SPEED_100_MBPS: + PhyReg0 |= PHY_R0_DFT_SPD_100; + PhyReg20 |= PHY_R20_DFT_SPD_100; + PhyReg21 |= PHY_REG21_100; + break; + + case XAE_SPEED_1000_MBPS: + PhyReg0 |= PHY_R0_DFT_SPD_1000; + PhyReg20 |= PHY_R20_DFT_SPD_1000; + PhyReg21 |= PHY_REG21_1000; + break; + + default: + AxiEthernetUtilErrorTrap("Intg_LinkSpeed not 10, 100, or 1000 mbps"); + return XST_FAILURE; + } + + /* RGMII mode Phy specific registers initialization */ + if ((PhyType == XAE_PHY_TYPE_RGMII_2_0) || + (PhyType == XAE_PHY_TYPE_RGMII_1_3)) { + if (PhyModel == MARVEL_PHY_88E1111_MODEL) { + PhyReg20 |= PHY_R20_RX_DLY; + /* + * Adding Rx delay. Configuring loopback speed. + */ + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, + PhyAddr, PHY_R20_EXTND_CTRL_REG, + PhyReg20); + } else if (PhyModel == MARVEL_PHY_88E1116R_MODEL) { + /* + * Switching to PAGE2 + */ + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, + PhyAddr, + PHY_R22_PAGE_ADDR_REG, 2); + /* + * Adding Tx and Rx delay. Configuring loopback speed. + */ + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, + PhyAddr, + PHY_PG2_R21_CTRL_REG, PhyReg21); + /* + * Switching to PAGE0 + */ + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, + PhyAddr, + PHY_R22_PAGE_ADDR_REG, 0); + } + PhyReg0 &= (~PHY_R0_ANEG_ENABLE); + } + + /* Configure interface modes */ + if (PhyModel == MARVEL_PHY_88E1111_MODEL) { + if ((PhyType == XAE_PHY_TYPE_RGMII_2_0) || + (PhyType == XAE_PHY_TYPE_RGMII_1_3)) { + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, + PhyAddr, PHY_R27_EXTND_STS_REG, + PHY_R27_MAC_CONFIG_RGMII); + } else if (PhyType == XAE_PHY_TYPE_SGMII) { + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, + PhyAddr, PHY_R27_EXTND_STS_REG, + PHY_R27_MAC_CONFIG_SGMII); + } else if ((PhyType == XAE_PHY_TYPE_GMII) || + (PhyType == XAE_PHY_TYPE_MII)) { + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, + PhyAddr, PHY_R27_EXTND_STS_REG, + PHY_R27_MAC_CONFIG_GMII ); + } + } + + /* Set the speed and put the PHY in reset, then put the PHY in loopback */ + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, PhyAddr, + PHY_R0_CTRL_REG, + PhyReg0 | PHY_R0_RESET); + AxiEthernetUtilPhyDelay(AXIETHERNET_PHY_DELAY_SEC); + XAxiEthernet_PhyRead(AxiEthernetInstancePtr,PhyAddr, + PHY_R0_CTRL_REG, &PhyReg0); + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, PhyAddr, + PHY_R0_CTRL_REG, + PhyReg0 | PHY_R0_LOOPBACK); + + if ((PhyType == XAE_PHY_TYPE_SGMII) || + (PhyType == XAE_PHY_TYPE_1000BASE_X)) { + AxiEthernetUtilConfigureInternalPhy(AxiEthernetInstancePtr, Speed); + } + + AxiEthernetUtilPhyDelay(1); + + return XST_SUCCESS; +} + +/******************************************************************************/ +/** +* +* This function is called by example code when an error is detected. It +* can be set as a breakpoint with a debugger or it can be used to print out the +* given message if there is a UART or STDIO device. +* +* @param Message is the text explaining the error +* +* @return None +* +* @note None +* +******************************************************************************/ +void AxiEthernetUtilErrorTrap(char *Message) +{ + static int Count = 0; + + Count++; + +#ifdef STDOUT_BASEADDRESS + xil_printf("%s\r\n", Message); +#endif +} + +/******************************************************************************/ +/** +* +* For Microblaze we use an assembly loop that is roughly the same regardless of +* optimization level, although caches and memory access time can make the delay +* vary. Just keep in mind that after resetting or updating the PHY modes, +* the PHY typically needs time to recover. +* +* @return None +* +* @note None +* +******************************************************************************/ +void AxiEthernetUtilPhyDelay(unsigned int Seconds) +{ +#if defined (__MICROBLAZE__) || defined(__PPC__) + static int WarningFlag = 0; + + /* If MB caches are disabled or do not exist, this delay loop could + * take minutes instead of seconds (e.g., 30x longer). Print a warning + * message for the user (once). If only MB had a built-in timer! + */ + if (((mfmsr() & 0x20) == 0) && (!WarningFlag)) { + WarningFlag = 1; + } + +#define ITERS_PER_SEC (XPAR_CPU_CORE_CLOCK_FREQ_HZ / 6) + asm volatile ("\n" + "1: \n\t" + "addik r7, r0, %0 \n\t" + "2: \n\t" + "addik r7, r7, -1 \n\t" + "bneid r7, 2b \n\t" + "or r0, r0, r0 \n\t" + "bneid %1, 1b \n\t" + "addik %1, %1, -1 \n\t" + :: "i"(ITERS_PER_SEC), "d" (Seconds)); +#else + sleep(Seconds); +#endif +} + +/******************************************************************************/ +/** +* +* This function configures the internal phy for SGMII and 1000baseX modes. +* * +* @param AxiEthernetInstancePtr is a pointer to the instance of the +* AxiEthernet component. +* @param Speed is the loopback speed 10, 100, or 1000 Mbit. +* +* @return - XST_SUCCESS if successful. +* - XST_FAILURE, in case of failure.. +* +* @note None. +* +******************************************************************************/ +int AxiEthernetUtilConfigureInternalPhy(XAxiEthernet *AxiEthernetInstancePtr, + int Speed) +{ + u16 PhyReg0; + signed int PhyAddr; + + PhyAddr = XPAR_AXIETHERNET_0_PHYADDR; + + /* Clear the PHY of any existing bits by zeroing this out */ + PhyReg0 = 0; + XAxiEthernet_PhyRead(AxiEthernetInstancePtr, PhyAddr, + PHY_R0_CTRL_REG, &PhyReg0); + + PhyReg0 &= (~PHY_R0_ANEG_ENABLE); + PhyReg0 &= (~PHY_R0_ISOLATE); + + switch (Speed) { + case XAE_SPEED_10_MBPS: + PhyReg0 |= PHY_R0_DFT_SPD_10; + break; + case XAE_SPEED_100_MBPS: + PhyReg0 |= PHY_R0_DFT_SPD_100; + break; + case XAE_SPEED_1000_MBPS: + PhyReg0 |= PHY_R0_DFT_SPD_1000; + break; + default: + AxiEthernetUtilErrorTrap( + "Intg_LinkSpeed not 10, 100, or 1000 mbps\n\r"); + return XST_FAILURE; + } + + AxiEthernetUtilPhyDelay(1); + XAxiEthernet_PhyWrite(AxiEthernetInstancePtr, PhyAddr, + PHY_R0_CTRL_REG, PhyReg0); + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/src/Makefile b/XilinxProcessorIPLib/drivers/axiethernet/src/Makefile new file mode 100644 index 00000000..f3fbe7da --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/src/Makefile @@ -0,0 +1,27 @@ +COMPILER= +ARCHIVER= +CP=cp +COMPILER_FLAGS= +EXTRA_COMPILER_FLAGS= +LIB=libxil.a + +RELEASEDIR=../../../lib +INCLUDEDIR=../../../include +INCLUDES=-I./. -I${INCLUDEDIR} + +INCLUDEFILES=xaxiethernet.h xaxiethernet_hw.h xdebug.h +LIBSOURCES=*.c +OUTS = *.o + + +libs: + echo "Compiling axiethernet" + $(COMPILER) $(COMPILER_FLAGS) $(EXTRA_COMPILER_FLAGS) $(INCLUDES) $(LIBSOURCES) + $(ARCHIVER) -r ${RELEASEDIR}/${LIB} ${OUTS} + make clean + +include: + ${CP} ${INCLUDEFILES} ${INCLUDEDIR} + +clean: + rm -rf ${OUTS} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet.c b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet.c new file mode 100644 index 00000000..263d234d --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet.c @@ -0,0 +1,1771 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2015 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xaxiethernet.c +* +* The APIs in this file takes care of the primary functionalities of the driver. +* The APIs in this driver take care of the following: +* - Starting or stopping the Axi Ethernet device +* - Initializing and resetting the Axi Ethernet device +* - Setting MAC address and speed/duplex of the device +* - Provide means for controlling the PHY and communicating with it. +* - Turn on/off various features/options provided by the Axi Ethernet +* device. +* See xaxiethernet.h for a detailed description of the driver. +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a asa 6/30/10 First release based on the ll temac driver +* 1.02a asa 2/16/11 Made changes in XAxiEthernet_Reset to insert delays. +* 3.02a srt 4/13/13 Removed Warnings (CR 704998). +* +*+******************************************************************************/ + +/***************************** Include Files *********************************/ +#include "xaxiethernet.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +static void InitHw(XAxiEthernet *InstancePtr); /* HW reset */ + +/************************** Variable Definitions *****************************/ + +xdbg_stmnt(int indent_on = 0;) +xdbg_stmnt(u32 _xaxiethernet_rir_value;) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_CfgInitialize initializes an AXI Ethernet device along with the +* InstancePtr that references it. +* +* The PHY is setup independently from the Ethernet core. Use the MII or +* whatever other interface may be present for setup. +* +* @param InstancePtr references the memory instance to be associated +* with the AXI Ethernet core instance upon initialization. +* @param CfgPtr references the structure holding the hardware +* configuration for the Axi Ethernet core to initialize. +* @param EffectiveAddress is the processor address used to access the +* base address of the AXI Ethernet instance. In systems with an +* MMU and virtual memory, EffectiveAddress is the +* virtual address mapped to the physical in +*
ConfigPtr->Config.BaseAddress
. In systems without
+* an active MMU, EffectiveAddress should be set to the
+* same value as ConfigPtr->Config.BaseAddress
.
+*
+* @return XST_SUCCESS.
+*
+* @note None.
+*
+******************************************************************************/
+int XAxiEthernet_CfgInitialize(XAxiEthernet *InstancePtr,
+ XAxiEthernet_Config *CfgPtr,
+ u32 EffectiveAddress)
+{
+ /* Verify arguments */
+ Xil_AssertNonvoid(InstancePtr != NULL);
+
+ /* Clear instance memory and make copy of configuration */
+ memset(InstancePtr, 0, sizeof(XAxiEthernet));
+ memcpy(&InstancePtr->Config, CfgPtr, sizeof(XAxiEthernet_Config));
+
+ xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_CfgInitialize\n");
+
+ /* Set device base address */
+ InstancePtr->Config.BaseAddress = EffectiveAddress;
+
+ /* Reset the hardware and set default options */
+ InstancePtr->IsReady = XIL_COMPONENT_IS_READY;
+
+ XAxiEthernet_Reset(InstancePtr);
+
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "AxiTEthernet_CfgInitialize: returning SUCCESS\n");
+ return XST_SUCCESS;
+}
+
+
+/*****************************************************************************/
+/**
+* XAxiEthernet_Start starts the Axi Ethernet device as follows:
+* - Enable transmitter if XAE_TRANSMIT_ENABLE_OPTION is set
+* - Enable receiver if XAE_RECEIVER_ENABLE_OPTION is set
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+* @return None.
+*
+* @note None.
+*
+*
+******************************************************************************/
+void XAxiEthernet_Start(XAxiEthernet *InstancePtr)
+{
+ u32 Reg;
+
+ /* Assert bad arguments and conditions */
+ Xil_AssertVoid(InstancePtr != NULL);
+ Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+
+
+ /* If already started, then there is nothing to do */
+ if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) {
+ return;
+ }
+
+ xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_Start\n");
+
+ /* Enable transmitter if not already enabled */
+ if (InstancePtr->Options & XAE_TRANSMITTER_ENABLE_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL, "enabling transmitter\n");
+ Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_TC_OFFSET);
+ if (!(Reg & XAE_TC_TX_MASK)) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "transmitter not enabled, enabling now\n");
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_TC_OFFSET,
+ Reg | XAE_TC_TX_MASK);
+ }
+ xdbg_printf(XDBG_DEBUG_GENERAL, "transmitter enabled\n");
+ }
+
+ /* Enable receiver */
+ if (InstancePtr->Options & XAE_RECEIVER_ENABLE_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL, "enabling receiver\n");
+ Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET);
+ if (!(Reg & XAE_RCW1_RX_MASK)) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "receiver not enabled, enabling now\n");
+
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET,
+ Reg | XAE_RCW1_RX_MASK);
+ }
+ xdbg_printf(XDBG_DEBUG_GENERAL, "receiver enabled\n");
+ }
+
+ /* Mark as started */
+ InstancePtr->IsStarted = XIL_COMPONENT_IS_STARTED;
+ xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_Start: done\n");
+}
+
+/*****************************************************************************/
+/**
+* XAxiEthernet_Stop gracefully stops the Axi Ethernet device as follows:
+* - Disable all interrupts from this device
+* - Disable the receiver
+*
+* XAxiEthernet_Stop does not modify any of the current device options.
+*
+* Since the transmitter is not disabled, frames currently in internal buffers
+* or in process by a DMA engine are allowed to be transmitted.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+* @return None
+*
+* @note None.
+*
+*
+******************************************************************************/
+void XAxiEthernet_Stop(XAxiEthernet *InstancePtr)
+{
+ u32 Reg;
+
+ Xil_AssertVoid(InstancePtr != NULL);
+ Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+
+
+ /* If already stopped, then there is nothing to do */
+ if (InstancePtr->IsStarted == 0) {
+ return;
+ }
+
+ xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_Stop\n");
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_Stop: disabling interrupts\n");
+
+ /* Disable interrupts */
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_IE_OFFSET, 0);
+
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_Stop: disabling receiver\n");
+
+ /* Disable the receiver */
+ Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET);
+ Reg &= ~XAE_RCW1_RX_MASK;
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET, Reg);
+
+ /*
+ * Stopping the receiver in mid-packet causes a dropped packet
+ * indication from HW. Clear it.
+ */
+ /* get the interrupt pending register */
+ Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_IP_OFFSET);
+ if (Reg & XAE_INT_RXRJECT_MASK) {
+ /* set the interrupt status register to clear the interrupt */
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK);
+ }
+
+ /* Mark as stopped */
+ InstancePtr->IsStarted = 0;
+ xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_Stop: done\n");
+}
+
+
+/*****************************************************************************/
+/**
+* XAxiEthernet_Reset does not perform a soft reset of the AxiEthernet core.
+* AxiEthernet hardware is reset by the device connected to the AXI4-Stream
+* interface.
+* This function inserts some delay before proceeding to check for MgtRdy bit.
+* The delay is necessary to be at a safe side. It takes a while for the reset
+* process to complete and for any of the AxiEthernet registers to be accessed.
+* It then checks for MgtRdy bit in IS register to know if AxiEthernet reset
+* is completed or not. Subsequently it calls one more driver function to
+* complete the AxiEthernet hardware initialization.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @note It is the responsibility of the user to reset the AxiEthernet
+* hardware before using it. AxiEthernet hardware should be reset
+* through the device connected to the AXI4-Stream interface of
+* AxiEthernet.
+*
+******************************************************************************/
+void XAxiEthernet_Reset(XAxiEthernet *InstancePtr)
+{
+ volatile u32 TimeoutLoops;
+
+ Xil_AssertVoid(InstancePtr != NULL);
+ Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+
+ /*
+ * Add delay of 10000 loops to give enough time to the core to come
+ * out of reset. Till the time core comes out of reset none of the
+ * AxiEthernet registers are accessible including the IS register.
+ */
+ TimeoutLoops = XAE_LOOPS_TO_COME_OUT_OF_RST;
+ while (TimeoutLoops > 0) {
+ TimeoutLoops--;
+ }
+
+ /*
+ * Check the status of the MgtRdy bit in the interrupt status
+ * registers. This must be done to allow the MGT clock to become stable
+ * for the Sgmii and 1000BaseX PHY interfaces. No other register reads
+ * will be valid until this bit is valid.
+ * The bit is always a 1 for all other PHY interfaces.
+ */
+ TimeoutLoops = XAE_RST_DELAY_LOOPCNT_VAL;
+ while (TimeoutLoops &&
+ (! (XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_IS_OFFSET) & XAE_INT_MGTRDY_MASK))) {
+ TimeoutLoops--;
+ }
+
+ if(0 == TimeoutLoops) {
+ Xil_AssertVoidAlways();
+ }
+
+ xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_Reset\n");
+
+ /* Stop the device and reset HW */
+ XAxiEthernet_Stop(InstancePtr);
+ InstancePtr->Options = XAE_DEFAULT_OPTIONS;
+
+ /* Setup HW */
+ InitHw(InstancePtr);
+}
+
+
+/******************************************************************************
+*
+* InitHw (internal use only) performs a one-time setup of a Axi Ethernet device.
+* The setup performed here only need to occur once after any reset.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+* @note None.
+*
+*
+******************************************************************************/
+static void InitHw(XAxiEthernet *InstancePtr)
+{
+ u32 Reg;
+
+ xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet InitHw\n");
+
+
+ /* Disable the receiver */
+ Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET);
+ Reg &= ~XAE_RCW1_RX_MASK;
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET, Reg);
+
+ /*
+ * Stopping the receiver in mid-packet causes a dropped packet
+ * indication from HW. Clear it.
+ */
+ /* Get the interrupt pending register */
+ Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_IP_OFFSET);
+ if (Reg & XAE_INT_RXRJECT_MASK) {
+ /*
+ * Set the interrupt status register to clear the pending
+ * interrupt
+ */
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_IS_OFFSET, XAE_INT_RXRJECT_MASK);
+ }
+
+ /*
+ * Sync default options with HW but leave receiver and transmitter
+ * disabled. They get enabled with XAxiEthernet_Start() if
+ * XAE_TRANSMITTER_ENABLE_OPTION and XAE_RECEIVER_ENABLE_OPTION
+ * are set
+ */
+ XAxiEthernet_SetOptions(InstancePtr, InstancePtr->Options &
+ ~(XAE_TRANSMITTER_ENABLE_OPTION |
+ XAE_RECEIVER_ENABLE_OPTION));
+
+ XAxiEthernet_ClearOptions(InstancePtr, ~InstancePtr->Options);
+
+ /* Set default MDIO divisor */
+ XAxiEthernet_PhySetMdioDivisor(InstancePtr, XAE_MDIO_DIV_DFT);
+
+ xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet InitHw: done\n");
+}
+
+/*****************************************************************************/
+/**
+ * XAxiEthernet_SetMacAddress sets the MAC address for the Axi Ethernet device,
+ * specified by InstancePtr to the MAC address specified by
+ * AddressPtr.
+ * The Axi Ethernet device must be stopped before calling this function.
+ *
+ * @param InstancePtr is a pointer to the Axi Ethernet instance to be
+ * worked on.
+ * @param AddressPtr is a reference to the 6-byte MAC address to set.
+ *
+ * @return
+ * - XST_SUCCESS on successful completion.
+ * - XST_DEVICE_IS_STARTED if the Axi Ethernet device has not
+ * stopped,
+ *
+ * @note
+ * This routine also supports the extended/new VLAN and multicast mode. The
+ * XAE_RAF_NEWFNCENBL_MASK bit dictates which offset will be configured.
+ *
+ ******************************************************************************/
+int XAxiEthernet_SetMacAddress(XAxiEthernet *InstancePtr, void *AddressPtr)
+{
+ u32 MacAddr;
+ u8 *Aptr = (u8 *) AddressPtr;
+
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+ Xil_AssertNonvoid(AddressPtr != NULL);
+
+
+ /* Be sure device has been stopped */
+ if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) {
+ return (XST_DEVICE_IS_STARTED);
+ }
+
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_SetMacAddress: setting mac address to:0x%08x%8x%8x%8x%8x%8x\n",
+ Aptr[0], Aptr[1], Aptr[2], Aptr[3], Aptr[4], Aptr[5]);
+
+ /* Prepare MAC bits in either UAW0/UAWL */
+ MacAddr = Aptr[0];
+ MacAddr |= Aptr[1] << 8;
+ MacAddr |= Aptr[2] << 16;
+ MacAddr |= Aptr[3] << 24;
+ /* Check to see if it is in extended/new mode. */
+ if (!(XAxiEthernet_IsExtFuncCap(InstancePtr))) {
+ /*
+ * Set the MAC bits [31:0] in UAW0.
+ * Having Aptr be unsigned type prevents the following
+ * operations from sign extending.
+ */
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_UAW0_OFFSET, MacAddr);
+
+ /* There are reserved bits in UAW1 so don't affect them */
+ MacAddr = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_UAW1_OFFSET);
+ MacAddr &= ~XAE_UAW1_UNICASTADDR_MASK;
+
+ /* Set MAC bits [47:32] in UAW1 */
+ MacAddr |= Aptr[4];
+ MacAddr |= Aptr[5] << 8;
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_UAW1_OFFSET, MacAddr);
+
+ return (XST_SUCCESS);
+ } else { /* Extended mode */
+ /*
+ * Set the MAC bits [31:0] in UAWL register.
+ * Having Aptr be unsigned type prevents the following
+ * operations from sign extending.
+ */
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_UAWL_OFFSET, MacAddr);
+
+ /* Set MAC bits [47:32] in UAWU register. */
+ MacAddr = 0;
+ MacAddr |= Aptr[4];
+ MacAddr |= Aptr[5] << 8;
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_UAWU_OFFSET, MacAddr);
+
+ return (XST_SUCCESS);
+ }
+}
+
+
+/*****************************************************************************/
+/**
+ * XAxiEthernet_GetMacAddress gets the MAC address for the Axi Ethernet,
+ * specified by InstancePtr into the memory buffer specified by
+ * AddressPtr.
+ *
+ * @param InstancePtr is a pointer to the Axi Ethernet instance to be
+ * worked on.
+ * @param AddressPtr references the memory buffer to store the retrieved
+ * MAC address. This memory buffer must be at least 6 bytes in
+ * length.
+ *
+ * @return None.
+ *
+ * @note
+ *
+ * This routine also supports the extended/new VLAN and multicast mode. The
+ * XAE_RAF_NEWFNCENBL_MASK bit dictates which offset will be configured.
+ *
+ ******************************************************************************/
+void XAxiEthernet_GetMacAddress(XAxiEthernet *InstancePtr, void *AddressPtr)
+{
+ u32 MacAddr;
+ u8 *Aptr = (u8 *) AddressPtr;
+
+ Xil_AssertVoid(InstancePtr != NULL);
+ Xil_AssertVoid(AddressPtr != NULL);
+ Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+
+
+ /* Check to see if it is in extended/new mode. */
+ if (!(XAxiEthernet_IsExtFuncCap(InstancePtr))) {
+ /* Read MAC bits [31:0] in UAW0 */
+ MacAddr = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_UAW0_OFFSET);
+ Aptr[0] = (u8) MacAddr;
+ Aptr[1] = (u8) (MacAddr >> 8);
+ Aptr[2] = (u8) (MacAddr >> 16);
+ Aptr[3] = (u8) (MacAddr >> 24);
+
+ /* Read MAC bits [47:32] in UAW1 */
+ MacAddr = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_UAW1_OFFSET);
+ Aptr[4] = (u8) MacAddr;
+ Aptr[5] = (u8) (MacAddr >> 8);
+ } else { /* Extended/new mode */
+ /* Read MAC bits [31:0] in UAWL register */
+ MacAddr = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_UAWL_OFFSET);
+ Aptr[0] = (u8) MacAddr;
+ Aptr[1] = (u8) (MacAddr >> 8);
+ Aptr[2] = (u8) (MacAddr >> 16);
+ Aptr[3] = (u8) (MacAddr >> 24);
+
+ /* Read MAC bits [47:32] in UAWU register */
+ MacAddr = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_UAWU_OFFSET);
+ Aptr[4] = (u8) MacAddr;
+ Aptr[5] = (u8) (MacAddr >> 8);
+ }
+}
+
+
+/*****************************************************************************/
+/**
+ * XAxiEthernet_UpdateDepOption check and update dependent options for
+ * new/extended features. This is a helper function that is meant to be called
+ * by XAxiEthernet_SetOptions() and XAxiEthernet_ClearOptions().
+ *
+ * @param InstancePtr is a pointer to the Axi Ethernet instance to be
+ * worked on.
+ *
+ * @return Dependent options that are required to set/clear per
+ * hardware requirement.
+ *
+ * @note
+ *
+ * This helper function collects the dependent OPTION(s) per hardware design.
+ * When conflicts arises, extended features have precedence over legacy ones.
+ * Two operations to be considered,
+ * 1. Adding extended options. If XATE_VLAN_OPTION is enabled and enable one of
+ * extended VLAN options, XATE_VLAN_OPTION should be off and configure to
+ * hardware.
+ * However, axi-ethernet instance Options variable still holds
+ * XATE_VLAN_OPTION so when all of the extended feature are removed,
+ * XATE_VLAN_OPTION can be effective and configured to hardware.
+ * 2. Removing extended options. Remove extended option can not just remove
+ * the selected extended option and dependent options. All extended
+ * options need to be verified and remained when one or more extended
+ * options are enabled.
+ *
+ * Dependent options are :
+ * - XAE_VLAN_OPTION,
+ * - XAE_JUMBO_OPTION
+ * - XAE_FCS_INSERT_OPTION,
+ * - XAE_FCS_STRIP_OPTION
+ * - XAE_PROMISC_OPTION.
+ *
+ ******************************************************************************/
+static u32 XAxiEthernet_UpdateDepOptions(XAxiEthernet *InstancePtr)
+{
+ /*
+ * This is a helper function for XAxiEthernet_[Set|Clear]Options(),
+ * verification has been done before invoke this function.
+ */
+ u32 DepOptions = InstancePtr->Options;
+
+ /*
+ * The extended/new features require some OPTIONS to be on/off per
+ * hardware design. We determine these extended/new functions here
+ * first and also on/off other OPTIONS later. So that dependent
+ * OPTIONS are in sync and _[Set|Clear]Options() can be performed
+ * seamlessly.
+ */
+
+ /* Enable extended multicast option */
+ if (DepOptions & XAE_EXT_MULTICAST_OPTION) {
+ /*
+ * When extended multicast module is enabled in HW,
+ * XAE_PROMISC_OPTION is required to be enabled.
+ */
+ if (XAxiEthernet_IsExtMcast(InstancePtr)) {
+ DepOptions |= XAE_PROMISC_OPTION;
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "CheckDepOptions: enabling ext multicast\n");
+ } else {
+ xdbg_printf(XDBG_DEBUG_ERROR,
+ "EXT MULTICAST is not built in hardware\n");
+ }
+ }
+
+ /* Enable extended transmit VLAN translation option */
+ if (DepOptions & XAE_EXT_TXVLAN_TRAN_OPTION) {
+ /*
+ * Check if hardware is built with extend TX VLAN translation.
+ * if not, output an information message.
+ */
+ if (XAxiEthernet_IsTxVlanTran(InstancePtr)) {
+ DepOptions |= XAE_FCS_INSERT_OPTION;
+ DepOptions &= ~XAE_VLAN_OPTION;
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "CheckDepOptions: enabling ext Tx VLAN trans\n");
+ } else {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "TX VLAN TRANSLATION is not built in hardware\n");
+ }
+ }
+
+ /* Enable extended receive VLAN translation option */
+ if (DepOptions & XAE_EXT_RXVLAN_TRAN_OPTION) {
+ /*
+ * Check if hardware is built with extend RX VLAN translation.
+ * if not, output an information message.
+ */
+ if (XAxiEthernet_IsRxVlanTran(InstancePtr)) {
+ DepOptions |= XAE_FCS_STRIP_OPTION;
+ DepOptions &= ~XAE_VLAN_OPTION;
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "CheckDepOptions: enabling ext Rx VLAN trans\n");
+ } else {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "RX VLAN TRANSLATION is not built in hardware\n");
+ }
+ }
+
+ /* Enable extended transmit VLAN tag option */
+ if (DepOptions & XAE_EXT_TXVLAN_TAG_OPTION) {
+ /*
+ * Check if hardware is built with extend TX VLAN tagging.
+ * if not, output an information message.
+ */
+ if (XAxiEthernet_IsTxVlanTag(InstancePtr)) {
+ DepOptions |= XAE_FCS_INSERT_OPTION;
+ DepOptions &= ~XAE_VLAN_OPTION;
+ DepOptions |= XAE_JUMBO_OPTION;
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "CheckDepOptions: enabling ext Tx VLAN tag\n");
+ } else {
+ xdbg_printf(XDBG_DEBUG_ERROR,
+ "TX VLAN TAG is not built in hardware\n");
+ }
+ }
+
+ /* Enable extended receive VLAN tag option */
+ if (DepOptions & XAE_EXT_RXVLAN_TAG_OPTION) {
+ /*
+ * Check if hardware is built with extend RX VLAN tagging.
+ * if not, output an information message.
+ */
+ if (XAxiEthernet_IsRxVlanTag(InstancePtr)) {
+ DepOptions |= XAE_FCS_STRIP_OPTION;
+ DepOptions &= ~XAE_VLAN_OPTION;
+ DepOptions |= XAE_JUMBO_OPTION;
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "CheckDepOptions: enabling ext Rx VLAN tag\n");
+ } else {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "RX VLAN TAG is not built in hardware\n");
+ }
+ }
+
+ /* Enable extended transmit VLAN strip option */
+ if (DepOptions & XAE_EXT_TXVLAN_STRP_OPTION) {
+ /*
+ * Check if hardware is built with extend TX VLAN stripping.
+ * if not, output an information message.
+ */
+ if (XAxiEthernet_IsTxVlanStrp(InstancePtr)) {
+ DepOptions |= XAE_FCS_INSERT_OPTION;
+ DepOptions &= ~XAE_VLAN_OPTION;
+ DepOptions |= XAE_JUMBO_OPTION;
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "CheckDepOptions: enabling ext Tx VLAN strip\n");
+ } else {
+ xdbg_printf(XDBG_DEBUG_ERROR,
+ "TX VLAN STRIP is not built in hardware\n");
+ }
+ }
+
+ /* Enable extended receive VLAN strip option */
+ if (DepOptions & XAE_EXT_RXVLAN_STRP_OPTION) {
+ /*
+ * Check if hardware is built with extend RX VLAN stripping.
+ * if not, output an information message.
+ */
+ if (XAxiEthernet_IsRxVlanStrp(InstancePtr)) {
+ DepOptions |= XAE_FCS_STRIP_OPTION;
+ DepOptions &= ~XAE_VLAN_OPTION;
+ DepOptions |= XAE_JUMBO_OPTION;
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "CheckDepOptions: enabling ext Rx VLAN strip\n");
+ } else {
+ xdbg_printf(XDBG_DEBUG_ERROR,
+ "RX VLAN STRIP is not built in hardware\n");
+ }
+ }
+
+ /*
+ * Options and dependent Options together is what hardware and user
+ * are happy with. But we still need to keep original options
+ * in case option(s) are set/cleared, overall options can be managed.
+ * Return DepOptions to XAxiEthernet_[Set|Clear]Options for final
+ * configuration.
+ */
+ return(DepOptions);
+}
+
+/*****************************************************************************/
+/**
+* XAxiEthernet_SetOptions enables the options, Options for the
+* Axi Ethernet, specified by InstancePtr. Axi Ethernet should be
+* stopped with XAxiEthernet_Stop() before changing options.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+* @param Options is a bitmask of OR'd XAE_*_OPTION values for options to
+* set. Options not specified are not affected.
+*
+* @return
+* - XST_SUCCESS on successful completion.
+* - XST_DEVICE_IS_STARTED if the device has not been stopped.
+*
+*
+* @note
+* See xaxiethernet.h for a description of the available options.
+*
+*
+******************************************************************************/
+int XAxiEthernet_SetOptions(XAxiEthernet *InstancePtr, u32 Options)
+{
+ u32 Reg; /* Generic register contents */
+ u32 RegRcw1; /* Reflects original contents of RCW1 */
+ u32 RegTc; /* Reflects original contents of TC */
+ u32 RegNewRcw1; /* Reflects new contents of RCW1 */
+ u32 RegNewTc; /* Reflects new contents of TC */
+ u32 DepOptions; /* Required dependent options for new features */
+
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+
+ /* Be sure device has been stopped */
+ if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) {
+ return (XST_DEVICE_IS_STARTED);
+ }
+
+ xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_SetOptions\n");
+
+ /*
+ * Set options word to its new value.
+ * The step is required before calling _UpdateDepOptions() since
+ * we are operating on updated options.
+ */
+ InstancePtr->Options |= Options;
+
+ /*
+ * There are options required to be on/off per hardware requirement.
+ * Invoke _UpdateDepOptions to check hardware availability and update
+ * options accordingly.
+ */
+ DepOptions = XAxiEthernet_UpdateDepOptions(InstancePtr);
+
+ /*
+ * New/extended function bit should be on if any new/extended features
+ * are on and hardware is built with them.
+ */
+ if (DepOptions & (XAE_EXT_MULTICAST_OPTION |
+ XAE_EXT_TXVLAN_TRAN_OPTION |
+ XAE_EXT_RXVLAN_TRAN_OPTION |
+ XAE_EXT_TXVLAN_TAG_OPTION |
+ XAE_EXT_RXVLAN_TAG_OPTION |
+ XAE_EXT_TXVLAN_STRP_OPTION |
+ XAE_EXT_RXVLAN_STRP_OPTION)) {
+
+ XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET,
+ XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET) | XAE_RAF_NEWFNCENBL_MASK);
+ }
+
+ /*
+ * Many of these options will change the RCW1 or TC registers.
+ * To reduce the amount of IO to the device, group these options here
+ * and change them all at once.
+ */
+ /* Get current register contents */
+ RegRcw1 = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET);
+ RegTc = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_TC_OFFSET);
+ RegNewRcw1 = RegRcw1;
+ RegNewTc = RegTc;
+
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "current control regs: RCW1: 0x%0x; TC: 0x%0x\n",
+ RegRcw1, RegTc);
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "Options: 0x%0x; default options: 0x%0x\n",Options,
+ XAE_DEFAULT_OPTIONS);
+
+ /* Turn on jumbo packet support for both Rx and Tx */
+ if (DepOptions & XAE_JUMBO_OPTION) {
+ RegNewTc |= XAE_TC_JUM_MASK;
+ RegNewRcw1 |= XAE_RCW1_JUM_MASK;
+ }
+
+ /* Turn on VLAN packet support for both Rx and Tx */
+ if (DepOptions & XAE_VLAN_OPTION) {
+ RegNewTc |= XAE_TC_VLAN_MASK;
+ RegNewRcw1 |= XAE_RCW1_VLAN_MASK;
+ }
+
+ /* Turn on FCS stripping on receive packets */
+ if (DepOptions & XAE_FCS_STRIP_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "setOptions: enabling fcs stripping\n");
+ RegNewRcw1 &= ~XAE_RCW1_FCS_MASK;
+ }
+
+ /* Turn on FCS insertion on transmit packets */
+ if (DepOptions & XAE_FCS_INSERT_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "setOptions: enabling fcs insertion\n");
+ RegNewTc &= ~XAE_TC_FCS_MASK;
+ }
+
+ /* Turn on length/type field checking on receive packets */
+ if (DepOptions & XAE_LENTYPE_ERR_OPTION) {
+ RegNewRcw1 &= ~XAE_RCW1_LT_DIS_MASK;
+ }
+
+ /* Enable transmitter */
+ if (DepOptions & XAE_TRANSMITTER_ENABLE_OPTION) {
+ RegNewTc |= XAE_TC_TX_MASK;
+ }
+
+ /* Enable receiver */
+ if (DepOptions & XAE_RECEIVER_ENABLE_OPTION) {
+ RegNewRcw1 |= XAE_RCW1_RX_MASK;
+ }
+
+ /* Change the TC or RCW1 registers if they need to be modified */
+ if (RegTc != RegNewTc) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "setOptions: writing tc: 0x%0x\n", RegNewTc);
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_TC_OFFSET, RegNewTc);
+ }
+
+ if (RegRcw1 != RegNewRcw1) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "setOptions: writing rcw1: 0x%0x\n", RegNewRcw1);
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET, RegNewRcw1);
+ }
+
+ /*
+ * Rest of options twiddle bits of other registers. Handle them one at
+ * a time
+ */
+
+ /* Turn on flow control */
+ if (DepOptions & XAE_FLOW_CONTROL_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "setOptions: enabling flow control\n");
+ Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_FCC_OFFSET);
+ Reg |= XAE_FCC_FCRX_MASK;
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_FCC_OFFSET, Reg);
+ }
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "setOptions: rcw1 is now (fcc):0x%0x\n",
+ XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET));
+
+ /* Turn on promiscuous frame filtering (all frames are received ) */
+ if (DepOptions & XAE_PROMISC_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "setOptions: enabling promiscuous mode\n");
+ Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_FMI_OFFSET);
+ Reg |= XAE_FMI_PM_MASK;
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_FMI_OFFSET, Reg);
+ }
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "setOptions: rcw1 is now (afm):0x%0x\n",
+ XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET));
+
+ /* Allow broadcast address filtering */
+ if (DepOptions & XAE_BROADCAST_OPTION) {
+ Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_RAF_OFFSET);
+ Reg &= ~XAE_RAF_BCSTREJ_MASK;
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_RAF_OFFSET, Reg);
+ }
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "setOptions: rcw1 is now (raf):0x%0x\n",
+ XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET));
+
+ /* Allow multicast address filtering */
+ if (DepOptions & (XAE_MULTICAST_OPTION | XAE_EXT_MULTICAST_OPTION)) {
+ Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_RAF_OFFSET);
+ Reg &= ~XAE_RAF_MCSTREJ_MASK;
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_RAF_OFFSET, Reg);
+ }
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "setOptions: rcw1 is now (raf2): 0x%0x\n",
+ XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET));
+
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "setOptions: rcw1 is now (raf2):0x%0x\n",
+ XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET));
+
+ /*
+ * 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.
+ */
+ /* Enable extended multicast option */
+ if (DepOptions & XAE_EXT_MULTICAST_OPTION) {
+ XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET,
+ XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET) | XAE_RAF_EMULTIFLTRENBL_MASK);
+ }
+
+ /*
+ * New/extended [TX|RX] VLAN translation option does not have specific
+ * bits to on/off.
+ */
+
+ /* Enable extended transmit VLAN tag option */
+ if (DepOptions & XAE_EXT_TXVLAN_TAG_OPTION) {
+ Reg = XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET);
+ Reg = (Reg & ~XAE_RAF_TXVTAGMODE_MASK) |
+ (XAE_DEFAULT_TXVTAG_MODE <<
+ XAE_RAF_TXVTAGMODE_SHIFT);
+ XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET, Reg);
+ }
+
+ /* Enable extended receive VLAN tag option */
+ if (DepOptions & XAE_EXT_RXVLAN_TAG_OPTION) {
+ Reg = XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET);
+ Reg = (Reg & ~XAE_RAF_RXVTAGMODE_MASK) |
+ (XAE_DEFAULT_RXVTAG_MODE <<
+ XAE_RAF_RXVTAGMODE_SHIFT);
+ XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET, Reg);
+ }
+
+ /* Enable extended transmit VLAN strip option */
+ if (Options & XAE_EXT_TXVLAN_STRP_OPTION) {
+ Reg = XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET);
+ Reg = (Reg & ~XAE_RAF_TXVSTRPMODE_MASK) |
+ (XAE_DEFAULT_TXVSTRP_MODE <<
+ XAE_RAF_TXVSTRPMODE_SHIFT);
+ XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET, Reg);
+ }
+
+ /* Enable extended receive VLAN strip option */
+ if (Options & XAE_EXT_RXVLAN_STRP_OPTION) {
+ Reg = XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET);
+ Reg = (Reg & ~XAE_RAF_RXVSTRPMODE_MASK) |
+ (XAE_DEFAULT_RXVSTRP_MODE <<
+ XAE_RAF_RXVSTRPMODE_SHIFT);
+ XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_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.
+ */
+ xdbg_printf(XDBG_DEBUG_GENERAL, "setOptions: returning SUCCESS\n");
+ return (XST_SUCCESS);
+}
+
+/*****************************************************************************/
+/**
+* XAxiEthernet_ClearOptions clears the options, Options for the
+* Axi Ethernet, specified by InstancePtr. Axi Ethernet should be stopped
+* with XAxiEthernet_Stop() before changing options.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+* @param Options is a bitmask of OR'd XAE_*_OPTION values for options to
+* clear. Options not specified are not affected.
+*
+* @return
+* - XST_SUCCESS on successful completion.
+* - XST_DEVICE_IS_STARTED if the device has not been stopped.
+*
+* @note
+* See xaxiethernet.h for a description of the available options.
+*
+******************************************************************************/
+int XAxiEthernet_ClearOptions(XAxiEthernet *InstancePtr, u32 Options)
+{
+ u32 Reg; /* Generic */
+ u32 RegRcw1; /* Reflects original contents of RCW1 */
+ u32 RegTc; /* Reflects original contents of TC */
+ u32 RegNewRcw1; /* Reflects new contents of RCW1 */
+ u32 RegNewTc; /* Reflects new contents of TC */
+ u32 DepOptions; /* Required dependent options for new features */
+
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+
+
+ xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_ClearOptions: 0x%08x\n",
+ Options);
+ /* Be sure device has been stopped */
+ if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) {
+ return (XST_DEVICE_IS_STARTED);
+ }
+
+ /*
+ * Set options word to its new value.
+ * The step is required before calling _UpdateDepOptions() since
+ * we are operating on updated options.
+ */
+ InstancePtr->Options &= ~Options;
+
+ /*
+ * There are options required to be on/off per hardware requirement.
+ * Invoke _UpdateDepOptions to check hardware availability and update
+ * options accordingly.
+ */
+ DepOptions = ~(XAxiEthernet_UpdateDepOptions(InstancePtr));
+
+ /*
+ * New/extended function bit should be off if none of new/extended
+ * features is on after hardware is validated and gone through
+ * _UpdateDepOptions().
+ */
+ if (!(~(DepOptions) & (XAE_EXT_MULTICAST_OPTION |
+ XAE_EXT_TXVLAN_TRAN_OPTION |
+ XAE_EXT_RXVLAN_TRAN_OPTION |
+ XAE_EXT_TXVLAN_TAG_OPTION |
+ XAE_EXT_RXVLAN_TAG_OPTION |
+ XAE_EXT_TXVLAN_STRP_OPTION |
+ XAE_EXT_RXVLAN_STRP_OPTION))) {
+ XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET,
+ XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET) & ~XAE_RAF_NEWFNCENBL_MASK);
+ }
+
+ /*
+ * Many of these options will change the RCW1 or TC registers.
+ * Group these options here and change them all at once. What we are
+ * trying to accomplish is to reduce the amount of IO to the device
+ */
+
+ /* Get the current register contents */
+ RegRcw1 = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET);
+ RegTc = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_TC_OFFSET);
+ RegNewRcw1 = RegRcw1;
+ RegNewTc = RegTc;
+
+ /* Turn off jumbo packet support for both Rx and Tx */
+ if (DepOptions & XAE_JUMBO_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_ClearOptions: disabling jumbo\n");
+ RegNewTc &= ~XAE_TC_JUM_MASK;
+ RegNewRcw1 &= ~XAE_RCW1_JUM_MASK;
+ }
+
+ /* Turn off VLAN packet support for both Rx and Tx */
+ if (DepOptions & XAE_VLAN_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_ClearOptions: disabling vlan\n");
+ RegNewTc &= ~XAE_TC_VLAN_MASK;
+ RegNewRcw1 &= ~XAE_RCW1_VLAN_MASK;
+ }
+
+ /* Turn off FCS stripping on receive packets */
+ if (DepOptions & XAE_FCS_STRIP_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_ClearOptions: disabling fcs strip\n");
+ RegNewRcw1 |= XAE_RCW1_FCS_MASK;
+ }
+
+ /* Turn off FCS insertion on transmit packets */
+ if (DepOptions & XAE_FCS_INSERT_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_ClearOptions: disabling fcs insert\n");
+ RegNewTc |= XAE_TC_FCS_MASK;
+ }
+
+ /* Turn off length/type field checking on receive packets */
+ if (DepOptions & XAE_LENTYPE_ERR_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_ClearOptions: disabling lentype err\n");
+ RegNewRcw1 |= XAE_RCW1_LT_DIS_MASK;
+ }
+
+ /* Disable transmitter */
+ if (DepOptions & XAE_TRANSMITTER_ENABLE_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_ClearOptions: disabling transmitter\n");
+ RegNewTc &= ~XAE_TC_TX_MASK;
+ }
+
+ /* Disable receiver */
+ if (DepOptions & XAE_RECEIVER_ENABLE_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_ClearOptions: disabling receiver\n");
+ RegNewRcw1 &= ~XAE_RCW1_RX_MASK;
+ }
+
+ /* Change the TC and RCW1 registers if they need to be
+ * modified
+ */
+ if (RegTc != RegNewTc) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_ClearOptions: setting TC: 0x%0x\n", RegNewTc);
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_TC_OFFSET, RegNewTc);
+ }
+
+ if (RegRcw1 != RegNewRcw1) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_ClearOptions: setting RCW1: 0x%0x\n",RegNewRcw1);
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET, RegNewRcw1);
+ }
+
+ /*
+ * Rest of options twiddle bits of other registers. Handle them one at
+ * a time
+ */
+
+ /* Turn off flow control */
+ if (DepOptions & XAE_FLOW_CONTROL_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_ClearOptions: disabling flow control\n");
+ Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_FCC_OFFSET);
+ Reg &= ~XAE_FCC_FCRX_MASK;
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_FCC_OFFSET, Reg);
+ }
+
+ /* Turn off promiscuous frame filtering */
+ if (DepOptions & XAE_PROMISC_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_ClearOptions: disabling promiscuous mode\n");
+ Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_FMI_OFFSET);
+ Reg &= ~XAE_FMI_PM_MASK;
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_FMI_OFFSET, Reg);
+ }
+
+ /* Disable broadcast address filtering */
+ if (DepOptions & XAE_BROADCAST_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_ClearOptions: disabling broadcast mode\n");
+ Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_RAF_OFFSET);
+ Reg |= XAE_RAF_BCSTREJ_MASK;
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_RAF_OFFSET, Reg);
+ }
+
+ /* Disable multicast address filtering */
+ if ((DepOptions & XAE_MULTICAST_OPTION) &&
+ (DepOptions & XAE_EXT_MULTICAST_OPTION)) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_ClearOptions:disabling multicast mode\n");
+ Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_RAF_OFFSET);
+ Reg |= XAE_RAF_MCSTREJ_MASK;
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_RAF_OFFSET, Reg);
+ }
+
+ /* Disable extended multicast option */
+ if (DepOptions & XAE_EXT_MULTICAST_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_ClearOptions:disabling extended multicast mode\n");
+ XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET,
+ XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET) & ~XAE_RAF_EMULTIFLTRENBL_MASK);
+ }
+
+ /* Disable extended transmit VLAN tag option */
+ if (DepOptions & XAE_EXT_TXVLAN_TAG_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_ClearOptions:disabling extended TX VLAN tag mode\n");
+ XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET,
+ XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET) & ~XAE_RAF_TXVTAGMODE_MASK);
+ }
+
+ /* Disable extended receive VLAN tag option */
+ if (DepOptions & XAE_EXT_RXVLAN_TAG_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_ClearOptions:disabling extended RX VLAN tag mode\n");
+ XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET,
+ XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET) & ~XAE_RAF_RXVTAGMODE_MASK);
+ }
+
+ /* Disable extended transmit VLAN strip option */
+ if (DepOptions & XAE_EXT_TXVLAN_STRP_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_ClearOptions:disabling extended TX VLAN strip mode\n");
+ XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET,
+ XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET) & ~XAE_RAF_TXVSTRPMODE_MASK);
+ }
+
+ /* Disable extended receive VLAN strip option */
+ if (DepOptions & XAE_EXT_RXVLAN_STRP_OPTION) {
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_ClearOptions:disabling extended RX VLAN strip mode\n");
+ XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET,
+ XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress,
+ XAE_RAF_OFFSET) & ~XAE_RAF_RXVSTRPMODE_MASK);
+ }
+
+ /*
+ * 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.
+ */
+ xdbg_printf(XDBG_DEBUG_GENERAL, "ClearOptions: returning SUCCESS\n");
+ return (XST_SUCCESS);
+}
+
+/*****************************************************************************/
+/**
+* XAxiEthernet_GetOptions returns the current option settings.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return Returns a bitmask of XAE_*_OPTION constants,
+* each bit specifying an option that is currently active.
+*
+* @note
+* See xaxiethernet.h for a description of the available options.
+*
+******************************************************************************/
+u32 XAxiEthernet_GetOptions(XAxiEthernet *InstancePtr)
+{
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+
+ return (InstancePtr->Options);
+}
+
+/*****************************************************************************/
+/**
+ * XAxiEthernet_GetOperatingSpeed gets the current operating link speed. This
+ * may be the value set by XAxiEthernet_SetOperatingSpeed() or a hardware
+ * default.
+ *
+ * @param InstancePtr is a pointer to the Axi Ethernet instance to be
+ * worked on.
+ *
+ * @return Returns the link speed in units of megabits per second (10 /
+ * 100 / 1000).
+ * Can return a value of 0, in case it does not get a valid
+ * speed from EMMC.
+ *
+ * @note None.
+ *
+ ******************************************************************************/
+u16 XAxiEthernet_GetOperatingSpeed(XAxiEthernet *InstancePtr)
+{
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+
+ xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_GetOperatingSpeed\n");
+ switch (XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_EMMC_OFFSET) & XAE_EMMC_LINKSPEED_MASK) {
+
+ case XAE_EMMC_LINKSPD_1000:
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_GetOperatingSpeed: returning 1000\n");
+ return XAE_SPEED_1000_MBPS;
+
+ case XAE_EMMC_LINKSPD_100:
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_GetOperatingSpeed: returning 100\n");
+ return XAE_SPEED_100_MBPS;
+
+ case XAE_EMMC_LINKSPD_10:
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_GetOperatingSpeed: returning 10\n");
+ return (XAE_SPEED_10_MBPS);
+
+ default:
+ return (0);
+ }
+}
+
+
+/*****************************************************************************/
+/**
+ * XAxiEthernet_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 Axi Ethernet on which to
+ * operate.
+ * @param Speed is the speed to set in units of Mbps.
+ * Valid values are 10, 100, or 1000.
+ *
+ * @return - XST_SUCCESS on successful setting of speed.
+ * - XST_FAILURE, if the speed cannot be set for the present
+ * harwdare configuration.
+ *
+ * @note None.
+ *
+ *
+ ******************************************************************************/
+int XAxiEthernet_SetOperatingSpeed(XAxiEthernet *InstancePtr, u16 Speed)
+{
+ u32 EmmcReg;
+ u8 TemacType;
+ u8 PhyType;
+ u8 SetSpeed = TRUE;
+
+ Xil_AssertNonvoid(InstancePtr != NULL);
+ Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
+ Xil_AssertNonvoid((Speed == XAE_SPEED_10_MBPS) ||
+ (Speed == XAE_SPEED_100_MBPS) ||
+ (Speed == XAE_SPEED_1000_MBPS));
+
+
+ xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_SetOperatingSpeed\n");
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_SetOperatingSpeed: setting speed to:%d (0x%0x)\n",
+ Speed, Speed);
+
+ TemacType = XAxiEthernet_GetTemacType(InstancePtr);
+ PhyType = XAxiEthernet_GetPhysicalInterface(InstancePtr);
+ (void) (TemacType);
+
+ /*
+ * The following code checks for all allowable speed conditions before
+ * writing to the register. Please refer to the hardware specs for
+ * more information on it.
+ * For PHY type 1000Base-x, 10 and 100 Mbps are not supported.
+ * For soft/hard Axi Ethernet core, 1000 Mbps is supported in all PHY
+ * types except MII.
+ */
+ if((Speed == XAE_SPEED_10_MBPS) || (Speed == XAE_SPEED_100_MBPS)) {
+ if(PhyType == XAE_PHY_TYPE_1000BASE_X) {
+ SetSpeed = FALSE;
+ }
+ }
+ else {
+ if((Speed == XAE_SPEED_1000_MBPS) &&
+ (PhyType == XAE_PHY_TYPE_MII)) {
+ SetSpeed = FALSE;
+ }
+ }
+
+ if(SetSpeed == TRUE) {
+ /*
+ * Get the current contents of the EMAC config register and
+ * zero out speed bits
+ */
+ EmmcReg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_EMMC_OFFSET) & ~XAE_EMMC_LINKSPEED_MASK;
+
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_SetOperatingSpeed: current speed: 0x%0x\n",
+ EmmcReg);
+ switch (Speed) {
+ case XAE_SPEED_10_MBPS:
+ break;
+
+ case XAE_SPEED_100_MBPS:
+ EmmcReg |= XAE_EMMC_LINKSPD_100;
+ break;
+
+ case XAE_SPEED_1000_MBPS:
+ EmmcReg |= XAE_EMMC_LINKSPD_1000;
+ break;
+
+ default:
+ return (XST_FAILURE);
+ }
+
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_SetOperatingSpeed: new speed: 0x%0x\n",
+ EmmcReg);
+ /* Set register and return */
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_EMMC_OFFSET, EmmcReg);
+ xdbg_printf(XDBG_DEBUG_GENERAL,
+ "XAxiEthernet_SetOperatingSpeed: done\n");
+ return (XST_SUCCESS);
+ }
+ else {
+ xdbg_printf(XDBG_DEBUG_ERROR,
+ "Speed not compatible with the Axi Ethernet Phy type\n");
+ return (XST_FAILURE);
+ }
+
+}
+
+/*****************************************************************************/
+/**
+* XAxiEthernet_SetBadFrmRcvOption is used to enable the bad frame receive
+* option. If enabled, this option ensures that bad receive frames are allowed
+* and passed to the AXI4-Stream interface as if they are good frames.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return None.
+*
+* @note None
+*
+******************************************************************************/
+void XAxiEthernet_SetBadFrmRcvOption(XAxiEthernet *InstancePtr)
+{
+ u32 Reg;
+
+ Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_RAF_OFFSET);
+ Reg |= XAE_RAF_RXBADFRMEN_MASK;
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_RAF_OFFSET, Reg);
+}
+
+/*****************************************************************************/
+/**
+* XAxiEthernet_ClearBadFrmRcvOption is used to disable the bad frame receive
+* option.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return None.
+*
+* @note None.
+*
+******************************************************************************/
+void XAxiEthernet_ClearBadFrmRcvOption(XAxiEthernet *InstancePtr)
+{
+ u32 Reg;
+
+ Reg = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_RAF_OFFSET);
+ Reg &= ~XAE_RAF_RXBADFRMEN_MASK;
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_RAF_OFFSET, Reg);
+}
+
+/*****************************************************************************/
+/**
+* XAxiEthernet_DisableControlFrameLenCheck is used to disable the length check
+* for control frames (pause frames). This means once the API is called, control
+* frames larger than the minimum frame length are accepted.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return None.
+*
+* @note None.
+*
+******************************************************************************/
+void XAxiEthernet_DisableControlFrameLenCheck(XAxiEthernet *InstancePtr)
+{
+ u32 RegRcw1;
+
+ /* Get the current register contents */
+ RegRcw1 = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET);
+ RegRcw1 |= XAE_RCW1_CL_DIS_MASK;
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET, RegRcw1);
+}
+
+/*****************************************************************************/
+/**
+* XAxiEthernet_EnableControlFrameLenCheck is used to enable the length check
+* for control frames (pause frames). After calling the API, all control frames
+* received will be checked for proper length (less than minimum frame length).
+* By default, upon normal start up, control frame length check is enabled.
+* Hence this API needs to be called only if previously the control frame length
+* check has been disabled by calling the API
+* XAxiEthernet_DisableControlFrameLenCheck.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return None.
+*
+* @note None.
+*
+******************************************************************************/
+void XAxiEthernet_EnableControlFrameLenCheck(XAxiEthernet *InstancePtr)
+{
+ u32 RegRcw1;
+
+ /* Get the current register contents */
+ RegRcw1 = XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET);
+ RegRcw1 &= ~XAE_RCW1_CL_DIS_MASK;
+ XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress,
+ XAE_RCW1_OFFSET, RegRcw1);
+}
+
+/*****************************************************************************/
+/**
+* XAxiEthernet_PhySetMdioDivisor sets the MDIO clock divisor in the
+* Axi Ethernet,specified by InstancePtr to the value, Divisor.
+* This function must be called once after each reset prior to accessing
+* MII PHY registers.
+*
+* From the Virtex-6(TM) and Spartan-6 (TM) Embedded Tri-Mode Ethernet
+* MAC User's Guide, the following equation governs the MDIO clock to the PHY:
+*
+* +* 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. +* +* @param InstancePtr references the Axi Ethernet instance on which to +* operate. +* @param Divisor is the divisor value to set within the range of 0 to +* XAE_MDIO_MC_CLK_DVD_MAX. +* +* @note None. +* +******************************************************************************/ +void XAxiEthernet_PhySetMdioDivisor(XAxiEthernet *InstancePtr, u8 Divisor) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY) + Xil_AssertVoid(Divisor <= XAE_MDIO_MC_CLOCK_DIVIDE_MAX); + + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_PhySetMdioDivisor\n"); + + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_MDIO_MC_OFFSET, + (u32) Divisor | XAE_MDIO_MC_MDIOEN_MASK); +} + +/*****************************************************************************/ +/* +* XAxiEthernet_PhyRead reads the specified PHY register, RegiseterNum +* on the PHY specified by PhyAddress into PhyDataPtr. +* This Ethernet driver does not require the device to be stopped before reading +* from the PHY. It is the responsibility of the calling code to stop the +* device if it is deemed necessary. +* +* Note that the Axi Ethernet hardware provides the ability to talk to a PHY +* that adheres to the Media Independent Interface (MII) as defined in the +* IEEE 802.3 standard. +* +* It is important that calling code set up the MDIO clock with +* XAxiEthernet_PhySetMdioDivisor() prior to accessing the PHY with this +* function. +* +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param PhyAddress is the address of the PHY to be written (multiple +* PHYs supported). +* @param RegisterNum is the register number, 0-31, of the specific PHY +* register to write. +* @param PhyDataPtr is a reference to the location where the 16-bit +* result value is stored. +* +* @return None. +* +* +* @note +* +* 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, the calling code should provide a mechanism +* suitable for recovery. +* +******************************************************************************/ +void XAxiEthernet_PhyRead(XAxiEthernet *InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 *PhyDataPtr) +{ + u32 MdioCtrlReg = 0; + + /* + * Verify that each of the inputs are valid. + */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(PhyAddress <= XAE_PHY_ADDR_LIMIT); + Xil_AssertVoid(RegisterNum <= XAE_PHY_REG_NUM_LIMIT); + + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_PhyRead: BaseAddress: 0x%08x\n", + InstancePtr->Config.BaseAddress); + + /* + * Wait till MDIO interface is ready to accept a new transaction. + */ + while (!(XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_MDIO_MCR_OFFSET) & XAE_MDIO_MCR_READY_MASK)) { + ; + } + + MdioCtrlReg = ((PhyAddress << XAE_MDIO_MCR_PHYAD_SHIFT) & + XAE_MDIO_MCR_PHYAD_MASK) | + ((RegisterNum << XAE_MDIO_MCR_REGAD_SHIFT) + & XAE_MDIO_MCR_REGAD_MASK) | + XAE_MDIO_MCR_INITIATE_MASK | + XAE_MDIO_MCR_OP_READ_MASK; + + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_MDIO_MCR_OFFSET, MdioCtrlReg); + + + /* + * Wait till MDIO transaction is completed. + */ + while (!(XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_MDIO_MCR_OFFSET) & XAE_MDIO_MCR_READY_MASK)) { + ; + } + + /* Read data */ + *PhyDataPtr = (u16) XAxiEthernet_ReadReg + (InstancePtr->Config.BaseAddress,XAE_MDIO_MRD_OFFSET); + xdbg_printf(XDBG_DEBUG_GENERAL, + "XAxiEthernet_PhyRead: Value retrieved: 0x%0x\n", *PhyDataPtr); + +} + + +/*****************************************************************************/ +/* +* XAxiEthernet_PhyWrite writes PhyData to the specified PHY register, +* RegiseterNum on the PHY specified by PhyAddress. This Ethernet +* driver does not require the device to be stopped before writing to the PHY. +* It is the responsibility of the calling code to stop the device if it is +* deemed necessary. +* +* Note that the Axi Ethernet hardware provides the ability to talk to a PHY +* that adheres to the Media Independent Interface (MII) as defined in the +* IEEE 802.3 standard. +* +* It is important that calling code set up the MDIO clock with +* XAxiEthernet_PhySetMdioDivisor() prior to accessing the PHY with this +* function. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @param PhyAddress is the address of the PHY to be written (multiple +* PHYs supported). +* @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 None. +* +* @note +* +* 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, the calling code should provide a mechanism +* suitable for recovery. +* +******************************************************************************/ +void XAxiEthernet_PhyWrite(XAxiEthernet *InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 PhyData) +{ + u32 MdioCtrlReg = 0; + + /* + * Verify that each of the inputs are valid. + */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(PhyAddress <= XAE_PHY_ADDR_LIMIT); + Xil_AssertVoid(RegisterNum <= XAE_PHY_REG_NUM_LIMIT); + + + xdbg_printf(XDBG_DEBUG_GENERAL, "XAxiEthernet_PhyWrite\n"); + + /* + * Wait till the MDIO interface is ready to accept a new transaction. + */ + while (!(XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_MDIO_MCR_OFFSET) & XAE_MDIO_MCR_READY_MASK)) { + ; + } + + MdioCtrlReg = ((PhyAddress << XAE_MDIO_MCR_PHYAD_SHIFT) & + XAE_MDIO_MCR_PHYAD_MASK) | + ((RegisterNum << XAE_MDIO_MCR_REGAD_SHIFT) & + XAE_MDIO_MCR_REGAD_MASK) | + XAE_MDIO_MCR_INITIATE_MASK | + XAE_MDIO_MCR_OP_WRITE_MASK; + + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_MDIO_MWD_OFFSET, PhyData); + + XAxiEthernet_WriteReg(InstancePtr->Config.BaseAddress, + XAE_MDIO_MCR_OFFSET, MdioCtrlReg); + + /* + * Wait till the MDIO interface is ready to accept a new transaction. + */ + while (!(XAxiEthernet_ReadReg(InstancePtr->Config.BaseAddress, + XAE_MDIO_MCR_OFFSET) & XAE_MDIO_MCR_READY_MASK)) { + ; + } + +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet.h b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet.h new file mode 100644 index 00000000..debb0c3f --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet.h @@ -0,0 +1,1480 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2015 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xaxiethernet.h +* +* The Xilinx AXI Ethernet MAC driver component. This driver supports hard +* Ethernet core for Virtex-6(TM) devices and soft Ethernet core for +* Spartan-6(TM) and other supported devices. The supported speed can be +* 10/100/1000 Mbps and can reach upto 2000/2500 Mbps (1000Base-X versions). +* +* For a full description of AXI Ethernet features, please see the hardware +* spec. +* This driver supports the following features: +* - Memory mapped access to host interface registers +* - Virtual memory support +* - Unicast, broadcast, and multicast receive address filtering +* - Full duplex operation +* - Automatic source address insertion or overwrite (programmable) +* - Automatic PAD & FCS insertion and stripping (programmable) +* - Flow control +* - VLAN frame support +* - Pause frame support +* - Jumbo frame support +* - Partial and full checksum offload +* - Extended multicast addresses to 2**23. +* - Extended VLAN translation, tagging and stripping supports. +* +*
+* Bits 1-0 : Transmit Checksum Enable: 01 - Partial checsum offload, +* 10 - Full checksum offload +* 00 - No checksum offloading +* 11 - Not used, reserved +* Bits 27-2 : Reserved +* Bits 31-28 : Used for AXI4-Stream Control Mode flag +*+* +*
+* Bits 31-16 (MSB): Transmit Checksum Calculation Starting Point: Offset +* in the frame where checksum calculation should begin. +* Relevant only for partial checksum offloading. +* Bits 15-0 (LSB): Transmit Checksum Insertion Point: Frame offset where +* the computed checksum value is stored, which should be +* in the TCP or UDP header. +* Relevant only for partial checksum offloading. +*+* +*
+* Bits 31-16 (MSB): Reserved +* Bits 0-15 (LSB): Transmit Checksum Calculation Initial Value: Checksum +* seed value. +* Relevant only for partial checksum offloading. +*+* +*
+* Bits 31-28 (MSB): Always 0x5 to represent receive status frame +* Bits 27-16 : Undefined +* Bits 15-0 (LSB): MCAST_ADR_U. Upper 16 bits of the multicast +* destination address of the frame. +* +*+* Bits 31-0 : MCAST_ADR_L. The lower 32 bits of the multicast +* destination address. +* +*AXI4-Stream Status Word 1:
+*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- --------------------------------------------------------- +* 1.00a asa 6/30/10 First release based on the ll temac driver +* 1.01a asa 12/10/10 Added macros XAxiEthernet_IsRxFullCsum and +* XAxiEthernet_IsTxFullCsum for supporting full checksum +* offload. The full checksum offload is only supported in +* newer versions of the core, please refer to the core +* HW datasheet. +* 1.02a asa 2/16/11 Inserted a delay in the driver function +* XAxiEthernet_Reset in file xaxiethernet.c. This is done +* because immediately after a core reset none of the +* AxiEthernet registers are accessible for some duration. +* Changed the value of XAE_LOOPS_TO_COME_OUT_OF_RST to +* 10000 in file xaxiethernet_hw.h. +* +* 2.00a asa 8/29/11 A new major version of AxiEthernet driver is being +* released to accomodate the change in avb software. The +* AxiEthernet hardware v3_00_a has the latest avb +* hardware which needs a corresponding change in avb +* software (released in examples/avb folder). This change +* in avb software is not backwards compatible (which +* means this avb software will not work with older +* axiethernet hardware). +* Hence a new major version of axiethernet is being +* released. +* Added defines for Ability Reg, Identification Reg, Rx max +* Frame and Tx Max Frame registers. +* Changed define for TEMAC RGMII/SGMII Config (PHYC) Reg. +* +* 3.00a asa 4/10/12 A new major version of AxiEthernet is being released to +* accomodate the change in AVB example. From AxiEthernet +* core version 3.01a onwards the AVB implementation has +* changed. The AVB module is now a part of AxiEthernet IP. +* Because of this change, the AVB example works only +* when promiscuous mode is not enabled (unlike earlier +* implementation where promiscuous mode was required for +* AVB example to work). Hence the file xavb_example.c is +* changed so that the core is not put in promiscuous mode. +* Also since AVB is a part of AxiEthernet some of the +* register mappings in xavb_hw.h has changed. +* These changes are not backward compatible which means +* this changed example will not work for previous versions +* of cores. +* Hence a new major version of axiethernet is being +* released. +* 3.01a srt 02/03/13 - Added support for SGMII mode (CR 676793) +* - Added support for IPI designs (CR 698249) +* 02/14/13 - Added support for Zynq (CR 681136) +* 3.02a srt 04/13/13 - Removed Warnings (CR 704998). +* 04/24/13 - Modified parameter *_SGMII_PHYADDR to *_PHYADDR, the +* config parameter C_PHYADDR applies to SGMII/1000BaseX +* modes of operation +* 04/24/13 - Added support for 1000BaseX mode in examples (_util.c) +* (CR 704195) +* 04/24/13 - Added support for RGMII mode in examples (_util.c) +* 3.02a srt 08/06/13 - Fixed CR 727634: +* Modified FifoHandler() function logic of FIFO +* interrupt example to reflect the bit changes in +* the Interrupt Status Register as per the latest +* AXI FIFO stream IP. +* - Fixed CR 721141: +* Added support to handle multiple instances of +* AxiEthernet FIFO interface (CR 721141) +* - Fixed CR 717949: +* Configures external Marvel 88E1111 PHY based on the +* AXI Ethernet physical interface type and allows to +* operate in specific interface mode without changing +* jumpers on the Microblaze boards. This change is in +* example_util.c +* 3.02a adk 15/11/13 - Fixed CR 761035 removed dependency with fifo in MDD file +* 4.0 adk 19/12/13 - Updated as per the New Tcl API's +* asa 30/01/14 - Added defines for 1588 registers and bit masks +* Added config parameter for SGMII over LVDS +* +* 4.1 adk 21/04/14 - Fixed CR:780537 Changes are Made in the file +* axiethernet test-app tcl +* 4.2 adk 08/08/14 - Fixed CR:810643 SDK generated 'xparamters.h' erroneously +* generated with errors due to part of '#define' misplaced +* changes are made in the driver tcl file. +* 4.3 adk 29/10/14 - Added support for generating parameters for SGMII/1000BaseX +* modes When IP is configured with the PCS/PMA core. +* Changes are made in the driver tcl file (CR 828796). +* 4.4 adk 8/1/15 - Fixed TCL errors when axiethernet is configured with the +* Axi stream fifo (CR 835605). Changes are made in the +* driver tcl file. +*+* +******************************************************************************/ + +#ifndef XAXIETHERNET_H /* prevent circular inclusions */ +#define XAXIETHERNET_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xenv.h" +#include "xstatus.h" +#include "xil_assert.h" +#include "xaxiethernet_hw.h" + +/************************** Constant Definitions *****************************/ + +/** @name Configuration options + * + * The following are device configuration options. See the + * XAxiEthernet_SetOptions, XAxiEthernet_ClearOptions and + * XAxiEthernet_GetOptions routines for information on how to use + * options. + * + * The default state of the options are also noted below. + * + * @{ + */ + +/**< XAE_PROMISC_OPTION specifies the Axi Ethernet device to accept all + * incoming packets. + * This driver sets this option to disabled (cleared) by default. + */ +#define XAE_PROMISC_OPTION 0x00000001 + +/**< XAE_JUMBO_OPTION specifies the Axi Ethernet device to accept jumbo + * frames for transmit and receive. + * This driver sets this option to disabled (cleared) by default. + */ +#define XAE_JUMBO_OPTION 0x00000002 + +/**< XAE_VLAN_OPTION specifies the Axi Ethernet device to enable VLAN support + * for transmit and receive. + * This driver sets this option to disabled (cleared) by default. + */ +#define XAE_VLAN_OPTION 0x00000004 + +/**< XAE_FLOW_CONTROL_OPTION specifies the Axi Ethernet device to recognize + * received flow control frames. + * This driver sets this option to enabled (set) by default. + */ +#define XAE_FLOW_CONTROL_OPTION 0x00000008 + +/**< XAE_FCS_STRIP_OPTION specifies the Axi Ethernet device to strip FCS and + * PAD from received frames. Note that PAD from VLAN frames is not stripped. + * This driver sets this option to enabled (set) by default. + */ +#define XAE_FCS_STRIP_OPTION 0x00000010 + +/**< XAE_FCS_INSERT_OPTION specifies the Axi Ethernet device to generate the + * FCS field and add PAD automatically for outgoing frames. + * This driver sets this option to enabled (set) by default. + */ +#define XAE_FCS_INSERT_OPTION 0x00000020 + +/**< XAE_LENTYPE_ERR_OPTION specifies the Axi Ethernet device to enable + * Length/Type error checking (mismatched type/length field) for received + * frames. + * This driver sets this option to enabled (set) by default. + */ +#define XAE_LENTYPE_ERR_OPTION 0x00000040 + +/**< XAE_TRANSMITTER_ENABLE_OPTION specifies the Axi Ethernet device + * transmitter to be enabled. + * This driver sets this option to enabled (set) by default. + */ +#define XAE_TRANSMITTER_ENABLE_OPTION 0x00000080 + +/**< XAE_RECEIVER_ENABLE_OPTION specifies the Axi Ethernet device receiver to + * be enabled. + * This driver sets this option to enabled (set) by default. + */ +#define XAE_RECEIVER_ENABLE_OPTION 0x00000100 + +/**< XAE_BROADCAST_OPTION specifies the Axi Ethernet device to receive frames + * sent to the broadcast Ethernet address. + * This driver sets this option to enabled (set) by default. + */ +#define XAE_BROADCAST_OPTION 0x00000200 + +/**< XAE_MULTICAST_OPTION specifies the Axi Ethernet device to receive frames + * sent to Ethernet addresses that are programmed into the Multicast Address + * Table (MAT). + * This driver sets this option to disabled (cleared) by default. + */ +#define XAE_MULTICAST_OPTION 0x00000400 + +/**< XAE_EXT_MULTICAST_OPTION specifies the Axi Ethernet device to receive + * frames sent to Ethernet addresses that are programmed into the Multicast + * Address Table. + * This driver sets this option to be dependent on HW configuration + * by default. + */ +#define XAE_EXT_MULTICAST_OPTION 0x00000800 + +/**< XAE_EXT_TXVLAN_TRAN_OPTION specifies the Axi Ethernet device to enable + * transmit VLAN translation. + * This driver sets this option to be dependent on HW configuration + * by default. + */ +#define XAE_EXT_TXVLAN_TRAN_OPTION 0x00001000 + +/**< XAE_EXT_RXVLAN_TRAN_OPTION specifies the Axi Ethernet device to enable + * receive VLAN translation. + * This driver sets this option to be dependent on HW configuration + * by default. + */ +#define XAE_EXT_RXVLAN_TRAN_OPTION 0x00002000 + +/**< XAE_EXT_TXVLAN_TAG_OPTION specifies the Axi Ethernet device to enable + * transmit VLAN tagging. + * This driver sets this option to be dependent during HW build time + * by default. + */ +#define XAE_EXT_TXVLAN_TAG_OPTION 0x00004000 + +/**< XAE_EXT_RXVLAN_TAG_OPTION specifies the Axi Ethernet device to enable + * receive VLAN tagging. + * This driver sets this option to be dependent during HW build time + * by default. + */ +#define XAE_EXT_RXVLAN_TAG_OPTION 0x00008000 + +/**< XAE_EXT_TXVLAN_STRP_OPTION specifies the Axi Ethernet device to enable + * transmit VLAN stripping. + * This driver sets this option to be dependent during HW build time + * by default. + */ +#define XAE_EXT_TXVLAN_STRP_OPTION 0x00010000 + +/**< XAE_EXT_RXVLAN_STRP_OPTION specifies the Axi Ethernet device to enable + * receive VLAN stripping. + * This driver sets this option to be dependent during HW build time + * by default. + */ +#define XAE_EXT_RXVLAN_STRP_OPTION 0x00020000 + + +#define XAE_DEFAULT_OPTIONS \ + (XAE_FLOW_CONTROL_OPTION | \ + XAE_BROADCAST_OPTION | \ + XAE_FCS_INSERT_OPTION | \ + XAE_FCS_STRIP_OPTION | \ + XAE_LENTYPE_ERR_OPTION | \ + XAE_TRANSMITTER_ENABLE_OPTION | \ + XAE_RECEIVER_ENABLE_OPTION) +/**< XAE_DEFAULT_OPTIONS specify the options set in XAxiEthernet_Reset() and + * XAxiEthernet_CfgInitialize() + */ +/*@}*/ + + +#define XAE_MULTI_MAT_ENTRIES 4 /**< Number of storable addresses in + * the Multicast Address Table + */ + +#define XAE_MDIO_DIV_DFT 29 /**< 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 XAE_MAC_ADDR_SIZE 6 /* MAC addresses are 6 bytes */ +#define XAE_MTU 1500 /* Max MTU size of an Ethernet + * frame + */ +#define XAE_JUMBO_MTU 8982 /* Max MTU size of a jumbo + * Ethernet frame + */ +#define XAE_HDR_SIZE 14 /* Size of an Ethernet header*/ +#define XAE_HDR_VLAN_SIZE 18 /* Size of an Ethernet header + * with VLAN + */ +#define XAE_TRL_SIZE 4 /* Size of an Ethernet trailer + * (FCS) + */ +#define XAE_MAX_FRAME_SIZE (XAE_MTU + XAE_HDR_SIZE + XAE_TRL_SIZE) +#define XAE_MAX_VLAN_FRAME_SIZE (XAE_MTU + XAE_HDR_VLAN_SIZE + XAE_TRL_SIZE) +#define XAE_MAX_JUMBO_FRAME_SIZE (XAE_JUMBO_MTU + XAE_HDR_SIZE + XAE_TRL_SIZE) + +/* + * Constant values returned by XAxiEthernet_GetPhysicalInterface(). Note that + * these values match design parameters from the Axi Ethernet spec. + */ +#define XAE_PHY_TYPE_MII 0 +#define XAE_PHY_TYPE_GMII 1 +#define XAE_PHY_TYPE_RGMII_1_3 2 +#define XAE_PHY_TYPE_RGMII_2_0 3 +#define XAE_PHY_TYPE_SGMII 4 +#define XAE_PHY_TYPE_1000BASE_X 5 + +#define XAE_TPID_MAX_ENTRIES 4 /* Number of storable TPIDs in + * Table + */ + +/* + * Constant values pass into XAxiEthernet_SetV[tag|Strp]Mode() and returned by + * XAxiEthernet_GetV[tag|Strp]Mode(). + */ +#define XAE_VTAG_NONE 0 /* No tagging */ +#define XAE_VTAG_ALL 1 /* Tag all frames */ +#define XAE_VTAG_EXISTED 2 /* Tag already tagged frames */ +#define XAE_VTAG_SELECT 3 /* + * Tag selected already tagged + * frames + */ +#define XAE_DEFAULT_TXVTAG_MODE XAE_VTAG_ALL +#define XAE_DEFAULT_RXVTAG_MODE XAE_VTAG_ALL + +#define XAE_VSTRP_NONE 0 /* No stripping */ +#define XAE_VSTRP_ALL 1 /* Strip one tag from all + * frames + */ +#define XAE_VSTRP_SELECT 3 /* Strip one tag from selected + * frames + */ +#define XAE_DEFAULT_TXVSTRP_MODE XAE_VSTRP_ALL +#define XAE_DEFAULT_RXVSTRP_MODE XAE_VSTRP_ALL + +#define XAE_RX 1 /* Receive direction */ +#define XAE_TX 2 /* Transmit direction */ + +#define XAE_SOFT_TEMAC_10_100_MBPS 0 +#define XAE_SOFT_TEMAC_10_100_1000_MBPS 1 +#define XAE_HARD_TEMC 2 + +/**************************** Type Definitions *******************************/ + + +/** + * This typedef contains configuration information for a Axi Ethernet device. + */ +typedef struct XAxiEthernet_Config { + u16 DeviceId; /**< DeviceId is the unique ID of the device */ + u32 BaseAddress;/**< BaseAddress is the physical base address of the + * device's registers + */ + u8 TemacType; /**< Temac Type can have 3 possible values. They are + * 0 for SoftTemac at 10/100 Mbps, 1 for SoftTemac + * at 10/100/1000 Mbps and 2 for Vitex6 Hard Temac + */ + u8 TxCsum; /**< TxCsum indicates that the device has checksum + * offload on the Tx channel or not. + */ + u8 RxCsum; /**< RxCsum indicates that the device has checksum + * offload on the Rx channel or not. + */ + u8 PhyType; /**< PhyType indicates which type of PHY interface is + * used (MII, GMII, RGMII, etc. + */ + u8 TxVlanTran; /**< TX VLAN Translation indication */ + u8 RxVlanTran; /**< RX VLAN Translation indication */ + u8 TxVlanTag; /**< TX VLAN tagging indication */ + u8 RxVlanTag; /**< RX VLAN tagging indication */ + u8 TxVlanStrp; /**< TX VLAN stripping indication */ + u8 RxVlanStrp; /**< RX VLAN stripping indication */ + u8 ExtMcast; /**< Extend multicast indication */ + u8 Stats; /**< Statistics gathering option */ + u8 Avb; /**< Avb option */ + u8 EnableSgmiiOverLvds; /**< Enable LVDS option */ + + u8 TemacIntr; /**< Axi Ethernet interrupt ID */ + + int AxiDevType; /**< AxiDevType is the type of device attached to the + * Axi Ethernet's AXI4-Stream interface. + */ + u32 AxiDevBaseAddress; /**< AxiDevBaseAddress is the base address of + * the device attached to the Axi Ethernet's + * AXI4-Stream interface. + */ + u8 AxiFifoIntr; /**< AxiFifoIntr interrupt ID (unused if DMA) */ + u8 AxiDmaRxIntr;/**< Axi DMA RX interrupt ID (unused if FIFO) */ + u8 AxiDmaTxIntr;/**< Axi DMA TX interrupt ID (unused if FIFO) */ +} XAxiEthernet_Config; + + +/** + * struct XAxiEthernet is the type for Axi Ethernet driver instance data. + * The calling code is required to use a unique instance of this structure + * for every Axi Ethernet device used in the system. A reference to a structure + * of this type is then passed to the driver API functions. + */ +typedef struct XAxiEthernet { + XAxiEthernet_Config Config; /**< Hardware configuration */ + u32 IsStarted; /**< Device is currently started */ + u32 IsReady; /**< Device is initialized and ready */ + u32 Options; /**< Current options word */ + u32 Flags; /**< Internal driver flags */ +} XAxiEthernet; + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsStarted reports if the device is in the started or stopped +* state. To be in the started state, the calling code must have made a +* successful call to XAxiEthernet_Start. To be in the stopped state, +* XAxiEthernet_Stop or XAxiEthernet_CfgInitialize function must +* have been called. +* +* @param InstancePtr is a pointer to the of Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the device has been started. +* - FALSE.if the device has not been started +* +* @note C-style signature: +* u32 XAxiEthernet_IsStarted(XAxiEthernet *InstancePtr) +* + ******************************************************************************/ +#define XAxiEthernet_IsStarted(InstancePtr) \ + (((InstancePtr)->IsStarted == XIL_COMPONENT_IS_STARTED) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsDma reports if the device is currently connected to DMA. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @return +* - TRUE if the Axi Ethernet device is connected DMA. +* - FALSE.if the Axi Ethernet device is NOT connected to DMA +* +* @note C-style signature: +* u32 XAxiEthernet_IsDma(XAxiEthernet *InstancePtr) +* +******************************************************************************/ +#define XAxiEthernet_IsDma(InstancePtr) \ + (((InstancePtr)->Config.AxiDevType == XPAR_AXI_DMA) ? TRUE: FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsFifo reports if the device is currently connected to a fifo +* core. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the Axi Ethernet device is connected to a fifo +* - FALSE if the Axi Ethernet device is NOT connected to a fifo. +* +* @note C-style signature: +* u32 XAxiEthernet_IsFifo(XAxiEthernet *InstancePtr) +* +******************************************************************************/ +#define XAxiEthernet_IsFifo(InstancePtr) \ + (((InstancePtr)->Config.AxiDevType == XPAR_AXI_FIFO) ? TRUE: FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_AxiDevBaseAddress reports the base address of the core connected +* to the Axi Ethernet's Axi4 Stream interface. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return The base address of the core connected to the Axi Ethernet's +* streaming interface. +* +* @note C-style signature: +* u32 XAxiEthernet_AxiDevBaseAddress(XAxiEthernet *InstancePtr) +* +******************************************************************************/ +#define XAxiEthernet_AxiDevBaseAddress(InstancePtr) \ + ((InstancePtr)->Config.AxiDevBaseAddress) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsRecvFrameDropped determines if the device thinks it has +* dropped a receive frame. The device interrupt status register is read to +* determine this. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if a frame has been dropped +* - FALSE if a frame has NOT been dropped. +* +* @note C-style signature: +* u32 XAxiEthernet_IsRecvFrameDropped(XAxiEthernet *InstancePtr) +* +******************************************************************************/ +#define XAxiEthernet_IsRecvFrameDropped(InstancePtr) \ + ((XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, \ + XAE_IS_OFFSET) & XAE_INT_RXRJECT_MASK) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsRxPartialCsum determines if the device is configured with +* partial checksum offloading on the receive channel. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @return +* - TRUE if the device is configured with partial checksum +* offloading on the receive channel. +* - FALSE.if the device is not configured with partial checksum +* offloading on the receive side. +* +* @note C-style signature: +* u32 XAxiEthernet_IsRxPartialCsum(XAxiEthernet *InstancePtr) +* +******************************************************************************/ +#define XAxiEthernet_IsRxPartialCsum(InstancePtr) \ + ((((InstancePtr)->Config.RxCsum) == 0x01) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsTxPartialCsum determines if the device is configured with +* partial checksum offloading on the transmit channel. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the device is configured with partial checksum +* offloading on the transmit side. +* - FALSE.if the device is not configured with partial checksum +* offloading on the transmit side. +* +* @note C-style signature: +* u32 XAxiEthernet_IsTxPartialCsum(XAxiEthernet *InstancePtr) +* +******************************************************************************/ +#define XAxiEthernet_IsTxPartialCsum(InstancePtr) \ + ((((InstancePtr)->Config.TxCsum) == 0x01) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsRxFullCsum determines if the device is configured with full +* checksum offloading on the receive channel. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* @return +* - TRUE if the device is configured with full checksum +* offloading on the receive channel. +* - FALSE.if the device is not configured with full checksum +* offloading on the receive side. +* +* @note C-style signature: +* u32 XAxiEthernet_IsRxFullCsum(XAxiEthernet *InstancePtr) +* +******************************************************************************/ +#define XAxiEthernet_IsRxFullCsum(InstancePtr) \ + ((((InstancePtr)->Config.RxCsum) == 0x02) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_IsTxFullCsum determines if the device is configured with full +* checksum offloading on the transmit channel. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return +* - TRUE if the device is configured with full checksum +* offloading on the transmit side. +* - FALSE.if the device is not configured with full checksum +* offloading on the transmit side. +* +* @note C-style signature: +* u32 XAxiEthernet_IsTxFullCsum(XAxiEthernet *InstancePtr) +* +******************************************************************************/ +#define XAxiEthernet_IsTxFullCsum(InstancePtr) \ + ((((InstancePtr)->Config.TxCsum) == 0x02) ? TRUE : FALSE) + +/*****************************************************************************/ +/** +* +* XAxiEthernet_GetPhysicalInterface returns the type of PHY interface being +* used by the given instance, specified by InstancePtr. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return The Physical Interface type which is one of XAE_PHY_TYPE_x +* where x is MII, GMII, RGMII_1_3, RGMII_2_0, SGMII, or +* 1000BASE_X (defined in xaxiethernet.h). +* +* @note C-style signature: +* int XAxiEthernet_GetPhysicalInterface(XAxiEthernet +* *InstancePtr) +* +******************************************************************************/ +#define XAxiEthernet_GetPhysicalInterface(InstancePtr) \ + ((InstancePtr)->Config.PhyType) + +/****************************************************************************/ +/** +* +* XAxiEthernet_GetIntStatus returns a bit mask of the interrupt status +* register (ISR). XAxiEthernet_GetIntStatus can be used to query the status +* without having to have interrupts enabled. +* +* @param InstancePtr is a pointer to the Axi Ethernet instance to be +* worked on. +* +* @return Returns a bit mask of the interrupt status conditions. The +* mask will be a set of bit wise or'd values from the +*
XAE_INT_*_MASK
definitions in xaxitemac_hw.h file.
+*
+* @note C-style signature:
+* u32 XAxiEthernet_GetIntStatus(XAxiEthernet *InstancePtr)
+*
+*****************************************************************************/
+#define XAxiEthernet_GetIntStatus(InstancePtr) \
+ XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, XAE_IS_OFFSET)
+
+/****************************************************************************/
+/**
+*
+* XAxiEthernet_IntEnable enables the 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 Axi Ethernet instance to be
+* worked on.
+*
+* @param Mask contains a bit mask of the interrupts to enable. The mask
+* can be formed using a set of bit wise or'd values from the
+* XAE_INT_*_MASK
definitions in xaxitemac_hw.h file.
+*
+* @return None.
+*
+* @note C-style signature:
+* void XAxiEthernet_IntEnable(XAxiEthernet *InstancePtr,
+* u32 Mask)
+*
+*****************************************************************************/
+#define XAxiEthernet_IntEnable(InstancePtr, Mask) \
+ XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress, \
+ XAE_IE_OFFSET, \
+ XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, \
+ XAE_IE_OFFSET) | ((Mask) & XAE_INT_ALL_MASK));
+
+/****************************************************************************/
+/**
+*
+* XAxiEthernet_IntDisable disables the interrupts specified in Mask. The
+* corresponding interrupt for each bit set to 1 in Mask, will be
+* disabled. In other words, XAxiEthernet_IntDisable uses the "set a bit to
+* clear it" scheme.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+* @param Mask contains a bit mask of the interrupts to disable. The mask
+* can be formed using a set of bit wise or'd values from the
+* XAE_INT_*_MASK
definitions in xaxitemac_hw.h file
+*
+* @return None.
+*
+* @note C-style signature:
+* void XAxiEthernet_IntDisable(XAxiEthernet *InstancePtr,
+* u32 Mask)
+*
+*****************************************************************************/
+#define XAxiEthernet_IntDisable(InstancePtr, Mask) \
+ XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress, \
+ XAE_IE_OFFSET, \
+ XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, \
+ XAE_IE_OFFSET) & ~((Mask) & XAE_INT_ALL_MASK));
+
+/****************************************************************************/
+/**
+*
+* XAxiEthernet_IntPending returns a bit mask of the pending interrupts. Each
+* bit set to 1 in the return value represents a pending interrupt.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return Returns a bit mask of the interrupts that are pending. The mask
+* will be a set of bit wise or'd values from the
+* XAE_INT_*_MASK
definitions in xaxitemac_hw.h file.
+*
+* @note C-style signature:
+* u32 XAxiEthernet_IntPending(XAxiEthernet *InstancePtr)
+*
+*****************************************************************************/
+#define XAxiEthernet_IntPending(InstancePtr) \
+ XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, XAE_IP_OFFSET)
+
+/****************************************************************************/
+/**
+*
+* XAxiEthernet_IntClear clears pending interrupts specified in Mask.
+* The corresponding pending interrupt for each bit set to 1 in Mask,
+* will be cleared. In other words, XAxiEthernet_IntClear uses the "set a bit to
+* clear it" scheme.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+* @param Mask contains a bit mask of the pending interrupts to clear.
+* The mask can be formed using a set of bit wise or'd values from
+* the XAE_INT_*_MASK
definitions in xaxitemac_hw.h
+* file.
+*
+* @note C-style signature:
+* void XAxiEthernet_IntClear(XAxiEthernet *InstancePtr,
+* u32 Mask)
+*
+*****************************************************************************/
+#define XAxiEthernet_IntClear(InstancePtr, Mask) \
+ XAxiEthernet_WriteReg((InstancePtr)->Config.BaseAddress, \
+ XAE_IS_OFFSET, ((Mask) & XAE_INT_ALL_MASK))
+
+/*****************************************************************************/
+/**
+*
+* XAxiEthernet_IsExtFuncCap determines if the device is capable of the
+* new/extend VLAN and multicast features.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return
+* - TRUE if the device is capable and configured with extended
+* Multicast and VLAN Tagging/Stripping and Translation.
+* - TRUE if the device is NOT capable and NOT configured with
+* extended Multicast and VLAN Tagging/Stripping and
+* Translation.
+*
+* @note C-style signature:
+* u32 XAxiEthernet_IsExtFuncCap(XAxiEthernet *InstancePtr)
+*
+ *****************************************************************************/
+#define XAxiEthernet_IsExtFuncCap(InstancePtr) \
+ ((XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, \
+ XAE_RAF_OFFSET) & XAE_RAF_NEWFNCENBL_MASK) ? \
+ TRUE : FALSE)
+
+/*****************************************************************************/
+/**
+*
+* XAxiEthernet_IsExtMcastEnable determines if the extended multicast features
+* is enabled.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return
+* - TRUE if the extended multicast features are enabled.
+* - FALSE if the extended multicast features are NOT enabled
+*
+* @note : This function indicates when extended Multicast is enabled in
+* HW, extended multicast mode in wrapper can be tested.
+*
+* C-style signature:
+* u32 XAxiEthernet_IsExtMcastEnable(XAxiEthernet *InstancePtr)
+*
+*****************************************************************************/
+#define XAxiEthernet_IsExtMcastEnable(InstancePtr) \
+ ((XAxiEthernet_ReadReg((InstancePtr)->Config.BaseAddress, \
+ XAE_RAF_OFFSET) & XAE_RAF_EMULTIFLTRENBL_MASK) ? \
+ TRUE : FALSE)
+
+/*****************************************************************************/
+/**
+*
+* XAxiEthernet_IsExtMcast determines if the device is built with new/extended
+* multicast features.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return
+* - TRUE if the device is built with extended multicast features.
+* - FALSE if the device is not built with the extended multicast
+* features.
+*
+* @note This function indicates when hardware is built with extended
+* Multicast feature.
+*
+* C-style signature:
+* u32 XAxiEthernet_IsExtMcast(XAxiEthernet *InstancePtr)
+*
+*****************************************************************************/
+#define XAxiEthernet_IsExtMcast(InstancePtr) \
+ (((InstancePtr)->Config.ExtMcast) ? TRUE : FALSE)
+
+/*****************************************************************************/
+/**
+*
+* XAxiEthernet_IsTxVlanStrp determines if the device is configured with transmit
+* VLAN stripping on the transmit channel.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return
+* - TRUE if the device is configured with
+* VLAN stripping on the Transmit channel.
+* - FALSE if the device is NOT configured with
+* VLAN stripping on the Transmit channel.
+*
+* @note C-style signature:
+* u32 XAxiEthernet_IsTxVlanStrp(XAxiEthernet *InstancePtr)
+*
+*****************************************************************************/
+#define XAxiEthernet_IsTxVlanStrp(InstancePtr) \
+ (((InstancePtr)->Config.TxVlanStrp) ? TRUE : FALSE)
+
+/*****************************************************************************/
+/**
+*
+* XAxiEthernet_IsRxVlanStrp determines if the device is configured with receive
+* VLAN stripping on the receive channel.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return
+* - TRUE if the device is configured with
+* VLAN stripping on the Receive channel.
+* - FALSE if the device is NOT configured with
+* VLAN stripping on the Receive channel.
+*
+* @note C-style signature:
+* u32 XAxiEthernet_IsRxVlanTran(XAxiEthernet *InstancePtr)
+*
+ *****************************************************************************/
+#define XAxiEthernet_IsRxVlanStrp(InstancePtr) \
+ (((InstancePtr)->Config.RxVlanStrp) ? TRUE : FALSE)
+
+/*****************************************************************************/
+/**
+*
+* XAxiEthernet_IsTxVlanTran determines if the device is configured with
+* transmit VLAN translation on the transmit channel.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return
+* - TRUE if the device is configured with
+* VLAN translation on the Transmit channel.
+* - FALSE if the device is NOT configured with
+* VLAN translation on the Transmit channel.
+*
+* @note C-style signature:
+* u32 XAxiEthernet_IsTxVlanTran(XAxiEthernet *InstancePtr)
+*
+*****************************************************************************/
+#define XAxiEthernet_IsTxVlanTran(InstancePtr) \
+ (((InstancePtr)->Config.TxVlanTran) ? TRUE : FALSE)
+
+/*****************************************************************************/
+/**
+*
+* XAxiEthernet_IsRxVlanTran determines if the device is configured with receive
+* VLAN translation on the receive channel.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return
+* - TRUE if the device is configured with
+* VLAN translation on the Receive channel.
+* - FALSE if the device is NOT configured with
+* VLAN translation on the Receive channel.
+*
+* @note C-style signature:
+* u32 XAxiEthernet_IsRxVlanTran(XAxiEthernet *InstancePtr)
+*
+*****************************************************************************/
+#define XAxiEthernet_IsRxVlanTran(InstancePtr) \
+ (((InstancePtr)->Config.RxVlanTran) ? TRUE : FALSE)
+
+/*****************************************************************************/
+/**
+*
+* XAxiEthernet_IsTxVlanTag determines if the device is configured with transmit
+* VLAN tagging on the transmit channel.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return
+* - TRUE if the device is configured with
+* VLAN tagging on the Transmit channel.
+* - FALSE if the device is NOT configured with
+* VLAN tagging on the Transmit channel.
+*
+* @note C-style signature:
+* u32 XAxiEthernet_IsTxVlanTag(XAxiEthernet *InstancePtr)
+*
+*****************************************************************************/
+#define XAxiEthernet_IsTxVlanTag(InstancePtr) \
+ (((InstancePtr)->Config.TxVlanTag) ? TRUE : FALSE)
+
+/*****************************************************************************/
+/**
+*
+* XAxiEthernet_IsRxVlanTag determines if the device is configured with receive
+* VLAN tagging on the receive channel.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return
+* - TRUE if the device is configured with
+* VLAN tagging on the Receive channel.
+* - FALSE if the device is NOT configured with
+* VLAN tagging on the Receive channel.
+*
+* @note C-style signature:
+* u32 XAxiEthernet_IsRxVlanTag(XAxiEthernet *InstancePtr)
+*
+ *****************************************************************************/
+#define XAxiEthernet_IsRxVlanTag(InstancePtr) \
+ (((InstancePtr)->Config.RxVlanTag) ? TRUE : FALSE)
+
+/*****************************************************************************/
+/**
+*
+* XAxiEthernet_GetTemacType returns the Axi Ethernet type of the core.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return
+* - Returns the values of TemacType, which can be
+* XAE_SOFT_TEMAC_10_100_MBPS (0) for Soft Temac Core with
+* speed 10/100 Mbps.
+* XAE_SOFT_TEMAC_10_100_1000_MBPS (1) for Soft Temac core with
+* speed 10/100/1000 Mbps
+* XAE_HARD_TEMC (2) for Hard Temac Core for Virtex-6
+*
+* @note C-style signature:
+* u32 XAxiEthernet_GetTemacType(XAxiEthernet *InstancePtr)
+*
+ *****************************************************************************/
+#define XAxiEthernet_GetTemacType(InstancePtr) \
+ ((InstancePtr)->Config.TemacType)
+
+/*****************************************************************************/
+/**
+*
+* XAxiEthernet_IsAvbConfigured returns determines if Ethernet AVB.is configured
+* in the harwdare or not.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return
+* - TRUE if the device is configured with
+* Ethernet AVB.
+* - FALSE if the device is NOT configured with
+* Ethernet AVB.
+*
+* @note C-style signature:
+* u32 XAxiEthernet_IsAvbConfigured(XAxiEthernet *InstancePtr)
+*
+ *****************************************************************************/
+#define XAxiEthernet_IsAvbConfigured(InstancePtr) \
+ (((InstancePtr)->Config.Avb) ? TRUE : FALSE)
+
+/*****************************************************************************/
+/**
+*
+* XAxiEthernet_IsSgmiiOverLvdsEnabled determines if SGMII over LVDS is enabled
+* in the harwdare or not.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return
+* - TRUE if the device is configured with
+* SGMII over LVDS.
+* - FALSE if the device is NOT configured with
+* SGMII over LVDS.
+*
+* @note C-style signature:
+* u32 XAxiEthernet_IsSgmiiOverLvdsEnabled(XAxiEthernet *InstancePtr)
+*
+ *****************************************************************************/
+#define XAxiEthernet_IsSgmiiOverLvdsEnabled(InstancePtr) \
+ (((InstancePtr)->Config.EnableSgmiiOverLvds) ? TRUE : FALSE)
+
+/*****************************************************************************/
+/**
+*
+* XAxiEthernet_IsStatsConfigured returns determines if Statistics gathering.
+* is configured in the harwdare or not.
+*
+* @param InstancePtr is a pointer to the Axi Ethernet instance to be
+* worked on.
+*
+* @return
+* - TRUE if the device is configured with
+* statistics gathering.
+* - FALSE if the device is NOT configured with
+* statistics gathering.
+*
+* @note C-style signature:
+* u32 XAxiEthernet_IsStatsConfigured(XAxiEthernet *InstancePtr)
+*
+ *****************************************************************************/
+#define XAxiEthernet_IsStatsConfigured(InstancePtr) \
+ (((InstancePtr)->Config.Stats) ? TRUE : FALSE)
+
+/************************** Function Prototypes ******************************/
+
+/*
+ * Initialization functions in xaxiethernet.c
+ */
+int XAxiEthernet_CfgInitialize(XAxiEthernet *InstancePtr,
+ XAxiEthernet_Config *CfgPtr,u32 VirtualAddress);
+void XAxiEthernet_Start(XAxiEthernet *InstancePtr);
+void XAxiEthernet_Stop(XAxiEthernet *InstancePtr);
+void XAxiEthernet_Reset(XAxiEthernet *InstancePtr);
+
+/*
+ * Initialization functions in xaxitemac_sinit.c
+ */
+XAxiEthernet_Config *XAxiEthernet_LookupConfig(u16 DeviceId);
+
+/*
+ * MAC configuration/control functions in xaxitemac_control.c
+ */
+int XAxiEthernet_SetOptions(XAxiEthernet *InstancePtr, u32 Options);
+int XAxiEthernet_ClearOptions(XAxiEthernet *InstancePtr, u32 Options);
+u32 XAxiEthernet_GetOptions(XAxiEthernet *InstancePtr);
+
+int XAxiEthernet_SetMacAddress(XAxiEthernet *InstancePtr, void *AddressPtr);
+void XAxiEthernet_GetMacAddress(XAxiEthernet *InstancePtr, void *AddressPtr);
+
+int XAxiEthernet_SetMacPauseAddress(XAxiEthernet *InstancePtr,
+ void *AddressPtr);
+void XAxiEthernet_GetMacPauseAddress(XAxiEthernet *InstancePtr,
+ void *AddressPtr);
+int XAxiEthernet_SendPausePacket(XAxiEthernet *InstancePtr, u16 PauseValue);
+
+int XAxiEthernet_GetSgmiiStatus(XAxiEthernet *InstancePtr, u16 *SpeedPtr);
+int XAxiEthernet_GetRgmiiStatus(XAxiEthernet *InstancePtr, u16 *SpeedPtr,
+ int *IsFullDuplexPtr, int *IsLinkUpPtr);
+u16 XAxiEthernet_GetOperatingSpeed(XAxiEthernet *InstancePtr);
+int XAxiEthernet_SetOperatingSpeed(XAxiEthernet *InstancePtr, u16 Speed);
+
+void XAxiEthernet_SetBadFrmRcvOption(XAxiEthernet *InstancePtr);
+void XAxiEthernet_ClearBadFrmRcvOption(XAxiEthernet *InstancePtr);
+
+void XAxiEthernet_DisableControlFrameLenCheck(XAxiEthernet *InstancePtr);
+void XAxiEthernet_EnableControlFrameLenCheck(XAxiEthernet *InstancePtr);
+
+void XAxiEthernet_PhySetMdioDivisor(XAxiEthernet *InstancePtr, u8 Divisor);
+void XAxiEthernet_PhyRead(XAxiEthernet *InstancePtr, u32 PhyAddress,
+ u32 RegisterNum, u16 *PhyDataPtr);
+void XAxiEthernet_PhyWrite(XAxiEthernet *InstancePtr, u32 PhyAddress,
+ u32 RegisterNum, u16 PhyData);
+int XAxiEthernet_MulticastAdd(XAxiEthernet *InstancePtr, void *AddressPtr,
+ int Entry);
+void XAxiEthernet_MulticastGet(XAxiEthernet *InstancePtr, void *AddressPtr,
+ int Entry);
+int XAxiEthernet_MulticastClear(XAxiEthernet *InstancePtr, int Entry);
+
+int XAxiEthernet_SetTpid(XAxiEthernet *InstancePtr, u16 Tpid, u8 Entry);
+int XAxiEthernet_ClearTpid(XAxiEthernet *InstancePtr, u8 Entry);
+void XAxiEthernet_GetTpid(XAxiEthernet *InstancePtr, u16 *TpidPtr, u8 Entry);
+
+int XAxiEthernet_SetVTagMode(XAxiEthernet *InstancePtr, u32 Mode, int Dir);
+void XAxiEthernet_GetVTagMode(XAxiEthernet *InstancePtr, u8 *ModePtr, int Dir);
+
+int XAxiEthernet_SetVStripMode(XAxiEthernet *InstancePtr, u32 Mode, int Dir);
+void XAxiEthernet_GetVStripMode(XAxiEthernet *InstancePtr, u8 *ModePtr,
+ int Dir);
+
+int XAxiEthernet_SetVTagValue(XAxiEthernet *InstancePtr, u32 VTagValue,
+ int Dir);
+void XAxiEthernet_GetVTagValue(XAxiEthernet *InstancePtr, u32 *VTagValuePtr,
+ int Dir);
+
+int XAxiEthernet_SetVidTable(XAxiEthernet *InstancePtr, u32 Entry, u32 Vid,
+ u8 Strip, u8 Tag, int Dir);
+void XAxiEthernet_GetVidTable(XAxiEthernet *InstancePtr, u32 Entry, u32 *VidPtr,
+ u8 *StripPtr, u8 *TagPtr, int Dir);
+
+int XAxiEthernet_AddExtMulticastGroup(XAxiEthernet *InstancePtr,
+ void *AddressPtr);
+int XAxiEthernet_ClearExtMulticastGroup(XAxiEthernet *InstancePtr,
+ void *AddressPtr);
+int XAxiEthernet_GetExtMulticastGroup(XAxiEthernet *InstancePtr,
+ void *AddressPtr);
+void XAxiEthernet_DumpExtMulticastGroup(XAxiEthernet *InstancePtr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* end of protection macro */
diff --git a/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_control.c b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_control.c
new file mode 100644
index 00000000..293cb200
--- /dev/null
+++ b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_control.c
@@ -0,0 +1,1712 @@
+/******************************************************************************
+*
+* Copyright (C) 2010 - 2015 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.
+*
+* Use of the Software is limited solely to applications:
+* (a) running on a Xilinx device, or
+* (b) that interact with a Xilinx device through a bus or interconnect.
+*
+* 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
+* XILINX 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.
+*
+* Except as contained in this notice, the name of the Xilinx shall not be used
+* in advertising or otherwise to promote the sale, use or other dealings in
+* this Software without prior written authorization from Xilinx.
+*
+******************************************************************************/
+/**
+*
+* @file xaxiethernet_control.c
+*
+* This file has driver APIs related to the controlling of the extended
+* features of the AXI Ethernet device. Please note that APIs for turning on/off
+* any of the driver features are present in axiethernet.c. This file takes care
+* of controlling these features.
+* - Normal/extended multicast filtering
+* - Normal/extended VLAN features
+* - RGMII/SGMII features
+*
+* See xaxiethernet.h for a detailed description of the driver.
+*
+* +* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a asa 6/30/10 First release based on the ll temac driver +*+*****************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xaxiethernet.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Definitions *****************************/ + +/*****************************************************************************/ +/** +* XAxiEthernet_MulticastAdd adds the Ethernet address, AddressPtr to the +* Axi Ethernet device's multicast filter list, at list index Entry. The +* address referenced by AddressPtr may be of any unicast, multicast, or +* broadcast address form. The hardware for the Axi Ethernet device can hold up +* to XAE_MULTI_MAT_ENTRIES addresses in this filter list.
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- --------------------------------------------------------- +* 1.00a asa 6/30/10 First release for Axi Ethernet driver +* 1.02a asa 2/16/11 Changes the value of XAE_LOOPS_TO_COME_OUT_OF_RST to +* 10000. +* 2.00a asa 8/29/11 Added defines for Ability Reg, Identification Reg, Rx max +* Frame and Tx Max Frame registers. +* Changed define for TEMAC RGMII/SGMII Config (PHYC) Reg. +*+ +******************************************************************************/ +#ifndef XAXIETHERNET_HW_H /* prevent circular inclusions */ +#define XAXIETHERNET_HW_H /* by using protection macros */ + +/***************************** Include Files *********************************/ + +#include "xdebug.h" + +#include "xil_io.h" +#include "xil_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************** Constant Definitions *****************************/ + +/* + * Register offset definitions. Unless otherwise noted, register access is + * 32 bit. + */ + +/** @name Axi Ethernet registers offset + * @{ + */ +#define XAE_RAF_OFFSET 0x00000000 /**< Reset and Address filter */ +#define XAE_TPF_OFFSET 0x00000004 /**< Tx Pause Frame */ +#define XAE_IFGP_OFFSET 0x00000008 /**< Tx Inter-frame gap adjustment*/ +#define XAE_IS_OFFSET 0x0000000C /**< Interrupt status */ +#define XAE_IP_OFFSET 0x00000010 /**< Interrupt pending */ +#define XAE_IE_OFFSET 0x00000014 /**< Interrupt enable */ +#define XAE_TTAG_OFFSET 0x00000018 /**< Tx VLAN TAG */ +#define XAE_RTAG_OFFSET 0x0000001C /**< Rx VLAN TAG */ +#define XAE_UAWL_OFFSET 0x00000020 /**< Unicast address word lower */ +#define XAE_UAWU_OFFSET 0x00000024 /**< Unicast address word upper */ +#define XAE_TPID0_OFFSET 0x00000028 /**< VLAN TPID0 register */ +#define XAE_TPID1_OFFSET 0x0000002C /**< VLAN TPID1 register */ + +/* + * Statistics Counter Registers are from offset 0x200 to 0x3FF + * They are defined from offset 0x200 to 0x34C in this device. + * The offsets from 0x350 to 0x3FF are reserved. + * The counters are 64 bit. + * The Least Significant Word (LSW) are stored in one 32 bit register and + * the Most Significant Word (MSW) are stored in one 32 bit register + */ +/* Start of Statistics Counter Registers Definitions */ +#define XAE_RXBL_OFFSET 0x00000200 /**< Received Bytes, LSW */ +#define XAE_RXBU_OFFSET 0x00000204 /**< Received Bytes, MSW */ +#define XAE_TXBL_OFFSET 0x00000208 /**< Transmitted Bytes, LSW */ +#define XAE_TXBU_OFFSET 0x0000020C /**< Transmitted Bytes, MSW */ +#define XAE_RXUNDRL_OFFSET 0x00000210 /**< Count of undersize(less than + * 64 bytes) frames received, + * LSW + */ +#define XAE_RXUNDRU_OFFSET 0x00000214 /**< Count of undersize(less than + * 64 bytes) frames received, + * MSW + */ +#define XAE_RXFRAGL_OFFSET 0x00000218 /**< Count of undersized(less + * than 64 bytes) and bad FCS + * frames received, LSW + */ +#define XAE_RXFRAGU_OFFSET 0x0000021C /**< Count of undersized(less + * than 64 bytes) and bad FCS + * frames received, MSW + */ +#define XAE_RX64BL_OFFSET 0x00000220 /**< Count of 64 bytes frames + * received, LSW + */ +#define XAE_RX64BU_OFFSET 0x00000224 /**< Count of 64 bytes frames + * received, MSW + */ +#define XAE_RX65B127L_OFFSET 0x00000228 /**< Count of 65-127 bytes + * Frames received, LSW + */ +#define XAE_RX65B127U_OFFSET 0x0000022C /**< Count of 65-127 bytes + * Frames received, MSW + */ +#define XAE_RX128B255L_OFFSET 0x00000230 /**< Count of 128-255 bytes + * Frames received, LSW + */ +#define XAE_RX128B255U_OFFSET 0x00000234 /**< Count of 128-255 bytes + * frames received, MSW + */ +#define XAE_RX256B511L_OFFSET 0x00000238 /**< Count of 256-511 bytes + * Frames received, LSW + */ +#define XAE_RX256B511U_OFFSET 0x0000023C /**< Count of 256-511 bytes + * frames received, MSW + */ +#define XAE_RX512B1023L_OFFSET 0x00000240 /**< Count of 512-1023 bytes + * frames received, LSW + */ +#define XAE_RX512B1023U_OFFSET 0x00000244 /**< Count of 512-1023 bytes + * frames received, MSW + */ +#define XAE_RX1024BL_OFFSET 0x00000248 /**< Count of 1024-MAX bytes + * frames received, LSW + */ +#define XAE_RX1024BU_OFFSET 0x0000024C /**< Count of 1024-MAX bytes + * frames received, MSW + */ +#define XAE_RXOVRL_OFFSET 0x00000250 /**< Count of oversize frames + * received, LSW + */ +#define XAE_RXOVRU_OFFSET 0x00000254 /**< Count of oversize frames + * received, MSW + */ +#define XAE_TX64BL_OFFSET 0x00000258 /**< Count of 64 bytes frames + * transmitted, LSW + */ +#define XAE_TX64BU_OFFSET 0x0000025C /**< Count of 64 bytes frames + * transmitted, MSW + */ +#define XAE_TX65B127L_OFFSET 0x00000260 /**< Count of 65-127 bytes + * frames transmitted, LSW + */ +#define XAE_TX65B127U_OFFSET 0x00000264 /**< Count of 65-127 bytes + * frames transmitted, MSW + */ +#define XAE_TX128B255L_OFFSET 0x00000268 /**< Count of 128-255 bytes + * frames transmitted, LSW + */ +#define XAE_TX128B255U_OFFSET 0x0000026C /**< Count of 128-255 bytes + * frames transmitted, MSW + */ +#define XAE_TX256B511L_OFFSET 0x00000270 /**< Count of 256-511 bytes + * frames transmitted, LSW + */ +#define XAE_TX256B511U_OFFSET 0x00000274 /**< Count of 256-511 bytes + * frames transmitted, MSW + */ +#define XAE_TX512B1023L_OFFSET 0x00000278 /**< Count of 512-1023 bytes + * frames transmitted, LSW + */ +#define XAE_TX512B1023U_OFFSET 0x0000027C /**< Count of 512-1023 bytes + * frames transmitted, MSW + */ +#define XAE_TX1024L_OFFSET 0x00000280 /**< Count of 1024-MAX bytes + * frames transmitted, LSW + */ +#define XAE_TX1024U_OFFSET 0x00000284 /**< Count of 1024-MAX bytes + * frames transmitted, MSW + */ +#define XAE_TXOVRL_OFFSET 0x00000288 /**< Count of oversize frames + * transmitted, LSW + */ +#define XAE_TXOVRU_OFFSET 0x0000028C /**< Count of oversize frames + * transmitted, MSW + */ +#define XAE_RXFL_OFFSET 0x00000290 /**< Count of frames received OK, + * LSW + */ +#define XAE_RXFU_OFFSET 0x00000294 /**< Count of frames received OK, + * MSW + */ +#define XAE_RXFCSERL_OFFSET 0x00000298 /**< Count of frames received with + * FCS error and at least 64 + * bytes, LSW + */ +#define XAE_RXFCSERU_OFFSET 0x0000029C /**< Count of frames received with + * FCS error and at least 64 + * bytes,MSW + */ +#define XAE_RXBCSTFL_OFFSET 0x000002A0 /**< Count of broadcast frames + * received, LSW + */ +#define XAE_RXBCSTFU_OFFSET 0x000002A4 /**< Count of broadcast frames + * received, MSW + */ +#define XAE_RXMCSTFL_OFFSET 0x000002A8 /**< Count of multicast frames + * received, LSW + */ +#define XAE_RXMCSTFU_OFFSET 0x000002AC /**< Count of multicast frames + * received, MSW + */ +#define XAE_RXCTRFL_OFFSET 0x000002B0 /**< Count of control frames + * received, LSW + */ +#define XAE_RXCTRFU_OFFSET 0x000002B4 /**< Count of control frames + * received, MSW + */ +#define XAE_RXLTERL_OFFSET 0x000002B8 /**< Count of frames received + * with length error, LSW + */ +#define XAE_RXLTERU_OFFSET 0x000002BC /**< Count of frames received + * with length error, MSW + */ +#define XAE_RXVLANFL_OFFSET 0x000002C0 /**< Count of VLAN tagged + * frames received, LSW + */ +#define XAE_RXVLANFU_OFFSET 0x000002C4 /**< Count of VLAN tagged frames + * received, MSW + */ +#define XAE_RXPFL_OFFSET 0x000002C8 /**< Count of pause frames received, + * LSW + */ +#define XAE_RXPFU_OFFSET 0x000002CC /**< Count of pause frames received, + * MSW + */ +#define XAE_RXUOPFL_OFFSET 0x000002D0 /**< Count of control frames + * received with unsupported + * opcode, LSW + */ +#define XAE_RXUOPFU_OFFSET 0x000002D4 /**< Count of control frames + * received with unsupported + * opcode, MSW + */ +#define XAE_TXFL_OFFSET 0x000002D8 /**< Count of frames transmitted OK, + * LSW + */ +#define XAE_TXFU_OFFSET 0x000002DC /**< Count of frames transmitted OK, + * MSW + */ +#define XAE_TXBCSTFL_OFFSET 0x000002E0 /**< Count of broadcast frames + * transmitted OK, LSW + */ +#define XAE_TXBCSTFU_OFFSET 0x000002E4 /**< Count of broadcast frames + * transmitted, MSW + */ +#define XAE_TXMCSTFL_OFFSET 0x000002E8 /**< Count of multicast frames + * transmitted, LSW + */ +#define XAE_TXMCSTFU_OFFSET 0x000002EC /**< Count of multicast frames + * transmitted, MSW + */ +#define XAE_TXUNDRERL_OFFSET 0x000002F0 /**< Count of frames transmitted + * underrun error, LSW + */ +#define XAE_TXUNDRERU_OFFSET 0x000002F4 /**< Count of frames transmitted + * underrun error, MSW + */ +#define XAE_TXCTRFL_OFFSET 0x000002F8 /**< Count of control frames + * transmitted, LSW + */ +#define XAE_TXCTRFU_OFFSET 0x000002FC /**< Count of control frames, + * transmitted, MSW + */ +#define XAE_TXVLANFL_OFFSET 0x00000300 /**< Count of VLAN tagged frames + * transmitted, LSW + */ +#define XAE_TXVLANFU_OFFSET 0x00000304 /**< Count of VLAN tagged + * frames transmitted, MSW + */ +#define XAE_TXPFL_OFFSET 0x00000308 /**< Count of pause frames + * transmitted, LSW + */ +#define XAE_TXPFU_OFFSET 0x0000030C /**< Count of pause frames + * transmitted, MSW + */ +#define XAE_TXSCL_OFFSET 0x00000310 /**< Single Collision Frames + * Transmitted OK, LSW + */ +#define XAE_TXSCU_OFFSET 0x00000314 /**< Single Collision Frames + * Transmitted OK, MSW + */ +#define XAE_TXMCL_OFFSET 0x00000318 /**< Multiple Collision Frames + * Transmitted OK, LSW + */ +#define XAE_TXMCU_OFFSET 0x0000031C /**< Multiple Collision Frames + * Transmitted OK, MSW + */ +#define XAE_TXDEFL_OFFSET 0x00000320 /**< Deferred Tx Frames, LSW */ +#define XAE_TXDEFU_OFFSET 0x00000324 /**< Deferred Tx Frames, MSW */ +#define XAE_TXLTCL_OFFSET 0x00000328 /**< Frames transmitted with late + * Collisions, LSW + */ +#define XAE_TXLTCU_OFFSET 0x0000032C /**< Frames transmitted with late + * Collisions, MSW + */ +#define XAE_TXAECL_OFFSET 0x00000330 /**< Frames aborted with excessive + * Collisions, LSW + */ +#define XAE_TXAECU_OFFSET 0x00000334 /**< Frames aborted with excessive + * Collisions, MSW + */ +#define XAE_TXEDEFL_OFFSET 0x00000338 /**< Transmit Frames with excessive + * Defferal, LSW + */ +#define XAE_TXEDEFU_OFFSET 0x0000033C /**< Transmit Frames with excessive + * Defferal, MSW + */ +#define XAE_RXAERL_OFFSET 0x00000340 /**< Frames received with alignment + * errors, LSW + */ +#define XAE_RXAERU_OFFSET 0x0000034C /**< Frames received with alignment + * errors, MSW + */ +/* End of Statistics Counter Registers Offset definitions */ + +#define XAE_RCW0_OFFSET 0x00000400 /**< Rx Configuration Word 0 */ +#define XAE_RCW1_OFFSET 0x00000404 /**< Rx Configuration Word 1 */ +#define XAE_TC_OFFSET 0x00000408 /**< Tx Configuration */ +#define XAE_FCC_OFFSET 0x0000040C /**< Flow Control Configuration */ +#define XAE_EMMC_OFFSET 0x00000410 /**< EMAC mode configuration */ +#define XAE_RXFC_OFFSET 0x00000414 /**< Rx Max Frm Config Register */ +#define XAE_TXFC_OFFSET 0x00000418 /**< Tx Max Frm Config Register */ +#define XAE_TX_TIMESTAMP_ADJ_OFFSET 0x0000041C /**< Transmitter time stamp + * adjust control Register + */ +#define XAE_PHYC_OFFSET 0x00000420 /**< RGMII/SGMII configuration */ + +/* 0x00000424 to 0x000004F4 are reserved */ + +#define XAE_IDREG_OFFSET 0x000004F8 /**< Identification Register */ +#define XAE_ARREG_OFFSET 0x000004FC /**< Ability Register */ +#define XAE_MDIO_MC_OFFSET 0x00000500 /**< MII Management Config */ +#define XAE_MDIO_MCR_OFFSET 0x00000504 /**< MII Management Control */ +#define XAE_MDIO_MWD_OFFSET 0x00000508 /**< MII Management Write Data */ +#define XAE_MDIO_MRD_OFFSET 0x0000050C /**< MII Management Read Data */ + +/* 0x00000510 to 0x000005FC are reserved */ + +#define XAE_MDIO_MIS_OFFSET 0x00000600 /**< MII Management Interrupt + * Status + */ +/* 0x00000604-0x0000061C are reserved */ + +#define XAE_MDIO_MIP_OFFSET 0x00000620 /**< MII Management Interrupt + * Pending register offse + */ +/* 0x00000624-0x0000063C are reserved */ + +#define XAE_MDIO_MIE_OFFSET 0x00000640 /**< MII Management Interrupt + * Enable register offset + */ +/* 0x00000644-0x0000065C are reserved */ + +#define XAE_MDIO_MIC_OFFSET 0x00000660 /**< MII Management Interrupt + * Clear register offset. + */ + +/* 0x00000664-0x000006FC are reserved */ + +#define XAE_UAW0_OFFSET 0x00000700 /**< Unicast address word 0 */ +#define XAE_UAW1_OFFSET 0x00000704 /**< Unicast address word 1 */ +#define XAE_FMI_OFFSET 0x00000708 /**< Filter Mask Index */ +/* 0x0000070C is reserved */ +#define XAE_AF0_OFFSET 0x00000710 /**< Address Filter 0 */ +#define XAE_AF1_OFFSET 0x00000714 /**< Address Filter 1 */ + +/* 0x00000718-0x00003FFC are reserved */ + +/* + * Transmit VLAN Table is from 0x00004000 to 0x00007FFC + * This offset defines an offset to table that has provisioned transmit + * VLAN data. The VLAN table will be used by hardware to provide + * transmit VLAN tagging, stripping, and translation. + */ +#define XAE_TX_VLAN_DATA_OFFSET 0x00004000 /**< TX VLAN data table address */ + + +/* + * Receive VLAN Data Table is from 0x00008000 to 0x0000BFFC + * This offset defines an offset to table that has provisioned receive + * VLAN data. The VLAN table will be used by hardware to provide + * receive VLAN tagging, stripping, and translation. + */ +#define XAE_RX_VLAN_DATA_OFFSET 0x00008000 /**< RX VLAN data table address */ + +/* 0x0000C000-0x0000FFFC are reserved */ + +/* 0x00010000-0x00013FFC are Ethenet AVB address offset */ + +/* 0x00014000-0x0001FFFC are reserved */ + +/* + * Extended Multicast Address Table is from 0x0020000 to 0x0003FFFC. + * This offset defines an offset to table that has provisioned multicast + * addresses. It is stored in BRAM and will be used by hardware to provide + * first line of address matching when a multicast frame is reveived. It + * can minimize the use of CPU/software hence minimize performance impact. + */ +#define XAE_MCAST_TABLE_OFFSET 0x00020000 /**< Multicast table address */ +/*@}*/ + + +/* Register masks. The following constants define bit locations of various + * bits in the registers. Constants are not defined for those registers + * that have a single bit field representing all 32 bits. For further + * information on the meaning of the various bit masks, refer to the HW spec. + */ + +/** @name Reset and Address Filter (RAF) Register bit definitions. + * These bits are associated with the XAE_RAF_OFFSET register. + * @{ + */ +#define XAE_RAF_MCSTREJ_MASK 0x00000002 /**< Reject receive + * multicast destination + * address + */ +#define XAE_RAF_BCSTREJ_MASK 0x00000004 /**< Reject receive + * broadcast destination + * address + */ +#define XAE_RAF_TXVTAGMODE_MASK 0x00000018 /**< Tx VLAN TAG mode */ +#define XAE_RAF_RXVTAGMODE_MASK 0x00000060 /**< Rx VLAN TAG mode */ +#define XAE_RAF_TXVSTRPMODE_MASK 0x00000180 /**< Tx VLAN STRIP mode */ +#define XAE_RAF_RXVSTRPMODE_MASK 0x00000600 /**< Rx VLAN STRIP mode */ +#define XAE_RAF_NEWFNCENBL_MASK 0x00000800 /**< New function mode */ +#define XAE_RAF_EMULTIFLTRENBL_MASK 0x00001000 /**< Exteneded Multicast + * Filtering mode + */ +#define XAE_RAF_STATSRST_MASK 0x00002000 /**< Statistics Counter + * Reset + */ +#define XAE_RAF_RXBADFRMEN_MASK 0x00004000 /**< Receive Bad Frame + * Enable + */ +#define XAE_RAF_TXVTAGMODE_SHIFT 3 /**< Tx Tag mode shift bits */ +#define XAE_RAF_RXVTAGMODE_SHIFT 5 /**< Rx Tag mode shift bits */ +#define XAE_RAF_TXVSTRPMODE_SHIFT 7 /**< Tx strip mode shift bits*/ +#define XAE_RAF_RXVSTRPMODE_SHIFT 9 /**< Rx Strip mode shift bits*/ +/*@}*/ + +/** @name Transmit Pause Frame Register (TPF) bit definitions + * @{ + */ +#define XAE_TPF_TPFV_MASK 0x0000FFFF /**< Tx pause frame value */ +/*@}*/ + +/** @name Transmit Inter-Frame Gap Adjustement Register (TFGP) bit definitions + * @{ + */ +#define XAE_TFGP_IFGP_MASK 0x0000007F /**< Transmit inter-frame + * gap adjustment value + */ +/*@}*/ + +/** @name Interrupt Status/Enable/Mask Registers bit definitions + * The bit definition of these three interrupt registers are the same. + * These bits are associated with the XAE_IS_OFFSET, XAE_IP_OFFSET, and + * XAE_IE_OFFSET registers. + * @{ + */ +#define XAE_INT_HARDACSCMPLT_MASK 0x00000001 /**< Hard register + * access complete + */ +#define XAE_INT_AUTONEG_MASK 0x00000002 /**< Auto negotiation + * complete + */ +#define XAE_INT_RXCMPIT_MASK 0x00000004 /**< Rx complete */ +#define XAE_INT_RXRJECT_MASK 0x00000008 /**< Rx frame rejected */ +#define XAE_INT_RXFIFOOVR_MASK 0x00000010 /**< Rx fifo overrun */ +#define XAE_INT_TXCMPIT_MASK 0x00000020 /**< Tx complete */ +#define XAE_INT_RXDCMLOCK_MASK 0x00000040 /**< Rx Dcm Lock */ +#define XAE_INT_MGTRDY_MASK 0x00000080 /**< MGT clock Lock */ +#define XAE_INT_PHYRSTCMPLT_MASK 0x00000100 /**< Phy Reset complete */ + +#define XAE_INT_ALL_MASK 0x0000003F /**< All the ints */ + +#define XAE_INT_RECV_ERROR_MASK \ + (XAE_INT_RXRJECT_MASK | XAE_INT_RXFIFOOVR_MASK) /**< INT bits that + * indicate receive + * errors + */ +/*@}*/ + + +/** @name TPID Register (TPID) bit definitions + * @{ + */ +#define XAE_TPID_0_MASK 0x0000FFFF /**< TPID 0 */ +#define XAE_TPID_1_MASK 0xFFFF0000 /**< TPID 1 */ +/*@}*/ + + +/** @name Receive Configuration Word 1 (RCW1) Register bit definitions + * @{ + */ +#define XAE_RCW1_RST_MASK 0x80000000 /**< Reset */ +#define XAE_RCW1_JUM_MASK 0x40000000 /**< Jumbo frame enable */ +#define XAE_RCW1_FCS_MASK 0x20000000 /**< In-Band FCS enable + * (FCS not stripped) */ +#define XAE_RCW1_RX_MASK 0x10000000 /**< Receiver enable */ +#define XAE_RCW1_VLAN_MASK 0x08000000 /**< VLAN frame enable */ +#define XAE_RCW1_LT_DIS_MASK 0x02000000 /**< Length/type field valid check + * disable + */ +#define XAE_RCW1_CL_DIS_MASK 0x01000000 /**< Control frame Length check + * disable + */ +#define XAE_RCW1_1588_TIMESTAMP_EN_MASK 0x00400000 /**< Inband 1588 time + * stamp enable + */ +#define XAE_RCW1_PAUSEADDR_MASK 0x0000FFFF /**< Pause frame source + * address bits [47:32].Bits + * [31:0] are stored in register + * RCW0 + */ +/*@}*/ + + +/** @name Transmitter Configuration (TC) Register bit definitions + * @{ + */ +#define XAE_TC_RST_MASK 0x80000000 /**< Reset */ +#define XAE_TC_JUM_MASK 0x40000000 /**< Jumbo frame enable */ +#define XAE_TC_FCS_MASK 0x20000000 /**< In-Band FCS enable + * (FCS not generated) + */ +#define XAE_TC_TX_MASK 0x10000000 /**< Transmitter enable */ +#define XAE_TC_VLAN_MASK 0x08000000 /**< VLAN frame enable */ +#define XAE_TC_IFG_MASK 0x02000000 /**< Inter-frame gap adjustment + * enable + */ +#define XAE_TC_1588_CMD_EN_MASK 0x00400000 /**< 1588 Cmd field enable */ +/*@}*/ + + +/** @name Flow Control Configuration (FCC) Register Bit definitions + * @{ + */ +#define XAE_FCC_FCRX_MASK 0x20000000 /**< Rx flow control enable */ +#define XAE_FCC_FCTX_MASK 0x40000000 /**< Tx flow control enable */ +/*@}*/ + + +/** @name Ethernet MAC Mode Configuration (EMMC) Register bit definitions + * @{ + */ +#define XAE_EMMC_LINKSPEED_MASK 0xC0000000 /**< Link speed */ +#define XAE_EMMC_RGMII_MASK 0x20000000 /**< RGMII mode enable */ +#define XAE_EMMC_SGMII_MASK 0x10000000 /**< SGMII mode enable */ +#define XAE_EMMC_GPCS_MASK 0x08000000 /**< 1000BaseX mode enable*/ +#define XAE_EMMC_HOST_MASK 0x04000000 /**< Host interface enable*/ +#define XAE_EMMC_TX16BIT 0x02000000 /**< 16 bit Tx client + * enable + */ +#define XAE_EMMC_RX16BIT 0x01000000 /**< 16 bit Rx client + * enable + */ +#define XAE_EMMC_LINKSPD_10 0x00000000 /**< Link Speed mask for + * 10 Mbit + */ +#define XAE_EMMC_LINKSPD_100 0x40000000 /**< Link Speed mask for 100 + * Mbit + */ +#define XAE_EMMC_LINKSPD_1000 0x80000000 /**< Link Speed mask for + * 1000 Mbit + */ +/*@}*/ + + +/** @name RGMII/SGMII Configuration (PHYC) Register bit definitions + * @{ + */ +#define XAE_PHYC_SGMIILINKSPEED_MASK 0xC0000000 /**< SGMII link speed mask*/ +#define XAE_PHYC_RGMIILINKSPEED_MASK 0x0000000C /**< RGMII link speed */ +#define XAE_PHYC_RGMIIHD_MASK 0x00000002 /**< RGMII Half-duplex */ +#define XAE_PHYC_RGMIILINK_MASK 0x00000001 /**< RGMII link status */ +#define XAE_PHYC_RGLINKSPD_10 0x00000000 /**< RGMII link 10 Mbit */ +#define XAE_PHYC_RGLINKSPD_100 0x00000004 /**< RGMII link 100 Mbit */ +#define XAE_PHYC_RGLINKSPD_1000 0x00000008 /**< RGMII link 1000 Mbit */ +#define XAE_PHYC_SGLINKSPD_10 0x00000000 /**< SGMII link 10 Mbit */ +#define XAE_PHYC_SGLINKSPD_100 0x40000000 /**< SGMII link 100 Mbit */ +#define XAE_PHYC_SGLINKSPD_1000 0x80000000 /**< SGMII link 1000 Mbit */ +/*@}*/ + + +/** @name MDIO Management Configuration (MC) Register bit definitions + * @{ + */ +#define XAE_MDIO_MC_MDIOEN_MASK 0x00000040 /**< MII management enable*/ +#define XAE_MDIO_MC_CLOCK_DIVIDE_MAX 0x3F /**< Maximum MDIO divisor */ +/*@}*/ + + +/** @name MDIO Management Control Register (MCR) Register bit definitions + * @{ + */ +#define XAE_MDIO_MCR_PHYAD_MASK 0x1F000000 /**< Phy Address Mask */ +#define XAE_MDIO_MCR_PHYAD_SHIFT 24 /**< Phy Address Shift */ +#define XAE_MDIO_MCR_REGAD_MASK 0x001F0000 /**< Reg Address Mask */ +#define XAE_MDIO_MCR_REGAD_SHIFT 16 /**< Reg Address Shift */ +#define XAE_MDIO_MCR_OP_MASK 0x0000C000 /**< Operation Code Mask */ +#define XAE_MDIO_MCR_OP_SHIFT 13 /**< Operation Code Shift */ +#define XAE_MDIO_MCR_OP_READ_MASK 0x00008000 /**< Op Code Read Mask */ +#define XAE_MDIO_MCR_OP_WRITE_MASK 0x00004000 /**< Op Code Write Mask */ +#define XAE_MDIO_MCR_INITIATE_MASK 0x00000800 /**< Ready Mask */ +#define XAE_MDIO_MCR_READY_MASK 0x00000080 /**< Ready Mask */ + +/*@}*/ + +/** @name MDIO Interrupt Enable/Mask/Status Registers bit definitions + * The bit definition of these three interrupt registers are the same. + * These bits are associated with the XAE_IS_OFFSET, XAE_IP_OFFSET, and + * XAE_IE_OFFSET registers. + * @{ + */ +#define XAE_MDIO_INT_MIIM_RDY_MASK 0x00000001 /**< MIIM Interrupt */ +/*@}*/ + + +/** @name Axi Ethernet Unicast Address Register Word 1 (UAW1) Register Bit + * definitions + * @{ + */ +#define XAE_UAW1_UNICASTADDR_MASK 0x0000FFFF /**< Station address bits + * [47:32] + * Station address bits [31:0] + * are stored in register + * UAW0 */ +/*@}*/ + + +/** @name Filter Mask Index (FMI) Register bit definitions + * @{ + */ +#define XAE_FMI_PM_MASK 0x80000000 /**< Promiscuous mode + * enable + */ +#define XAE_FMI_IND_MASK 0x00000003 /**< Index Mask */ + +/*@}*/ + + +/** @name Extended multicast buffer descriptor bit mask + * @{ + */ +#define XAE_BD_RX_USR2_BCAST_MASK 0x00000004 +#define XAE_BD_RX_USR2_IP_MCAST_MASK 0x00000002 +#define XAE_BD_RX_USR2_MCAST_MASK 0x00000001 +/*@}*/ + +/** @name Axi Ethernet Multicast Address Register Word 1 (MAW1) + * @{ + */ +#define XAE_MAW1_RNW_MASK 0x00800000 /**< Multicast address + * table register read + * enable + */ +#define XAE_MAW1_ADDR_MASK 0x00030000 /**< Multicast address + * table register address + */ +#define XAE_MAW1_MULTICADDR_MASK 0x0000FFFF /**< Multicast address + * bits [47:32] + * Multicast address + * bits [31:0] are stored + * in register MAW0 + */ +#define XAE_MAW1_MATADDR_SHIFT_MASK 16 /**< Number of bits to shift + * right to align with + * XAE_MAW1_CAMADDR_MASK + */ +/*@}*/ + + +/** @name Other Constant definitions used in the driver + * @{ + */ + +#define XAE_SPEED_10_MBPS 10 /**< Speed of 10 Mbps */ +#define XAE_SPEED_100_MBPS 100 /**< Speed of 100 Mbps */ +#define XAE_SPEED_1000_MBPS 1000 /**< Speed of 1000 Mbps */ + +#define XAE_SOFT_TEMAC_LOW_SPEED 0 /**< For soft cores with 10/100 + * Mbps speed. + */ +#define XAE_SOFT_TEMAC_HIGH_SPEED 1 /**< For soft cores with + * 10/100/1000 Mbps speed. + */ +#define XAE_HARD_TEMAC_TYPE 2 /**< For hard TEMAC cores used + * virtex-6. + */ +#define XAE_PHY_ADDR_LIMIT 31 /**< Max limit while accessing + * and searching for available + * PHYs. + */ +#define XAE_PHY_REG_NUM_LIMIT 31 /**< Max register limit in PHY + * as mandated by the spec. + */ +#define XAE_LOOPS_TO_COME_OUT_OF_RST 10000 /**< Number of loops in the driver + * API to wait for before + * returning a failure case. + */ + +#define XAE_RST_DELAY_LOOPCNT_VAL 200 /**< Timeout in ticks used + * while checking if the core + * had come out of reset. The + * exact tick time is defined + * in each case/loop where it + * will be used + */ +#define XAE_VLAN_TABL_STRP_FLD_LEN 1 /**< Strip field length in vlan + * table used for extended + * vlan features. + */ +#define XAE_VLAN_TABL_TAG_FLD_LEN 1 /**< Tag field length in vlan + * table used for extended + * vlan features. + */ +#define XAE_MAX_VLAN_TABL_ENTRY 0xFFF /**< Max possible number of + * entries in vlan table used + * for extended vlan + * features. + */ +#define XAE_VLAN_TABL_VID_START_OFFSET 2 /**< VID field start offset in + * each entry in the VLAN + * table. + */ +#define XAE_VLAN_TABL_STRP_STRT_OFFSET 1 /**< Strip field start offset + * in each entry in the VLAN + * table. + */ +#define XAE_VLAN_TABL_STRP_ENTRY_MASK 0x01 /**< Mask used to extract the + * the strip field from an + * entry in VLAN table. + */ +#define XAE_VLAN_TABL_TAG_ENTRY_MASK 0x01 /**< Mask used to extract the + * the tag field from an + * entry in VLAN table. + */ + +/*@}*/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ +xdbg_stmnt(extern int indent_on); + +#define XAxiEthernet_indent(RegOffset) \ + ((indent_on && ((RegOffset) >= XAE_RAF_OFFSET) && ((RegOffset) <= \ + XAE_AF1_OFFSET)) ? "\t" : "") + + +#define XAxiEthernet_reg_name(RegOffset) \ + (((RegOffset) == XAE_RAF_OFFSET) ? "XAE_RAF_OFFSET": \ + ((RegOffset) == XAE_TPF_OFFSET) ? "XAE_TPF_OFFSET": \ + ((RegOffset) == XAE_IFGP_OFFSET) ? "XAE_IFGP_OFFSET": \ + ((RegOffset) == XAE_IS_OFFSET) ? "XAE_IS_OFFSET": \ + ((RegOffset) == XAE_IP_OFFSET) ? "XAE_IP_OFFSET": \ + ((RegOffset) == XAE_IE_OFFSET) ? "XAE_IE_OFFSET": \ + ((RegOffset) == XAE_TTAG_OFFSET) ? "XAE_TTAG_OFFSET": \ + ((RegOffset) == XAE_RTAG_OFFSET) ? "XAE_RTAG_OFFSET": \ + ((RegOffset) == XAE_UAWL_OFFSET) ? "XAE_UAWL_OFFSET": \ + ((RegOffset) == XAE_UAWU_OFFSET) ? "XAE_UAWU_OFFSET": \ + ((RegOffset) == XAE_TPID0_OFFSET) ? "XAE_TPID0_OFFSET": \ + ((RegOffset) == XAE_TPID1_OFFSET) ? "XAE_TPID1_OFFSET": \ + ((RegOffset) == XAE_RCW0_OFFSET) ? "XAE_RCW0_OFFSET": \ + ((RegOffset) == XAE_RCW1_OFFSET) ? "XAE_RCW1_OFFSET": \ + ((RegOffset) == XAE_TC_OFFSET) ? "XAE_TC_OFFSET": \ + ((RegOffset) == XAE_FCC_OFFSET) ? "XAE_FCC_OFFSET": \ + ((RegOffset) == XAE_EMMC_OFFSET) ? "XAE_EMMC_OFFSET": \ + ((RegOffset) == XAE_PHYC_OFFSET) ? "XAE_PHYC_OFFSET": \ + ((RegOffset) == XAE_UAW0_OFFSET) ? "XAE_UAW0_OFFSET": \ + ((RegOffset) == XAE_UAW1_OFFSET) ? "XAE_UAW1_OFFSET": \ + ((RegOffset) == XAE_FMI_OFFSET) ? "XAE_FMI_OFFSET": \ + ((RegOffset) == XAE_AF0_OFFSET) ? "XAE_AF0_OFFSET": \ + ((RegOffset) == XAE_AF1_OFFSET) ? "XAE_AF1_OFFSET": \ + ((RegOffset) == XAE_TXBL_OFFSET) ? "XAE_TXBL_OFFSET": \ + ((RegOffset) == XAE_TXBU_OFFSET) ? "XAE_TXBU_OFFSET": \ + ((RegOffset) == XAE_RXBL_OFFSET) ? "XAE_RXBL_OFFSET": \ + ((RegOffset) == XAE_RXBU_OFFSET) ? "XAE_RXBU_OFFSET": \ + ((RegOffset) == XAE_RXUNDRL_OFFSET) ? "XAE_RXUNDRL_OFFSET": \ + ((RegOffset) == XAE_RXUNDRU_OFFSET) ? "XAE_RXUNDRU_OFFSET": \ + ((RegOffset) == XAE_RXFRAGL_OFFSET) ? "XAE_RXFRAGL_OFFSET": \ + ((RegOffset) == XAE_RXFRAGU_OFFSET) ? "XAE_RXFRAGU_OFFSET": \ + ((RegOffset) == XAE_RX64BL_OFFSET) ? "XAE_RX64BL_OFFSET": \ + ((RegOffset) == XAE_RX64BU_OFFSET) ? "XAE_RX64BU_OFFSET": \ + ((RegOffset) == XAE_RX65B127L_OFFSET) ? "XAE_RX65B127L_OFFSET": \ + ((RegOffset) == XAE_RX65B127U_OFFSET) ? "XAE_RX65B127U_OFFSET": \ + ((RegOffset) == XAE_RX128B255L_OFFSET) ? "XAE_RX128B255L_OFFSET": \ + ((RegOffset) == XAE_RX128B255U_OFFSET) ? "XAE_RX128B255U_OFFSET": \ + ((RegOffset) == XAE_RX256B511L_OFFSET) ? "XAE_RX256B511L_OFFSET": \ + ((RegOffset) == XAE_RX256B511U_OFFSET) ? "XAE_RX256B511U_OFFSET": \ + ((RegOffset) == XAE_RX512B1023L_OFFSET) ? "XAE_RX512B1023L_OFFSET": \ + ((RegOffset) == XAE_RX512B1023U_OFFSET) ? "XAE_RX512B1023U_OFFSET": \ + ((RegOffset) == XAE_RX1024BL_OFFSET) ? "XAE_RX1024L_OFFSET": \ + ((RegOffset) == XAE_RX1024BU_OFFSET) ? "XAE_RX1024U_OFFSET": \ + ((RegOffset) == XAE_RXOVRL_OFFSET) ? "XAE_RXOVRL_OFFSET": \ + ((RegOffset) == XAE_RXOVRU_OFFSET) ? "XAE_RXOVRU_OFFSET": \ + ((RegOffset) == XAE_TX64BL_OFFSET) ? "XAE_TX64BL_OFFSET": \ + ((RegOffset) == XAE_TX64BU_OFFSET) ? "XAE_TX64BU_OFFSET": \ + ((RegOffset) == XAE_TX65B127L_OFFSET) ? "XAE_TX65B127L_OFFSET": \ + ((RegOffset) == XAE_TX65B127U_OFFSET) ? "XAE_TX65B127U_OFFSET": \ + ((RegOffset) == XAE_TX128B255L_OFFSET) ? "XAE_TX128B255L_OFFSET": \ + ((RegOffset) == XAE_TX128B255U_OFFSET) ? "XAE_TX128B255U_OFFSET": \ + ((RegOffset) == XAE_TX256B511L_OFFSET) ? "XAE_TX256B511L_OFFSET": \ + ((RegOffset) == XAE_TX256B511U_OFFSET) ? "XAE_TX256B511U_OFFSET": \ + ((RegOffset) == XAE_TX512B1023L_OFFSET) ? "XAE_TX512B1023L_OFFSET": \ + ((RegOffset) == XAE_TX512B1023U_OFFSET) ? "XAE_TX512B1023U_OFFSET": \ + ((RegOffset) == XAE_TX1024L_OFFSET) ? "XAE_TX1024L_OFFSET": \ + ((RegOffset) == XAE_TX1024U_OFFSET) ? "XAE_TX1024U_OFFSET": \ + ((RegOffset) == XAE_TXOVRL_OFFSET) ? "XAE_TXOVRL_OFFSET": \ + ((RegOffset) == XAE_TXOVRU_OFFSET) ? "XAE_TXOVRU_OFFSET": \ + ((RegOffset) == XAE_RXFL_OFFSET) ? "XAE_RXFL_OFFSET": \ + ((RegOffset) == XAE_RXFU_OFFSET) ? "XAE_RXFU_OFFSET": \ + ((RegOffset) == XAE_RXFCSERL_OFFSET) ? "XAE_RXFCSERL_OFFSET": \ + ((RegOffset) == XAE_RXFCSERU_OFFSET) ? "XAE_RXFCSERU_OFFSET": \ + ((RegOffset) == XAE_RXBCSTFL_OFFSET) ? "XAE_RXBCSTFL_OFFSET": \ + ((RegOffset) == XAE_RXBCSTFU_OFFSET) ? "XAE_RXBCSTFU_OFFSET": \ + ((RegOffset) == XAE_RXMCSTFL_OFFSET) ? "XAE_RXMCSTFL_OFFSET": \ + ((RegOffset) == XAE_RXMCSTFU_OFFSET) ? "XAE_RXMCSTFU_OFFSET": \ + ((RegOffset) == XAE_RXCTRFL_OFFSET) ? "XAE_RXCTRFL_OFFSET": \ + ((RegOffset) == XAE_RXCTRFU_OFFSET) ? "XAE_RXCTRFU_OFFSET": \ + ((RegOffset) == XAE_RXLTERL_OFFSET) ? "XAE_RXLTERL_OFFSET": \ + ((RegOffset) == XAE_RXLTERU_OFFSET) ? "XAE_RXLTERU_OFFSET": \ + ((RegOffset) == XAE_RXVLANFL_OFFSET) ? "XAE_RXVLANFL_OFFSET": \ + ((RegOffset) == XAE_RXVLANFU_OFFSET) ? "XAE_RXVLANFU_OFFSET": \ + ((RegOffset) == XAE_RXPFL_OFFSET) ? "XAE_RXFL_OFFSET": \ + ((RegOffset) == XAE_RXPFU_OFFSET) ? "XAE_RXFU_OFFSET": \ + ((RegOffset) == XAE_RXUOPFL_OFFSET) ? "XAE_RXUOPFL_OFFSET": \ + ((RegOffset) == XAE_RXUOPFU_OFFSET) ? "XAE_RXUOPFU_OFFSET": \ + ((RegOffset) == XAE_TXFL_OFFSET) ? "XAE_TXFL_OFFSET": \ + ((RegOffset) == XAE_TXFU_OFFSET) ? "XAE_TXFU_OFFSET": \ + ((RegOffset) == XAE_TXBCSTFL_OFFSET) ? "XAE_TXBCSTFL_OFFSET": \ + ((RegOffset) == XAE_TXBCSTFU_OFFSET) ? "XAE_TXBCSTFU_OFFSET": \ + ((RegOffset) == XAE_TXMCSTFL_OFFSET) ? "XAE_TXMCSTFL_OFFSET": \ + ((RegOffset) == XAE_TXMCSTFU_OFFSET) ? "XAE_TXMCSTFU_OFFSET": \ + ((RegOffset) == XAE_TXUNDRERL_OFFSET) ? "XAE_TXUNDRERL_OFFSET": \ + ((RegOffset) == XAE_TXUNDRERU_OFFSET) ? "XAE_TXUNDRERU_OFFSET": \ + ((RegOffset) == XAE_TXCTRFL_OFFSET) ? "XAE_TXCTRFL_OFFSET": \ + ((RegOffset) == XAE_TXCTRFU_OFFSET) ? "XAE_TXCTRFU_OFFSET": \ + ((RegOffset) == XAE_TXVLANFL_OFFSET) ? "XAE_TXVLANFL_OFFSET": \ + ((RegOffset) == XAE_TXVLANFU_OFFSET) ? "XAE_TXVLANFU_OFFSET": \ + ((RegOffset) == XAE_TXPFL_OFFSET) ? "XAE_TXPFL_OFFSET": \ + ((RegOffset) == XAE_TXPFU_OFFSET) ? "XAE_TXPFU_OFFSET": \ + ((RegOffset) == XAE_TXSCL_OFFSET) ? "XAE_TXSCL_OFFSET": \ + ((RegOffset) == XAE_TXSCU_OFFSET) ? "XAE_TXSCU_OFFSET": \ + ((RegOffset) == XAE_TXMCL_OFFSET) ? "XAE_TXMCL_OFFSET": \ + ((RegOffset) == XAE_TXMCU_OFFSET) ? "XAE_TXMCU_OFFSET": \ + ((RegOffset) == XAE_TXDEFL_OFFSET) ? "XAE_TXDEFL_OFFSET": \ + ((RegOffset) == XAE_TXDEFU_OFFSET) ? "XAE_TXDEFU_OFFSET": \ + ((RegOffset) == XAE_TXLTCL_OFFSET) ? "XAE_TXLTCL_OFFSET": \ + ((RegOffset) == XAE_TXLTCU_OFFSET) ? "XAE_TXLTCU_OFFSET": \ + ((RegOffset) == XAE_TXAECL_OFFSET) ? "XAE_TXAECL_OFFSET": \ + ((RegOffset) == XAE_TXAECU_OFFSET) ? "XAE_TXAECU_OFFSET": \ + ((RegOffset) == XAE_TXEDEFL_OFFSET) ? "XAE_TXEDEFL_OFFSET": \ + ((RegOffset) == XAE_TXEDEFU_OFFSET) ? "XAE_TXEDEFU_OFFSET": \ + ((RegOffset) == XAE_RXAERL_OFFSET) ? "XAE_RXAERL_OFFSET": \ + ((RegOffset) == XAE_RXAERU_OFFSET) ? "XAE_RXAERU_OFFSET": \ + "unknown") + +#define XAxiEthernet_print_reg_o(BaseAddress, RegOffset, Value) \ + xdbg_printf(XDBG_DEBUG_TEMAC_REG, "%s0x%0x -> %s(0x%0x)\n", \ + XAxiEthernet_indent(RegOffset), (Value), \ + XAxiEthernet_reg_name(RegOffset), (RegOffset)) \ + +#define XAxiEthernet_print_reg_i(BaseAddress, RegOffset, Value) \ + xdbg_printf(XDBG_DEBUG_TEMAC_REG, "%s%s(0x%0x) -> 0x%0x\n", \ + XAxiEthernet_indent(RegOffset), \ + XAxiEthernet_reg_name(RegOffset),(RegOffset), (Value)) \ + +/****************************************************************************/ +/** +* +* XAxiEthernet_ReadReg returns the value read from the register specified by +* RegOffset. +* +* @param BaseAddress is the base address of the Axi Ethernet device. +* @param RegOffset is the offset of the register to be read. +* +* @return Returns the 32-bit value of the register. +* +* @note C-style signature: +* u32 XAxiEthernet_ReadReg(u32 BaseAddress, u32 RegOffset) +* +*****************************************************************************/ +#ifdef DEBUG +#define XAxiEthernet_ReadReg(BaseAddress, RegOffset) \ +({ \ + u32 value; \ + value = Xil_In32(((BaseAddress) + (RegOffset))); \ + XAxiEthernet_print_reg_i((BaseAddress), (RegOffset), value); \ +}) +#else +#define XAxiEthernet_ReadReg(BaseAddress, RegOffset) \ + (Xil_In32(((BaseAddress) + (RegOffset)))) +#endif + +/****************************************************************************/ +/** +* +* XAxiEthernet_WriteReg, writes Data to the register specified by +* RegOffset. +* +* @param BaseAddress is the base address of the Axi Ethernet device. +* @param RegOffset is the offset of the register to be written. +* @param Data is the 32-bit value to write to the register. +* +* @return None. +* +* @note +* C-style signature: +* void XAxiEthernet_WriteReg(u32 BaseAddress, u32 RegOffset, u32 Data) +* +*****************************************************************************/ +#ifdef DEBUG +#define XAxiEthernet_WriteReg(BaseAddress, RegOffset, Data) \ +({ \ + XAxiEthernet_print_reg_o((BaseAddress), (RegOffset), (Data)); \ + Xil_Out32(((BaseAddress) + (RegOffset)), (Data)); \ +}) +#else +#define XAxiEthernet_WriteReg(BaseAddress, RegOffset, Data) \ + Xil_Out32(((BaseAddress) + (RegOffset)), (Data)) +#endif + + +#ifdef __cplusplus + } +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_porting_guide.h b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_porting_guide.h new file mode 100644 index 00000000..1945a931 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_porting_guide.h @@ -0,0 +1,180 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2015 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/*****************************************************************************/ +/** +* +* @file xaxiethernet_porting_guide.h +* +* This is a guide on how to move from using the ll temac driver to use the +* xaxiethernet driver. +* +* The AXI Ethernet IP is based on the XPS_LL TEMAC IP. +* There are few changes in the IP and some of them are listed below +* - The Interface to access the IP is now AXI instead of the PLBV46 +* - AXI4 streaming interfaces is used instead of LL (Local Link) +* - All indirect accesses to Ethernet core registers have been removed. +* - The AxiEthernet reset line is connected to the reset line of the +* device connected to the AXI4-Stream interface. Hence any reset +* of the connected device would reset AxiEthernet. +* +* Please read the HW Device specification of the AXI Ethernet IP for further +* information. +* +* +* The AXI Ethernet can be used in a DMA mode using the AXI DMA or +* used in a FIFO mode using the AXI Streaming FIFO. +* +* There is a new driver for AXI DMA which is used by the AXi Ethernet. Please +* refer the xaxidma_porting_guide.h provided as a part of the AXI DMA driver to +* see the differences from the LL DMA driver. +* +* The LL FIFO driver is a common driver for the LL FIFO and the +* AXI Streaming FIFO. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a ASA 07/18/10 First release +* +*+* +* Overview +* +* The API for xaxiethernet driver are similar to xlltemac driver. The prefix for the +* API functions and structures is XAxiEthernet_ for the xaxiethernet driver. +* +* The prefix for all hash-defines (option masks or generic hash-defined constants) +* start with XAE_. +* +* The Axi Ethernet API "XAxiEthernet_Reset" is different from the corresponding +* LLTEMAC API "XLlTemac_Reset". The AxiEthernet version does not do a soft +* reset of the AxiEthernet hardware. Since AxiEthernet hardware could only be +* reset through the device connected to the AxiEthernet AXI4-Stream interface, +* the user must ensure that AxiEthernet hardware initialization happens after +* the initialization of the other device. +* +* These are the classification of the APIs +* - APIs that only have prefix changes +* - APIs that have been renamed +* - APIs that are new + +* +* Note that data structures have different prefix of XAxiEthernet_. Those API +* functions, that have data structures with prefix change, are considered as +* prefix change. +* +* API Functions That Only Have Prefix Changes +* +* Most of the functions have the prefix change and are given below +*
+* xlltemac driver | xaxiethernet driver +* --------------------------------------------------------------------------------- +* XLlTemac_IsStarted(...) | XAxiEthernet_IsStarted(...) +* XLlTemac_IsDma(...) | XAxiEthernet_IsDma(...) +* XLlTemac_IsFifo(...) | XAxiEthernet_IsFifo(...) +* XLlTemac_LlDevBaseAddress(...) | XAxiEthernet_AxiDevBaseAddress(...) +* XLlTemac_IsRecvFrameDropped(...) | XAxiEthernet_IsRecvFrameDropped(...) +* XLlTemac_GetPhysicalInterface(...) | XAxiEthernet_GetPhysicalInterface(...) +* XLlTemac_IntEnable(...) | XAxiEthernet_IntEnable(...) +* XLlTemac_IntDisable(...) | XAxiEthernet_IntDisable(...) +* XLlTemac_IntPending(...) | XAxiEthernet_IntPending(...) +* XLlTemac_IntClear(...) | XAxiEthernet_IntClear(...) +* XLlTemac_IsExtFuncCap(...) | XAxiEthernet_IsExtFuncCap(...) +* XLlTemac_IsExtMcastEnable(...) | XAxiEthernet_IsExtMcastEnable(...) +* XLlTemac_IsExtMcast(...) | XAxiEthernet_IsExtMcast(...) +* XLlTemac_IsTxVlanStrp(...) | XAxiEthernet_IsTxVlanStrp(...) +* XLlTemac_IsRxVlanStrp(...) | XAxiEthernet_IsRxVlanStrp(...) +* XLlTemac_IsTxVlanTran(...) | XAxiEthernet_IsTxVlanTran(...) +* XLlTemac_IsRxVlanTran(...) | XAxiEthernet_IsRxVlanTran(...) +* XLlTemac_IsTxVlanTag(...) | XAxiEthernet_IsTxVlanTag(...) +* XLlTemac_IsRxVlanTag(...) | XAxiEthernet_IsRxVlanTag(...) +* XLlTemac_SetOptions (...) | XAxiEthernet_SetOptions(...) +* XLlTemac_ClearOptions(...) | XAxiEthernet_ClearOptions(...) +* XLlTemac_GetOptions(...) | XAxiEthernet_GetOptions(...) +* XLlTemac_SetMacAddress(...) | XAxiEthernet_SetMacAddress(...) +* XLlTemac_GetMacAddress(...) | XAxiEthernet_GetMacAddress(...) +* XLlTemac_SetMacPauseAddress(...) | XAxiEthernet_SetMacPauseAddress(...) +* XLlTemac_GetMacPauseAddress(...) | XAxiEthernet_GetMacPauseAddress(...) +* XLlTemac_SendPausePacket(...) | XAxiEthernet_SendPausePacket(...) +* XLlTemac_GetSgmiiStatus(...) | XAxiEthernet_GetSgmiiStatus(...) +* XLlTemac_GetRgmiiStatus(...) | XAxiEthernet_GetRgmiiStatus(...) +*... XLlTemac_GetOperatingSpeed(...) | XAxiEthernet_GetOperatingSpeed(...) +* XLlTemac_SetOperatingSpeed(...) | XAxiEthernet_SetOperatingSpeed(...) +* XLlTemac_PhySetMdioDivisor(...) | XAxiEthernet_PhySetMdioDivisor(...) +* XLlTemac_PhyRead(...) | XAxiEthernet_PhyRead(...) +* XLlTemac_PhyWrite(...) | XAxiEthernet_PhyWrite(...) +* XLlTemac_MulticastAdd(...) | XAxiEthernet_MulticastAdd(...) +* XLlTemac_MulticastGet(...) | XAxiEthernet_MulticastGet(...) +* XLlTemac_MulticastClear(...) | XAxiEthernet_MulticastClear(...) +* XLlTemac_SetTpid(...) | XAxiEthernet_SetTpid(...) +* XLlTemac_ClearTpid(...) | XAxiEthernet_ClearTpid(...) +* XLlTemac_GetTpid(...) | XAxiEthernet_GetTpid(...) +* XLlTemac_SetVTagMode(...) | XAxiEthernet_SetVTagMode(...) +* XLlTemac_GetVTagMode(...) | XAxiEthernet_GetVTagMode(...) +* XLlTemac_SetVStripMode(...) | XAxiEthernet_SetVStripMode(...) +* XLlTemac_GetVStripMode(...) | XAxiEthernet_GetVStripMode(...) +* XLlTemac_SetVTagValue(...) | XAxiEthernet_SetVTagValue(...) +* XLlTemac_GetVTagValue(...) | XAxiEthernet_GetVTagValue(...) +* XLlTemac_SetVidTable(...) | XAxiEthernet_SetVidTable(...) +* XLlTemac_GetVidTable(...) | XAxiEthernet_GetVidTable(...) +* XLlTemac_AddExtMulticastGroup(...) | XAxiEthernet_AddExtMulticastGroup(...) +* XLlTemac_ClearExtMulticastGroup(..)| XAxiEthernet_ClearExtMulticastGroup(...) +* XLlTemac_GetExtMulticastGroup(...) | XAxiEthernet_GetExtMulticastGroup(...) +* XLlTemac_DumpExtMulticastGroup(..) | XAxiEthernet_DumpExtMulticastGroup(...) + +*+* +* API Function names that have changed +* +*
+* xlltemac driver | xaaxiethernet driver +* ----------------------------------------------------------------------- +* XLlTemac_IsRxCsum(...) | XAxiEthernet_IsRxPartialCsum(...) +* XLlTemac_IsTxCsum(...) | XAxiEthernet_IsTxPartialCsum(...) +* XLlTemac_Status(...) | XAxiEthernet_GetIntStatus +*+* +* +* API Functions That Are New API Functions +* +* - XAxiEthernet_GetTemacType(...) +* - XAxiEthernet_IsAvbConfigured(...) +* - XAxiEthernet_IsStatsConfigured(...) +* - XAxiEthernet_SetBadFrmRcvOption((...); +* - XAxiEthernet_ClearBadFrmRcvOption(...); +* - XAxiEthernet_DisableControlFrameLenCheck(...) +* - XAxiEthernet_EnableControlFrameLenCheck(...) +* +* +******************************************************************************/ diff --git a/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_sinit.c b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_sinit.c new file mode 100644 index 00000000..f3f0af05 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/src/xaxiethernet_sinit.c @@ -0,0 +1,95 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2015 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +/** +* +* @file xaxiethernet_sinit.c +* +* This file contains static initialzation functionality for Axi Ethernet driver. +* +*
+* MODIFICATION HISTORY: +* +* Ver Who Date Changes +* ----- ---- -------- ------------------------------------------------------- +* 1.00a asa 6/30/10 First release +*+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xaxiethernet.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ +/** +* XAxiEthernet_LookupConfig returns a reference to an XAxiEthernet_Config +* structure based on an unique device id, DeviceId. The return value +* will refer to an entry in the device configuration table defined in the +* xaxiethernet_g.c file. +* +* @param DeviceId is the unique device ID of the device for the lookup +* operation. +* +* @return +* - Returns a reference to a config record in the +* configuration table (in xaxiethernet_g.c) corresponding to +* DeviceId, or NULL +* - NULL if no match is found. +* +******************************************************************************/ +XAxiEthernet_Config *XAxiEthernet_LookupConfig(u16 DeviceId) +{ + extern XAxiEthernet_Config XAxiEthernet_ConfigTable[]; + XAxiEthernet_Config *CfgPtr = NULL; + int Index; + + for (Index = 0; Index < XPAR_XAXIETHERNET_NUM_INSTANCES; Index++) { + if (XAxiEthernet_ConfigTable[Index].DeviceId == DeviceId) { + CfgPtr = &XAxiEthernet_ConfigTable[Index]; + break; + } + } + + return (CfgPtr); +} diff --git a/XilinxProcessorIPLib/drivers/axiethernet/src/xdebug.h b/XilinxProcessorIPLib/drivers/axiethernet/src/xdebug.h new file mode 100644 index 00000000..7d7dc5a7 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axiethernet/src/xdebug.h @@ -0,0 +1,84 @@ +/****************************************************************************** +* +* Copyright (C) 2010 - 2015 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. +* +* Use of the Software is limited solely to applications: +* (a) running on a Xilinx device, or +* (b) that interact with a Xilinx device through a bus or interconnect. +* +* 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 +* XILINX 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. +* +* Except as contained in this notice, the name of the Xilinx shall not be used +* in advertising or otherwise to promote the sale, use or other dealings in +* this Software without prior written authorization from Xilinx. +* +******************************************************************************/ +#ifndef XDEBUG +#define XDEBUG + +#undef DEBUG + +#if defined(DEBUG) && !defined(NDEBUG) + +#ifndef XDEBUG_WARNING +#define XDEBUG_WARNING +#warning DEBUG is enabled +#endif + +int printf(const char *format, ...); + +#define XDBG_DEBUG_ERROR 0x00000001 /* error condition messages */ +#define XDBG_DEBUG_GENERAL 0x00000002 /* general debug messages */ +#define XDBG_DEBUG_ALL 0xFFFFFFFF /* all debugging data */ + +#define XDBG_DEBUG_FIFO_REG 0x00000100 /* display register reads/writes */ +#define XDBG_DEBUG_FIFO_RX 0x00000101 /* receive debug messages */ +#define XDBG_DEBUG_FIFO_TX 0x00000102 /* transmit debug messages */ +#define XDBG_DEBUG_FIFO_ALL 0x0000010F /* all fifo debug messages */ + +#define XDBG_DEBUG_TEMAC_REG 0x00000400 /* display register reads/writes */ +#define XDBG_DEBUG_TEMAC_RX 0x00000401 /* receive debug messages */ +#define XDBG_DEBUG_TEMAC_TX 0x00000402 /* transmit debug messages */ +#define XDBG_DEBUG_TEMAC_ALL 0x0000040F /* all temac debug messages */ + +#define XDBG_DEBUG_TEMAC_ADPT_RX 0x00000800 /* receive debug messages */ +#define XDBG_DEBUG_TEMAC_ADPT_TX 0x00000801 /* transmit debug messages */ +#define XDBG_DEBUG_TEMAC_ADPT_IOCTL 0x00000802 /* ioctl debug messages */ +#define XDBG_DEBUG_TEMAC_ADPT_MISC 0x00000803 /* debug msg for other routines */ +#define XDBG_DEBUG_TEMAC_ADPT_ALL 0x0000080F /* all temac adapter debug messages */ + +#define xdbg_current_types (XDBG_DEBUG_ERROR | XDBG_DEBUG_GENERAL | XDBG_DEBUG_FIFO_REG | XDBG_DEBUG_TEMAC_REG) + +#define xdbg_stmnt(x) x + +/* ANSI Syntax */ +#define xdbg_printf(type, ...) (((type) & xdbg_current_types) ? printf (__VA_ARGS__) : 0) + + +#else /* defined(DEBUG) && !defined(NDEBUG) */ + +#define xdbg_stmnt(x) + +/* ANSI Syntax */ +#define xdbg_printf(...) + + +#endif /* defined(DEBUG) && !defined(NDEBUG) */ + +#endif /* XDEBUG */