From 35e0aac3335ed8b811e63fc28a049cff10e80fc1 Mon Sep 17 00:00:00 2001 From: Punnaiah Choudary Kalluri Date: Tue, 9 Dec 2014 20:22:20 +0530 Subject: [PATCH] emacps: Create new version v3_0 and deprectaed older one Create new version v3_0 and deprectaed older one. Signed-off-by: Punnaiah Choudary Kalluri --- .../drivers/emacps/data/dependencies.props | 2 + .../drivers/emacps/data/emacps.mdd | 42 + .../drivers/emacps/data/emacps.tcl | 219 ++ .../drivers/emacps/data/emacps_header.h | 44 + .../drivers/emacps/data/emacps_tapp.tcl | 164 ++ .../drivers/emacps/examples/index.html | 20 + .../drivers/emacps/examples/xemacps_example.h | 122 + .../examples/xemacps_example_intr_dma.c | 1079 ++++++++ .../examples/xemacps_example_readme.txt | 94 + .../emacps/examples/xemacps_example_util.c | 615 +++++ .../emacps/examples/xemacps_ieee1588.c | 1811 +++++++++++++ .../emacps/examples/xemacps_ieee1588.h | 610 +++++ .../examples/xemacps_ieee1588_example.c | 2384 +++++++++++++++++ .../drivers/emacps/src/Makefile | 40 + .../drivers/emacps/src/xemacps.c | 392 +++ .../drivers/emacps/src/xemacps.h | 719 +++++ .../drivers/emacps/src/xemacps_bd.h | 728 +++++ .../drivers/emacps/src/xemacps_bdring.c | 1001 +++++++ .../drivers/emacps/src/xemacps_bdring.h | 233 ++ .../drivers/emacps/src/xemacps_control.c | 1075 ++++++++ .../drivers/emacps/src/xemacps_g.c | 90 + .../drivers/emacps/src/xemacps_hw.c | 119 + .../drivers/emacps/src/xemacps_hw.h | 596 +++++ .../drivers/emacps/src/xemacps_intr.c | 220 ++ .../drivers/emacps/src/xemacps_sinit.c | 93 + 25 files changed, 12512 insertions(+) create mode 100644 XilinxProcessorIPLib/drivers/emacps/data/dependencies.props create mode 100755 XilinxProcessorIPLib/drivers/emacps/data/emacps.mdd create mode 100755 XilinxProcessorIPLib/drivers/emacps/data/emacps.tcl create mode 100755 XilinxProcessorIPLib/drivers/emacps/data/emacps_header.h create mode 100755 XilinxProcessorIPLib/drivers/emacps/data/emacps_tapp.tcl create mode 100755 XilinxProcessorIPLib/drivers/emacps/examples/index.html create mode 100755 XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example.h create mode 100755 XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example_intr_dma.c create mode 100755 XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example_readme.txt create mode 100755 XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example_util.c create mode 100755 XilinxProcessorIPLib/drivers/emacps/examples/xemacps_ieee1588.c create mode 100755 XilinxProcessorIPLib/drivers/emacps/examples/xemacps_ieee1588.h create mode 100755 XilinxProcessorIPLib/drivers/emacps/examples/xemacps_ieee1588_example.c create mode 100755 XilinxProcessorIPLib/drivers/emacps/src/Makefile create mode 100755 XilinxProcessorIPLib/drivers/emacps/src/xemacps.c create mode 100755 XilinxProcessorIPLib/drivers/emacps/src/xemacps.h create mode 100755 XilinxProcessorIPLib/drivers/emacps/src/xemacps_bd.h create mode 100755 XilinxProcessorIPLib/drivers/emacps/src/xemacps_bdring.c create mode 100755 XilinxProcessorIPLib/drivers/emacps/src/xemacps_bdring.h create mode 100755 XilinxProcessorIPLib/drivers/emacps/src/xemacps_control.c create mode 100755 XilinxProcessorIPLib/drivers/emacps/src/xemacps_g.c create mode 100755 XilinxProcessorIPLib/drivers/emacps/src/xemacps_hw.c create mode 100755 XilinxProcessorIPLib/drivers/emacps/src/xemacps_hw.h create mode 100755 XilinxProcessorIPLib/drivers/emacps/src/xemacps_intr.c create mode 100755 XilinxProcessorIPLib/drivers/emacps/src/xemacps_sinit.c diff --git a/XilinxProcessorIPLib/drivers/emacps/data/dependencies.props b/XilinxProcessorIPLib/drivers/emacps/data/dependencies.props new file mode 100644 index 00000000..5f04b6c7 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/data/dependencies.props @@ -0,0 +1,2 @@ +xemacps_example_intr_dma.c=xemacps_example_util.c,xemacps_example.h +xemacps_ieee1588_example.c=xemacps_example_util.c,xemacps_example.h,xemacps_ieee1588.c,xemacps_ieee1588.h \ No newline at end of file diff --git a/XilinxProcessorIPLib/drivers/emacps/data/emacps.mdd b/XilinxProcessorIPLib/drivers/emacps/data/emacps.mdd new file mode 100755 index 00000000..48134936 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/data/emacps.mdd @@ -0,0 +1,42 @@ +############################################################################### +# +# Copyright (C) 2011 - 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 THE +# XILINX CONSORTIUM 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. +# +############################################################################### +OPTION psf_version = 2.1; + +BEGIN driver emacps + + OPTION supported_peripherals = (ps7_ethernet); + OPTION driver_state = ACTIVE; + OPTION copyfiles = all; + OPTION VERSION = 3.0; + OPTION NAME = emacps; + +END driver diff --git a/XilinxProcessorIPLib/drivers/emacps/data/emacps.tcl b/XilinxProcessorIPLib/drivers/emacps/data/emacps.tcl new file mode 100755 index 00000000..c9f022c0 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/data/emacps.tcl @@ -0,0 +1,219 @@ +############################################################################### +# +# Copyright (C) 2011 - 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 THE +# XILINX CONSORTIUM 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.00a sdm 11/22/11 Created +# 2.0 adk 10/12/13 Updated as per the New Tcl API's +# 2.1 adk 11/08/14 Fixed the CR#811288 when PCS/PMA core is present in the hw +# XPAR_GIGE_PCS_PMA_CORE_PRESENT and phy address values +# should export to the xparameters.h file. +# 2.1 bss 09/08/14 Fixed CR#820349 to export phy address in xparameters.h +# when GMII to RGMII converter is present in hw. +# 2.2 adk 29/10/14 Fixed CR#827686 when PCS/PMA core is configured with +# 1000BASE-X mode export proper values to the xparameters.h +# file. +# +############################################################################## + +#uses "xillib.tcl" + +proc generate {drv_handle} { + xdefine_zynq_include_file $drv_handle "xparameters.h" "XEmacPs" "NUM_INSTANCES" "DEVICE_ID" "C_S_AXI_BASEADDR" "C_S_AXI_HIGHADDR" "C_ENET_CLK_FREQ_HZ" "C_ENET_SLCR_1000Mbps_DIV0" "C_ENET_SLCR_1000Mbps_DIV1" "C_ENET_SLCR_100Mbps_DIV0" "C_ENET_SLCR_100Mbps_DIV1" "C_ENET_SLCR_10Mbps_DIV0" "C_ENET_SLCR_10Mbps_DIV1" + + xdefine_zynq_config_file $drv_handle "xemacps_g.c" "XEmacPs" "DEVICE_ID" "C_S_AXI_BASEADDR" + + xdefine_zynq_canonical_xpars $drv_handle "xparameters.h" "XEmacPs" "DEVICE_ID" "C_S_AXI_BASEADDR" "C_S_AXI_HIGHADDR" "C_ENET_CLK_FREQ_HZ" "C_ENET_SLCR_1000Mbps_DIV0" "C_ENET_SLCR_1000Mbps_DIV1" "C_ENET_SLCR_100Mbps_DIV0" "C_ENET_SLCR_100Mbps_DIV1" "C_ENET_SLCR_10Mbps_DIV0" "C_ENET_SLCR_10Mbps_DIV1" + + generate_gmii2rgmii_params $drv_handle "xparameters.h" + + generate_sgmii_params $drv_handle "xparameters.h" + +} + +proc generate_gmii2rgmii_params {drv_handle file_name} { + set file_handle [::hsm::utils::open_include_file $file_name] + set ips [get_cells "*"] + foreach ip $ips { + set ipname [get_property NAME $ip] + set periph [get_property IP_NAME $ip] + if { [string compare -nocase $periph "ps7_ethernet"] == 0} { + set phya [is_gmii2rgmii_conv_present $ip] + if { $phya == 0} { + close $file_handle + return 0 + } + puts $file_handle "/* Definition for the MDIO address for the GMII2RGMII converter PL IP*/" + + if { [string compare -nocase $ipname "ps7_ethernet_0"] == 0} { + puts $file_handle "\#define XPAR_GMII2RGMIICON_0N_ETH0_ADDR $phya" + } + if { [string compare -nocase $ipname "ps7_ethernet_1"] == 0} { + puts $file_handle "\#define XPAR_GMII2RGMIICON_0N_ETH1_ADDR $phya" + } + puts $file_handle "\n/******************************************************************/\n" + } + + } + close $file_handle +} + +proc is_gmii2rgmii_conv_present {slave} { + set port_value 0 + set phy_addr 0 + set ipconv 0 + set ips [get_cells "*"] + set enetipinstance_name [get_property NAME $slave] + + foreach ip $ips { + set convipname [get_property NAME $ip] + set periph [get_property IP_NAME $ip] + if { [string compare -nocase $periph "gmii_to_rgmii"] == 0} { + 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 } { + set tmp [string first "ENET0" $port_value] + if { $tmp >= 0 } { + if { [string compare -nocase $enetipinstance_name "ps7_ethernet_0"] == 0} { + set phyaddr [::hsm::utils::get_param_value $ipconv C_PHYADDR] + set phy_addr [::hsm::utils::convert_binary_to_decimal $phyaddr] + if {[llength $phy_addr] == 0} { + set phy_addr 0 + } + } + } else { + set tmp0 [string first "ENET1" $port_value] + if { $tmp0 >= 0 } { + if { [string compare -nocase $enetipinstance_name "ps7_ethernet_1"] == 0} { + set phyaddr [::hsm::utils::get_param_value $ipconv C_PHYADDR] + set phy_addr [::hsm::utils::convert_binary_to_decimal $phyaddr] + if {[llength $phy_addr] == 0} { + set phy_addr 0 + } + } + } + } + } + } + return $phy_addr +} + +proc generate_sgmii_params {drv_handle file_name} { + set file_handle [::hsm::utils::open_include_file $file_name] + set ips [get_cells "*"] + + foreach ip $ips { + set ipname [get_property NAME $ip] + set periph [get_property IP_NAME $ip] + if { [string compare -nocase $periph "gig_ethernet_pcs_pma"] == 0} { + set PhyStandard [get_property CONFIG.Standard $ip] + } + if { [string compare -nocase $ipname "ps7_ethernet_0"] == 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 convipname [get_property NAME $ip] + 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 } { + set tmp [string first "ENET0" $port_value] + if { $tmp >= 0 } { + if { [string compare -nocase $enetipinstance_name "ps7_ethernet"] == 0} { + set phyaddr [::hsm::utils::get_param_value $ipconv C_PHYADDR] + set phy_addr [::hsm::utils::convert_binary_to_decimal $phyaddr] + if {[llength $phy_addr] == 0} { + set phy_addr 0 + } + } + } else { + set tmp0 [string first "ENET1" $port_value] + if { $tmp0 >= 0 } { + if { [string compare -nocase $enetipinstance_name "ps7_ethernet"] == 0} { + set phyaddr [::hsm::utils::get_param_value $ipconv C_PHYADDR] + set phy_addr [::hsm::utils::convert_binary_to_decimal $phyaddr] + puts [format "phy_addr %s phyaddr %s" $phy_addr $phyaddr] + if {[llength $phy_addr] == 0} { + set phy_addr 0 + } + } + } + } + } + } + return $phy_addr +} diff --git a/XilinxProcessorIPLib/drivers/emacps/data/emacps_header.h b/XilinxProcessorIPLib/drivers/emacps/data/emacps_header.h new file mode 100755 index 00000000..b0b268b5 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/data/emacps_header.h @@ -0,0 +1,44 @@ +/* $Id: tmrctr_header.h,v 1.1.2.1 2010/12/01 07:53:56 svemula Exp $ */ +/****************************************************************************** +* +* Copyright (C) 2011 - 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 THE +* XILINX CONSORTIUM 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 EMACPS_HEADER_H /* prevent circular inclusions */ +#define EMACPS_HEADER_H /* by using protection macros */ + +#include "xil_types.h" +#include "xil_assert.h" +#include "xstatus.h" + +int EmacPsDmaIntrExample(XScuGic *IntcInstancePtr, + XEmacPs *EmacPsInstancePtr, + u16 EmacPsDeviceId, u16 EmacPsIntrId); + +#endif diff --git a/XilinxProcessorIPLib/drivers/emacps/data/emacps_tapp.tcl b/XilinxProcessorIPLib/drivers/emacps/data/emacps_tapp.tcl new file mode 100755 index 00000000..2ed4d7cc --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/data/emacps_tapp.tcl @@ -0,0 +1,164 @@ +############################################################################### +# +# Copyright (C) 2011 - 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 THE +# XILINX CONSORTIUM 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 +# ----- ---- -------- ----------------------------------------------- +# 2.0 adk 10/12/13 Updated as per the New Tcl API's +############################################################################## + +# Uses $XILINX_EDK/bin/lib/xillib_sw.tcl +# ----------------------------------------------------------------- +# 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 inc_file_lines {xemacps.h xemacps_example.h emacps_header.h} + } + return $inc_file_lines +} + +proc gen_src_files {swproj mhsinst} { + if {$swproj == 0} { + return "" + } + if {$swproj == 1} { + + set inc_file_lines {examples/xemacps_example_intr_dma.c examples/xemacps_example_util.c examples/xemacps_example.h data/emacps_header.h} + + 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 decl " static XEmacPs ${ipname};" + set inc_file_lines $decl + return $inc_file_lines + + } + +} + +proc gen_testfunc_call {swproj mhsinst} { + + if {$swproj == 0} { + return "" + } + + set ipname [get_property NAME $mhsinst] + set deviceid [::hsm::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 isintr [::hsm::utils::is_ip_interrupting_current_proc $mhsinst] + set intcvar intc + + + set testfunc_call "" + + if {${hasStdout} == 0} { + + if {$isintr == 1} { + set intr_id "XPAR_${ipname}_INTR" + set intr_id [string toupper $intr_id] + + append testfunc_call " + + { + int Status; + Status = EmacPsDmaIntrExample(&${intcvar}, &${ipname}, \\ + ${deviceid}, \\ + ${intr_id}); + }" + + } + + + } else { + + if {$isintr == 1} { + set intr_id "XPAR_${ipname}_INTR" + set intr_id [string toupper $intr_id] + + append testfunc_call " + { + int Status; + + print(\"\\r\\n Running Interrupt Test for ${ipname}...\\r\\n\"); + + Status = EmacPsDmaIntrExample(&${intcvar}, &${ipname}, \\ + ${deviceid}, \\ + ${intr_id}); + + if (Status == 0) { + print(\"EmacPsDmaIntrExample PASSED\\r\\n\"); + } + else { + print(\"EmacPsDmaIntrExample FAILED\\r\\n\"); + } + + }" + + } + + } + + return $testfunc_call +} diff --git a/XilinxProcessorIPLib/drivers/emacps/examples/index.html b/XilinxProcessorIPLib/drivers/emacps/examples/index.html new file mode 100755 index 00000000..7875180a --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/examples/index.html @@ -0,0 +1,20 @@ + + + + + +Driver example applications + + + +

Example Applications for the driver emacps_v2_1

+
+ +

Copyright � 1995-2014 Xilinx, Inc. All rights reserved.

+ + diff --git a/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example.h b/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example.h new file mode 100755 index 00000000..b6dab0ad --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example.h @@ -0,0 +1,122 @@ +/****************************************************************************** +* +* 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 THE +* XILINX CONSORTIUM 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 xemacps_example.h +* +* Defines common data types, prototypes, and includes the proper headers +* for use with the EMACPS example code residing in this directory. +* +* This file along with xemacps_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 SDK +* standalone BSP development environment. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a wsy  01/10/10 First release
+* 1.01a asa  02/27/12 Hash define added for EMACPS_SLCR_DIV_MASK.
+* 1.05a asa  09/22/13 The EthernetFrame is made cache line aligned (32 bytes).
+*					  Fix for CR #663885.
+* 
+* +*****************************************************************************/ +#ifndef XEMACPS_EXAMPLE_H +#define XEMACPS_EXAMPLE_H + + +/***************************** Include Files ********************************/ + +#include +#include +#include "sleep.h" +#include "xparameters.h" +#include "xparameters_ps.h" /* defines XPAR values */ +#include "xil_types.h" +#include "xil_assert.h" +#include "xil_io.h" +#include "xil_exception.h" +#include "xpseudo_asm.h" +#include "xil_cache.h" +#include "xil_printf.h" +#include "xscugic.h" +#include "xemacps.h" /* defines XEmacPs API */ + +/************************** Constant Definitions ****************************/ + +#define EMACPS_LOOPBACK_SPEED 100 /* 100Mbps */ +#define EMACPS_LOOPBACK_SPEED_1G 1000 /* 1000Mbps */ +#define EMACPS_PHY_DELAY_SEC 4 /* Amount of time to delay waiting on + PHY to reset */ +#define EMACPS_SLCR_DIV_MASK 0xFC0FC0FF + +/***************** Macros (Inline Functions) Definitions ********************/ + + +/**************************** Type Definitions ******************************/ + +/* + * Define an aligned data type for an ethernet frame. This declaration is + * specific to the GNU compiler + */ +typedef char EthernetFrame[XEMACPS_MAX_VLAN_FRAME_SIZE] + __attribute__ ((aligned(32))); + +/************************** Function Prototypes *****************************/ + + + +/* + * Utility functions implemented in xemacps_example_util.c + */ +void EmacPsUtilSetupUart(void); +void EmacPsUtilFrameHdrFormatMAC(EthernetFrame * FramePtr, char *DestAddr); +void EmacPsUtilFrameHdrFormatType(EthernetFrame * FramePtr, u16 FrameType); +void EmacPsUtilFrameSetPayloadData(EthernetFrame * FramePtr, int PayloadSize); +int EmacPsUtilFrameVerify(EthernetFrame * CheckFrame, + EthernetFrame * ActualFrame); +void EmacPsUtilFrameMemClear(EthernetFrame * FramePtr); +int EmacPsUtilEnterLoopback(XEmacPs * XEmacPsInstancePtr, int Speed); +void EmacPsUtilstrncpy(char *Destination, const char *Source, u32 n); +void EmacPsUtilErrorTrap(const char *Message); + +/************************** Variable Definitions ****************************/ + +extern XEmacPs EmacPsInstance; /* Device instance used throughout examples */ +extern char EmacPsMAC[]; /* Local MAC address */ + + +#endif /* XEMACPS_EXAMPLE_H */ diff --git a/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example_intr_dma.c b/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example_intr_dma.c new file mode 100755 index 00000000..9875cb24 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example_intr_dma.c @@ -0,0 +1,1079 @@ +/****************************************************************************** +* +* 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 THE +* XILINX CONSORTIUM 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 xemacps_example_intr_dma.c +* +* Implements examples that utilize the EmacPs's interrupt driven DMA +* packet transfer mode to send and receive frames. +* +* These examples demonstrate: +* +* - How to perform simple send and receive. +* - Interrupt +* - Error handling +* - Device reset +* +* Functional guide to example: +* +* - EmacPsDmaSingleFrameIntrExample demonstrates the simplest way to send and +* receive frames in in interrupt driven DMA mode. +* +* - EmacPsErrorHandler() demonstrates how to manage asynchronous errors. +* +* - EmacPsResetDevice() demonstrates how to reset the driver/HW without +* loosing all configuration settings. +* +* NOTE: +* Define PEEP in xemacps_example.h to run the example on a PEEP board. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a wsy  01/10/10 First release
+* 1.00a asa  11/25/11 The cache disable routines are removed. So now both
+*		      I-cache and D-cache are enabled. The array RxBuffer is
+*		      removed to avoid an extra copy from RxBuffer to RxFrame.
+*		      Now the address of RxFrame is submitted to the Rx BD
+*		      instead of the address of RxBuffer.
+*		      In function EmacPsDmaSingleFrameIntrExample, BdRxPtr
+*		      is made as a pointer instead of array of pointers. This
+*		      is done since on the Rx path we now submit a single BD
+*		      instead of all 32 BDs. Because of this change, relevant
+*		      changes are made throughout the function
+*		      EmacPsDmaSingleFrameIntrExample.
+*		      Cache invalidation is now being done for the RxFrame
+*		      buffer.
+*		      The unnecessary cache flush (Xil_DCacheFlushRange) is
+*		      removed. This was being done towards the end of the
+*		      example which was unnecessary.
+* 1.00a asa 01/24/12  Support for Zynq board is added. The SLCR divisors are
+* 		      different for Zynq. Changes are made for the same.
+* 		      Presently the SLCR GEM clock divisors are hard-coded
+*		      assuming that IO PLL output frequency is 1000 MHz.
+* 		      The BDs are allocated at the address 0xFF00000 and the
+* 		      1 MB address range starting from this address is made
+* 		      uncached. This is because, for GEM the BDs need to be
+* 		      placed in uncached memory. The RX BDs are allocated at
+* 		      address 0xFF00000 and TX BDs are allocated at address
+* 		      0xFF10000.
+* 		      The MDIO divisor used of 224 is used for Zynq board.
+* 1.01a asa 02/27/12  The hardcoded SLCR divisors for Zynq are removed. The
+*		      divisors are obtained from xparameters.h.c. The sleep
+*		      values are reduced for Zynq. One sleep is added after
+*		      MDIO divisor is set. Some of the prints are removed.
+* 1.01a asa 03/14/12  The SLCR divisor support for ENET1 is added.
+* 1.01a asa 04/15/12  The funcation calls to Xil_DisableMMU and Xil_EnableMMU
+*		      are removed for setting the translation table
+*		      attributes for the BD memory region.
+* 1.05a asa 09/22/13 Cache handling is changed to fix an issue (CR#663885).
+*			  The cache invalidation of the Rx frame is now moved to
+*			  XEmacPsRecvHandler so that invalidation happens after the
+*			  received data is available in the memory. The variable
+*			  TxFrameLength is now made global.
+*
+* 
+* +*****************************************************************************/ + +/***************************** Include Files ********************************/ +#include "xemacps_example.h" +#include "xil_exception.h" +#include "xil_mmu.h" + +/*************************** 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 EMACPS_DEVICE_ID XPAR_XEMACPS_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#define EMACPS_IRPT_INTR XPS_GEM0_INT_ID + +#define RXBD_CNT 32 /* Number of RxBDs to use */ +#define TXBD_CNT 32 /* Number of TxBDs to use */ + +/* + * SLCR setting + */ +#define SLCR_LOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x4) +#define SLCR_UNLOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x8) +#define SLCR_GEM0_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x140) +#define SLCR_GEM1_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x144) + +#ifdef PEEP /* Define PEEP in xemacps_example.h if the example is run on PEEP */ +#define SLCR_GEM_10M_CLK_CTRL_VALUE 0x00103031 +#define SLCR_GEM_100M_CLK_CTRL_VALUE 0x00103001 +#define SLCR_GEM_1G_CLK_CTRL_VALUE 0x00103011 +#endif + +#define SLCR_LOCK_KEY_VALUE 0x767B +#define SLCR_UNLOCK_KEY_VALUE 0xDF0D +#define SLCR_ADDR_GEM_RST_CTRL (XPS_SYS_CTRL_BASEADDR + 0x214) + + +/*************************** Variable Definitions ***************************/ + +EthernetFrame TxFrame; /* Transmit buffer */ +EthernetFrame RxFrame; /* Receive buffer */ + +/* + * Buffer descriptors are allocated in uncached memory. The memory is made + * uncached by setting the attributes appropriately in the MMU table. + */ +#define RX_BD_LIST_START_ADDRESS 0x0FF00000 +#define TX_BD_LIST_START_ADDRESS 0x0FF10000 + +#define FIRST_FRAGMENT_SIZE 64 + +/* + * Counters to be incremented by callbacks + */ +volatile int FramesRx; /* Frames have been received */ +volatile int FramesTx; /* Frames have been sent */ +volatile int DeviceErrors; /* Number of errors detected in the device */ + +u32 TxFrameLength; + +#ifndef TESTAPP_GEN +static XScuGic IntcInstance; +#endif + +/*************************** Function Prototypes ****************************/ + +/* + * Example + */ +int EmacPsDmaIntrExample(XScuGic *IntcInstancePtr, + XEmacPs *EmacPsInstancePtr, + u16 EmacPsDeviceId, u16 EmacPsIntrId); + +int EmacPsDmaSingleFrameIntrExample(XEmacPs * EmacPsInstancePtr); + +/* + * Interrupt setup and Callbacks for examples + */ + +static int EmacPsSetupIntrSystem(XScuGic * IntcInstancePtr, + XEmacPs * EmacPsInstancePtr, + u16 EmacPsIntrId); + +static void EmacPsDisableIntrSystem(XScuGic * IntcInstancePtr, + u16 EmacPsIntrId); + +static void XEmacPsSendHandler(void *Callback); +static void XEmacPsRecvHandler(void *Callback); +static void XEmacPsErrorHandler(void *Callback, u8 direction, u32 word); + +/* + * Utility routines + */ +static int EmacPsResetDevice(XEmacPs * EmacPsInstancePtr); + +void XEmacPs_SetMdioDivisor(XEmacPs *InstancePtr, XEmacPs_MdcDiv Divisor); +/****************************************************************************/ +/** +* +* This is the main function for the EmacPs example. This function is not +* included if the example is generated from the TestAppGen test tool. +* +* @param None. +* +* @return XST_SUCCESS to indicate success, otherwise XST_FAILURE. +* +* @note None. +* +****************************************************************************/ +#ifndef TESTAPP_GEN +int main(void) +{ + int Status; + + xil_printf("Entering into main() \r\n"); + + /* + * Call the EmacPs DMA interrupt example , specify the parameters + * generated in xparameters.h + */ + Status = EmacPsDmaIntrExample(&IntcInstance, + &EmacPsInstance, + EMACPS_DEVICE_ID, + EMACPS_IRPT_INTR); + + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap("Failure in examples"); + return XST_FAILURE; + } + + xil_printf("Success in examples\r\n"); + return XST_SUCCESS; +} +#endif + +/****************************************************************************/ +/** +* +* This function demonstrates the usage of the EmacPs driver by sending by +* sending and receiving frames in interrupt driven DMA mode. +* +* +* @param IntcInstancePtr is a pointer to the instance of the Intc driver. +* @param EmacPsInstancePtr is a pointer to the instance of the EmacPs +* driver. +* @param EmacPsDeviceId is Device ID of the EmacPs Device , typically +* XPAR__DEVICE_ID value from xparameters.h. +* @param EmacPsIntrId is the Interrupt ID and is typically +* XPAR__INTR value from xparameters.h. +* +* @return XST_SUCCESS to indicate success, otherwise XST_FAILURE. +* +* @note None. +* +*****************************************************************************/ +int EmacPsDmaIntrExample(XScuGic * IntcInstancePtr, + XEmacPs * EmacPsInstancePtr, + u16 EmacPsDeviceId, + u16 EmacPsIntrId) +{ + int Status; + XEmacPs_Config *Config; + XEmacPs_Bd BdTemplate; +#ifndef PEEP + u32 SlcrTxClkCntrl; +#endif + + /*************************************/ + /* Setup device for first-time usage */ + /*************************************/ + + /* SLCR unlock */ + *(volatile unsigned int *)(SLCR_UNLOCK_ADDR) = SLCR_UNLOCK_KEY_VALUE; +#ifdef PEEP + *(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR) = + SLCR_GEM_1G_CLK_CTRL_VALUE; + *(volatile unsigned int *)(SLCR_GEM1_CLK_CTRL_ADDR) = + SLCR_GEM_1G_CLK_CTRL_VALUE; +#else + if (EmacPsIntrId == XPS_GEM0_INT_ID) { +#ifdef XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 + /* GEM0 1G clock configuration*/ + SlcrTxClkCntrl = + *(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR); + SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK; + SlcrTxClkCntrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1 << 20); + SlcrTxClkCntrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 << 8); + *(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR) = + SlcrTxClkCntrl; +#endif + } else if (EmacPsIntrId == XPS_GEM1_INT_ID) { +#ifdef XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV1 + /* GEM1 1G clock configuration*/ + SlcrTxClkCntrl = + *(volatile unsigned int *)(SLCR_GEM1_CLK_CTRL_ADDR); + SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK; + SlcrTxClkCntrl |= (XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV1 << 20); + SlcrTxClkCntrl |= (XPAR_PS7_ETHERNET_1_ENET_SLCR_1000MBPS_DIV0 << 8); + *(volatile unsigned int *)(SLCR_GEM1_CLK_CTRL_ADDR) = + SlcrTxClkCntrl; +#endif + } +#endif + /* SLCR lock */ + *(unsigned int *)(SLCR_LOCK_ADDR) = SLCR_LOCK_KEY_VALUE; + sleep(1); + + /* + * Initialize instance. Should be configured for DMA + * This example calls _CfgInitialize instead of _Initialize due to + * retiring _Initialize. So in _CfgInitialize we use + * XPAR_(IP)_BASEADDRESS to make sure it is not virtual address. + */ + Config = XEmacPs_LookupConfig(EmacPsDeviceId); + + Status = XEmacPs_CfgInitialize(EmacPsInstancePtr, Config, + Config->BaseAddress); + + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap("Error in initialize"); + return XST_FAILURE; + } + + /* + * Set the MAC address + */ + Status = XEmacPs_SetMacAddress(EmacPsInstancePtr, EmacPsMAC, 1); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap("Error setting MAC address"); + return XST_FAILURE; + } + + /* + * Setup callbacks + */ + Status = XEmacPs_SetHandler(EmacPsInstancePtr, + XEMACPS_HANDLER_DMASEND, + (void *) XEmacPsSendHandler, + EmacPsInstancePtr); + Status |= + XEmacPs_SetHandler(EmacPsInstancePtr, + XEMACPS_HANDLER_DMARECV, + (void *) XEmacPsRecvHandler, + EmacPsInstancePtr); + Status |= + XEmacPs_SetHandler(EmacPsInstancePtr, XEMACPS_HANDLER_ERROR, + (void *) XEmacPsErrorHandler, + EmacPsInstancePtr); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap("Error assigning handlers"); + return XST_FAILURE; + } + + /* + * The BDs need to be allocated in uncached memory. Hence the 1 MB + * address range that starts at address 0xFF00000 is made uncached. + */ + Xil_SetTlbAttributes(0x0FF00000, 0xc02); + /* + * Setup RxBD space. + * + * We have already defined a properly aligned area of memory to store + * RxBDs at the beginning of this source code file so just pass its + * address into the function. No MMU is being used so the physical + * and virtual addresses are the same. + * + * Setup a BD template for the Rx channel. This template will be + * copied to every RxBD. We will not have to explicitly set these + * again. + */ + XEmacPs_BdClear(&BdTemplate); + + /* + * Create the RxBD ring + */ + Status = XEmacPs_BdRingCreate(&(XEmacPs_GetRxRing + (EmacPsInstancePtr)), + RX_BD_LIST_START_ADDRESS, + RX_BD_LIST_START_ADDRESS, + XEMACPS_BD_ALIGNMENT, + RXBD_CNT); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap + ("Error setting up RxBD space, BdRingCreate"); + return XST_FAILURE; + } + + Status = XEmacPs_BdRingClone(&(XEmacPs_GetRxRing(EmacPsInstancePtr)), + &BdTemplate, XEMACPS_RECV); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap + ("Error setting up RxBD space, BdRingClone"); + return XST_FAILURE; + } + + /* + * Setup TxBD space. + * + * Like RxBD space, we have already defined a properly aligned area + * of memory to use. + * + * Also like the RxBD space, we create a template. Notice we don't + * set the "last" attribute. The example will be overriding this + * attribute so it does no good to set it up here. + */ + XEmacPs_BdClear(&BdTemplate); + XEmacPs_BdSetStatus(&BdTemplate, XEMACPS_TXBUF_USED_MASK); + + /* + * Create the TxBD ring + */ + Status = XEmacPs_BdRingCreate(&(XEmacPs_GetTxRing + (EmacPsInstancePtr)), + TX_BD_LIST_START_ADDRESS, + TX_BD_LIST_START_ADDRESS, + XEMACPS_BD_ALIGNMENT, + TXBD_CNT); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap + ("Error setting up TxBD space, BdRingCreate"); + return XST_FAILURE; + } + Status = XEmacPs_BdRingClone(&(XEmacPs_GetTxRing(EmacPsInstancePtr)), + &BdTemplate, XEMACPS_SEND); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap + ("Error setting up TxBD space, BdRingClone"); + return XST_FAILURE; + } + + /* + * Set emacps to phy loopback + */ +#ifndef PEEP /* For Zynq board */ + XEmacPs_SetMdioDivisor(EmacPsInstancePtr, MDC_DIV_224); + sleep(1); +#endif + EmacPsUtilEnterLoopback(EmacPsInstancePtr, EMACPS_LOOPBACK_SPEED_1G); + XEmacPs_SetOperatingSpeed(EmacPsInstancePtr, EMACPS_LOOPBACK_SPEED_1G); + + /* + * Setup the interrupt controller and enable interrupts + */ + Status = EmacPsSetupIntrSystem(IntcInstancePtr, + EmacPsInstancePtr, EmacPsIntrId); + /* + * Run the EmacPs DMA Single Frame Interrupt example + */ + Status = EmacPsDmaSingleFrameIntrExample(EmacPsInstancePtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Disable the interrupts for the EmacPs device + */ + EmacPsDisableIntrSystem(IntcInstancePtr, EmacPsIntrId); + + /* + * Stop the device + */ + XEmacPs_Stop(EmacPsInstancePtr); + + return XST_SUCCESS; +} + + +/****************************************************************************/ +/** +* +* This function demonstrates the usage of the EMACPS by sending and +* receiving a single frame in DMA interrupt mode. +* The source packet will be described by two descriptors. It will be +* received into a buffer described by a single descriptor. +* +* @param EmacPsInstancePtr is a pointer to the instance of the EmacPs +* driver. +* +* @return XST_SUCCESS to indicate success, otherwise XST_FAILURE. +* +* @note None. +* +*****************************************************************************/ +int EmacPsDmaSingleFrameIntrExample(XEmacPs *EmacPsInstancePtr) +{ + int Status; + u32 PayloadSize = 1000; + u32 NumRxBuf = 0; + XEmacPs_Bd *Bd1Ptr; + XEmacPs_Bd *Bd2Ptr; + XEmacPs_Bd *BdRxPtr; + + /* + * Clear variables shared with callbacks + */ + FramesRx = 0; + FramesTx = 0; + DeviceErrors = 0; + + /* + * Calculate the frame length (not including FCS) + */ + TxFrameLength = XEMACPS_HDR_SIZE + PayloadSize; + + /* + * Setup packet to be transmitted + */ + EmacPsUtilFrameHdrFormatMAC(&TxFrame, EmacPsMAC); + EmacPsUtilFrameHdrFormatType(&TxFrame, PayloadSize); + EmacPsUtilFrameSetPayloadData(&TxFrame, PayloadSize); + + Xil_DCacheFlushRange((u32)&TxFrame, TxFrameLength); + + /* + * Clear out receive packet memory area + */ + EmacPsUtilFrameMemClear(&RxFrame); + Xil_DCacheFlushRange((u32)&RxFrame, TxFrameLength); + /* + * Allocate RxBDs since we do not know how many BDs will be used + * in advance, use RXBD_CNT here. + */ + Status = XEmacPs_BdRingAlloc(& + (XEmacPs_GetRxRing(EmacPsInstancePtr)), + 1, &BdRxPtr); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap("Error allocating RxBD"); + return XST_FAILURE; + } + + /* + * Setup the BD. The XEmacPs_BdRingClone() call will mark the + * "wrap" field for last RxBD. Setup buffer address to associated + * BD. + */ + + XEmacPs_BdSetAddressRx(BdRxPtr, &RxFrame); + + /* + * Enqueue to HW + */ + Status = XEmacPs_BdRingToHw(&(XEmacPs_GetRxRing(EmacPsInstancePtr)), + 1, BdRxPtr); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap("Error committing RxBD to HW"); + return XST_FAILURE; + } + + /* + * Allocate, setup, and enqueue 2 TxBDs. The first BD will + * describe the first 32 bytes of TxFrame and the rest of BDs + * will describe the rest of the frame. + * + * The function below will allocate 2 adjacent BDs with Bd1Ptr + * being set as the lead BD. + */ + Status = XEmacPs_BdRingAlloc(&(XEmacPs_GetTxRing(EmacPsInstancePtr)), + 2, &Bd1Ptr); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap("Error allocating TxBD"); + return XST_FAILURE; + } + + /* + * Setup first TxBD + */ + XEmacPs_BdSetAddressTx(Bd1Ptr, &TxFrame); + XEmacPs_BdSetLength(Bd1Ptr, FIRST_FRAGMENT_SIZE); + XEmacPs_BdClearTxUsed(Bd1Ptr); + XEmacPs_BdClearLast(Bd1Ptr); + + /* + * Setup second TxBD + */ + Bd2Ptr = XEmacPs_BdRingNext(&(XEmacPs_GetTxRing(EmacPsInstancePtr)), + Bd1Ptr); + XEmacPs_BdSetAddressTx(Bd2Ptr, + (u32) (&TxFrame) + FIRST_FRAGMENT_SIZE); + XEmacPs_BdSetLength(Bd2Ptr, TxFrameLength - FIRST_FRAGMENT_SIZE); + XEmacPs_BdClearTxUsed(Bd2Ptr); + XEmacPs_BdSetLast(Bd2Ptr); + + /* + * Enqueue to HW + */ + Status = XEmacPs_BdRingToHw(&(XEmacPs_GetTxRing(EmacPsInstancePtr)), + 2, Bd1Ptr); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap("Error committing TxBD to HW"); + return XST_FAILURE; + } + + /* + * Start the device + */ + XEmacPs_Start(EmacPsInstancePtr); + + /* Start transmit */ + XEmacPs_Transmit(EmacPsInstancePtr); + + /* + * Wait for transmission to complete + */ + while (!FramesTx); + + /* + * Now that the frame has been sent, post process our TxBDs. + * Since we have only submitted 2 to hardware, then there should + * be only 2 ready for post processing. + */ + if (XEmacPs_BdRingFromHwTx(&(XEmacPs_GetTxRing(EmacPsInstancePtr)), + 2, &Bd1Ptr) == 0) { + EmacPsUtilErrorTrap + ("TxBDs were not ready for post processing"); + return XST_FAILURE; + } + + /* + * Examine the TxBDs. + * + * There isn't much to do. The only thing to check would be DMA + * exception bits. But this would also be caught in the error + * handler. So we just return these BDs to the free list. + */ + Status = XEmacPs_BdRingFree(&(XEmacPs_GetTxRing(EmacPsInstancePtr)), + 2, Bd1Ptr); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap("Error freeing up TxBDs"); + return XST_FAILURE; + } + + /* + * Wait for Rx indication + */ + while (!FramesRx); + + /* + * Now that the frame has been received, post process our RxBD. + * Since we have submitted to hardware, then there should be only 1 + * ready for post processing. + */ + NumRxBuf = XEmacPs_BdRingFromHwRx(&(XEmacPs_GetRxRing + (EmacPsInstancePtr)), 1, + &BdRxPtr); + if (0 == NumRxBuf) { + EmacPsUtilErrorTrap("RxBD was not ready for post processing"); + return XST_FAILURE; + } + + /* + * There is no device status to check. If there was a DMA error, + * it should have been reported to the error handler. Check the + * receive lengthi against the transmitted length, then verify + * the data. + */ + if ((XEmacPs_BdGetLength(BdRxPtr)) != TxFrameLength) { + EmacPsUtilErrorTrap("Length mismatch"); + return XST_FAILURE; + } + + if (EmacPsUtilFrameVerify(&TxFrame, &RxFrame) != 0) { + EmacPsUtilErrorTrap("Data mismatch"); + return XST_FAILURE; + } + + /* + * Return the RxBD back to the channel for later allocation. Free + * the exact number we just post processed. + */ + Status = XEmacPs_BdRingFree(&(XEmacPs_GetRxRing(EmacPsInstancePtr)), + NumRxBuf, BdRxPtr); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap("Error freeing up RxBDs"); + return XST_FAILURE; + } + + /* + * Finished this example. If everything worked correctly, all TxBDs + * and RxBDs should be free for allocation. Stop the device. + */ + XEmacPs_Stop(EmacPsInstancePtr); + + return XST_SUCCESS; +} + + +/****************************************************************************/ +/** +* This function resets the device but preserves the options set by the user. +* +* The descriptor list could be reinitialized with the same calls to +* XEmacPs_BdRingClone() as used in main(). Doing this is a matter of +* preference. +* In many cases, an OS may have resources tied up in the descriptors. +* Reinitializing in this case may bad for the OS since its resources may be +* permamently lost. +* +* @param EmacPsInstancePtr is a pointer to the instance of the EmacPs +* driver. +* +* @return XST_SUCCESS if successful, else XST_FAILURE. +* +* @note None. +* +*****************************************************************************/ +static int EmacPsResetDevice(XEmacPs * EmacPsInstancePtr) +{ + int Status = 0; + u8 MacSave[6]; + u32 Options; + XEmacPs_Bd BdTemplate; + + /* + * Stop device + */ + XEmacPs_Stop(EmacPsInstancePtr); + + /* + * Save the device state + */ + XEmacPs_GetMacAddress(EmacPsInstancePtr, &MacSave, 1); + Options = XEmacPs_GetOptions(EmacPsInstancePtr); + + /* + * Stop and reset the device + */ + XEmacPs_Reset(EmacPsInstancePtr); + + /* + * Restore the state + */ + XEmacPs_SetMacAddress(EmacPsInstancePtr, &MacSave, 1); + Status |= XEmacPs_SetOptions(EmacPsInstancePtr, Options); + Status |= XEmacPs_ClearOptions(EmacPsInstancePtr, ~Options); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap("Error restoring state after reset"); + return XST_FAILURE; + } + + /* + * Setup callbacks + */ + Status = XEmacPs_SetHandler(EmacPsInstancePtr, + XEMACPS_HANDLER_DMASEND, + (void *) XEmacPsSendHandler, + EmacPsInstancePtr); + Status |= XEmacPs_SetHandler(EmacPsInstancePtr, + XEMACPS_HANDLER_DMARECV, + (void *) XEmacPsRecvHandler, + EmacPsInstancePtr); + Status |= XEmacPs_SetHandler(EmacPsInstancePtr, XEMACPS_HANDLER_ERROR, + (void *) XEmacPsErrorHandler, + EmacPsInstancePtr); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap("Error assigning handlers"); + return XST_FAILURE; + } + + /* + * Setup RxBD space. + * + * We have already defined a properly aligned area of memory to store + * RxBDs at the beginning of this source code file so just pass its + * address into the function. No MMU is being used so the physical and + * virtual addresses are the same. + * + * Setup a BD template for the Rx channel. This template will be copied + * to every RxBD. We will not have to explicitly set these again. + */ + XEmacPs_BdClear(&BdTemplate); + + /* + * Create the RxBD ring + */ + Status = XEmacPs_BdRingCreate(&(XEmacPs_GetRxRing + (EmacPsInstancePtr)), + RX_BD_LIST_START_ADDRESS, + RX_BD_LIST_START_ADDRESS, + XEMACPS_BD_ALIGNMENT, + RXBD_CNT); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap + ("Error setting up RxBD space, BdRingCreate"); + return XST_FAILURE; + } + + Status = XEmacPs_BdRingClone(& + (XEmacPs_GetRxRing(EmacPsInstancePtr)), + &BdTemplate, XEMACPS_RECV); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap + ("Error setting up RxBD space, BdRingClone"); + return XST_FAILURE; + } + + /* + * Setup TxBD space. + * + * Like RxBD space, we have already defined a properly aligned area of + * memory to use. + * + * Also like the RxBD space, we create a template. Notice we don't set + * the "last" attribute. The examples will be overriding this + * attribute so it does no good to set it up here. + */ + XEmacPs_BdClear(&BdTemplate); + XEmacPs_BdSetStatus(&BdTemplate, XEMACPS_TXBUF_USED_MASK); + + /* + * Create the TxBD ring + */ + Status = XEmacPs_BdRingCreate(&(XEmacPs_GetTxRing + (EmacPsInstancePtr)), + TX_BD_LIST_START_ADDRESS, + TX_BD_LIST_START_ADDRESS, + XEMACPS_BD_ALIGNMENT, + TXBD_CNT); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap + ("Error setting up TxBD space, BdRingCreate"); + return XST_FAILURE; + } + Status = XEmacPs_BdRingClone(& + (XEmacPs_GetTxRing(EmacPsInstancePtr)), + &BdTemplate, XEMACPS_SEND); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap + ("Error setting up TxBD space, BdRingClone"); + return XST_FAILURE; + } + + /* + * Restart the device + */ + XEmacPs_Start(EmacPsInstancePtr); + + return XST_SUCCESS; +} + + +/****************************************************************************/ +/** +* +* This function setups the interrupt system so interrupts can occur for the +* EMACPS. +* @param IntcInstancePtr is a pointer to the instance of the Intc driver. +* @param EmacPsInstancePtr is a pointer to the instance of the EmacPs +* driver. +* @param EmacPsIntrId is the Interrupt ID and is typically +* XPAR__INTR value from xparameters.h. +* +* @return XST_SUCCESS if successful, otherwise XST_FAILURE. +* +* @note None. +* +*****************************************************************************/ +static int EmacPsSetupIntrSystem(XScuGic *IntcInstancePtr, + XEmacPs *EmacPsInstancePtr, + u16 EmacPsIntrId) +{ + int Status; + +#ifndef TESTAPP_GEN + XScuGic_Config *GicConfig; + Xil_ExceptionInit(); + + /* + * Initialize the interrupt controller driver so that it is ready to + * use. + */ + GicConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); + if (NULL == GicConfig) { + return XST_FAILURE; + } + + Status = XScuGic_CfgInitialize(IntcInstancePtr, GicConfig, + GicConfig->CpuBaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + /* + * Connect the interrupt controller interrupt handler to the hardware + * interrupt handling logic in the processor. + */ + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT, + (Xil_ExceptionHandler)XScuGic_InterruptHandler, + IntcInstancePtr); +#endif + + /* + * Connect a device driver handler that will be called when an + * interrupt for the device occurs, the device driver handler performs + * the specific interrupt processing for the device. + */ + Status = XScuGic_Connect(IntcInstancePtr, EmacPsIntrId, + (Xil_InterruptHandler) XEmacPs_IntrHandler, + (void *) EmacPsInstancePtr); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap + ("Unable to connect ISR to interrupt controller"); + return XST_FAILURE; + } + + /* + * Enable interrupts from the hardware + */ + XScuGic_Enable(IntcInstancePtr, EmacPsIntrId); + +#ifndef TESTAPP_GEN + /* + * Enable interrupts in the processor + */ + Xil_ExceptionEnable(); +#endif + return XST_SUCCESS; +} + + +/****************************************************************************/ +/** +* +* This function disables the interrupts that occur for EmacPs. +* +* @param IntcInstancePtr is the pointer to the instance of the ScuGic +* driver. +* @param EmacPsIntrId is interrupt ID and is typically +* XPAR__INTR value from xparameters.h. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +static void EmacPsDisableIntrSystem(XScuGic * IntcInstancePtr, + u16 EmacPsIntrId) +{ + /* + * Disconnect and disable the interrupt for the EmacPs device + */ + XScuGic_Disconnect(IntcInstancePtr, EmacPsIntrId); + +} + +/****************************************************************************/ +/** +* +* This the Transmit handler callback function and will increment a shared +* counter that can be shared by the main thread of operation. +* +* @param Callback is the pointer to the instance of the EmacPs device. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +static void XEmacPsSendHandler(void *Callback) +{ + XEmacPs *EmacPsInstancePtr = (XEmacPs *) Callback; + + /* + * Disable the transmit related interrupts + */ + XEmacPs_IntDisable(EmacPsInstancePtr, (XEMACPS_IXR_TXCOMPL_MASK | + XEMACPS_IXR_TX_ERR_MASK)); + /* + * Increment the counter so that main thread knows something + * happened. + */ + FramesTx++; +} + + +/****************************************************************************/ +/** +* +* This is the Receive handler callback function and will increment a shared +* counter that can be shared by the main thread of operation. +* +* @param Callback is a pointer to the instance of the EmacPs device. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +static void XEmacPsRecvHandler(void *Callback) +{ + XEmacPs *EmacPsInstancePtr = (XEmacPs *) Callback; + + /* + * Disable the transmit related interrupts + */ + XEmacPs_IntDisable(EmacPsInstancePtr, (XEMACPS_IXR_FRAMERX_MASK | + XEMACPS_IXR_RX_ERR_MASK)); + /* + * Increment the counter so that main thread knows something + * happened. + */ + FramesRx++; + Xil_DCacheInvalidateRange((u32)&RxFrame, TxFrameLength); +} + + +/****************************************************************************/ +/** +* +* This is the Error handler callback function and this function increments +* the error counter so that the main thread knows the number of errors. +* +* @param Callback is the callback function for the driver. This +* parameter is not used in this example. +* @param Direction is passed in from the driver specifying which +* direction error has occurred. +* @param ErrorWord is the status register value passed in. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +static void XEmacPsErrorHandler(void *Callback, u8 Direction, u32 ErrorWord) +{ + XEmacPs *EmacPsInstancePtr = (XEmacPs *) Callback; + + /* + * Increment the counter so that main thread knows something + * happened. Reset the device and reallocate resources ... + */ + DeviceErrors++; + + switch (Direction) { + case XEMACPS_RECV: + if (ErrorWord & XEMACPS_RXSR_HRESPNOK_MASK) { + EmacPsUtilErrorTrap("Receive DMA error"); + } + if (ErrorWord & XEMACPS_RXSR_RXOVR_MASK) { + EmacPsUtilErrorTrap("Receive over run"); + } + if (ErrorWord & XEMACPS_RXSR_BUFFNA_MASK) { + EmacPsUtilErrorTrap("Receive buffer not available"); + } + break; + case XEMACPS_SEND: + if (ErrorWord & XEMACPS_TXSR_HRESPNOK_MASK) { + EmacPsUtilErrorTrap("Transmit DMA error"); + } + if (ErrorWord & XEMACPS_TXSR_URUN_MASK) { + EmacPsUtilErrorTrap("Transmit under run"); + } + if (ErrorWord & XEMACPS_TXSR_BUFEXH_MASK) { + EmacPsUtilErrorTrap("Transmit buffer exhausted"); + } + if (ErrorWord & XEMACPS_TXSR_RXOVR_MASK) { + EmacPsUtilErrorTrap("Transmit retry excessed limits"); + } + if (ErrorWord & XEMACPS_TXSR_FRAMERX_MASK) { + EmacPsUtilErrorTrap("Transmit collision"); + } + if (ErrorWord & XEMACPS_TXSR_USEDREAD_MASK) { + EmacPsUtilErrorTrap("Transmit buffer not available"); + } + break; + } + EmacPsResetDevice(EmacPsInstancePtr); +} diff --git a/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example_readme.txt b/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example_readme.txt new file mode 100755 index 00000000..46f1008b --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example_readme.txt @@ -0,0 +1,94 @@ +xemacps_ieee1588_example_readme.txt +----------------------------------- +The examples in this directory are provided to give the user some idea of the +following: +- How the EmacPs and its driver are intended to be used. +- How the protocol packets flow and processed for IEEE1588 (PTP). + + + +FILES + +Three files are provided to demonstrate the usage of EmacPs and the +driver. They are: + +- xemacps_example.h - Top level include for the example. + +- xemacps_example_util.c - Provide various utilities for debugging, and + ethernet frame construction. + +- xemacps_example_intr_dma.c - Implements the example that uses EmacPs internal + DMA to send and receive packets in loopback mode. It uses interrupts. + +The user must include the above three files for building the binary to see how +Ethernet packets are sent and received in PHY loopback mode.. + + +Three files are provided for demonstrating the IEEE1588 protocol. They are: + +- xemacps_ieee1588_example.c: The top level C file that has the programe + entry "main". It also has initialization code for EmacPs, Timer etc. + It has initialization code for PTP packets. + +- xemacps_ieee1588.h: Include file that contains all function prototypes, + hash defines etc. + +- xemacps_ieee1588.c: The protocol packets are processed in this file. + +The user must include the above three files for building the binary to see +how IEEE1588 (PTP) works. + + +SYSTEM REQUIREMENTS + +The system containing the EmacPs should have the following capabilities: + + - An interrupt controller + - A UART to display messages + - A Timer that is used to send protocol packets at regular intervals + +For testing the example in xemacps_example_intr_dma.c which uses PHY loopback, +a single hardware system is sufficient. + +To run and test the binary created for IEEE1588 (PTP), the user +needs to have two EmacPs based hardware systems connected back-to-back. +One would act as a Master and other as a slave. + +HOW THE IEEE1588 EXAMPLE WORKS + +- The example should be run between two boards, both having capability to + time stamp the PTP packets. For example, it can be run between two Zynq + boards, two PEEP boards, one Zynq and one PEEP board etc. Additionally + this example is also tested between a Zynq/PEEP board and a ML605 board. + However, on ML605 board we need to run a slightly modified AVB example + (for AxiEthernet) available in Perforce for AxiEthernet driver. +- To run the example on a PEEP board, please define the flag PEEP in + xemacps_ieee1588.h (or with -DPEEP compile time option). +- The example can be run in PTP MASTER mode or PTP SLAVE mode. To run it in + PTP MASTER mode please define the flag IEEE1588_MASTER + (with -DIEEE1588_MASTER) in the compiler options or just define it in + xemacps_ieee1588.h. If this flag is defined then the software runs in + MASTER mode or else in SLAVE mode. +- The example by default initializes the PHY and GEM for 100 Mbps speed. + Additionally autonegotiation can be used. To use autonegotiation, please + define the flag PHY_AUTONEGOTIATION. However this feature is applicable + only for Zynq boards. +- ScuTimer is used to generate interrupts every 500 mseconds. This timer + interrupt is used to send various protocol packets. For example, Sync/ + FollowUp packets are sent every 1 seconds. Announce frames are sent every + 5 seconds and PDelay packets are sent every 4 seconds. +- In a typical test setup, 2 Zynq boards are connected back to back. Please + build the SDK projects (with the above 3 files) in MASTER mode and download + the elf to one Zynq board. Then build the SDK project in SLAVE mode and + download and run it in the other board. You can start seeing the console + messages. +- There are two debug levels. By default debug level 1 is defined to see + some of the important PTP messages. For example, the link delay and the + time correction values. The other debug level can be defined to see the + messages from ISR. It can be handy to debug issues if any. To define the + 1st debug level, define the flag DEBUG_XEMACPS_LEVEL1 in + xemacps_ieee1588.h. To define the other debug level, define the flag + DEBUG_LEVEL_TWO. +- Signalling frames are not implemented. So at runtime, we cannot change + mode between MASTER and SLAVE. Clock adjustment is implemented, but + clock rate adjustment is not implemented. diff --git a/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example_util.c b/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example_util.c new file mode 100755 index 00000000..f580e72f --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_example_util.c @@ -0,0 +1,615 @@ +/****************************************************************************** +* +* 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 THE +* XILINX CONSORTIUM 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 xemacps_example_util.c +* +* This file implements the utility functions for the XEmacPs example code. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a wsy  01/10/10 First release
+* 1.00a asa  01/24/12 A new version of EmacPsUtilEnterLoopback is used for
+* 		      Zynq boards. Now there are two versions of
+* 		      EmacPsUtilEnterLoopback, one for PEEP and one for Zynq.
+* 		      If the example is to be run  on a PEEP board, define PEEP
+* 		      in xemacps_example.h.
+* 1.01a asa  02/27/12 The sleep value after PHY loopback is setup is reduced
+*		      for Zynq.
+* 
+* +*****************************************************************************/ + +/***************************** Include Files ********************************/ + +#include "xemacps_example.h" +#include "sleep.h" + +/************************** Variable Definitions ****************************/ + +XEmacPs EmacPsInstance; /* XEmacPs instance used throughout examples */ + +/* + * Local MAC address + */ +char EmacPsMAC[] = { 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 EmacPsUtilFrameHdrFormatMAC(EthernetFrame * FramePtr, char *DestAddr) +{ + char *Frame = (char *) FramePtr; + char *SourceAddress = EmacPsMAC; + int Index; + + /* Destination address */ + for (Index = 0; Index < XEMACPS_MAC_ADDR_SIZE; Index++) { + *Frame++ = *DestAddr++; + } + + /* Source address */ + for (Index = 0; Index < XEMACPS_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 EmacPsUtilFrameHdrFormatType(EthernetFrame * FramePtr, u16 FrameType) +{ + char *Frame = (char *) FramePtr; + + /* + * Increment to type field + */ + Frame = Frame + 12; + /* + * Do endian swap from little to big-endian. + */ + FrameType = Xil_EndianSwap16(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 EmacPsUtilFrameSetPayloadData(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 + XEMACPS_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--; + } +} + +/****************************************************************************/ +/** +* 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, else XST_FAILURE. +* +* @note None. +*****************************************************************************/ +int EmacPsUtilFrameVerify(EthernetFrame * CheckFrame, + EthernetFrame * ActualFrame) +{ + char *CheckPtr = (char *) CheckFrame; + char *ActualPtr = (char *) ActualFrame; + u16 BytesLeft; + u16 Counter; + int Index; + + /* + * Compare the headers + */ + for (Index = 0; Index < XEMACPS_HDR_SIZE; Index++) { + if (CheckPtr[Index] != ActualPtr[Index]) { + return XST_FAILURE; + } + } + + /* + * Get the length of the payload + */ + BytesLeft = *(u16 *) &ActualPtr[12]; + /* + * Do endian swap from big back to little-endian. + */ + BytesLeft = Xil_EndianSwap16(BytesLeft); + /* + * Validate the payload + */ + Counter = 0; + ActualPtr = &ActualPtr[14]; + + /* + * Check 8 bit incrementing pattern + */ + while (BytesLeft && (Counter < 256)) { + if (*ActualPtr++ != (char) Counter++) { + return XST_FAILURE; + } + BytesLeft--; + } + + /* + * Check 16 bit incrementing pattern + */ + while (BytesLeft) { + if (*ActualPtr++ != (char) (Counter >> 8)) { /* high */ + return XST_FAILURE; + } + + BytesLeft--; + + if (!BytesLeft) + break; + + if (*ActualPtr++ != (char) 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 EmacPsUtilFrameMemClear(EthernetFrame * FramePtr) +{ + u32 *Data32Ptr = (u32 *) FramePtr; + u32 WordsLeft = sizeof(EthernetFrame) / sizeof(u32); + + /* frame should be an integral number of words */ + while (WordsLeft--) { + *Data32Ptr++ = 0xDEADBEEF; + } +} + + +/****************************************************************************/ +/** +* +* This function copys data from source to desitnation for n bytes. +* +* @param Destination is the targeted string to copy to. +* @param Source is the source string to copy from. +* @param n is number of bytes to be copied. +* +* @note This function is similiar to strncpy(), however strncpy will +* stop either at null byte or n bytes is been copied. +* This function will copy n bytes without checking the content. +* +*****************************************************************************/ +void EmacPsUtilstrncpy(char *Destination, const char *Source, u32 n) +{ + do { + *Destination++ = *Source++; + } while (--n != 0); +} + + +/****************************************************************************/ +/** +* +* This function sets the emacps to loopback mode. +* +* @param EmacPsInstancePtr is the XEmacPs driver instance. +* +* @note None. +* +*****************************************************************************/ +void EmacPsUtilEnterLocalLoopback(XEmacPs * EmacPsInstancePtr) +{ + u32 reg; + + reg = XEmacPs_ReadReg(EmacPsInstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET); + XEmacPs_WriteReg(EmacPsInstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET, + reg | XEMACPS_NWCTRL_LOOPEN_MASK); +} + + +/****************************************************************************/ +/** +* +* This function detects the PHY address by looking for successful MII status +* register contents. +* +* @param The XEMACPS driver instance +* +* @return The address of the PHY (defaults to 32 if none detected) +* +* @note None. +* +*****************************************************************************/ +#define PHY_DETECT_REG1 2 +#define PHY_DETECT_REG2 3 + +u32 XEmacPsDetectPHY(XEmacPs * EmacPsInstancePtr) +{ + u32 PhyAddr; + int Status; + u16 PhyReg1; + u16 PhyReg2; + + for (PhyAddr = 0; PhyAddr <= 31; PhyAddr++) { + Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, + PHY_DETECT_REG1, &PhyReg1); + + Status |= XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, + PHY_DETECT_REG2, &PhyReg2); + + if ((Status == XST_SUCCESS) && + (PhyReg1 > 0x0000) && (PhyReg1 < 0xffff) && + (PhyReg2 > 0x0000) && (PhyReg2 < 0xffff)) { + /* Found a valid PHY address */ + return PhyAddr; + } + } + + return PhyAddr; /* default to 32(max of iteration) */ +} + + +/****************************************************************************/ +/** +* +* This function sets the PHY to loopback mode. +* +* @param The XEMACPS driver instance +* @param Speed is the loopback speed 10/100 Mbit. +* +* @return XST_SUCCESS if successful, else XST_FAILURE. +* +* @note None. +* +*****************************************************************************/ +#ifdef PEEP /* Define PEEP in xemacps_example.h if the example is run on PEEP*/ +#define PHY_REG0_RESET 0x8000 +#define PHY_REG0_LOOPBACK 0x4000 +#define PHY_REG0_10 0x0100 +#define PHY_REG0_100 0x2100 +#define PHY_REG0_1000 0x0140 +#define PHY_R20_DFT_SPD_MASK 0x0070 +#define PHY_R20_DFT_SPD_10 0x0040 +#define PHY_R20_DFT_SPD_100 0x0050 +#define PHY_R20_DFT_SPD_1000 0x0060 +int EmacPsUtilEnterLoopback(XEmacPs * EmacPsInstancePtr, int Speed) +{ + int Status; + u16 PhyReg0 = 0; + u16 PhyReg20 = 0; + u32 PhyAddr; + + /* Detect the PHY address */ + PhyAddr = XEmacPsDetectPHY(EmacPsInstancePtr); + if (PhyAddr >= 32) { + EmacPsUtilErrorTrap("Error detect phy"); + return XST_FAILURE; + } + + + Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 20, &PhyReg20); + Status |= XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 0, &PhyReg0); + PhyReg20 &= ~PHY_R20_DFT_SPD_MASK; + + switch (Speed) { + case 10: + PhyReg20 |= PHY_R20_DFT_SPD_10; + break; + case 100: + PhyReg20 |= PHY_R20_DFT_SPD_100; + break; + case 1000: + PhyReg20 |= PHY_R20_DFT_SPD_1000; + break; + default: + EmacPsUtilErrorTrap("Error: speed not recognized "); + return XST_FAILURE; + } + + Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 20, PhyReg20); + Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 0, + PhyReg0 | PHY_REG0_RESET); + + /* setup speed and duplex */ + switch (Speed) { + case 10: + PhyReg0 = PHY_REG0_10; + break; + case 100: + PhyReg0 = PHY_REG0_100; + break; + case 1000: + PhyReg0 = PHY_REG0_1000; + break; + default: + EmacPsUtilErrorTrap("Error: speed not recognized "); + return XST_FAILURE; + } + Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 0, PhyReg0); + Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 0, + (PhyReg0 | PHY_REG0_RESET)); + sleep(1); + Status |= XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 0, &PhyReg0); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap("Error setup phy speed"); + return XST_FAILURE; + } + + /* enable loopback */ + PhyReg0 |= PHY_REG0_LOOPBACK; + Status = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 0, PhyReg0); + + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap("Error setup phy loopback"); + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +#else /*For Zynq board*/ + +#define PHY_REG0_RESET 0x8000 +#define PHY_REG0_LOOPBACK 0x4000 +#define PHY_REG0_10 0x0100 +#define PHY_REG0_100 0x2100 +#define PHY_REG0_1000 0x0140 +#define PHY_REG21_10 0x0030 +#define PHY_REG21_100 0x2030 +#define PHY_REG21_1000 0x0070 + +int EmacPsUtilEnterLoopback(XEmacPs * EmacPsInstancePtr, int Speed) +{ + int Status; + u16 PhyReg0 = 0; + u16 PhyReg21 = 0; + u16 PhyReg22 = 0; + u32 PhyAddr; + + /* + * Detect the PHY address + */ + PhyAddr = XEmacPsDetectPHY(EmacPsInstancePtr); + + if (PhyAddr >= 32) { + EmacPsUtilErrorTrap("Error detect phy"); + return XST_FAILURE; + } + + /* + * Setup speed and duplex + */ + switch (Speed) { + case 10: + PhyReg0 |= PHY_REG0_10; + PhyReg21 |= PHY_REG21_10; + break; + case 100: + PhyReg0 |= PHY_REG0_100; + PhyReg21 |= PHY_REG21_100; + break; + case 1000: + PhyReg0 |= PHY_REG0_1000; + PhyReg21 |= PHY_REG21_1000; + break; + default: + EmacPsUtilErrorTrap("Error: speed not recognized "); + return XST_FAILURE; + } + + Status = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 0, PhyReg0); + /* + * Make sure new configuration is in effect + */ + Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 0, &PhyReg0); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap("Error setup phy speed"); + return XST_FAILURE; + } + + /* + * Switching to PAGE2 + */ + PhyReg22 = 0x2; + Status = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 22, PhyReg22); + + /* + * Adding Tx and Rx delay. Configuring loopback speed. + */ + Status = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 21, PhyReg21); + /* + * Make sure new configuration is in effect + */ + Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 21, &PhyReg21); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap("Error setting Reg 21 in Page 2"); + return XST_FAILURE; + } + /* + * Switching to PAGE0 + */ + PhyReg22 = 0x0; + Status = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 22, PhyReg22); + + /* + * Issue a reset to phy + */ + Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 0, &PhyReg0); + PhyReg0 |= PHY_REG0_RESET; + Status = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 0, PhyReg0); + + Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 0, &PhyReg0); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap("Error reset phy"); + return XST_FAILURE; + } + + /* + * Enable loopback + */ + PhyReg0 |= PHY_REG0_LOOPBACK; + Status = XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddr, 0, PhyReg0); + + Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, 0, &PhyReg0); + if (Status != XST_SUCCESS) { + EmacPsUtilErrorTrap("Error setup phy loopback"); + return XST_FAILURE; + } + + /* + * Delay loop + */ + sleep(1); + + return XST_SUCCESS; +} +#endif /*PEEP*/ + +/****************************************************************************/ +/** +* +* 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 EmacPsUtilErrorTrap(const char *Message) +{ + static int Count = 0; + + Count++; + +#ifdef STDOUT_BASEADDRESS + xil_printf("%s\r\n", Message); +#else + (void) Message; +#endif +} diff --git a/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_ieee1588.c b/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_ieee1588.c new file mode 100755 index 00000000..4135d99a --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_ieee1588.c @@ -0,0 +1,1811 @@ +/****************************************************************************** +* +* Copyright (C) 2011 - 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 THE +* XILINX CONSORTIUM 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 xemacps_ieee1588.c +* +* This file implements the following functionalities. +* - Contains a routine upon reception of Tx done ISR to store the time stamp of +* the transmitted packet. +* - Does formatting and initiates a Tx for Announce frame, Sync frame, FollowUp +* frame, PDelayReq, PDelayResp and PDelayRespFollowUp frames. +* - Decodes and processes the received PTP frames of type Sync Frame, FollowUp +* frame, Announce Frame, PDelayReq frame, PDelayResp frame and +* PDelayRespFollowUp frame. +* - Implements the best master clock algorithm. +* - Contains function that calculates the link delay from existing data. +* - Contains function that calculates the clock offset from existing data and +* applies the clock offset to correct the PTP clock. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -----------------------------------------------
+* 1.00a asa  09/16/11 First release based on the AVB driver.
+* 1.01a asa  03/03/12 Support for Zynq is added.
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_io.h" +#include "xil_assert.h" +#include "xparameters.h" +#include "stdio.h" +#include "sleep.h" +#include "xparameters.h" +#include "xparameters_ps.h" /* defines XPAR values */ +#include "xil_types.h" +#include "xil_assert.h" +#include "xil_io.h" +#include "xil_exception.h" +#include "xpseudo_asm.h" +#include "xil_cache.h" +#include "xil_printf.h" +#include "xscugic.h" +#include "xemacps.h" /* defines XEmacPs API */ +#include "xemacps_ieee1588.h" +#include "xil_mmu.h" +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Variable Definitions *****************************/ + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ +/*****************************************************************************/ +/** +* +* This function is invoked from the TxDone callback. For sync frame it obtains +* the time stamp and populates the FollowUp frame Tx buffer. For PDelayReq and +* PDelayResp frames it obtains the time stamp and stores it is appropriate +* buffers. +* +* @param InstancePntr is a pointer to the instance of the +* XEmacPs_Ieee1588. +* @param PacketBuf which contains the buffer just transmitted +* +* @return None. +* +* @note None. +* +****************************************************************************/ +void XEmacPs_PtpTxDoFurtherProcessing (XEmacPs_Ieee1588 *InstancePtr, + u8 *PacketBuf) +{ + u8 MessageType; + u32 Sec; + u32 NanoSec; + u8 TimeStampTemp[10]; + u32 *TempLongPntr; + u16 SeqId; + u16 *TempPntr; + + MessageType = XEmacPs_GetMsgType (PacketBuf); + if (MessageType == XEMACPS_PTP_TYPE_SYNC) { + SyncSent = TRUE; + /* + * Read the seconds and nanoseconds register values + */ + Sec = XEmacPs_ReadReg ( + InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_PTP_TXSEC_OFFSET); + + NanoSec = XEmacPs_ReadReg ( + InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_PTP_TXNANOSEC_OFFSET); + + /* + * Now store the timestamps in the follow-up msg + */ + TimeStampTemp[0] = 0; + TimeStampTemp[1] = 0; + TempLongPntr = (u32 *)&(TimeStampTemp[2]); + *TempLongPntr = Xil_Htonl (Sec); + TempLongPntr = (u32 *)&(TimeStampTemp[6]); + *TempLongPntr = Xil_Htonl (NanoSec); + memcpy ((u8 *)&(InstancePtr-> + FollowUpFrmToTx[XEMACPS_PRECISE_TS_OFFSET]), + TimeStampTemp, 10); + /* + * Update the sequence id of the followup frame with + * the sequence id extracted from the sync frame. + */ + SeqId = XEmacPs_GetSequenceId (InstancePtr->SyncFrmToTx); + TempPntr = (u16 *)&(InstancePtr-> + FollowUpFrmToTx[XEMACPS_SEQID_OFFSET]); + *TempPntr = Xil_Htons (SeqId); + + InstancePtr->PtpRecords.Nanosec = NanoSec; + } + + else if (MessageType == XEMACPS_PTP_TYPE_PDELAYREQ) { + /* + * Read the nanoseconds register value + */ + NanoSec = XEmacPs_ReadReg ( + InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_PTPP_TXNANOSEC_OFFSET); + InstancePtr->PtpRecords.PDelayTimestampT1 = NanoSec; + InstancePtr->SequenceIdRecords.PDelayReqSequenceId = + XEmacPs_GetSequenceId (InstancePtr->PDelayReqFrmToTx); + } + + else if (MessageType == XEMACPS_PTP_TYPE_PDELAYRESP) { + PDelayRespSent = TRUE; + /* + * Read the seconds and nanoseconds register values + */ + InstancePtr->PtpRecords.PDelayRespTxedTSNs = XEmacPs_ReadReg ( + InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_PTPP_TXNANOSEC_OFFSET); + InstancePtr->PtpRecords.PDelayRespTxedTSSec = + XEmacPs_ReadReg ( + InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_PTPP_TXSEC_OFFSET); + } + +} + +/****************************************************************************/ +/** +* +* A function to format and then initiate the Tx of a PTP Announce Packet. The +* sequence Id of the announce frame is incremented before initiating the Tx. +* +* @param InstancePtr is a pointer to the XEmacPs_Ieee1588 instance. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_MasterSendAnnounce(XEmacPs_Ieee1588 *InstancePtr) +{ + u16 SeqId = 0; + + /* + * Increment the sequenceId + */ + SeqId = XEmacPs_IncSequenceId(InstancePtr->AnnounceFrmToTx); + +#ifdef DEBUG_LEVEL_TWO + xil_printf("\r\n------------------------------------"); + xil_printf("\r\n---XEmacPs_MasterSendAnnounce()----"); + xil_printf("\r\n------------------------------------"); + xil_printf("\r\nsequenceId is %x", SeqId); +#endif + /* Send the Announce Frame! */ + XEmacPs_PtpTxPacket (InstancePtr, InstancePtr->AnnounceFrmToTx, + XEMACPS_ANNOUNCEMSG_TOT_LEN); + +} + +/****************************************************************************/ +/** +* +* A function to format and then initiate the Tx of a PTP SYNC Packet. The +* sequence Id of the announce frame is incremented before initiating the Tx. +* +* @param InstancePtr is a pointer to the XEmacPs_Ieee1588 instance. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_MasterSendSync(XEmacPs_Ieee1588 *InstancePtr) +{ + u16 SeqId = 0; + + SyncSent = FALSE; + /* + * Increment the sequenceId + */ + SeqId = XEmacPs_IncSequenceId(InstancePtr->SyncFrmToTx); + + /* + * Send the SYNC Frame! + */ + PTPSendPacket |= SEND_SYNC; + +#ifdef DEBUG_LEVEL_TWO + xil_printf("\r\n------------------------------------"); + xil_printf("\r\n-----XEmacPs_MasterSendSync()------"); + xil_printf("\r\n------------------------------------"); + xil_printf("\r\nsequenceId is %x", SeqId); +#endif +} + +/****************************************************************************/ +/** +* +* A function to format and then initiate the Tx of a PTP FOLLOWUP Packet. +* Updates the correction field in the buffer. +* +* @param InstancePtr is a pointer to the XEmacPs_Ieee1588 instance. +* +* @return None. +* +* @note The correction field is hard coded to zero as of now. +* +*****************************************************************************/ +void XEmacPs_MasterSendFollowUp(XEmacPs_Ieee1588 *InstancePtr) +{ + u32 CorrectionField = 0; + u32 BufferWord = 0; + u32 *TempLongPntr; + + /* + * Correction Field is 0 for the time being! + */ + CorrectionField = 0; + + BufferWord = Xil_Htonl (CorrectionField); + + TempLongPntr = (u32 *)&(InstancePtr-> + FollowUpFrmToTx[XEMACPS_CORRFIELD_OFFSET]); + *TempLongPntr = BufferWord; + + XEmacPs_PtpTxPacket (InstancePtr, InstancePtr->FollowUpFrmToTx, + XEMACPS_FOLLOWUPMSG_TOT_LEN); + +#ifdef DEBUG_LEVEL_TWO + xil_printf("\r\n------------------------------------"); + xil_printf("\r\n---XEmacPs_MasterSendFollowUp()----"); + xil_printf("\r\n------------------------------------"); + xil_printf("\r\nRTC nano seconds field is %x", + InstancePtr->PtpRecords.Nanosec); + xil_printf("\r\nCorrection Field %x", CorrectionField); +#endif +} + +/****************************************************************************/ +/** +* +* A function to format and then initiate the Tx of a PTP PDelayReq Packet. +* The sequence Id of the announce frame is incremented before initiating the +* Tx. +* +* @param InstancePtr is a pointer to the XEmacPs_Ieee1588 instance. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_SendPDelayReq(XEmacPs_Ieee1588 *InstancePtr) +{ + u32 SequenceId; + + /* + * Increment the SequenceId + */ + SequenceId = XEmacPs_IncSequenceId(InstancePtr->PDelayReqFrmToTx); + InstancePtr->SequenceIdRecords.PDelayReqSequenceId = SequenceId; + +#ifdef DEBUG_LEVEL_TWO + xil_printf("\r\n------------------------------------"); + xil_printf("\r\n------XEmacPs_SendPDelayReq()------"); + xil_printf("\r\n------------------------------------"); + xil_printf("\r\nsequenceId is %x", SequenceId); +#endif + Xil_DCacheFlushRange((u32)&(InstancePtr->PDelayReqFrmToTx[0]), + XEMACPS_PDELAYREQMSG_TOT_LEN); + /* + * Update the corresponding bit in PTPSendPacket so that a Tx + * can be initiated in function XEmacPs_RunIEEE1588Protocol. + */ + PTPSendPacket |= SEND_PDELAY_REQ; + +} + +/****************************************************************************/ +/** +* +* A function to format and then initiate the Tx of a PTP PDelayResp Packet. +* This function is invoked upon receiving a PDelayReq frame. It first gets +* the time stamps of the received PDelayReq from the hardware and stores +* them at appropriate entries in the structure instance PtpRecords. It then +* formats the PDelayResp frame with these time stamp values. +* +* @param InstancePtr is a pointer to the XEmacPs_Ieee1588 instance. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_SendPDelayResp(XEmacPs_Ieee1588 *InstancePtr) +{ + u16 SequenceId = 0; + u32 TimestampT2Ns = 0; + u32 TimestampT2Sec = 0; + u8 TimeStampTemp[10]; + u32 *TempLongPntr; + u16 *TempPntr; + XEmacPs_PortIdentity TempPortIdentity; + + PDelayRespSent = FALSE; + /* + * Get the time stamp for the received PDelayReq frame and + * store them. + */ + InstancePtr->PtpRecords.PDelayReqRecdTSSec = XEmacPs_ReadReg ( + InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_PTPP_RXSEC_OFFSET); + InstancePtr->PtpRecords.PDelayReqRecdTSNs = XEmacPs_ReadReg ( + InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_PTPP_RXNANOSEC_OFFSET); + TimestampT2Sec = InstancePtr->PtpRecords.PDelayReqRecdTSSec; + TimestampT2Ns = InstancePtr->PtpRecords.PDelayReqRecdTSNs; + /* + * Populate the PDelayResp buffer with PDelayReq time stamp. + */ + TimeStampTemp[0] = 0; + TimeStampTemp[1] = 0; + TempLongPntr = (u32 *)&(TimeStampTemp[2]); + *TempLongPntr = Xil_Htonl (TimestampT2Sec); + TempLongPntr = (u32 *)&(TimeStampTemp[6]); + *TempLongPntr = Xil_Htonl (TimestampT2Ns); + memcpy ((u8 *)&(InstancePtr-> + PDelayRespFrmToTx[XEMACPS_PRECISE_TS_OFFSET]), TimeStampTemp, 10); + /* + * Copy the sequence id from Pdelay request frame + */ + SequenceId=XEmacPs_GetSequenceId (InstancePtr->LastRecdPDelayReqFrm); + TempPntr = (u16 *)&(InstancePtr-> + PDelayRespFrmToTx[XEMACPS_SEQID_OFFSET]); + *TempPntr = Xil_Htons (SequenceId); + + /* + * Copy the source port identity + */ + XEmacPs_GetPortIdentity (InstancePtr->LastRecdPDelayReqFrm, + &TempPortIdentity); + memcpy ((u8 *)&(InstancePtr-> + PDelayRespFrmToTx[XEMACPS_REQPORTID_OFFSET]), + (u8 *)&(TempPortIdentity.ClockIdentity[0]), 8); + TempPntr = (u16 *)&(InstancePtr-> + PDelayRespFrmToTx[XEMACPS_REQPORTID_OFFSET + 8]); + *TempPntr = Xil_Htons (TempPortIdentity.PortNumber); + + /* + * Update the corresponding bit in PTPSendPacket so that a Tx + * can be initiated in function XEmacPs_RunIEEE1588Protocol. + */ + PTPSendPacket |= SEND_PDELAY_RESP; + +#ifdef DEBUG_LEVEL_TWO + xil_printf("\r\n------------------------------------"); + xil_printf("\r\n------XEmacPs_SendPDelayResp()-----"); + xil_printf("\r\n------------------------------------"); + xil_printf("\r\nTimestampT2 is %x", TimestampT2Ns); +#endif +} + +/****************************************************************************/ +/** +* +* A function to format and then initiate the Tx of a PTP PDelayRespFollowUp +* Packet. This function is invoked after a PDelayResp is successfully sent +* out (Tx done interrupt is received for PDelayResp packet). +* It populates the PDelayRespFollowUp frame with time stamps of the just +* transmitted PDelayResp packet. +* +* @param InstancePtr is a pointer to the XEmacPs_Ieee1588 instance. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_SendPDelayRespFollowUp(XEmacPs_Ieee1588 *InstancePtr) +{ + u16 SequenceId = 0; + u32 TimestampT3Ns = 0; + u32 TimestampT3Sec = 0; + u8 TimeStampTemp[10]; + u32 *TempLongPntr; + u16 *TempPntr; + XEmacPs_PortIdentity TempPortIdentity; + + TimestampT3Sec = InstancePtr->PtpRecords.PDelayRespTxedTSSec; + TimestampT3Ns = InstancePtr->PtpRecords.PDelayRespTxedTSNs; + /* + * Populate the PDelayRespFollowUp buffer with PDelayResp time stamp. + */ + TimeStampTemp[0] = 0; + TimeStampTemp[1] = 0; + TempLongPntr = (u32 *)&(TimeStampTemp[2]); + *TempLongPntr = Xil_Htonl (TimestampT3Sec); + TempLongPntr = (u32 *)&(TimeStampTemp[6]); + *TempLongPntr = Xil_Htonl (TimestampT3Ns); + memcpy ((u8 *)&(InstancePtr-> + PDelayRespFollowUpFrmToTx[XEMACPS_PRECISE_TS_OFFSET]), + TimeStampTemp, 10); + + /* + * Copy the sequence id from last received Pdelay request frame + */ + SequenceId=XEmacPs_GetSequenceId (InstancePtr->LastRecdPDelayReqFrm); + TempPntr = (u16 *)&(InstancePtr-> + PDelayRespFollowUpFrmToTx[XEMACPS_SEQID_OFFSET]); + *TempPntr = Xil_Htons (SequenceId); + + /* + * Copy the source port identity from last received PDelayReq frame. + */ + XEmacPs_GetPortIdentity (InstancePtr->LastRecdPDelayReqFrm, + &TempPortIdentity); + memcpy ((u8 *)&(InstancePtr-> + PDelayRespFollowUpFrmToTx[XEMACPS_REQPORTID_OFFSET]), + (u8 *)&(TempPortIdentity.ClockIdentity[0]), 8); + TempPntr = (u16 *)&(InstancePtr-> + PDelayRespFollowUpFrmToTx[XEMACPS_REQPORTID_OFFSET + 8]); + *TempPntr = Xil_Htons (TempPortIdentity.PortNumber); + + /* + * Tx the packet. + */ + XEmacPs_PtpTxPacket(InstancePtr, + InstancePtr->PDelayRespFollowUpFrmToTx, + XEMACPS_PDELAYRESPFOLLOWUP_TOT_LEN); +#ifdef DEBUG_LEVEL_TWO + xil_printf("\r\n---------------------------------------"); + xil_printf("\r\n--XEmacPs_SendPDelayRespFollowUp()----"); + xil_printf("\r\n---------------------------------------"); +#endif +} + +/****************************************************************************/ +/** +* +* A function to decode a received PTP Sync Packet. It extracts the sync frame +* time stamp and stores it in appropriate buffer. It stores the sequence ID +* as well. +* +* @param InstancePtr is a pointer to the XEmacPs_Ieee1588 instance. +* @param PacketBuf is the buffer that contains the sync packet. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_DecodeRxSync(XEmacPs_Ieee1588 *InstancePtr, u8 *PacketBuf) +{ + XEmacPs_PortIdentity syncPortID; + + /* + * Read sourcePortIdentity from packet + */ + XEmacPs_GetPortIdentity(PacketBuf, &syncPortID); + + /* + * Only decode if configured for a slave and if SourcePortID is that + * of the RTC Clock Master + */ + if ((InstancePtr->CurrentBmc.IAmTheRtcMaster == 0) && + XEmacPs_ComparePortIdentity( + 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 + */ + + InstancePtr->PtpRecords.SlaveSyncTimestampSec + = XEmacPs_ReadReg( + InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_PTP_RXSEC_OFFSET ); + InstancePtr->PtpRecords.SlaveSyncTimestampNSec + = XEmacPs_ReadReg( + InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_PTP_RXNANOSEC_OFFSET + ); + InstancePtr->SequenceIdRecords.SyncSequenceId = + XEmacPs_GetSequenceId (PacketBuf); + InstancePtr->LatestMDSyncReceive.LogMessageInterval = 0; + InstancePtr->LatestMDSyncReceive.SyncIntervalDuration = 2; + + } else { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("\r\nXEmacPs_DecodeRxSync()"); + xil_printf("\r\nSync ignored due to unmatched SourcePortID"); +#endif + } +} + +/****************************************************************************/ +/** +* +* A function to decode a received PTP FollowUp Packet. If the PTP node is +* master, source port identity of the received FollowUp frame matches that +* with this node's source port identity, the sequence Id of the received +* folowup frame matches that of last received Sync frame sequence Id, the +* function XEmacPs_CalcRtcOffset is invoked to calculate clock offset. +* Similalry for every 2 sync frames clock rate adjustment is done by +* calling XEmacPs_UpdateRtcIncrement. However, as of now, this function +* is not implemented and is empty. +* +* @param InstancePtr is a pointer to the XEmacPs_Ieee1588 instance. +* @param PacketBuf is the buffer that contains the followup packet. +* +* @return None. +* +* @note The clock rate adjustment is not implemented as of now. +* Though the function XEmacPs_UpdateRtcIncrement is called +* from here, the function does nothing! +* +*****************************************************************************/ +void XEmacPs_DecodeRxFollowUp(XEmacPs_Ieee1588 *InstancePtr, u8 *PacketBuf) +{ + XEmacPs_PortIdentity followUpPortID; + + /* + * Read sourcePortIdentity from packet + */ + XEmacPs_GetPortIdentity(PacketBuf, &followUpPortID); + /* + * Only decode if configured for a slave and if SA is that of the RTC + * Clock Master + */ + if ( (InstancePtr->CurrentBmc.IAmTheRtcMaster == 0) && + XEmacPs_ComparePortIdentity( + InstancePtr->CurrentBmc.SourcePortIdentity, + followUpPortID) ) { + + /* + * Capture the Follow Up SequenceID + */ + InstancePtr->SequenceIdRecords.FollowUpSequenceId = + XEmacPs_GetSequenceId (PacketBuf); + + /* + * 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 = + *((u32 *)(PacketBuf + XEMACPS_CORRFIELD_OFFSET)); + + /* + * Perform the Course RTC Offset correction for every + * Sync FollowUp pair + */ + XEmacPs_CalcRtcOffset(InstancePtr); + + /* + * Every n Sync / FollowUp pairs, we are going to + * calculate a corrected increment rate of RTC + */ + if ((InstancePtr->PtpCounters.CounterSyncEvents & 0xF) + == (XEMACPS_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 + = InstancePtr-> + SequenceIdRecords.FollowUpSequenceId; + + /* + * Perform the RTC increment rate adjustment + * calculation + */ + XEmacPs_UpdateRtcIncrement(InstancePtr); + + InstancePtr->PtpRecords.OldSlaveTime + = InstancePtr->PtpRecords.NewSlaveTime; + + InstancePtr->PtpRecords.OldMasterTime + = InstancePtr->PtpRecords.NewMasterTime; + + InstancePtr-> + SequenceIdRecords.OldSyncSequenceId + = InstancePtr-> + SequenceIdRecords.NewSyncSequenceId; + + } else { + InstancePtr-> + PtpCounters.CounterSyncEvents + = InstancePtr-> + PtpCounters.CounterSyncEvents + 1; + } + + } else { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("SequenceIDs on RxFollowup don't match.\r\n"); + xil_printf("FollowupSeqID is : %d", + InstancePtr->SequenceIdRecords.FollowUpSequenceId); + xil_printf("SyncSeqID is : %d", + InstancePtr->SequenceIdRecords.SyncSequenceId); +#endif + ; + } + } else { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("\r\nXEmacPs_DecodeRxFollowUp()"); + xil_printf("\r\nFollowUp ignored due to unmatched SourcePortID\r\n"); +#endif + ; + } +} + +/****************************************************************************/ +/** +* +* A function to decode a received PTP PDelayResp Packet. +* +* @param InstancePtr is a pointer to the XEmacPs_Ieee1588 instance. +* @param PacketBuf is the buffer that contains the PDelayResp packet. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_DecodeRxPDelayResp(XEmacPs_Ieee1588 *InstancePtr, u8 *PacketBuf) +{ + u16 *TempPntr; + + /* + * Have we already seen a PDelayResp since the last + * PDelayReq was sent? If so, ignore the packet + */ + if( InstancePtr->StateMachineData.RcvdPDelayResp ) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("Error: already saw a PDelayResp since the last PDelayReq was sent\r\n"); +#endif + return; + } + + /* + * Find the ClockIdentity of the Sender + */ + XEmacPs_GetPortIdentity (PacketBuf, + &(InstancePtr->StateMachineData.RespPortIdentity)); + + /* + * Is the PDelayResp message from ourself? If so, the Peer + * is most likely a dumb hub and should be considered not + * IEEE1588v2 Capable + */ + if (XEmacPs_ComparePortIdentity (InstancePtr->PortIdLocal, + InstancePtr->StateMachineData.RespPortIdentity)) { + XEmacPs_ChangePeerIeee1588v2Capability(InstancePtr, 0); +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("\r\nXEmacPs_DecodeRxPDelayResp():The peer is no longer IEEE1588v2 Capable "); + xil_printf("\r\nXEmacPs_DecodeRxPDelayResp():Error: saw a PDelayResp from myself\r\n"); +#endif + return; + } + + memcpy (&(InstancePtr-> + StateMachineData.RespReqPortIdentity.ClockIdentity[0]), + (u8 *)&(PacketBuf[XEMACPS_REQPORTID_OFFSET]), 8); + TempPntr = (u16 *)&(PacketBuf[XEMACPS_REQPORTID_OFFSET + 8]); + InstancePtr-> + StateMachineData.RespReqPortIdentity.PortNumber = + Xil_Htons (*TempPntr); + + /* + * Capture the PDelayResp SequenceID + */ + InstancePtr->SequenceIdRecords.PDelayRespSequenceId = + XEmacPs_GetSequenceId (PacketBuf); + + /* + * Verify that the requestingPortIdentity matches our + * portIdentity + */ + if (!(XEmacPs_ComparePortIdentity (InstancePtr->PortIdLocal, + InstancePtr->StateMachineData.RespReqPortIdentity))) { + +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("Error: PDelayResp reqPortID doesn't match our portID\r\n"); +#endif + 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; + + InstancePtr->PtpRecords.PDelayTimestampT2 = + Xil_Ntohl (*(u32 *)&(PacketBuf[XEMACPS_PRECISE_TS_OFFSET + 6])); + /* + * Capture timestamp for receipt time of PDelayResp at Slave (t4) + * and adjust it for MAC receive latency + */ + InstancePtr->PtpRecords.PDelayTimestampT4 = XEmacPs_ReadReg ( + InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_PTPP_RXNANOSEC_OFFSET); + } else { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("Error: PDelayResp seqID's don't match\r\n"); +#endif + ; + } +} + +/****************************************************************************/ +/** +* +* A function to decode a received PTP PDelayRespFollowUp Packet. +* +* @param InstancePtr is a pointer to the XEmacPs_Ieee1588 instance. +* @param PacketBuf is the buffer that contains the PDelayRespFollowUp +* packet. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_DecodeRxPDelayRespFollowUp(XEmacPs_Ieee1588 *InstancePtr, + u8 *PacketBuf) +{ + XEmacPs_PortIdentity portId; + u16 *TempPntr; + + /* + * Has a valid PDelayResp packet been received since the + * last PDelayReq packet was sent? + */ + if( !InstancePtr->StateMachineData.RcvdPDelayResp ) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("Error: Received a PDelayRespFollowUp before receiving a PDelayResp\r\n"); +#endif + return; + } + + /* Capture the PDelayRespFollowUp SequenceID */ + InstancePtr->SequenceIdRecords.PDelayFollowUpSequenceId = + XEmacPs_GetSequenceId (PacketBuf); + + /* Get the sourcePortIdentity of the sender */ + XEmacPs_GetPortIdentity (PacketBuf, &portId); + + /* + * The sourcePortIdentity of the PDelayRespFollowUp should + * match that of the last PDelayResp packet received + */ + if (!(XEmacPs_ComparePortIdentity (portId, + InstancePtr->StateMachineData.RespPortIdentity))) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("Error: sourcePortIdentity of PDelayRespFollowUp doesn't match PDelayResp\r\n"); +#endif + return; + } + + memcpy (&(portId.ClockIdentity[0]), + (u8 *)&(PacketBuf[XEMACPS_REQPORTID_OFFSET]), 8); + TempPntr = (u16 *)&(PacketBuf[XEMACPS_REQPORTID_OFFSET + 8]); + portId.PortNumber = Xil_Htons (*TempPntr); + + if (!(XEmacPs_ComparePortIdentity (portId, + InstancePtr->StateMachineData.RespReqPortIdentity))) { + +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("Error: reqPortID of PDelayRespFollowUp doesn't match PDelayResp\r\n"); +#endif + 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 = + Xil_Ntohl (*(u32 *)&(PacketBuf[XEMACPS_PRECISE_TS_OFFSET + + 6])); + + /* Now we know t1, t2, t3 and t4, calculate the link delay */ + XEmacPs_CalcDelay(InstancePtr); + } else { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("Error: seqID of PDelayRespFollowUp doesn't match PDelayResp\r\n"); +#endif + ; + } +} + +/****************************************************************************/ +/** +* +* A function to decode a received PTP Signalling Packet. Empty as of now. +* +* @param InstancePtr is a pointer to the XEmacPs_Ieee1588 instance. +* @param PacketBuf is the buffer that contains the signalling packet. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_DecodeRxSignaling(XEmacPs_Ieee1588 *InstancePtr, u8 *PacketBuf) +{ + /*TO DO*/ +} + +/****************************************************************************/ +/** +* This function is invoked to compare the Current Master clock's parameter +* with that of the PTP node's (own) and run Best Master Clock Algorithm. A +* typical scenario is a new Announce frame has been received from the PTP +* Master and the PTP master record has been updated. Then this function is +* invoked to run Best Master Clock Algorithm with the PTP node's Announce +* Frame parameters and Current PTP Master's parameter. +* +* @param InstancePtr is a pointer to the XEmacPs_Ieee1588 instance. +* @param PacketBuf is the buffer that contains the Announce Frame. +* For this function the buffer passed is the Tx Announce Frame +* stored in the buffer AnnounceFrmToTx in XEmacPs_Ieee1588 +* instance. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_DecodeTxAnnounceFrame(XEmacPs_Ieee1588 *InstancePtr, + u8 *PacketBuf) +{ + + u32 NewMaster = 0; + XEmacPs_BmcData TxAnnounceFrame; + + /* + * Read the attributes for the new Announce frame in the Tx PTP buffer + */ + XEmacPs_ReadAnnounceFrame(PacketBuf, &TxAnnounceFrame); + + /* + * Compare the clock attributes between then new Announce frame and the + * current master + */ + NewMaster = XEmacPs_BestMasterClockAlgorithm(&TxAnnounceFrame, + &InstancePtr->CurrentBmc); + + + if ((NewMaster == 1) | (InstancePtr->CurrentBmc.IAmTheRtcMaster == 1)) + { + /* + * Update records with the NEW best master + */ + XEmacPs_UpdateBmcRecords(&TxAnnounceFrame, + &InstancePtr->CurrentBmc); + +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("\r\nXEmacPs_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\nPriority1 %x", + InstancePtr->CurrentBmc.GrandmasterPriority1); + + xil_printf("\r\nclockClass %x", + InstancePtr->CurrentBmc.ClockQuality.clockClass); + + xil_printf("\r\nPriority2 %x", + InstancePtr->CurrentBmc.GrandmasterPriority2); + + /* + * Our new Tx Announce Packet has won - so this device must be the + * master + */ + xil_printf("\r\n*** XEmacPs_DecodeTxAnnounceFrame() : Call XEmacPs_BecomeRtcMaster() *** \r\n"); +#endif + XEmacPs_BecomeRtcMaster(InstancePtr, 1); + } +} + +/****************************************************************************/ +/** +* This function is invoked from various places to extract clock information +* from a buffer and populate the XEmacPs_BmcData instance passed. +* +* @param PacketBuf from which the clock information is extracted +* @param AnnounceFrame which is populated with clock information +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_ReadAnnounceFrame(u8 *PacketBuf, XEmacPs_BmcData *AnnounceFrame) +{ + u32 ReadWord; + + memset(AnnounceFrame->SourcePortIdentity.ClockIdentity, 0, 8); + + /* + * Get the Source Port Identity of the port sending the Announce Packet + */ + XEmacPs_GetPortIdentity (PacketBuf, &AnnounceFrame->SourcePortIdentity); + + + /* + * Read priority1 and top half of ClockQuality + */ + AnnounceFrame->GrandmasterPriority1 = + PacketBuf[XEMACPS_GMPRI_ONE_OFFSET]; + + ReadWord = + Xil_Ntohl(*((u32 *)&(PacketBuf[XEMACPS_GM_CLK_QUALITY_OFFSET]))); + memcpy ((u8 *)&(AnnounceFrame->ClockQuality), (u8 *)&ReadWord, 4); + + AnnounceFrame->GrandmasterPriority2 = + PacketBuf[XEMACPS_GMPRI_TWO_OFFSET]; + + memcpy((u8 *)&(AnnounceFrame->GrandmasterIdentity.ClockIdentity), + (u8 *)&PacketBuf[XEMACPS_GM_IDENTITY_OFFSET], 8); + + /* AnnounceFrame->StepsRemoved = + Xil_Ntohs (*((u16 *)&(PacketBuf[XEMACPS_STEPS_REMOVED_OFFSET])));*/ + AnnounceFrame->StepsRemoved = 0; + +} + +/*****************************************************************************/ +/** +* This function is invoked when a new Announce frame is received. This function +* first reads the Announce frame parameters. If it is found that the announce +* frame has been received from the PTP master then the records are updated +* with the clock parameters. The Best Master Clock Algorithm is run in case +* any of the parameters in the announce frame has changed. There can be +* cases when the PTP master reduces its clock priority that may force the +* current PTP node to become master. +* If the PTP node is master and it has received this announce frame, then +* BMCA is run and if the incoming clock parameters are better tyhan that of +* the present node, the present node becomes SLAVE. +* +* @param InstancePtr is a pointer to the XEmacPs_Ieee1588 instance. +* @param PacketBuf is the buffer that contains the Announce Frame. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_DecodeRxAnnounceFrame(XEmacPs_Ieee1588 *InstancePtr, + u8 *PacketBuf) +{ + + u32 NewMaster = 0; + XEmacPs_BmcData RxAnnounceFrame; + + /* + * Read the attributes for the new Announce frame received + */ + XEmacPs_ReadAnnounceFrame(PacketBuf, &RxAnnounceFrame); + /* + * If the received packet's clockIdentity matches our + * clockIdentity, ignore the packet + */ + if( XEmacPs_ComparePortIdentity(InstancePtr->PortIdLocal, + RxAnnounceFrame.SourcePortIdentity) ) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("Got an announce from myself.. ignoring\r\n"); +#endif + return; + } + + /* + * If the received packet's StepsRemoved field is >= 255, + * ignore the packet + */ + if( RxAnnounceFrame.StepsRemoved >= 255 ) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("Got an announce with StepsRemoved > 255.. ignoring\r\n"); +#endif + 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( XEmacPs_CompareClockIdentity( + RxAnnounceFrame.GrandmasterIdentity, + InstancePtr->CurrentBmc.GrandmasterIdentity) ) { + /* + * Update timeout information + */ + InstancePtr->PtpCounters.CounterAnnounceInterval = 0; + + XEmacPs_UpdateBmcRecords(&RxAnnounceFrame, + &InstancePtr->CurrentBmc); + /* + * Compare against this device's information to see if we + * should be GM + */ + XEmacPs_DecodeTxAnnounceFrame(InstancePtr, + InstancePtr->AnnounceFrmToTx); + + } else if( InstancePtr->CurrentBmc.IAmTheRtcMaster ) { + /* + * Run BMCA on this announce to see if it is better than me + */ + NewMaster = XEmacPs_BestMasterClockAlgorithm(&RxAnnounceFrame, + &InstancePtr->CurrentBmc); + + if (NewMaster == 1) { + /* + * Update records with the NEW best master + */ + XEmacPs_UpdateBmcRecords(&RxAnnounceFrame, + &InstancePtr->CurrentBmc); + + /* + * Capture the Announce Receipt Timeout Interval. + * Reset the announce receipt timeout interval to + * use the new value. + */ + RxAnnounceFrame.LogMessageInterval = + PacketBuf[XEMACPS_LOGMSG_INTERVAL_OFFSET]; + InstancePtr->CurrentBmc.AnnounceIntervalDuration = 10; +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("\r\r\nXEmacPs_DecodeRxAnnounceFrame()"); + xil_printf("\r\n* XEmacPs_DecodeRxAnnounceFrame()::BMC : I am a SLAVE"); + xil_printf("\r\n-----------------------"); + xil_printf("\r\nWinning Announce Frame"); + xil_printf("\r\n-----------------------"); + + 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 + */ + XEmacPs_BecomeRtcSlave(InstancePtr); + } + } +} + +/****************************************************************************/ +/** +* 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. TheBest Master Clock Algorithm (BMCA) is then performed on these +* two data structures by comparing the data fields +* +* @param AnnounceFrame of the received new frame +* @param CurrentBmc is the existing BMC records +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +u32 XEmacPs_BestMasterClockAlgorithm(XEmacPs_BmcData *AnnounceFrame, + XEmacPs_BmcData *CurrentBmc) +{ + + u32 NewMaster = 0; +#ifdef DEBUG_XEMACPS_LEVEL1 + 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 DEBUG_XEMACPS_LEVEL1 + 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) { + + u32 AnnClockQualityInteger; + u32 BmcClockQualityInteger; +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("BMCA: priority1 equal moving on: (%d)\r\n", + AnnounceFrame->GrandmasterPriority1); +#endif + /* + * Convert structs to u32 values for easy comparison + */ + + 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 DEBUG_XEMACPS_LEVEL1 + 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 DEBUG_XEMACPS_LEVEL1 + 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 DEBUG_XEMACPS_LEVEL1 + 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) { + + signed int CompareResult; +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("BMCA: priority2 equal moving on: (%d)\r\n", + AnnounceFrame->GrandmasterPriority2); +#endif + + CompareResult = + memcmp (AnnounceFrame-> + GrandmasterIdentity.ClockIdentity, + CurrentBmc->GrandmasterIdentity.ClockIdentity, + 8); + if (CompareResult < 0) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("BMCA: Found new GM on GMIDClockID\r\n"); +#endif + /* + * We have found a better master! + */ + NewMaster = 1; + + } else if (CompareResult == 0) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("BMCA: GMIDclockID equal moving on\r\n"); +#endif + if( AnnounceFrame->StepsRemoved < + CurrentBmc->StepsRemoved ) { +#ifdef DEBUG_XEMACPS_LEVEL1 + 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 ) { + signed int CompareResult; +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("BMCA: StepsRemoved equal moving on: (%d)\r\n", + AnnounceFrame->StepsRemoved); +#endif + CompareResult = + memcmp (AnnounceFrame-> + SourcePortIdentity. + ClockIdentity, + CurrentBmc->SourcePortIdentity. + ClockIdentity, + 8); + if( CompareResult < 0) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("BMCA: Found new GM on sourceIDClockID\r\n"); +#endif + /* + * We have found a better master! + */ + NewMaster = 1; + + } else if( CompareResult + == 0 ) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("BMCA: sourceIDport equal moving on\r\n"); +#endif + /* + * If all else fails, the SourcePortIdentity Port Number must + * act as the tie-breaker + */ + if( AnnounceFrame-> + SourcePortIdentity. + PortNumber < + CurrentBmc-> + SourcePortIdentity. + PortNumber ) { +#ifdef DEBUG_XEMACPS_LEVEL1 + 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 DEBUG_XEMACPS_LEVEL1 + xil_printf("*** END BMCA ***\r\n"); +#endif + return NewMaster; + +} + +/****************************************************************************/ +/** +* This function updates the PTP master records (BMC records) with incoming +* BMC data. +* +* @param NewMaster is the new data to be updated +* @param CurrentBmc is the existing BMC records that needs to be +* updated. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_UpdateBmcRecords(XEmacPs_BmcData *NewMaster, + XEmacPs_BmcData *CurrentBmc) +{ + memcpy (CurrentBmc->SourcePortIdentity.ClockIdentity, + NewMaster->SourcePortIdentity.ClockIdentity, + 8); + CurrentBmc->SourcePortIdentity.PortNumber = + NewMaster->SourcePortIdentity.PortNumber; + + memcpy (CurrentBmc->GrandmasterIdentity.ClockIdentity, + NewMaster->GrandmasterIdentity.ClockIdentity, + 8); + CurrentBmc->StepsRemoved = NewMaster->StepsRemoved; + CurrentBmc->ClockQuality = NewMaster->ClockQuality; + CurrentBmc->GrandmasterPriority1 = NewMaster->GrandmasterPriority1; + CurrentBmc->GrandmasterPriority2 = NewMaster->GrandmasterPriority2; +} + +/****************************************************************************/ +/** +* This function is called when the PTP node becomes RTC or PTP Master. This +* 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 XEmacPs_Ieee1588 instance. +* @param txAnnounceHasWon if 1, indicates that this function has been +* called from the function XEmacPs_DecodeTxAnnounceFrame(). This +* way it can avoid performing things that are already done. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_BecomeRtcMaster(XEmacPs_Ieee1588 *InstancePtr, + u8 txAnnounceHasWon) +{ + + XEmacPs_BmcData deviceData; + unsigned int NSIncrementVal; + + if (txAnnounceHasWon == 0) { + /* + * Update the BMCA records to this device's information + */ + + /* + * Read the attributes in the Tx PTP buffer + */ + XEmacPs_ReadAnnounceFrame(InstancePtr->AnnounceFrmToTx, + &deviceData); + + /* + * Update records + */ + XEmacPs_UpdateBmcRecords(&deviceData,&InstancePtr->CurrentBmc); + } + +#ifdef PEEP + /* + * Set the 1588 Timer register for 50 MHz timer, i.e. 20 ns increment + * for every clock cycle. + */ + XEmacPs_WriteReg(InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_1588_INC_OFFSET, + XEMACPS_1588_INC_VAL); +#else + NSIncrementVal = XEmacPs_TsuCalcClk(XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ / 6); + /* + * Set the 1588 Timer register for 50 MHz timer, i.e. 20 ns increment + * for every clock cycle. + */ + XEmacPs_WriteReg(InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_1588_INC_OFFSET, + NSIncrementVal); +#endif + /* + * Set timestamp uncertainty if new status + */ + if( !InstancePtr->CurrentBmc.IAmTheRtcMaster ) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("\r\n*** I am now the Grand Master ***"); + xil_printf("\r\nNOTICE: timestamps are now certain\r\n"); +#endif + ; + } + + /* + * Inform the rest of the system + */ + InstancePtr->CurrentBmc.IAmTheRtcMaster = 1; +} + +/****************************************************************************/ +/** +* This function is called when the PTP node becomes PTP Slave. +* +* @param InstancePtr is a pointer to the XEmacPs_Ieee1588 instance. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_BecomeRtcSlave(XEmacPs_Ieee1588 *InstancePtr) +{ + /* + * Set timestamp uncertainty if new status + */ + if( InstancePtr->CurrentBmc.IAmTheRtcMaster ) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("\r\n*** I am now a PTP slave ***"); + xil_printf("\r\nNOTICE: timestamps are now uncertain\r\n"); +#endif + ; + } + + /* + * Reset the syncReceiptTimeoutTimeInterval counter as this has now + * changed purpose. + */ + InstancePtr->PtpCounters.CounterSyncInterval = 0; + + /* + * Inform the rest of the system + */ + InstancePtr->CurrentBmc.IAmTheRtcMaster = 0; +} + +/****************************************************************************/ +/** +* This function is called to change the Peer capability of processing +* Iee1588v2 specific frames, e.g. PDelayReq, PDelayResp etc. A peer is +* Ieee1588v2 capable when it is able to send PDelayReq frames or able to +* respond to PDelayReq frames. +* +* @param InstancePtr is a pointer to the XEmacPs_Ieee1588 instance. +* @param capable is Peer's capability +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_ChangePeerIeee1588v2Capability(XEmacPs_Ieee1588 *InstancePtr, + u8 Capable) +{ + u32 CapableOld; + + CapableOld = InstancePtr->PeerIeee1588v2Capable; + + /* set status variable */ + InstancePtr->PeerIeee1588v2Capable = Capable; + + if( Capable != CapableOld ) { + if( Capable ) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("\r\nThe Peer is now IEEE1588 v2 Capable\r\n"); +#endif + ; + } else { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("\r\nThe Peer is no longer IEEE1588 v2 Capable\r\n"); +#endif + ; + } + } + +} + +/****************************************************************************/ +/** +* This function is called to calculate the link delay. This is called after +* a complete sequence of PDelay packets. The PTP node sends a PDelayReq +* packet to start. Afterwards it receives the PDelayResp and +* PDelayRespFollowUp frames. Upon receiving the PDelayRespFollowUp, this +* function is invoked to calculate the link delay. +* +* @param InstancePtr is a pointer to the XEmacPs_Ieee1588 instance. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_CalcDelay(XEmacPs_Ieee1588 *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 times 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_LEVEL_TWO + xil_printf("\r\nXEmacPs_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 + + XEMACPS_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 + + XEMACPS_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 < XEMACPS_NEIGHBOR_PROP_DELAY_THRESH ) { + InstancePtr->PtpRecords.LinkDelay = Delay; +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("THE FINAL LINK DELAY IS %x \r\n", + InstancePtr->PtpRecords.LinkDelay); +#endif + /* + * The peer has responded to the pDelay_Req and the measured + * delay is within tolerance: the peer is deemed to be + * Ieee1588v2 capable + */ + XEmacPs_ChangePeerIeee1588v2Capability(InstancePtr, 1); + + } else { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("\r\nXEmacPs_CalcDelay()"); + xil_printf("\r\n Bad Link Delay %d ", Delay); + 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 + ; + + } +} + +/****************************************************************************/ +/** +* This function calculates the Slave Offset from the GrandMaster time. It is +* called after receiving a Sync and FollowUp frame pair. +* +* @param InstancePtr is a pointer to the XEmacPs_Ieee1588 instance. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_CalcRtcOffset (XEmacPs_Ieee1588 *InstancePtr) +{ + u32 MasterNanosec = 0; + u32 MasterSeconds = 0; + u32 SlaveSecs = 0; + + u32 SyncRouteDelay = 0; + u32 MasterNsCorrected = 0; + u32 MasterNsHasWrapped = 0; + + XEmacPs_RtcFormat RtcError; + u32 MCorrection; + u32 ToSubtract = 0; + u32 NSecsRemaining = 0; + +#ifdef DEBUG_XEMACPS_LEVEL2 + xil_printf("*** In XEmacPs_CalcRtcOffset***\r\n"); +#endif + /* + * Capture the Master Origin Timestamp (from received FollowUp Frame). + */ + MasterNanosec = Xil_Ntohl (*((u32 *)&(InstancePtr-> + LastRecdFollowUpFrm[XEMACPS_PRECISE_TS_OFFSET + 6]))); + MasterSeconds = Xil_Ntohl (*((u32 *)&(InstancePtr-> + LastRecdFollowUpFrm[XEMACPS_PRECISE_TS_OFFSET + 2]))); + + /* + * 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. + */ + MCorrection = (u32) (InstancePtr->PtpRecords.MasterCorrectionField); + SyncRouteDelay = MCorrection + 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 >= XEMACPS_ONE_SECOND) { + MasterNsCorrected = MasterNsCorrected - XEMACPS_ONE_SECOND; + MasterNsHasWrapped = 1; + } + + /* Make the Master and Slave comparison and discover the difference! */ + if (MasterNsCorrected > InstancePtr->PtpRecords.SlaveSyncTimestampNSec) + { + RtcError.NanoSeconds = MasterNsCorrected + - InstancePtr->PtpRecords.SlaveSyncTimestampNSec; + ToSubtract = 0; + } else { + RtcError.NanoSeconds = + InstancePtr->PtpRecords.SlaveSyncTimestampNSec + - MasterNsCorrected; + ToSubtract = 0x80000000; + } + + /* + * 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.SlaveSyncTimestampNSec; + InstancePtr->PtpRecords.NewMasterTime = MasterNsCorrected; + + /* + * If the Master nano seconds field wrapped during the Sync frame + * routing delay, then we need to increment the seconds field. + */ + + if (MasterNsHasWrapped == 1) { + MasterSeconds = MasterSeconds + 0x1; + } + + /* + * Calculate the slave RTC error: the master time minus the timestamp + * taken by this slave for Sync Frame reception. + */ + if (MasterSeconds > InstancePtr->PtpRecords.SlaveSyncTimestampSec) { + RtcError.Seconds = MasterSeconds - + InstancePtr->PtpRecords.SlaveSyncTimestampSec; + SlaveSecs = XEmacPs_ReadReg + (InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_1588_SEC_OFFSET); + SlaveSecs += RtcError.Seconds; + + } else { + RtcError.Seconds = + InstancePtr->PtpRecords.SlaveSyncTimestampSec + - MasterSeconds; + SlaveSecs = XEmacPs_ReadReg + (InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_1588_SEC_OFFSET); + SlaveSecs = SlaveSecs - RtcError.Seconds; + } + + XEmacPs_WriteReg (InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_1588_SEC_OFFSET, SlaveSecs); + +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("*** RtcError.NanoSeconds = %d***\r\n", + RtcError.NanoSeconds); + xil_printf("*** RtcError.Seconds = %d***\r\n",RtcError.Seconds); +#endif + /* + * Write the results to the RTC registers + * --------------------------------------------- + */ + if(RtcError.NanoSeconds < 0x40000000UL) { + RtcError.NanoSeconds = RtcError.NanoSeconds | ToSubtract; + XEmacPs_WriteReg ( + InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_1588_ADJ_OFFSET, RtcError.NanoSeconds); + } else { + NSecsRemaining = RtcError.NanoSeconds - 0x40000000UL; + XEmacPs_WriteReg ( + InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_1588_ADJ_OFFSET, 0xA0000000); + + NSecsRemaining = NSecsRemaining | ToSubtract; + XEmacPs_WriteReg ( + InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_1588_ADJ_OFFSET, NSecsRemaining); + } +} + +/****************************************************************************/ +/** +* This function clock rate adjustment. Not implemented as of now. +* +* @param InstancePtr is a pointer to the XEmacPs_Ieee1588 instance. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_UpdateRtcIncrement(XEmacPs_Ieee1588 *InstancePtr) +{ + /* TO DO */ +} diff --git a/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_ieee1588.h b/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_ieee1588.h new file mode 100755 index 00000000..e8d0087a --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_ieee1588.h @@ -0,0 +1,610 @@ +/****************************************************************************** +* +* Copyright (C) 2011 - 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 THE +* XILINX CONSORTIUM 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 xemacps_ieee1588.h +* +* Defines hash defines, common data types and prototypes to be used with the +* PTP standalone example source code residing in this directory. +* +* The PTP standalone example files implement the basic PTPv2 protocol as an +* example application. However the accuracy of clock offset adjustment is +* not guaranted as of now. Also the clock rate adjustment and signalling +* frames are not implemented. Also it may not be implementing all aspects of +* PTPv2 strictly as per specs. Since it is based on AVB driver (which is +* 802.1as based), some aspects of 802.1as which are not there in IEEE1588 +* may be there in the protocol implementation inadvertently. The sync frame +* interval, announce frame interval and PDelayReq frame intervals are +* hard-coded. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -----------------------------------------------
+* 1.00a asa  09/16/11 First release based on AVB driver
+* 1.01a asa  03/03/12 New hashdefines are added and new function prototypes
+* 					  are added.
+*
+* 
+* +******************************************************************************/ + +#ifndef XEMACPS_IEEE1588_H +#define XEMACPS_IEEE1588_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/***************************** Include Files *********************************/ + +/************************** Constant Definitions *****************************/ + +#define DEBUG_XEMACPS_LEVEL1 /* + * Error messages which should be printed on + * console. It does not include error messages + * from interrupt service routines. + */ +#undef DEBUG_LEVEL_TWO /* + * Other debug messages, e.g. function names being + * executed, PTP protocl messages etc. + */ + +/* PTP Packet Message Type Definitions */ +#define XEMACPS_PTP_TYPE_SYNC 0x0 +#define XEMACPS_PTP_TYPE_FOLLOW_UP 0x8 +#define XEMACPS_PTP_TYPE_PDELAYREQ 0x2 +#define XEMACPS_PTP_TYPE_PDELAYRESP 0x3 +#define XEMACPS_PTP_TYPE_PDELAYRESP_FOLLOW_UP 0xA +#define XEMACPS_PTP_TYPE_ANNOUNCE 0xB +#define XEMACPS_PTP_TYPE_SIGNALING 0xC + + +#define XEMACPS_PKT_TYPE_DISABLED 0xffff +#define XEMACPS_PKT_MAX_BUF_LEN 128 + + +/* + * XEMACPS_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 XEMACPS_ANNOUNCE_RECEIPT_TIMEOUT 5 + +/* + * XEMACPS_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 XEMACPS_SYNC_RECEIPT_TIMEOUT 5 + +/* + * XEMACPS_NEIGHBOR_PROP_DELAY_THRESH is the maximum allowed delay + * (in nanosecs) across a full duplex link for which the PTP protocol is + * allowed to function. Although this parameter is defined in the + * IEEE spec, no default is defined. + */ +#define XEMACPS_NEIGHBOR_PROP_DELAY_THRESH 5000 + +/* + * XEMACPS_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 PTPv2 capable. + */ +#define XEMACPS_ALLOWED_LOST_RESPONSES 3 + +#ifdef PEEP +/* + * Currently the PEEP/GEM is drivern by 50 MHz clock. Which means each + * clock cycle corresponds to 20 nano seconds. Hence the increment + * register should contain a value of 20 (0x14). + */ +#define XEMACPS_1588_INC_VAL 0x00000014 +#endif + +/* Standard PTP Frame Field Definitions (from IEEE1588 specification) */ +#define XEMACPS_PTP_ETHERTYPE 0x88F7 +#define XEMACPS_PTP_VERSION_PTP 2 + + +/* Real Time Clock Definitions.*/ +#define XEMACPS_ONE_SECOND 1000000000 /* In ns */ + +/* + * 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 XEMACPS_NUM_SYNC_FU_PAIR_CALC_RTC_INCREMENT 2 + +/* PHY register number and register content mask used for PHY detection.*/ +#define PHY_DETECT_REG 1 +#define PHY_DETECT_MASK 0x1808 + +/* PHY register 0 and Register 16 masks*/ +#define PHY_R0_RESET 0x8000 +#define PHY_R0_LOOPBACK 0x4000 +#define PHY_R0_AUTONEG_EN 0x1000 +#define PHY_R0_AUTONEG_START 0x0200 +#define PHY_R0_10 0x0100 +#define PHY_R0_100 0x2100 +#define PHY_R0_1000 0x0140 +#define PHY_R16_FIFO_DEPTH 0xF078 + +/* Maximum buffer length used to store the PTP pakcets */ +#define XEMACPS_PACKET_LEN 1538 + +/* BD alignment used to allocate the BDs */ +#define XEMACPS_IEEE1588_BD_ALIGNMENT 4 + +/* Number of BDs used in the Tx and Rx paths */ +#define XEMACPS_IEEE1588_NO_OF_RX_DESCS 32 +#define XEMACPS_IEEE1588_NO_OF_TX_DESCS 32 + +/* Various offsets in the PTP Ethernet packet and masks to extract contents */ +#define XEMACPS_MSGTYP_OFFSET 14 +#define XEMACPS_MSGTYP_MASK 0x0F +#define XEMACPS_VERSPTP_OFFSET 15 +#define XEMACPS_MSGLENGTH_OFFSET 16 +#define XEMACPS_FLAGS_OFFSET 20 +#define XEMACPS_CORRFIELD_OFFSET 22 +#define XEMACPS_PORTIDENTITY_OFFSET 34 +#define XEMACPS_SEQID_OFFSET 44 +#define XEMACPS_CONTROL_OFFSET 46 +#define XEMACPS_LOGMSG_INTERVAL_OFFSET 47 +#define XEMACPS_PRECISE_TS_OFFSET 48 +#define XEMACPS_CURRUTCOFFSET_OFFSET 58 +#define XEMACPS_GMPRI_ONE_OFFSET 61 +#define XEMACPS_GM_CLK_QUALITY_OFFSET 62 +#define XEMACPS_GMPRI_TWO_OFFSET 66 +#define XEMACPS_GM_IDENTITY_OFFSET 67 +#define XEMACPS_STEPS_REMOVED_OFFSET 75 +#define XEMACPS_TIMESOURCE_OFFSET 77 +#define XEMACPS_TLVTYPE_OFFSET 78 +#define XEMACPS_LENGTHFIELD_OFFSET 80 +#define XEMACPS_PATHSEQ_OFFSET 82 +#define XEMACPS_REQPORTID_OFFSET 58 + +/* + * The PTP message type, length value, flags value that are + * populated in different PTP frames + */ +#define XEMACPS_SYNCFRM_MSG_TYPE 0x10 +#define XEMACPS_SYNCFRM_LENGTH 0x002C +#define XEMACPS_SYNCFRM_FLAGS_VAL 0x0200 +#define XEMACPS_FOLLOWUPFRM_MSG_TYPE 0x18 +#define XEMACPS_FOLLOWUPFRM_LENGTH 0x004C +#define XEMACPS_PDELAYREQFRM_LENGTH 54 +#define XEMACPS_PDELAYREQFRM_FLAGS_VAL 0x0200 +#define XEMACPS_PDELAYREQFRM_MSG_TYPE 0x02 +#define XEMACPS_PDELAYRESPFRM_MSG_TYPE 0x03 +#define XEMACPS_PDELAYRESPFRM_LENGTH 54 +#define XEMACPS_PDELAYRESPFOLLOWUPFRM_MSG_TYPE 0x0A +#define XEMACPS_PDELAYRESPFOLLOWUP_LENGTH 54 +#define XEMACPS_ANNOUNCEFRM_MSG_TYPE 0x1B +#define XEMACPS_ANNOUNCEFRM_LENGTH 0x0040 +#define XEMACPS_ANNOUNCEFRM_FLAGS_VAL 0x0008 + +/* The total length of various PTP packets */ +#define XEMACPS_ANNOUNCEMSG_TOT_LEN 90 +#define XEMACPS_SYNCMSG_TOT_LEN 58 +#define XEMACPS_FOLLOWUPMSG_TOT_LEN 90 +#define XEMACPS_PDELAYREQMSG_TOT_LEN 68 +#define XEMACPS_PDELAYRESPMSG_TOT_LEN 68 +#define XEMACPS_PDELAYRESPFOLLOWUP_TOT_LEN 68 + +/* + * The bit field information for different PTP packets in the variable + * PTPSendPacket. This variable controls the sending of PTP packets. + */ +#define SEND_PDELAY_RESP 0x00000001 +#define SEND_PDELAY_RESP_FOLLOWUP 0x00000002 +#define SEND_PDELAY_REQ 0x00000004 +#define SEND_SYNC 0x00000008 +#define SEND_FOLLOW_UP 0x00000010 + +#define NS_PER_SEC 1000000000ULL /* Nanoseconds per second */ +#define FP_MULT 1000ULL + +/* Advertisement control register. */ +#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ +#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */ +#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ +#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */ +#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ +#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */ +#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ +#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */ +#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ + + +#define ADVERTISE_100_AND_10 (ADVERTISE_10FULL | ADVERTISE_100FULL | \ + ADVERTISE_10HALF | ADVERTISE_100HALF) +#define ADVERTISE_100 (ADVERTISE_100FULL | ADVERTISE_100HALF) +#define ADVERTISE_10 (ADVERTISE_10FULL | ADVERTISE_10HALF) + +#define ADVERTISE_1000 0x0300 + + +#define IEEE_CONTROL_REG_OFFSET 0 +#define IEEE_STATUS_REG_OFFSET 1 +#define IEEE_AUTONEGO_ADVERTISE_REG 4 +#define IEEE_PARTNER_ABILITIES_1_REG_OFFSET 5 +#define IEEE_PARTNER_ABILITIES_2_REG_OFFSET 8 +#define IEEE_PARTNER_ABILITIES_3_REG_OFFSET 10 +#define IEEE_1000_ADVERTISE_REG_OFFSET 9 +#define IEEE_SPECIFIC_STATUS_REG 17 +#define IEEE_CTRL_1GBPS_LINKSPEED_MASK 0x2040 +#define IEEE_CTRL_LINKSPEED_MASK 0x0040 +#define IEEE_CTRL_LINKSPEED_1000M 0x0040 +#define IEEE_CTRL_LINKSPEED_100M 0x2000 +#define IEEE_CTRL_LINKSPEED_10M 0x0000 +#define IEEE_CTRL_RESET_MASK 0x8000 +#define IEEE_CTRL_AUTONEGOTIATE_ENABLE 0x1000 +#define IEEE_STAT_AUTONEGOTIATE_CAPABLE 0x0008 +#define IEEE_STAT_AUTONEGOTIATE_COMPLETE 0x0020 +#define IEEE_STAT_AUTONEGOTIATE_RESTART 0x0200 +#define IEEE_STAT_1GBPS_EXTENSIONS 0x0100 +#define IEEE_AN1_ABILITY_MASK 0x1FE0 +#define IEEE_AN3_ABILITY_MASK_1GBPS 0x0C00 +#define IEEE_AN1_ABILITY_MASK_100MBPS 0x0380 +#define IEEE_AN1_ABILITY_MASK_10MBPS 0x0060 + +#define PHY_REG0_RESET 0x8000 +#define PHY_REG0_LOOPBACK 0x4000 +#define PHY_REG0_10 0x0100 +#define PHY_REG0_100 0x2100 +#define PHY_REG0_1000 0x0140 +#define PHY_REG21_10 0x0030 +#define PHY_REG21_100 0x2030 +#define PHY_REG21_1000 0x0070 + +/* Frequency setting */ +#define SLCR_LOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x4) +#define SLCR_UNLOCK_ADDR (XPS_SYS_CTRL_BASEADDR + 0x8) +#define SLCR_GEM0_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x140) +#define SLCR_GEM1_CLK_CTRL_ADDR (XPS_SYS_CTRL_BASEADDR + 0x144) +#ifdef PEEP +#define SLCR_GEM_10M_CLK_CTRL_VALUE 0x00103031 +#define SLCR_GEM_100M_CLK_CTRL_VALUE 0x00103001 +#define SLCR_GEM_1G_CLK_CTRL_VALUE 0x00103011 +#endif +#define SLCR_LOCK_KEY_VALUE 0x767B +#define SLCR_UNLOCK_KEY_VALUE 0xDF0D +#define SLCR_ADDR_GEM_RST_CTRL (XPS_SYS_CTRL_BASEADDR + 0x214) +#define EMACPS_SLCR_DIV_MASK 0xFC0FC0FF + +/**************************** Type Definitions *******************************/ +/* + * This typedef defines the format for a data structure which stores the Port + * Identity information specified in IEEE1588. + */ +typedef struct +{ + u8 ClockIdentity[8]; + u16 PortNumber; +} XEmacPs_PortIdentity; + +/* + * This typedef defines the format for a data structure which stores the Clock + * Identity information specified in IEEE1588. + */ +typedef struct +{ + u8 ClockIdentity[8]; +} XEmacPs_ClockIdentity; + +/* + * This typedef defines the quality of a clock + */ +typedef struct +{ + u8 clockClass; + u8 clockAccuracy; + u16 offsetScaledLogVariance; +} XEmacPs_ClockQuality; + +/* + * This typedef defines the format for a data structure which stores the + * relevant fields which are captured from Announce Packets. + */ +typedef struct +{ + XEmacPs_PortIdentity SourcePortIdentity; + XEmacPs_ClockIdentity GrandmasterIdentity; + u16 StepsRemoved; + XEmacPs_ClockQuality ClockQuality; + u8 GrandmasterPriority1; + u8 GrandmasterPriority2; + u8 IAmTheRtcMaster; + u16 TlvLengthField; + char LogMessageInterval; + u16 AnnounceIntervalDuration; +} XEmacPs_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 SlaveSyncTimestampSec; + u32 SlaveSyncTimestampNSec; + 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 PDelayReqRecdTSNs; + u32 PDelayReqRecdTSSec; + u32 PDelayRespTxedTSNs; + u32 PDelayRespTxedTSSec; +} XEmacPs_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; + u16 FollowUpSequenceId; + u16 PDelayReqSequenceId; + u16 PDelayRespSequenceId; + u16 PDelayFollowUpSequenceId; + u16 OldSyncSequenceId; + u16 NewSyncSequenceId; +} XEmacPs_SequenceIdStruct; + + +/* + * The Signalling frame defines the delays to be used between Sync Frames, Link + * Delay measurements and Announce Frame events + */ +typedef struct +{ + u16 SyncIntervalDuration; + u16 LinkDelayIntervalDuration; + u16 AnnounceIntervalDuration; +} XEmacPs_SignallingFrameData; + + +/* + * This typedef defines the various counters which have to maintained for the + * PTP operation. + */ +typedef struct +{ + u16 CounterSyncInterval; + u16 CounterLinkDelayInterval; + u16 CounterAnnounceInterval; + u8 CounterSyncEvents; +} XEmacPs_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 + */ + XEmacPs_PortIdentity RespPortIdentity;/* + * SourcePortIdentity of the last + * PDelayResp packet received + */ + XEmacPs_PortIdentity RespReqPortIdentity;/* + * RequestingPortIdentity of + * the last PDelayResp packet + received */ +} XEmacPs_StateMachineData; + + +/* + * This struct captures information from RX'd Sync/FollowUp message pairs in a + * format similiar to the MDSyncReceive structure described in the IEEE1588 + * specification. + */ +typedef struct +{ + u8 LogMessageInterval; + u16 SyncIntervalDuration; + +} XEmacPs_MDSyncReceive; + +typedef struct +{ + u32 Seconds; + u32 NanoSeconds; +} XEmacPs_RtcFormat; + +/* + * The XEmacPs_Ieee1588 driver instance data. The user is required to allocate + * a variable of this type for every PTP device in the system. A pointer + * to a variable of this type is then passed to the driver API functions. + */ +typedef struct { + /* The Emac Pss instance to be used for accessing the hardware */ + XEmacPs *EmacPsInstance; + + /* The current port protocol state */ + u32 PtpProtocolState; + + u32 PtpNewPktRecd; + + /* 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 PeerIeee1588v2Capable; + + u32 PTPLocked; + + /* Store the info from the latest RX'd Sync/Follow message pair */ + XEmacPs_MDSyncReceive LatestMDSyncReceive; + + /* Contains the local port Identity information */ + XEmacPs_PortIdentity PortIdLocal; + + /* Create a data structure for the Best Master Clock Algorithm (BMCA)*/ + XEmacPs_BmcData CurrentBmc; + + /* Create a data structure for the Precise Timing Protocol (PTP) */ + XEmacPs_PtpStruct PtpRecords; + + /* Create data structure to record the PTP frames Sequence ID values*/ + XEmacPs_SequenceIdStruct SequenceIdRecords; + + /* Create a data structure to store the Signalling frame information*/ + XEmacPs_SignallingFrameData SignallingFrameData; + + /* Create a data structure to store various PTP counters/timers */ + XEmacPs_Counters PtpCounters; + + /* Create a data structure to store state machine flags */ + XEmacPs_StateMachineData StateMachineData; + + /* Buffers to store the last recd PTP packet */ + u8 LastRecdSyncFrm[XEMACPS_PKT_MAX_BUF_LEN]; + u8 LastRecdFollowUpFrm[XEMACPS_PKT_MAX_BUF_LEN]; + u8 LastRecdPDelayReqFrm[XEMACPS_PKT_MAX_BUF_LEN]; + u8 LastRecdPDelayRespFrm[XEMACPS_PKT_MAX_BUF_LEN]; + u8 LastRecdPDelayRespFollowUpFrm[XEMACPS_PKT_MAX_BUF_LEN]; + u8 LastRecdSignallingFrm[XEMACPS_PKT_MAX_BUF_LEN]; + u8 LastRecdAnnounceFrm[XEMACPS_PKT_MAX_BUF_LEN]; + + /* Buffers to store the PTP packet to be Txed */ + u8 SyncFrmToTx[XEMACPS_PKT_MAX_BUF_LEN]; + u8 FollowUpFrmToTx[XEMACPS_PKT_MAX_BUF_LEN]; + u8 PDelayReqFrmToTx[XEMACPS_PKT_MAX_BUF_LEN]; + u8 PDelayRespFrmToTx[XEMACPS_PKT_MAX_BUF_LEN]; + u8 PDelayRespFollowUpFrmToTx[XEMACPS_PKT_MAX_BUF_LEN]; + u8 SignallingFrmToTx[XEMACPS_PKT_MAX_BUF_LEN]; + u8 AnnounceFrmToTx[XEMACPS_PKT_MAX_BUF_LEN]; + +} XEmacPs_Ieee1588; + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/************************** Function Prototypes ******************************/ + +void XEmacPs_PtpTimerInterruptHandler(XEmacPs_Ieee1588 *InstancePtr); +void XEmacPs_PtpRxInterruptHandler(XEmacPs_Ieee1588 *InstancePtr); +int XEmacPs_PtpTxPacket(XEmacPs_Ieee1588 *InstancePtr, u8 *PacketBuf, + int PacketLen); +u32 XEmacPs_ComparePortIdentity( + XEmacPs_PortIdentity Identity1, + XEmacPs_PortIdentity Identity2); +u32 XEmacPs_CompareClockIdentity( + XEmacPs_ClockIdentity Identity1, + XEmacPs_ClockIdentity Identity2); + +void XEmacPs_MasterSendAnnounce(XEmacPs_Ieee1588 *InstancePtr); +void XEmacPs_MasterSendSync(XEmacPs_Ieee1588 *InstancePtr); +void XEmacPs_MasterSendFollowUp(XEmacPs_Ieee1588 *InstancePtr); +void XEmacPs_SendPDelayReq(XEmacPs_Ieee1588 *InstancePtr); +void XEmacPs_SendPDelayResp(XEmacPs_Ieee1588 *InstancePtr); +void XEmacPs_SendPDelayRespFollowUp(XEmacPs_Ieee1588 *InstancePtr); +u32 XEmacPs_IsRxFramePTP(u8 *PacketBuf); +void XEmacPs_DecodeRxSync(XEmacPs_Ieee1588 *InstancePtr,u8 *PacketBuf); +void XEmacPs_DecodeRxFollowUp(XEmacPs_Ieee1588 *InstancePtr, u8 *PacketBuf); +void XEmacPs_DecodeRxPDelayResp(XEmacPs_Ieee1588 *InstancePtr, u8 *PacketBuf); +void XEmacPs_DecodeRxPDelayRespFollowUp(XEmacPs_Ieee1588 *InstancePtr, + u8 *PacketBuf); +void XEmacPs_DecodeRxSignaling(XEmacPs_Ieee1588 *InstancePtr, u8 *PacketBuf); +u16 XEmacPs_UpdateIntervalDuration(u16 currentIntervalDuration, + signed char logMeanVal); + +u16 XEmacPs_ConvertLogMeanToDuration(signed char logMeanVal); + +signed char XEmacPs_ConvertDurationToLogMean(u16 fractionalVal); +void XEmacPs_UpdateLogMeanMessageInterval(XEmacPs_Ieee1588 *InstancePtr); +void XEmacPs_SetupSourcePortIdentity(XEmacPs_Ieee1588 *InstancePtr, + XEmacPs_PortIdentity systemIdentity); + +void XEmacPs_DecodeTxAnnounceFrame(XEmacPs_Ieee1588 *InstancePtr, + u8 *PacketBuf); +void XEmacPs_DecodeRxAnnounceFrame(XEmacPs_Ieee1588 *InstancePtr, + u8 *PacketBuf); +void XEmacPs_ReadAnnounceFrame(u8 *PacketBuf, XEmacPs_BmcData *AnnounceFrame); +void XEmacPs_UpdateBmcRecords(XEmacPs_BmcData *NewMaster, + XEmacPs_BmcData *CurrentBmc); +u32 XEmacPs_BestMasterClockAlgorithm(XEmacPs_BmcData *AnnounceFrame, + XEmacPs_BmcData *CurrentBmc); +void XEmacPs_BecomeRtcMaster(XEmacPs_Ieee1588 *InstancePtr, + u8 txAnnounceHasWon); +void XEmacPs_BecomeRtcSlave(XEmacPs_Ieee1588 *InstancePtr); +void XEmacPs_ChangePTPLockStatus(XEmacPs_Ieee1588 *InstancePtr, u8 locked); +void XEmacPs_ChangePeerIeee1588v2Capability(XEmacPs_Ieee1588 *InstancePtr, + u8 capable); +void XEmacPs_CalcDelay(XEmacPs_Ieee1588 *InstancePtr); +void XEmacPs_CalcRtcOffset(XEmacPs_Ieee1588 *InstancePtr); +void XEmacPs_UpdateRtcIncrement(XEmacPs_Ieee1588 *InstancePtr); +u32 XEmacPs_htonll (unsigned long long int n); +u32 XEmacPs_ntohll (long long int n); +u8 XEmacPs_GetMsgType (u8 *PacketBuf); +void XEmacPs_GetPortIdentity(u8 *PacketBuf, XEmacPs_PortIdentity *portID); +u16 XEmacPs_GetSequenceId(u8 *PacketBuf); +u16 XEmacPs_IncSequenceId(u8 *PacketBuf); +void XEmacPs_SetMdioDivisor(XEmacPs *InstancePtr, XEmacPs_MdcDiv Divisor); +unsigned int XEmacPs_TsuCalcClk(u32 Freq); +extern volatile u8 PDelayRespSent; +extern volatile u32 PTPSendPacket; +extern volatile u8 SyncSent; + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_ieee1588_example.c b/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_ieee1588_example.c new file mode 100755 index 00000000..fca37932 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/examples/xemacps_ieee1588_example.c @@ -0,0 +1,2384 @@ +/****************************************************************************** +* +* Copyright (C) 2011 - 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 THE +* XILINX CONSORTIUM 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 xemacps_ieee1588_example.c +* +* This is top level c file for the IEEE1588 (PTP) standalone example. It has the +* following functionalities. It uses SCUTimer to transmit PTP packets at +* regular intervals. +* - Contains the main routine for the PTP protocol example. +* - Initializes the SCUGIC, SCUTimer +* - Initializes the EmacPs hardware for packet transfer. +* - Initializes the buffer descriptors for the PTP packet transfer. +* - Initializes and handles the buffers that receive the PTP packets and whose +* address goes in the buffer descriptors. +* - Contains the interrupt handlers for Ethernet Tx and Ethernet Rx. +* - Contains the Timer interrupt handlers. +* - Implements the top level state machine for the PTP protocol. +* - Contains routines that initiate the PTP Tx. +* - Initializes the some fields in the PTP Tx packets. These fields are +* fixed and its entries do not change with time. +* - Contains various helper routines, e.g. routines for endian conversion. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -----------------------------------------------
+* 1.00a asa  09/16/11 First release based on the AVB driver.
+* 1.01a asa  03/03/12 Support for Zynq is added. BD handling is changed.
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_io.h" +#include "xil_assert.h" +#include "xparameters.h" +#include "stdio.h" +#include "sleep.h" +#include "xparameters.h" +#include "xparameters_ps.h" /* defines XPAR values */ +#include "xil_types.h" +#include "xil_assert.h" +#include "xil_io.h" +#include "xil_exception.h" +#include "xpseudo_asm.h" +#include "xil_cache.h" +#include "xil_printf.h" +#include "xscugic.h" +#include "xscutimer.h" +#include "xemacps.h" /* defines XEmacPs API */ +#include "xemacps_ieee1588.h" +#include "xil_mmu.h" +/************************** Constant Definitions *****************************/ + +/* + * The following constants map to the XPAR parameters created in the + * xparameters_ps.h file. They are defined here such that a user can easily + * change all the needed parameters in one place. + */ +#define EMACPS_DEVICE_ID XPAR_XEMACPS_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#define TIMER_DEVICE_ID XPAR_SCUTIMER_DEVICE_ID +#define EMACPS_IRPT_INTR XPS_GEM0_INT_ID +#define TIMER_IRPT_INTR XPAR_SCUTIMER_INTR + +#ifndef PEEP +#define RX_BD_START_ADDRESS 0x0FF00000 +#define TX_BD_START_ADDRESS 0x0FF10000 +#endif + +#ifdef PEEP +/* Timer load value for timer expiry in every 500 mseconds. */ +#define TIMER_LOAD_VALUE 0x2625A0 +#else +/* Timer load value for timer expiry in every 500 milli seconds. */ +#define TIMER_LOAD_VALUE XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ / 4 +#endif +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +#define RXBD_SPACE_BYTES \ +XEmacPs_BdRingMemCalc(XEMACPS_BD_ALIGNMENT, XEMACPS_IEEE1588_NO_OF_RX_DESCS) + +#define TXBD_SPACE_BYTES \ +XEmacPs_BdRingMemCalc(XEMACPS_BD_ALIGNMENT, XEMACPS_IEEE1588_NO_OF_TX_DESCS) + +/************************** Variable Definitions *****************************/ + +XEmacPs_Ieee1588 *GlobalInstancePntr; + +XEmacPs Mac; +XEmacPs_Ieee1588 IEEE1588ProtoHandler; +static XScuGic IntcInstance; /* The instance of the SCUGic Driver */ +static XScuTimer TimerInstance; /* The instance of the SCUTimer Driver */ + +/* Detected link speed goes here. */ +int Link_Speed = 100; +/* Detected PHY address goes here. */ +int PhyAddress; +#ifdef IEEE1588_MASTER +/* Set MAC address */ +u8 UnicastMAC[] = {0x00, 0x0A, 0x35, 0x01, 0x02, 0x03}; +#else +u8 UnicastMAC[] = {0x00, 0x0A, 0x35, 0x01, 0x02, 0x09}; +#endif +/* + * Aligned memory segments to be used for Rx buffer descriptors + */ +u8 RxBuf[XEMACPS_IEEE1588_NO_OF_RX_DESCS][XEMACPS_PACKET_LEN + 2] + __attribute__ ((aligned(XEMACPS_RX_BUF_ALIGNMENT))); + +#ifdef PEEP +u8 TxRingPntrBase[TXBD_SPACE_BYTES] + __attribute__ ((aligned(XEMACPS_BD_ALIGNMENT))); +u8 RxRingPntrBase[RXBD_SPACE_BYTES] + __attribute__ ((aligned(XEMACPS_BD_ALIGNMENT))); +#endif +#ifdef IEEE1588_MASTER +u8 SrcAddr[6] = {0x00,0x0A,0x35,0x01,0x02,0x03}; +u8 DestnAddr[6] = {0x01,0x80,0xC2,0x00,0x00,0x0E}; +#else +u8 SrcAddr[6] = {0x00,0x0A,0x35,0x01,0x02,0x09}; +u8 DestnAddr[6] = {0x01,0x80,0xC2,0x00,0x00,0x0E}; +#endif +volatile u8 PDelayRespSent; +volatile u8 SyncSent; +volatile u32 PTPSendPacket = 0; + +/************************** Function Prototypes ******************************/ + +int XEmacPs_InitScuTimer(void); +void XEmacPs_PHYSetup (XEmacPs *EmacPsInstancePtr); +int XEmacPs_SetupIntrSystem(XScuGic *IntcInstancePtr, + XEmacPs *EmacPsInstancePtr, XScuTimer *TimerInstancePtr, + u16 EmacPsIntrId, u16 TimerIntrId); +void XEmacPs_RunIEEE1588Protocol(XEmacPs *EmacInstance); +void XEmacPs_InitializeEmacPsDma (XEmacPs_Ieee1588 *InstancePntr); +void XEmacPs_InitializeProtocolData(XEmacPs_Ieee1588 *InstancePntr); +void XEmacPs_HandleRecdPTPPacket(XEmacPs_Ieee1588 *InstancePtr); +void XEmacPs_PtpTxInterruptHandler (XEmacPs_Ieee1588 *InstancePtr); +void XEmacPs_SetDfltTxFrms(XEmacPs_Ieee1588 *InstancePtr); +u8 XEmacPs_GetMsgType (u8 *PacketBuf); +void XEmacPs_PtpTxDoFurtherProcessing (XEmacPs_Ieee1588 *InstancePtr, + u8 *PacketBuf); +void XEmacPs_TimerInterruptHandler(XEmacPs_Ieee1588 *InstancePtr); +void XEmacPs_PtpErrorInterruptHandler (XEmacPs_Ieee1588 *InstancePtr, + u8 Direction, u32 ErrorWord); + +/*****************************************************************************/ + +/*****************************************************************************/ +/** +* +* This is the main function for the IEEE1588 (PTP) standalone example. It calls +* routines to initialize ScuTimer and EmacPs. It enables interrupts +* at the end of all initializations and calls XEmacPs_RunIEEE1588Protocol that +* runs the protocol state machine. +* +* @param None. +* +* @return - XST_SUCCESS to indicate success. +* - XST_FAILURE to indicate failure +* +* @note None. +* +****************************************************************************/ +int main(void) +{ + XEmacPs_Config *Cfg; + int Status = XST_SUCCESS; + XEmacPs *EmacPsInstancePtr = &Mac; + unsigned int NSIncrementVal; + +#ifdef PEEP + /* + * Caches are disabled for this example as of now. + */ + Xil_ICacheDisable(); + Xil_DCacheDisable(); +#endif + xil_printf("Entering into main() \r\n"); + +#ifndef PEEP + Xil_DisableMMU(); + Xil_SetTlbAttributes(0x0FF00000, 0xc02); // addr, attr + Xil_EnableMMU(); +#endif + /* Initialize SCUTIMER */ + + if (XEmacPs_InitScuTimer() != XST_SUCCESS) while(1); + + /* + * Get the configuration of EmacPs hardware. + */ + Cfg = XEmacPs_LookupConfig(EMACPS_DEVICE_ID); + + /* + * Initialize EmacPs hardware. + */ + Status = XEmacPs_CfgInitialize(EmacPsInstancePtr, Cfg, + Cfg->BaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Set the MAC address + */ + Status = XEmacPs_SetMacAddress(EmacPsInstancePtr, + (unsigned char*)UnicastMAC, 1); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } +#ifndef PEEP + XEmacPs_SetMdioDivisor(EmacPsInstancePtr, MDC_DIV_224); +#endif + /* + * Detect and initialize the PHY + */ + XEmacPs_PHYSetup (EmacPsInstancePtr); + sleep(1); + + /* + * Set the operating speed in EmacPs hardware. + */ + XEmacPs_SetOperatingSpeed(EmacPsInstancePtr, Link_Speed); + sleep(1); + + /* + * Enable the promiscuous mode in EmacPs hardware. + */ + Status = XEmacPs_SetOptions(EmacPsInstancePtr, XEMACPS_PROMISC_OPTION); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + +#ifdef PEEP + /* + * Set the 1588 Timer register for 50 MHz timer, i.e. 20 ns increment + * for every clock cycle. + */ + XEmacPs_WriteReg(EmacPsInstancePtr->Config.BaseAddress, + XEMACPS_1588_INC_OFFSET, + XEMACPS_1588_INC_VAL); +#else + + NSIncrementVal = XEmacPs_TsuCalcClk + (XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ / 6); + XEmacPs_WriteReg(EmacPsInstancePtr->Config.BaseAddress, + XEMACPS_1588_INC_OFFSET, + NSIncrementVal); +#endif + + /* + * Register Ethernet Rx, Tx and Error handlers with the EmacPs driver. + */ + Status = XEmacPs_SetHandler (EmacPsInstancePtr, + XEMACPS_HANDLER_DMARECV, + XEmacPs_PtpRxInterruptHandler, + &IEEE1588ProtoHandler); + Status |= XEmacPs_SetHandler (EmacPsInstancePtr, + XEMACPS_HANDLER_DMASEND, + XEmacPs_PtpTxInterruptHandler, + &IEEE1588ProtoHandler); + Status |= XEmacPs_SetHandler (EmacPsInstancePtr, + XEMACPS_HANDLER_ERROR, + XEmacPs_PtpErrorInterruptHandler, + &IEEE1588ProtoHandler); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Connect to the interrupt controller and enable interrupts in + * interrupt controller. + */ + Status = XEmacPs_SetupIntrSystem(&IntcInstance, EmacPsInstancePtr, + &TimerInstance, EMACPS_IRPT_INTR, + TIMER_IRPT_INTR); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable the timer interrupt in the timer module + */ + XScuTimer_EnableInterrupt(&TimerInstance); + + /* + * Start the PTP standalone state machine. + */ + XEmacPs_RunIEEE1588Protocol(EmacPsInstancePtr); + + return 0; +} + +/*****************************************************************************/ +/** +* +* This function initializes the SCUTimer. +* +* @param None. +* +* @return - XST_SUCCESS to indicate success. +* - XST_FAILURE to indicate failure +* +* @note None. +* +******************************************************************************/ +int XEmacPs_InitScuTimer(void) +{ + int Status = XST_SUCCESS; + XScuTimer_Config *ConfigPtr; + + /* + * Get the configuration of Timer hardware. + */ + ConfigPtr = XScuTimer_LookupConfig(TIMER_DEVICE_ID); + + /* + * Initialize ScuTimer hardware. + */ + Status = XScuTimer_CfgInitialize(&TimerInstance, ConfigPtr, + ConfigPtr->BaseAddr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + XScuTimer_EnableAutoReload(&TimerInstance); + + /* + * Initialize ScuTimer with a count so that the interrupt + * comes every 500 msec. + */ + XScuTimer_LoadTimer(&TimerInstance, TIMER_LOAD_VALUE); + return XST_SUCCESS; +} + +#ifndef PEEP +/*****************************************************************************/ +/** +* +* Calculate clock configuration register values for indicated input clock +* +* @param - Freq +* +* @return - XST_SUCCESS to indicate success. +* - XST_FAILURE to indicate failure +* +* @note None. +* +******************************************************************************/ +unsigned int XEmacPs_TsuCalcClk(u32 Freq) +{ + u64 Period_ns = (NS_PER_SEC * FP_MULT)/Freq; + unsigned Retval; + + Period_ns = (NS_PER_SEC * FP_MULT)/Freq; + Retval = Period_ns / FP_MULT; + return Retval; +} +#endif +/*****************************************************************************/ +/** +* +* This function sets up interrupts. It registers interrupt handlers and then +* enables them.. +* +* @param IntcInstancePtr is a pointer to the instance of the SCUGic.. +* @param EmacPsInstancePtr is a pointer to the instance of the EmacPs. +* @param TimerInstancePtr is a pointer to the instance of the SCUTimer. +* @param EmacPsIntrId is the Interrupt ID for EmacPs and the value +* used is taken from xparameters_ps.h. +* @param TimerIntrId is the Interrupt ID for SCUTimer and the value +* used is taken from xparameters_ps.h. +* +* @return - XST_SUCCESS to indicate success. +* - XST_FAILURE to indicate failure +* +* @note None. +* +******************************************************************************/ +int XEmacPs_SetupIntrSystem(XScuGic *IntcInstancePtr, + XEmacPs *EmacPsInstancePtr, XScuTimer *TimerInstancePtr, + u16 EmacPsIntrId, u16 TimerIntrId) +{ + int Status = XST_SUCCESS; + XScuGic_Config *GicConfig; + + Xil_ExceptionInit(); + + /* + * Initialize the interrupt controller driver so that it is ready to + * use. + */ + GicConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); + if (NULL == GicConfig) { + return XST_FAILURE; + } + + Status = XScuGic_CfgInitialize(&IntcInstance, GicConfig, + GicConfig->CpuBaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + /* + * Connect the interrupt controller interrupt handler to the hardware + * interrupt handling logic in the processor. + */ + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_IRQ_INT, + (Xil_ExceptionHandler)XScuGic_InterruptHandler, + IntcInstancePtr); + + /* + * Connect the EmacPs device driver handler that will be called when an + * interrupt for the device occurs. The device driver handler performs + * the specific interrupt processing for the device. + */ + Status = XScuGic_Connect(IntcInstancePtr, EmacPsIntrId, + (Xil_InterruptHandler) XEmacPs_IntrHandler, + (void *) EmacPsInstancePtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Connect the handler for timer interrupt that will be called when the + * timer.expires. + */ + Status = XScuGic_Connect(IntcInstancePtr, TimerIntrId, + (Xil_ExceptionHandler)XEmacPs_TimerInterruptHandler, + (void *)&IEEE1588ProtoHandler); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Enable interrupts from the hardware + */ + XScuGic_Enable(IntcInstancePtr, EmacPsIntrId); + XScuGic_Enable(IntcInstancePtr, TimerIntrId); + + /* + * Enable interrupts in the processor + */ + Xil_ExceptionEnableMask(XIL_EXCEPTION_IRQ); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function finds out if a PHY is connected or not and if connected what +* is the PHY address of the connected PHY. +* +* @param EmacPsInstancePtr is a pointer to the instance of the EmacPs. +* +* @return - Detected PHY address if successful. +* - 0 if no PHY is connected. +* +* @note None. +* +******************************************************************************/ +unsigned long XEmacPs_DetectPHY(XEmacPs *EmacPsInstancePtr) +{ + u16 PhyReg; + int PhyAddr; + + for (PhyAddr = 31; PhyAddr >= 0; PhyAddr--) { + XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddr, PHY_DETECT_REG, + &PhyReg); + + if ((PhyReg != 0xFFFF) && ((PhyReg & PHY_DETECT_MASK) == + PHY_DETECT_MASK)) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("In %s: Detected PHY address is %d \r\n", + __func__, PhyAddr); +#endif + return (u32) PhyAddr; + } + } + return 0; /* default to zero */ +} + +/*****************************************************************************/ +/** +* +* This function configures the PHY with proper speed settings and set up the +* PHY to be used subsequently. +* +* @param EmacPsInstancePtr is a pointer to the instance of the EmacPs. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XEmacPs_PHYSetup (XEmacPs *EmacPsInstancePtr) +{ +#ifdef PEEP + int Status; + int Index=0; + u16 PhyReg0; + u16 PhyReg20; + + /* + * Detect the connected PHY and get the PHY address. + */ + PhyAddress = XEmacPs_DetectPHY(EmacPsInstancePtr); + Status = XEmacPs_PhyRead(&Mac, PhyAddress, 20, &PhyReg20); + PhyReg20 |= 0x0080; + Status |= XEmacPs_PhyWrite(&Mac, PhyAddress, 20, PhyReg20); + + /* + * Set the PHY speed as 100 Mbps and reset the PHY. + */ + Status |= XEmacPs_PhyRead(&Mac, PhyAddress, 0, &PhyReg0); + PhyReg0 = PHY_R0_100; + Status |= XEmacPs_PhyWrite(&Mac, PhyAddress, 0, PhyReg0); + Status |= XEmacPs_PhyWrite(&Mac, PhyAddress, 0, (PhyReg0 | + PHY_R0_RESET)); + + if (Status != XST_SUCCESS) { + return; + } + + /* + * Delay for the PHY reset to get over. + */ + while (Index < 0x10000) Index++; +#else +#ifdef PHY_AUTONEGOTIATION + u16 Temp; + u16 Partner_capabilities; +#else + u16 PhyReg0 = 0; +#endif + u16 Control = 0; + u16 Status; + u32 SlcrTxClkCntrl; + +#ifdef PHY_AUTONEGOTIATION +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("In %s: Start PHY autonegotiation \r\n",__func__); +#endif + /* + * Detect the connected PHY and get the PHY address. + */ + PhyAddress = XEmacPs_DetectPHY(EmacPsInstancePtr); + XEmacPs_PhyWrite(EmacPsInstancePtr,PhyAddress, 22, 2); + XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 21, &Control); + Control |= 0x30; + XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 21, Control); + + XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 22, 0); + + XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, + IEEE_AUTONEGO_ADVERTISE_REG, &Control); + Control |= 0xd80; + Control |= 0x60; + XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, + IEEE_AUTONEGO_ADVERTISE_REG, Control); + + XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, + IEEE_1000_ADVERTISE_REG_OFFSET, &Control); + Control |= ADVERTISE_1000; + XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, + IEEE_1000_ADVERTISE_REG_OFFSET, Control); + + XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 22, 0); + XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 16, &Control); + Control |= (7 << 12); /* max number of gigabit attempts */ + Control |= (1 << 11); /* enable downshift */ + XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 16, Control); + + XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, + IEEE_CONTROL_REG_OFFSET, &Control); + Control |= IEEE_CTRL_AUTONEGOTIATE_ENABLE; + Control |= IEEE_STAT_AUTONEGOTIATE_RESTART; + XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, + IEEE_CONTROL_REG_OFFSET, Control); + + XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, + IEEE_CONTROL_REG_OFFSET, &Control); + Control |= IEEE_CTRL_RESET_MASK; + XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, + IEEE_CONTROL_REG_OFFSET, Control); + + while (1) { + XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, + IEEE_CONTROL_REG_OFFSET, &Control); + if (Control & IEEE_CTRL_RESET_MASK) + continue; + else + break; + + } + +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("In %s: Waiting for PHY to complete autonegotiation.\r\n", + __func__); +#endif + XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, + IEEE_STATUS_REG_OFFSET, &Status); + while ( !(Status & IEEE_STAT_AUTONEGOTIATE_COMPLETE) ) { + sleep(1); + XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 19, &Temp); + if (Temp & 0x8000) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("In %s: Auto negotiation error \r\n", + __func__); +#endif + } + XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, + IEEE_STATUS_REG_OFFSET, + &Status); + } +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("In %s: Autonegotiation complete \r\n", __func__); +#endif + + XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, + IEEE_SPECIFIC_STATUS_REG, + &Partner_capabilities); + if ( ((Partner_capabilities >> 14) & 3) == 2)/* 1000Mbps */ { + Link_Speed = 1000; + xil_printf("Partner_capabilities are %x\r\n", + Partner_capabilities); + /* GEM1 1G clock configuration*/ + *(volatile unsigned int *)(SLCR_UNLOCK_ADDR) = + SLCR_UNLOCK_KEY_VALUE; + SlcrTxClkCntrl = + *(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR); + SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK; + SlcrTxClkCntrl |= + (XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV1 << 20); + SlcrTxClkCntrl + |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_1000MBPS_DIV0 << 8); + *(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR) = + SlcrTxClkCntrl; + *(volatile unsigned int *)(SLCR_LOCK_ADDR) = + SLCR_LOCK_KEY_VALUE; + sleep(1); + } + else if ( ((Partner_capabilities >> 14) & 3) == 1)/* 100Mbps */ { + Link_Speed = 100; + *(volatile unsigned int *)(SLCR_UNLOCK_ADDR) = + SLCR_UNLOCK_KEY_VALUE; + SlcrTxClkCntrl = + *(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR); + SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK; + SlcrTxClkCntrl + |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1 << 20); + SlcrTxClkCntrl + |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0 << 8); + *(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR) = + SlcrTxClkCntrl; + *(volatile unsigned int *)(SLCR_LOCK_ADDR) = + SLCR_LOCK_KEY_VALUE; + sleep(1); + } + else /* 10Mbps */ { + Link_Speed = 10; + *(volatile unsigned int *)(SLCR_UNLOCK_ADDR) = + SLCR_UNLOCK_KEY_VALUE; + SlcrTxClkCntrl = + *(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR); + SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK; + SlcrTxClkCntrl |= + (XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV1 << 20); + SlcrTxClkCntrl |= + (XPAR_PS7_ETHERNET_0_ENET_SLCR_10MBPS_DIV0 << 8); + *(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR) = + SlcrTxClkCntrl; + *(volatile unsigned int *)(SLCR_LOCK_ADDR) = + SLCR_LOCK_KEY_VALUE; + sleep(1); + } + xil_printf("In %s: Autonegotiated link speed is %d\r\n", + __func__, Link_Speed); + return; +#else + /* + * Detect the connected PHY and get the PHY address. + */ + PhyAddress = XEmacPs_DetectPHY(EmacPsInstancePtr); + Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 0, &PhyReg0); + PhyReg0 &= (~IEEE_CTRL_AUTONEGOTIATE_ENABLE); + Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 0, PhyReg0); + + Status |= XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 0, &PhyReg0); + Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 0, + (PhyReg0 |PHY_R0_RESET)); + sleep(1); + XEmacPs_PhyWrite(EmacPsInstancePtr,PhyAddress, 22, 2); + Control |= PHY_REG21_100; + XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 21, Control); + XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 22, 0); + + /* + * Set the PHY speed and reset the PHY. + */ + Status = XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 0, &PhyReg0); + PhyReg0 = PHY_REG0_100; + Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 0, PhyReg0); + + Status |= XEmacPs_PhyRead(EmacPsInstancePtr, PhyAddress, 0, &PhyReg0); + Status |= XEmacPs_PhyWrite(EmacPsInstancePtr, PhyAddress, 0, + (PhyReg0 |PHY_R0_RESET)); + sleep(1); + *(volatile unsigned int *)(SLCR_UNLOCK_ADDR) = SLCR_UNLOCK_KEY_VALUE; + SlcrTxClkCntrl = *(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR); + SlcrTxClkCntrl &= EMACPS_SLCR_DIV_MASK; + SlcrTxClkCntrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV1 << 20); + SlcrTxClkCntrl |= (XPAR_PS7_ETHERNET_0_ENET_SLCR_100MBPS_DIV0 << 8); + *(volatile unsigned int *)(SLCR_GEM0_CLK_CTRL_ADDR) = SlcrTxClkCntrl; + *(volatile unsigned int *)(SLCR_LOCK_ADDR) = SLCR_LOCK_KEY_VALUE; + sleep(1); +#endif +#endif +} + +/*****************************************************************************/ +/** +* +* This function implements the main state machine. After initializing the +* EmacPs DMA and initializing some protocol data structures it enters into a +* while(1) loop. Here it repeatedly checks if a new packet has been received +* or not. If received (the ISR marks the variable PtpNewPktRecd as true), then +* it calls XEmacPs_HandleRecdPTPPacket for further processing. +* Similarly if a packet needs to be sent out (as marked by the bits in +* variable PTPSendPacket, it sends it out. +* +* @param EmacPsInstancePtr is a pointer to the instance of the EmacPs. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XEmacPs_RunIEEE1588Protocol(XEmacPs *EmacInstance) +{ + XEmacPs_Stop(EmacInstance); + GlobalInstancePntr = &IEEE1588ProtoHandler; + GlobalInstancePntr->EmacPsInstance = EmacInstance; + + /* + * Initialize the DMA and buffer descriptors + */ + XEmacPs_InitializeEmacPsDma (GlobalInstancePntr); + + /* + * Initialize some of the protocol structure instances and Tx frames + * with default data. + */ + XEmacPs_InitializeProtocolData(GlobalInstancePntr); + + + while(1) { + /* + * If a new packet has been received, copy the packet into + * corresponding buffer and call XEmacPs_HandleRecdPTPPacket to + * do further processing. + */ + if (GlobalInstancePntr->PtpNewPktRecd == TRUE) { + GlobalInstancePntr->PtpNewPktRecd = FALSE; + XEmacPs_HandleRecdPTPPacket(GlobalInstancePntr); + } + + /* + * If a packet needs to be sent + */ + if (PTPSendPacket != 0) { + /* + * If a PDelayResp needs to be sent, initiate a Tx. + * Set the corresponding bit in the variable + * PTPSendPacket to send a PDelayRespFollowUp packet + * once the PDelayResp is successfully sent out + * (Tx Done interrupt generated for PDelayResp.) + */ + + if (PTPSendPacket & SEND_PDELAY_RESP) { + XEmacPs_PtpTxPacket(GlobalInstancePntr, + GlobalInstancePntr->PDelayRespFrmToTx, + XEMACPS_PDELAYRESPMSG_TOT_LEN); + PTPSendPacket = PTPSendPacket & + (~SEND_PDELAY_RESP); + PTPSendPacket |= SEND_PDELAY_RESP_FOLLOWUP; + } + + /* + * If a PDelayRespFollowUp needs to be sent check if + * the previous PDelayResp is successfully sent out or + * not. If the PDelayResp is sent out successfully, + * the flag PDelayRespSent is marked as True in the + * Tx Done ISR. + */ + if (PTPSendPacket & SEND_PDELAY_RESP_FOLLOWUP) { + if (PDelayRespSent == TRUE) { + XEmacPs_SendPDelayRespFollowUp + (GlobalInstancePntr); + PTPSendPacket = PTPSendPacket & + (~SEND_PDELAY_RESP_FOLLOWUP); + } + } + + /* + * If a PDelayReq needs to be sent initiate a Tx here. + */ + if (PTPSendPacket & SEND_PDELAY_REQ) { + XEmacPs_PtpTxPacket(GlobalInstancePntr, + GlobalInstancePntr->PDelayReqFrmToTx, + XEMACPS_PDELAYREQMSG_TOT_LEN); + PTPSendPacket = PTPSendPacket & + (~SEND_PDELAY_REQ); + } + + /* + * If a SYNC packet needs to be sent initiate a Tx + * here. Set the bit corresponding to FOLLOWUP packet + * in the variable PTPSendPacket. This will initiate a + * Tx for FollowUp frame once the SYNC frame is + * successfully sent out and a Tx done interrupt is + * received. + */ + if (PTPSendPacket & SEND_SYNC) { + XEmacPs_PtpTxPacket (GlobalInstancePntr, + GlobalInstancePntr->SyncFrmToTx, + XEMACPS_SYNCMSG_TOT_LEN); + PTPSendPacket = PTPSendPacket & (~SEND_SYNC); + PTPSendPacket |= SEND_FOLLOW_UP; + } + + /* + * If a FollowUp needs to be sent check if + * the previous SYNC is successfully sent out or + * not. If the SYNC is sent out successfully, + * the flag SyncSent is marked as True in the + * Tx Done ISR. + */ + if (PTPSendPacket & SEND_FOLLOW_UP) { + if (SyncSent == TRUE) { + XEmacPs_MasterSendFollowUp + (GlobalInstancePntr); + PTPSendPacket = PTPSendPacket & + (~SEND_FOLLOW_UP); + } + } + } + } +} + +/*****************************************************************************/ +/** +* +* This function initializes the EmacPs DMA buffer descriptors. 16 BDs are used +* on the Tx path and 16 on the Rx path. On the Rx path a 2-dimensional array +* RxBuf[16][1540] is used. The last byte in each of the buffers is used to mark +* whether the RxBuf is already submitted or not. For example, if the location +* RxBuf[1][1539] is 1, then it means the RxBuf[1] is already submitted. During +* initialization, for 16 BDs, 16 RxBufs are submitted (RxBuf[0, RxBuf[1], ... +* RxBuf[15]]) and the corresponding entries RxBuf[0][1539], RxBuf[1][1539], ... +* RxBuf[15][1539] are marked as 1. +* On the Rx path, all 16 BDs are submitted to the hardware. +* Once that is done, the timer is started and so is the EmacPs. +* +* @param EmacPsInstancePtr is a pointer to the instance of the EmacPs. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XEmacPs_InitializeEmacPsDma (XEmacPs_Ieee1588 *InstancePntr) +{ + XEmacPs_BdRing *TxRingPtr; + XEmacPs_BdRing *RxRingPtr; + XEmacPs_Bd *RxBdPtr; + XEmacPs_Bd *CurrBdPtr; + int Status; + int Index; + XEmacPs_Bd BdTemplate; + + Status = XST_SUCCESS; + + TxRingPtr = &XEmacPs_GetTxRing(InstancePntr->EmacPsInstance); + RxRingPtr = &XEmacPs_GetRxRing(InstancePntr->EmacPsInstance); + + /* + * BdTemplate is used for cloning. Hence it is cleared so that + * all 16 BDs can be cleared. + */ + XEmacPs_BdClear(&BdTemplate); +#ifdef PEEP + /* + * Create 16 BDs for Rx path. + */ + Status = XEmacPs_BdRingCreate (RxRingPtr, + (u32)&RxRingPntrBase, + (u32)&RxRingPntrBase, + XEMACPS_IEEE1588_BD_ALIGNMENT, + XEMACPS_IEEE1588_NO_OF_RX_DESCS); +#else + Status = XEmacPs_BdRingCreate (RxRingPtr, + (u32)RX_BD_START_ADDRESS, + (u32)RX_BD_START_ADDRESS, + XEMACPS_IEEE1588_BD_ALIGNMENT, + XEMACPS_IEEE1588_NO_OF_RX_DESCS); +#endif + if (Status != XST_SUCCESS) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("In %s: BD Ring Creation failed for Rx path \r\n", + __func__); +#endif + return; + } + + /* + * Clone the 16 BDs with BdTemplate. This will clear all the 16 BDs. + */ + Status = XEmacPs_BdRingClone(RxRingPtr, &BdTemplate, XEMACPS_RECV); + if (Status != XST_SUCCESS) { + return; + } + + /* + * BdTemplate is used for cloning on Tx path. Hence it is cleared so + * that all 16 BDs can be cleared. + */ + XEmacPs_BdClear(&BdTemplate); + /* + * Set the Used Bit. + */ + XEmacPs_BdSetStatus(&BdTemplate, XEMACPS_TXBUF_USED_MASK); + + /* + * Create 16 BDs for Tx path. + */ +#ifdef PEEP + Status = XEmacPs_BdRingCreate (TxRingPtr, + (u32)&TxRingPntrBase, + (u32)&TxRingPntrBase, + XEMACPS_IEEE1588_BD_ALIGNMENT, + XEMACPS_IEEE1588_NO_OF_TX_DESCS); +#else + Status = XEmacPs_BdRingCreate (TxRingPtr, + (u32)TX_BD_START_ADDRESS, + (u32)TX_BD_START_ADDRESS, + XEMACPS_IEEE1588_BD_ALIGNMENT, + XEMACPS_IEEE1588_NO_OF_TX_DESCS); +#endif + if (Status != XST_SUCCESS) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("In %s: BD Ring Creation failed for Tx path \r\n", + __func__); +#endif + return; + } + + /* + * Clone the 16 BDs with BdTemplate. This will clear all the 16 BDs + * and set the Used bit in all of them. + */ + Status = XEmacPs_BdRingClone (TxRingPtr, &BdTemplate, XEMACPS_SEND); + if (Status != XST_SUCCESS) { + return; + } + + /* + * Allocate the 16 BDs on Rx path. + */ + Status = XEmacPs_BdRingAlloc (RxRingPtr, + XEMACPS_IEEE1588_NO_OF_RX_DESCS, + &RxBdPtr); + if (Status != XST_SUCCESS) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("In %s: BD Ring allocation failed for Rx path \r\n", + __func__); +#endif + return; + } + /* + * Mark the RxBufs as used. + */ + CurrBdPtr = RxBdPtr; + for (Index = 0; Index < XEMACPS_IEEE1588_NO_OF_RX_DESCS; Index++) { + XEmacPs_BdSetAddressRx (CurrBdPtr, &(RxBuf[Index][0])); + XEmacPs_BdSetLast(CurrBdPtr); + RxBuf[Index][XEMACPS_PACKET_LEN - 2] = 1; + CurrBdPtr = XEmacPs_BdRingNext (RxRingPtr, CurrBdPtr); + } + /* + * Submit the BDs on the Rx path. + */ + Status = XEmacPs_BdRingToHw (RxRingPtr, + XEMACPS_IEEE1588_NO_OF_RX_DESCS, + RxBdPtr); + if (Status != XST_SUCCESS) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("In %s: BD Ring submission failed for Rx path \r\n", + __func__); +#endif + return; + } + /* + * Start the timer and EmacPs. + */ + XEmacPs_Start(InstancePntr->EmacPsInstance); + XScuTimer_Start(&TimerInstance); +} + +/*****************************************************************************/ +/** +* +* This function does various initializations. +* - It initializes the Local Port Identity. Clock Identity is +* initialized with 000A35FFFE010203 and port number as 1. +* - It initializes some of the fields of Tx PTP buffers. These fields remain +* constant over time and hence are initialized at one place. +* - It initializes signalling frame data. Since signalling frames are +* not implemented, the entries in the structure SignallingFrameData are +* hard coded. +* - The entries in the structure instance PtpCounters are initialized to 0. +* - The variable PtpIsRunning is made as 1 so that PTP packets Tx can be +* initiated in the Timer ISR. +* - The PTP node is made as Master to start with. +* - The Peer Ieee1588v2 capability is made as 0 which means the peer is not +* Ieee1588v2 capable. +* +* @param InstancePntr is a pointer to the instance of the +* XEmacPs_Ieee1588. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XEmacPs_InitializeProtocolData(XEmacPs_Ieee1588 *InstancePntr) +{ + /* + * Populate the local port identity. + */ +#ifdef IEEE1588_MASTER + InstancePntr->PortIdLocal.ClockIdentity[0] = 0x00; + InstancePntr->PortIdLocal.ClockIdentity[1] = 0x0A; + InstancePntr->PortIdLocal.ClockIdentity[2] = 0x35; + InstancePntr->PortIdLocal.ClockIdentity[3] = 0xFF; + InstancePntr->PortIdLocal.ClockIdentity[4] = 0xFE; + InstancePntr->PortIdLocal.ClockIdentity[5] = 0x01; + InstancePntr->PortIdLocal.ClockIdentity[6] = 0x02; + InstancePntr->PortIdLocal.ClockIdentity[7] = 0x03; + InstancePntr->PortIdLocal.PortNumber = 0x0001; +#else + InstancePntr->PortIdLocal.ClockIdentity[0] = 0x00; + InstancePntr->PortIdLocal.ClockIdentity[1] = 0x0A; + InstancePntr->PortIdLocal.ClockIdentity[2] = 0x35; + InstancePntr->PortIdLocal.ClockIdentity[3] = 0xFF; + InstancePntr->PortIdLocal.ClockIdentity[4] = 0xFE; + InstancePntr->PortIdLocal.ClockIdentity[5] = 0x01; + InstancePntr->PortIdLocal.ClockIdentity[6] = 0x02; + InstancePntr->PortIdLocal.ClockIdentity[7] = 0x09; + InstancePntr->PortIdLocal.PortNumber = 0x0001; +#endif + /* + * Initialze some fields in the Tx Ptp buffers. + */ + XEmacPs_SetDfltTxFrms(InstancePntr); + + /* + * The PTP node is made Master.. + */ + XEmacPs_BecomeRtcMaster(InstancePntr,0); + + /* + * The Peer node not Ieee1588v2 capable to start with... + */ + XEmacPs_ChangePeerIeee1588v2Capability(InstancePntr, 0); + + InstancePntr->PtpIsRunning = 0; + InstancePntr->PtpRecords.LinkDelay = 0; + + InstancePntr->SignallingFrameData.SyncIntervalDuration = 2; + InstancePntr->SignallingFrameData.LinkDelayIntervalDuration = 8; + InstancePntr->SignallingFrameData.AnnounceIntervalDuration = 10; + + InstancePntr->LatestMDSyncReceive.SyncIntervalDuration = 2; + + /* + * Initialize other driver variables in the device's data structure + */ + InstancePntr->PtpCounters.CounterSyncInterval = 0; + InstancePntr->PtpCounters.CounterLinkDelayInterval = 0; + InstancePntr->PtpCounters.CounterAnnounceInterval = 0; + InstancePntr->PtpCounters.CounterSyncEvents = 0; + InstancePntr->StateMachineData.LostResponses = 0; + InstancePntr->StateMachineData.RcvdPDelayResp = 0; + InstancePntr->StateMachineData.RcvdPDelayRespFollowUp = 0; + + XEmacPs_DecodeTxAnnounceFrame (InstancePntr, + InstancePntr->AnnounceFrmToTx); + /* + * The PTP packets can now be transmitted out. + */ + InstancePntr->PtpIsRunning = 1; + XEmacPs_ChangePeerIeee1588v2Capability (InstancePntr, 0); +} + +/*****************************************************************************/ +/** +* +* This function is used when PTP node is initialized once again. +* +* @param InstancePntr is a pointer to the instance of the +* XEmacPs_Ieee1588. +* +* @return None. +* +* @note This function needs to be revisited as it is partially +* developed as of now.. +* +******************************************************************************/ +void XEmacPs_ResetIeee1588Protocol (XEmacPs_Ieee1588 *InstancePtr) +{ + /* Assert bad arguments and conditions */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->EmacPsInstance->IsReady + == XIL_COMPONENT_IS_READY); + + XEmacPs_InitializeProtocolData (InstancePtr); +} + +/*****************************************************************************/ +/** +* +* This function is the timer ISR that is invoked every 500 mseconds. The Tx of +* PTP packets are initiated from here at appropriate intervals. When the PTP +* node is Master, the Tx of SYNC frame is triggered from here. Similarly +* Announce frame and PDelayReq frame Tx are triggered from here. +* When the PTP node is Slave, the PDelayReq frame Tx is triggered from here. +* +* +* @param InstancePntr is a pointer to the instance of the +* XEmacPs_Ieee1588. +* +* @return None. +* +* @note The intervals at which SYNC, ANNOUNCE and PDelayReq are +* triggered are hard coded to 1 sec, 5 seconds and 4 seconds +* respectively. When signalling frames are implemented +* the hardcoded values can be replaced with proper signalling +* frame values. +* +******************************************************************************/ + +void XEmacPs_TimerInterruptHandler(XEmacPs_Ieee1588 *InstancePtr) +{ + XScuTimer *TimerInstancePntr = &TimerInstance; + /* + * Clear the Timer interrupt. + */ + XScuTimer_ClearInterruptStatus(TimerInstancePntr); + /* + * If PTP functions are marked as not running, then take no + * further action + */ + if (InstancePtr->PtpIsRunning == 1) { + + /* + * If the Link Partner is not Ieee1588 capable, then take no + * further action + */ + if (InstancePtr->PeerIeee1588v2Capable == 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 (1 second) expires + * (SyncIntervalDuration is used to count/time + * the duration) + */ + if ((InstancePtr->SignallingFrameData. + SyncIntervalDuration != + XEMACPS_PKT_TYPE_DISABLED) && + (InstancePtr->PtpCounters. + CounterSyncInterval >= + (InstancePtr->SignallingFrameData. + SyncIntervalDuration - 1))) { + XEmacPs_MasterSendSync(InstancePtr); + InstancePtr-> + PtpCounters.CounterSyncInterval = 0; + + } else { + InstancePtr->PtpCounters. + CounterSyncInterval + = InstancePtr-> + PtpCounters.CounterSyncInterval + + 1; + } + + /* + * Master will initiate an Announce Frame when + * the AnnounceIntervalDuration (5 secs) + * expires (CounterAnnounceInterval is used to + * count/time the duration) + */ + if ((InstancePtr->SignallingFrameData. + AnnounceIntervalDuration + != XEMACPS_PKT_TYPE_DISABLED) && + (InstancePtr-> + PtpCounters.CounterAnnounceInterval >= + (InstancePtr->SignallingFrameData. + AnnounceIntervalDuration - 1))) { + + XEmacPs_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: + * XEMACPS_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) * + XEMACPS_ANNOUNCE_RECEIPT_TIMEOUT) ) { + +#ifdef DEBUG_LEVEL_TWO + xil_printf("XEMACPS_ANNOUNCE_RECEIPT_TIMEOUT: Becoming GM! CounterAnnounceInterval = %d\r\n", + InstancePtr-> + PtpCounters.CounterAnnounceInterval); +#endif + InstancePtr-> + PtpCounters.CounterAnnounceInterval + = 0; + +#ifdef DEBUG_LEVEL_TWO + /* + * No Announce received from GM for timeout interval: + * we become the master */ + xil_printf("\r\n*** Announce timeout : Call XEmacPs_BecomeRtcMaster() *** \r\n"); +#endif + XEmacPs_BecomeRtcMaster(InstancePtr,0); + + } else { + InstancePtr-> + PtpCounters.CounterAnnounceInterval + = InstancePtr-> + PtpCounters.CounterAnnounceInterval + + 1; + } + + /* + * Timeout for Sync Packet reception: + * XEMACPS_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) * + XEMACPS_SYNC_RECEIPT_TIMEOUT) ) { +#ifdef DEBUG_LEVEL_TWO + xil_printf("\r\nXEMACPS_SYNC_RECEIPT_TIMEOUT: Becoming GM! CounterSyncInterval = %d\r\n", + InstancePtr->PtpCounters. + CounterSyncInterval); + xil_printf("\r\nXEMACPS_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 + */ +#ifdef DEBUG_LEVEL_TWO + xil_printf("\r\n*** Sync Timeout : Call XEmacPs_BecomeRtcMaster() *** \r\n"); +#endif + XEmacPs_BecomeRtcMaster(InstancePtr,0); + + } else { + InstancePtr-> + PtpCounters.CounterSyncInterval + = InstancePtr-> + PtpCounters.CounterSyncInterval + 1; + } + } + } + + /* + * Both Master and Slave will initiate a link delay + * measurement when the LinkDelayIntervalDuration (4 secs) + * expires (LinkDelayIntervalDuration is used to + * count/time the duration) + */ + if ((InstancePtr->SignallingFrameData.LinkDelayIntervalDuration + != XEMACPS_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 >= + XEMACPS_ALLOWED_LOST_RESPONSES ) { + /* + * The peer is no longer Ieee1588v2 Capable + */ + XEmacPs_ChangePeerIeee1588v2Capability + (InstancePtr, 0); + +#ifdef DEBUG_LEVEL_TWO + xil_printf("\r\n** XEmacPs_PtpTimerInterruptHandler(): The peer is no longer ASCapable **"); + xil_printf("\r\n** XEmacPs_PtpTimerInterruptHandler(): StateMachineData.LostResponses >= %d **", + XEMACPS_ALLOWED_LOST_RESPONSES); +#endif + /* avoid potential overflow */ + InstancePtr->StateMachineData.LostResponses = + XEMACPS_ALLOWED_LOST_RESPONSES; + } + + XEmacPs_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)' */ +} + +/*****************************************************************************/ +/** +* +* This function is the EmacPs Rx interrupt callback invoked from the EmacPs +* driver. Here we set the flag PtpNewPktRecd to true. This flag is checked for +* in the function XEmacPs_RunIEEE1588Protocol for further processing of +* packets. +* +* @param InstancePntr is a pointer to the instance of the +* XEmacPs_Ieee1588. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XEmacPs_PtpRxInterruptHandler(XEmacPs_Ieee1588 *InstancePtr) +{ + InstancePtr->PtpNewPktRecd = TRUE; +} + +/*****************************************************************************/ +/** +* +* This function is processes the received packets. This is invoked from +* XEmacPs_RunIEEE1588Protocol. It copies the received packet from the RxBuf +* to the corresponding buffer in XEmacPs_Ieee1588 structure instance.It then +* identifies the type of PTP packet received and calls the corresponding +* handlers to do further processing. +* It then frees the corresponding BD, does a allocation of the freed BD and +* populates the BD with appropriate buffer address (RxBuf). +* +* @param InstancePntr is a pointer to the instance of the +* XEmacPs_Ieee1588. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XEmacPs_HandleRecdPTPPacket(XEmacPs_Ieee1588 *InstancePtr) +{ + u8 MessageType = 0; + XEmacPs_Bd *BdPtr; + XEmacPs_Bd *CurBdPtr; + unsigned int NumBds; + unsigned int FreeBds; + int i; + int j; + int k; + u8 *BufAddr; + int BufLen; + int Status; + XEmacPs_BdRing *TxRingPtr; + XEmacPs_BdRing *RxRingPtr; + + /* + * Get the ring pointers from EmacPs instance + */ + TxRingPtr = &XEmacPs_GetTxRing(InstancePtr->EmacPsInstance); + RxRingPtr = &XEmacPs_GetRxRing(InstancePtr->EmacPsInstance); + + /* + * If PTP functions are marked as not running, then take no further + * action. + */ + if (InstancePtr->PtpIsRunning == 1) { + + /* + * Extract all available BDs from EmacPs. + */ + NumBds = XEmacPs_BdRingFromHwRx( RxRingPtr, + XEMACPS_IEEE1588_NO_OF_RX_DESCS, &BdPtr); + if (NumBds == 0) + return; + for (i = 0, CurBdPtr=BdPtr; i < NumBds; i++) { + /* + * Get the buffer address in which the PTP packet is + * stored from the BD. + */ + BufAddr = (void*)(XEmacPs_BdGetBufAddr(CurBdPtr) & + ~(XEMACPS_RXBUF_WRAP_MASK | XEMACPS_RXBUF_NEW_MASK)); + BufLen = XEmacPs_BdGetLength(CurBdPtr); +#ifndef PEEP + Xil_DCacheInvalidateRange((u32)BufAddr, 132); +#endif + /* + * If the received packet is not PTP, then there is + * some error. The example is used to demonstrate the + * PTP protocol and hence any other packet is not + * acceptable. Print the wrond packet to get some + * idea regarding what it contains. + */ + if (XEmacPs_IsRxFramePTP(BufAddr) == FALSE) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("A WRONG Packet Received \r\n"); + for (k = 0; k <= 100; k=k+10) { + xil_printf("%x %x %x %x %x %x %x %x %x %x\r\n", + BufAddr[k], + BufAddr[k+1], + BufAddr[k+2], + BufAddr[k+3], + BufAddr[k+4], + BufAddr[k+5], + BufAddr[k+6], + BufAddr[k+7], + BufAddr[k+8], + BufAddr[k+9]); + } +#endif + + } else { + /* + * Extract the PTP message type + */ + MessageType = XEmacPs_GetMsgType (BufAddr); + switch (MessageType) { + case XEMACPS_PTP_TYPE_SYNC: + /* + * Copy to relevant buffer and call the + * corresponding handler. + */ + memcpy(InstancePtr->LastRecdSyncFrm, + BufAddr, BufLen); + XEmacPs_DecodeRxSync(InstancePtr, + InstancePtr->LastRecdSyncFrm); + break; + + case XEMACPS_PTP_TYPE_FOLLOW_UP: + /* + * Copy to relevant buffer and call the + * corresponding handler. + */ + memcpy( + InstancePtr->LastRecdFollowUpFrm, + BufAddr, BufLen); + XEmacPs_DecodeRxFollowUp(InstancePtr, + InstancePtr->LastRecdFollowUpFrm); + break; + + case XEMACPS_PTP_TYPE_PDELAYREQ: + /* + * Copy to relevant buffer and call the + * corresponding handler. + */ + memcpy( + InstancePtr->LastRecdPDelayReqFrm, + BufAddr, BufLen); + XEmacPs_SendPDelayResp(InstancePtr); + break; + + case XEMACPS_PTP_TYPE_PDELAYRESP: + /* + * Copy to relevant buffer and call the + * corresponding handler. + */ + memcpy( + InstancePtr->LastRecdPDelayRespFrm, + BufAddr, BufLen); + XEmacPs_DecodeRxPDelayResp(InstancePtr, + InstancePtr->LastRecdPDelayRespFrm); + + break; + + case XEMACPS_PTP_TYPE_PDELAYRESP_FOLLOW_UP: + /* + * Copy to relevant buffer and call the + * corresponding handler. + */ + memcpy( + InstancePtr-> + LastRecdPDelayRespFollowUpFrm, BufAddr, + BufLen); + XEmacPs_DecodeRxPDelayRespFollowUp + (InstancePtr, + InstancePtr-> + LastRecdPDelayRespFollowUpFrm); + break; + + case XEMACPS_PTP_TYPE_ANNOUNCE: + /* + * Copy to relevant buffer and call the + * corresponding handler. + */ + memcpy( + InstancePtr->LastRecdAnnounceFrm, + BufAddr, BufLen); + XEmacPs_DecodeRxAnnounceFrame + (InstancePtr, + InstancePtr->LastRecdAnnounceFrm); + break; + + case XEMACPS_PTP_TYPE_SIGNALING: + /* + * Copy to relevant buffer and call the + * corresponding handler. + */ + memcpy( + InstancePtr->LastRecdSignallingFrm, + BufAddr, BufLen); + XEmacPs_DecodeRxSignaling + (InstancePtr, + InstancePtr->LastRecdSignallingFrm); + + break; + + default: + + break; + } + } + /* + * Clear the used bit in the buffer so that it can + * be reused. + */ + BufAddr[XEMACPS_PACKET_LEN - 2] = 0; + CurBdPtr = XEmacPs_BdRingNext( RxRingPtr, CurBdPtr); + } + + /* + * Time to free the BDs + */ + XEmacPs_BdRingFree(RxRingPtr, NumBds, BdPtr); + /* + * Time to reallocate the BDs + */ + FreeBds = XEmacPs_BdRingGetFreeCnt (RxRingPtr); + Status = XEmacPs_BdRingAlloc (RxRingPtr, FreeBds, + &BdPtr); + if (Status != XST_SUCCESS) { + return; + } + CurBdPtr = BdPtr; + for (i = 0; i < FreeBds; i++) { + for (j = 0; j < XEMACPS_IEEE1588_NO_OF_RX_DESCS; j++) { + if ((RxBuf[j][XEMACPS_PACKET_LEN - 2]) == 0) { + XEmacPs_BdSetAddressRx + (CurBdPtr, &(RxBuf[j][0])); + /* + * Set the used bit in the Buffer + */ + RxBuf[j][XEMACPS_PACKET_LEN - 2] = 1; + /* + * Clear the used bit so that it + * can be reused. + */ + XEmacPs_BdClearRxNew (CurBdPtr); + break; + } + } + CurBdPtr = XEmacPs_BdRingNext (RxRingPtr, CurBdPtr); + } + /* + * Submit the BDs to the hardware + */ + Status = XEmacPs_BdRingToHw (RxRingPtr, FreeBds, BdPtr); + } +} + +/*****************************************************************************/ +/** +* +* This function is the Tx Done interrupt callback invoked from the EmacPs +* driver. +* For some PTP packets, upon getting a Tx done interrupt some actions need +* to be taked. For example, when SYNC frame is successfully sent and Tx Done +* interrupt is received, the time stamp for the SYNC frame needs to be stored. +* For all such processing the function XEmacPs_PtpTxDoFurtherProcessing is +* invoked from here. +* +* @param InstancePntr is a pointer to the instance of the +* XEmacPs_Ieee1588. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XEmacPs_PtpTxInterruptHandler (XEmacPs_Ieee1588 *InstancePtr) +{ + unsigned int NumBds; + unsigned int NumBdsToProcess; + XEmacPs_Bd *BdPtr, *CurBdPtr; + void *BufAddr; + int BufLen; + int Status; + XEmacPs_BdRing *TxRingPtr; + unsigned int *Temp; + + TxRingPtr = &XEmacPs_GetTxRing(InstancePtr->EmacPsInstance); + + NumBds = XEmacPs_BdRingFromHwTx( TxRingPtr, + XEMACPS_IEEE1588_NO_OF_TX_DESCS, &BdPtr); + if (NumBds == 0) { + return; + } + NumBdsToProcess = NumBds; + CurBdPtr=BdPtr; + while (NumBdsToProcess > 0) { + BufAddr = (void*)(XEmacPs_BdGetBufAddr(CurBdPtr)); + BufLen = XEmacPs_BdGetLength(CurBdPtr); + + XEmacPs_PtpTxDoFurtherProcessing (InstancePtr, (u8 *)BufAddr); + Temp = (unsigned int *)CurBdPtr; + Temp++; + *Temp &= XEMACPS_TXBUF_WRAP_MASK; + *Temp |= XEMACPS_TXBUF_USED_MASK; + + CurBdPtr = XEmacPs_BdRingNext(TxRingPtr, CurBdPtr); + NumBdsToProcess--; + dmb(); + dsb(); + } + Status = XEmacPs_BdRingFree( TxRingPtr, NumBds, BdPtr); + if (Status != XST_SUCCESS) { + return; + } + return; +} + +/*****************************************************************************/ +/** +* +* This function is the Error interrupt callback invoked from the EmacPs driver. +* +* @param InstancePntr is a pointer to the instance of the +* XEmacPs_Ieee1588. +* @param Direction can be Rx or Tx +* @param ErrorWord gives further information about the exact error type. +* +* @return None. +* +* @note This function needs to be revisited. Probably upon an error +* we need to reset the EmacPs hardware and reinitialize the BDs. +* However further study is needed. Whether for all errors we +* need to reset or some errors can be ignored. +* +******************************************************************************/ +void XEmacPs_PtpErrorInterruptHandler (XEmacPs_Ieee1588 *InstancePtr, + u8 Direction, u32 ErrorWord) +{ + XEmacPs_Config *Cfg; + int Status = XST_SUCCESS; + unsigned int NSIncrementVal; + +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("In %s: EMAC Error Interrupt, Direction is %d and ErrorWord is %x \r\n", + __func__, Direction, ErrorWord); +#endif + XScuTimer_Stop(&TimerInstance); + XEmacPs_Stop(InstancePtr->EmacPsInstance); + Xil_ExceptionDisable(); + PDelayRespSent = 0; + SyncSent = 0; + PTPSendPacket = 0; + memset(RxBuf, 0, sizeof(RxBuf)); + Link_Speed = 100; + /* Initialize SCUTIMER */ + if (XEmacPs_InitScuTimer() != XST_SUCCESS) while(1); + /* + * Get the configuration of EmacPs hardware. + */ + Cfg = XEmacPs_LookupConfig(EMACPS_DEVICE_ID); + + /* + * Initialize EmacPs hardware. + */ + Status = XEmacPs_CfgInitialize(InstancePtr->EmacPsInstance, Cfg, Cfg->BaseAddress); + if (Status != XST_SUCCESS) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("In function %s: XEmacPs_CfgInitialize failure \r\n",__func__); +#endif + } + + /* + * Set the MAC address + */ + Status = XEmacPs_SetMacAddress(InstancePtr->EmacPsInstance, + (unsigned char*)UnicastMAC, 1); + if (Status != XST_SUCCESS) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("In function %s: XEmacPs_SetMacAddress failure \r\n",__func__); +#endif + } +#ifndef PEEP + XEmacPs_SetMdioDivisor(InstancePtr->EmacPsInstance, MDC_DIV_224); +#endif + /* + * Detect and initialize the PHY + */ + XEmacPs_PHYSetup (InstancePtr->EmacPsInstance); + sleep(1); + + /* + * Set the operating speed in EmacPs hardware. + */ + XEmacPs_SetOperatingSpeed(InstancePtr->EmacPsInstance, Link_Speed); + sleep(1); + + /* + * Enable the promiscuous mode in EmacPs hardware. + */ + Status = XEmacPs_SetOptions(InstancePtr->EmacPsInstance, XEMACPS_PROMISC_OPTION); + if (Status != XST_SUCCESS) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("In function %s: XEmacPs_SetOptions failure \r\n",__func__); +#endif + return; + } + +#ifdef PEEP + /* + * Set the 1588 Timer register for 50 MHz timer, i.e. 20 ns increment + * for every clock cycle. + */ + XEmacPs_WriteReg(EmacPsInstancePtr->Config.BaseAddress, + XEMACPS_1588_INC_OFFSET, + XEMACPS_1588_INC_VAL); +#else + + NSIncrementVal = XEmacPs_TsuCalcClk(XPAR_CPU_CORTEXA9_0_CPU_CLK_FREQ_HZ / 6); + XEmacPs_WriteReg(InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_1588_INC_OFFSET, + NSIncrementVal); +#endif + + /* + * Register Ethernet Rx, Tx and Error handlers with the EmacPs driver. + */ + Status = XEmacPs_SetHandler (InstancePtr->EmacPsInstance, + XEMACPS_HANDLER_DMARECV, + XEmacPs_PtpRxInterruptHandler, + &IEEE1588ProtoHandler); + Status |= XEmacPs_SetHandler (InstancePtr->EmacPsInstance, + XEMACPS_HANDLER_DMASEND, + XEmacPs_PtpTxInterruptHandler, + &IEEE1588ProtoHandler); + Status |= XEmacPs_SetHandler (InstancePtr->EmacPsInstance, + XEMACPS_HANDLER_ERROR, + XEmacPs_PtpErrorInterruptHandler, + &IEEE1588ProtoHandler); + if (Status != XST_SUCCESS) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("In function %s: XEmacPs_SetHandler failure \r\n", + __func__); +#endif + } + /* + * Connect to the interrupt controller and enable interrupts in + * interrupt controller. + */ + Status = XEmacPs_SetupIntrSystem(&IntcInstance, + InstancePtr->EmacPsInstance, + &TimerInstance, EMACPS_IRPT_INTR, + TIMER_IRPT_INTR); + if (Status != XST_SUCCESS) { +#ifdef DEBUG_XEMACPS_LEVEL1 + xil_printf("In function %s: XEmacPs_SetupIntrSystem failure \r\n", + __func__); +#endif + } + Xil_ExceptionEnable(); + /* + * Enable the timer interrupt in the timer module + */ + XScuTimer_EnableInterrupt(&TimerInstance); + /* + * Start the PTP standalone state machine. + */ + XEmacPs_RunIEEE1588Protocol(InstancePtr->EmacPsInstance); +} + +/*****************************************************************************/ +/** +* +* This function is initiates a PTP Tx. This is called from various places. +* +* @param InstancePntr is a pointer to the instance of the +* XEmacPs_Ieee1588. +* @param PacketBuf is the buffer that contains the packet to be Txed +* @param PacketLen is the length of the packet to be Txed. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +int XEmacPs_PtpTxPacket(XEmacPs_Ieee1588 *InstancePtr, u8 *PacketBuf, + int PacketLen) +{ + int Status; + XEmacPs_Bd *BdPtr; + XEmacPs_BdRing *TxRingPtr; + Xil_ExceptionDisable(); + + while((XEmacPs_ReadReg(InstancePtr->EmacPsInstance->Config.BaseAddress, + XEMACPS_TXSR_OFFSET)) & 0x08); + + TxRingPtr = &(XEmacPs_GetTxRing(InstancePtr->EmacPsInstance)); + Status = XEmacPs_BdRingAlloc(TxRingPtr, 1, &BdPtr); + if (Status != XST_SUCCESS) { + Xil_ExceptionEnable(); + return XST_FAILURE; + } + /* + * Fill the BD entries for the Tx1!!1` + */ +#ifndef PEEP + Xil_DCacheFlushRange((u32)PacketBuf, 128); +#endif + + XEmacPs_BdSetAddressTx (BdPtr, PacketBuf); + XEmacPs_BdSetLength(BdPtr, PacketLen); + XEmacPs_BdClearTxUsed(BdPtr); + XEmacPs_BdSetLast(BdPtr); + dmb(); + dsb(); + + Status = XEmacPs_BdRingToHw(TxRingPtr, 1, BdPtr); + if (Status != XST_SUCCESS) { + Xil_ExceptionEnable(); + return XST_FAILURE; + } + dmb(); + dsb(); + /* + * Start the Tx + */ + XEmacPs_Transmit(InstancePtr->EmacPsInstance); + Xil_ExceptionEnable(); + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function extracts length/type information from the Ethernet packet. +* +* @param PacketBuf contains the Ethernet packet. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +u32 XEmacPs_IsRxFramePTP (u8 *PacketBuf) +{ + if ((Xil_Ntohs (*(u16 *) (PacketBuf + 12))) == + XEMACPS_PTP_ETHERTYPE) + return TRUE; + else + return FALSE; +} + +/*****************************************************************************/ +/** +* +* This function extracts PTP messgae type information from the PTP packet. +* +* @param PacketBuf contains the Ethernet packet. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +u8 XEmacPs_GetMsgType (u8 *PacketBuf) +{ + return PacketBuf[XEMACPS_MSGTYP_OFFSET] & XEMACPS_MSGTYP_MASK; +} + +/*****************************************************************************/ +/** +* +* This function is used to populate the PTP Tx buffers. Some of the entries +* in a PTP Tx packet do not change with time and are constants over time for +* this PTP standalone example. Those entries are populated here. +* +* @param InstancePntr is a pointer to the instance of the +* XEmacPs_Ieee1588. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +void XEmacPs_SetDfltTxFrms(XEmacPs_Ieee1588 *InstancePtr) +{ + u8 TemplateFrm[50]; + u16 *TempPntr; + XEmacPs_PortIdentity TempIdentity; + u32 GmClkQuality = 0xF8FE4100; + u32 *TempLongPntr; + u8 OrgId[3] = {0x00, 0x80, 0xC2}; + u8 OrgSubType[3] = {0x00, 0x00, 0x01}; + + /* + * Zero out the template frame. Template frame is used to clone all + * the Tx buffers. + */ + memset (&TemplateFrm[0],0,sizeof(TemplateFrm)); + memset (InstancePtr->SyncFrmToTx,0,sizeof(InstancePtr->SyncFrmToTx)); + memset (InstancePtr->FollowUpFrmToTx,0, + sizeof(InstancePtr->FollowUpFrmToTx)); + memset (InstancePtr->PDelayReqFrmToTx,0, + sizeof(InstancePtr->PDelayReqFrmToTx)); + memset (InstancePtr->PDelayRespFrmToTx,0, + sizeof(InstancePtr->PDelayRespFrmToTx)); + memset (InstancePtr->PDelayRespFollowUpFrmToTx, 0, + sizeof(InstancePtr->PDelayRespFollowUpFrmToTx)); + memset (InstancePtr->SignallingFrmToTx, 0, + sizeof(InstancePtr->SignallingFrmToTx)); + memset (InstancePtr->AnnounceFrmToTx, 0, + sizeof(InstancePtr->AnnounceFrmToTx)); + + /* + * Populate the template frame with source and destination MAC. + */ + memcpy(&TemplateFrm[0],DestnAddr,6); + memcpy(&TemplateFrm[6],SrcAddr,6); + + /* + * Populate the template frame with source and destination MAC. + */ + TempPntr = (u16 *)(&(TemplateFrm[12])); + *TempPntr = Xil_Htons (XEMACPS_PTP_ETHERTYPE); + + /* + * Populate the template frame with PTP version + */ + TemplateFrm[XEMACPS_VERSPTP_OFFSET] = XEMACPS_PTP_VERSION_PTP; +#ifdef IEEE1588_MASTER + /* + * Populate the template frame with Port identity + */ + TempIdentity.ClockIdentity[0] = 0x00; + TempIdentity.ClockIdentity[1] = 0x0A; + TempIdentity.ClockIdentity[2] = 0x35; + TempIdentity.ClockIdentity[3] = 0xFF; + TempIdentity.ClockIdentity[4] = 0xFE; + TempIdentity.ClockIdentity[5] = 0x01; + TempIdentity.ClockIdentity[6] = 0x02; + TempIdentity.ClockIdentity[7] = 0x03; + TempIdentity.PortNumber = Xil_Htons (0x0001); +#else + /* + * Populate the template frame with Port identity + */ + TempIdentity.ClockIdentity[0] = 0x00; + TempIdentity.ClockIdentity[1] = 0x0A; + TempIdentity.ClockIdentity[2] = 0x35; + TempIdentity.ClockIdentity[3] = 0xFF; + TempIdentity.ClockIdentity[4] = 0xFE; + TempIdentity.ClockIdentity[5] = 0x01; + TempIdentity.ClockIdentity[6] = 0x02; + TempIdentity.ClockIdentity[7] = 0x09; + TempIdentity.PortNumber = Xil_Htons (0x0001); +#endif + memcpy(&(TemplateFrm[XEMACPS_PORTIDENTITY_OFFSET]), + (u8 *)&TempIdentity,10); + + /* + * Clone all Tx buffers with template frame + */ + memcpy (InstancePtr->SyncFrmToTx,TemplateFrm,50); + memcpy (InstancePtr->FollowUpFrmToTx,TemplateFrm,50); + memcpy (InstancePtr->PDelayReqFrmToTx,TemplateFrm,50); + memcpy (InstancePtr->PDelayRespFrmToTx,TemplateFrm,50); + memcpy (InstancePtr->PDelayRespFollowUpFrmToTx,TemplateFrm,50); + memcpy (InstancePtr->SignallingFrmToTx,TemplateFrm,50); + memcpy (InstancePtr->AnnounceFrmToTx,TemplateFrm,50); + + /* + * Now initialize the individual frames + */ + /* + * Announce Frame + */ + InstancePtr->AnnounceFrmToTx[XEMACPS_MSGTYP_OFFSET] = + XEMACPS_ANNOUNCEFRM_MSG_TYPE; + + TempPntr = (u16 *)&(InstancePtr-> + AnnounceFrmToTx[XEMACPS_MSGLENGTH_OFFSET]); + *TempPntr = Xil_Htons (XEMACPS_ANNOUNCEFRM_LENGTH); + + TempPntr = (u16 *)&(InstancePtr-> + AnnounceFrmToTx[XEMACPS_FLAGS_OFFSET]); + *TempPntr = Xil_Htons (XEMACPS_ANNOUNCEFRM_FLAGS_VAL); + + InstancePtr->AnnounceFrmToTx[XEMACPS_CONTROL_OFFSET] = 0x05; + InstancePtr->AnnounceFrmToTx[XEMACPS_LOGMSG_INTERVAL_OFFSET] = 10; + InstancePtr->AnnounceFrmToTx[XEMACPS_CURRUTCOFFSET_OFFSET] = 0; + InstancePtr->AnnounceFrmToTx[XEMACPS_CURRUTCOFFSET_OFFSET + 1] = 0; + +#ifdef IEEE1588_MASTER + InstancePtr->AnnounceFrmToTx[XEMACPS_GMPRI_ONE_OFFSET] = 0x01; +#else + InstancePtr->AnnounceFrmToTx[XEMACPS_GMPRI_ONE_OFFSET] = 0xFE; +#endif + TempLongPntr = (u32 *)&(InstancePtr-> + AnnounceFrmToTx[XEMACPS_GM_CLK_QUALITY_OFFSET]); + *TempLongPntr = Xil_Htonl (GmClkQuality); + InstancePtr->AnnounceFrmToTx[XEMACPS_GMPRI_TWO_OFFSET] = 0xF8; + memcpy((u8 *)(&InstancePtr-> + AnnounceFrmToTx[XEMACPS_GM_IDENTITY_OFFSET]), + (u8 *)TempIdentity.ClockIdentity, 8); + InstancePtr->AnnounceFrmToTx[XEMACPS_STEPS_REMOVED_OFFSET] = 0; + InstancePtr->AnnounceFrmToTx[XEMACPS_STEPS_REMOVED_OFFSET + 1] = 0; + + InstancePtr->AnnounceFrmToTx[XEMACPS_TIMESOURCE_OFFSET] = 0x90; + + TempPntr = (u16 *)&(InstancePtr-> + AnnounceFrmToTx[XEMACPS_TLVTYPE_OFFSET]); + *TempPntr = Xil_Htons (0x0008); + + TempPntr = (u16 *)&(InstancePtr-> + AnnounceFrmToTx[XEMACPS_LENGTHFIELD_OFFSET]); + *TempPntr = Xil_Htons (0x0008); + + memcpy((u8 *)(&InstancePtr->AnnounceFrmToTx[XEMACPS_PATHSEQ_OFFSET]), + (u8 *)TempIdentity.ClockIdentity, 8); + + /* + * Sync Frame + */ + InstancePtr->SyncFrmToTx[XEMACPS_MSGTYP_OFFSET] = + XEMACPS_SYNCFRM_MSG_TYPE; + TempPntr = (u16 *)&(InstancePtr-> + SyncFrmToTx[XEMACPS_MSGLENGTH_OFFSET]); + *TempPntr = Xil_Htons (XEMACPS_SYNCFRM_LENGTH); + + TempPntr = (u16 *)&(InstancePtr->SyncFrmToTx[XEMACPS_FLAGS_OFFSET]); + *TempPntr = Xil_Htons (XEMACPS_SYNCFRM_FLAGS_VAL); + + /* + * Follow-up Frame + */ + InstancePtr->FollowUpFrmToTx[XEMACPS_MSGTYP_OFFSET] = + XEMACPS_FOLLOWUPFRM_MSG_TYPE; + TempPntr = (u16 *)&(InstancePtr-> + FollowUpFrmToTx[XEMACPS_MSGLENGTH_OFFSET]); + *TempPntr = Xil_Htons (XEMACPS_FOLLOWUPFRM_LENGTH); + InstancePtr->FollowUpFrmToTx[XEMACPS_CONTROL_OFFSET] = 0x05; + + TempPntr = (u16 *)&(InstancePtr->FollowUpFrmToTx[58]); + *TempPntr = Xil_Htons (0x0003); + + TempPntr = (u16 *)&(InstancePtr->FollowUpFrmToTx[60]); + *TempPntr = Xil_Htons (28); + + memcpy ((u8 *)&(InstancePtr->FollowUpFrmToTx[62]), OrgId, 3); + memcpy ((u8 *)&(InstancePtr->FollowUpFrmToTx[65]), OrgSubType, 3); + + /* + * PDelay Req Frame + */ + InstancePtr->PDelayReqFrmToTx[XEMACPS_MSGTYP_OFFSET] = + XEMACPS_PDELAYREQFRM_MSG_TYPE; + + TempPntr = (u16 *)&(InstancePtr-> + PDelayReqFrmToTx[XEMACPS_MSGLENGTH_OFFSET]); + *TempPntr = Xil_Htons (XEMACPS_PDELAYREQFRM_LENGTH); + InstancePtr->PDelayReqFrmToTx[XEMACPS_CONTROL_OFFSET] = 0x05; + + TempPntr = (u16 *)&(InstancePtr-> + PDelayReqFrmToTx[XEMACPS_FLAGS_OFFSET]); + *TempPntr = Xil_Htons (XEMACPS_PDELAYREQFRM_FLAGS_VAL); + + /* + * PDelay Resp Frame + */ + InstancePtr->PDelayRespFrmToTx[XEMACPS_MSGTYP_OFFSET] = + XEMACPS_PDELAYRESPFRM_MSG_TYPE; + TempPntr = (u16 *)&(InstancePtr-> + PDelayRespFrmToTx[XEMACPS_MSGLENGTH_OFFSET]); + *TempPntr = Xil_Htons (XEMACPS_PDELAYRESPFRM_LENGTH); + InstancePtr->PDelayRespFrmToTx[XEMACPS_CONTROL_OFFSET] = 0x05; + InstancePtr->PDelayRespFrmToTx[XEMACPS_LOGMSG_INTERVAL_OFFSET] = 0x7F; + + /* + * PDelay Response Follow Up Frame + */ + InstancePtr->PDelayRespFollowUpFrmToTx[XEMACPS_MSGTYP_OFFSET] = + XEMACPS_PDELAYRESPFOLLOWUPFRM_MSG_TYPE; + TempPntr = (u16 *)&(InstancePtr-> + PDelayRespFollowUpFrmToTx[XEMACPS_MSGLENGTH_OFFSET]); + *TempPntr = Xil_Htons (XEMACPS_PDELAYRESPFOLLOWUP_LENGTH); + InstancePtr->PDelayRespFollowUpFrmToTx[XEMACPS_CONTROL_OFFSET] = 0x05; + InstancePtr->PDelayRespFollowUpFrmToTx[XEMACPS_LOGMSG_INTERVAL_OFFSET] + = 0x7F; +} + +/****************************************************************************/ +/** +* +* A function to compare two PortIdentity values. +* +* @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 XEmacPs_ComparePortIdentity(XEmacPs_PortIdentity Identity1, + XEmacPs_PortIdentity Identity2) +{ + + int Result = memcmp (&(Identity1.ClockIdentity[0]), + &(Identity2.ClockIdentity[0]), + 8); + if (Result != 0) { + return 0; + } + + if( Identity1.PortNumber != Identity2.PortNumber ) { + return 0; + } + + /* values are equal */ + return 1; +} + +/****************************************************************************/ +/** +* +* A function to compare two ClockIdentity values. +* +* @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 None. +* +*****************************************************************************/ +u32 XEmacPs_CompareClockIdentity( + XEmacPs_ClockIdentity Identity1, + XEmacPs_ClockIdentity Identity2) +{ + int Result = memcmp (&(Identity1.ClockIdentity[0]), + &(Identity2.ClockIdentity[0]), + 8); + if (Result != 0) { + 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 PacketBuf contains the PTP buffer from which the portIdentity +* is to be extracted. +* @param portID is the address of type XEmacPs_PortIdentity is which +* the extracted port identity is put. +* +* @return None. +* +* @note None. +* +*****************************************************************************/ +void XEmacPs_GetPortIdentity(u8 *PacketBuf, XEmacPs_PortIdentity *portID) +{ + XEmacPs_PortIdentity TempIdentity; + u8 *ReadFromAddr = PacketBuf + XEMACPS_PORTIDENTITY_OFFSET; + + memcpy ((u8 *)&(TempIdentity.ClockIdentity[0]), ReadFromAddr, 8); + TempIdentity.PortNumber = Xil_Ntohs (*(u16 *)(ReadFromAddr + 8)); + + memcpy ((u8 *)portID, (u8 *)&TempIdentity, + sizeof(XEmacPs_PortIdentity)); + +} + +/****************************************************************************/ +/** +* +* A function to extract SequenceId information from a received PTP frame. +* +* @param PacketBuf contains the PTP buffer from which the portIdentity +* is to be extracted. +* +* @return The extracted sequence ID. +* +* @note None. +* +*****************************************************************************/ +u16 XEmacPs_GetSequenceId(u8 *PacketBuf) +{ + u8 *ReadFromAddr = PacketBuf + XEMACPS_SEQID_OFFSET; + u16 SequenceId; + + SequenceId = Xil_Htons (*((u16 *)ReadFromAddr)); + return SequenceId; +} + +/****************************************************************************/ +/** +* +* A function to increment sequence ID in a PTP frames. It first extracts the +* sequence ID and then increments and puts it back in the PTP frame. +* +* @param PacketBuf contains the PTP buffer from which the portIdentity +* is to be extracted. +* +* @return The incremented sequence ID. +* +* @note None. +* +*****************************************************************************/ +u16 XEmacPs_IncSequenceId(u8 *PacketBuf) +{ + u8 *ReadFromAddr = PacketBuf + XEMACPS_SEQID_OFFSET; + u8 *WriteToAddr = PacketBuf + XEMACPS_SEQID_OFFSET; + u16 SequenceId = 0; + + SequenceId = Xil_Ntohs (*((u16 *)ReadFromAddr)); + SequenceId = SequenceId + 1; + + *((u16 *)WriteToAddr) = Xil_Htons (SequenceId); + + return SequenceId; +} + +/****************************************************************************/ +/** +* +* A function to do endian conversion for long long int type. This is for little +* to big endian conversion. +* +* @param Parameter whose endian conversion is needed +* +* @return The endian converted value. +* +* @note None. +* +*****************************************************************************/ +u32 XEmacPs_htonll (unsigned long long int n) +{ + union { + unsigned long lv[2]; + unsigned long long int llv; + } u; + u.lv[0] = Xil_Htonl(n >> 32); + u.lv[1] = Xil_Htonl(n & 0xFFFFFFFFULL); + return u.llv; +} + +/****************************************************************************/ +/** +* +* A function to do endian conversion for long long int type. This is for big +* to little endian conversion. +* +* @param Parameter whose endian conversion is needed +* +* @return The endian converted value. +* +* @note None. +* +*****************************************************************************/ +u32 XEmacPs_ntohll (long long int n) +{ + return XEmacPs_htonll (n); +} diff --git a/XilinxProcessorIPLib/drivers/emacps/src/Makefile b/XilinxProcessorIPLib/drivers/emacps/src/Makefile new file mode 100755 index 00000000..7002e622 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/src/Makefile @@ -0,0 +1,40 @@ +COMPILER= +ARCHIVER= +CP=cp +COMPILER_FLAGS= +EXTRA_COMPILER_FLAGS= +LIB=libxil.a + +CC_FLAGS = $(COMPILER_FLAGS) +ECC_FLAGS = $(EXTRA_COMPILER_FLAGS) + +RELEASEDIR=../../../lib +INCLUDEDIR=../../../include +INCLUDES=-I./. -I${INCLUDEDIR} + +OUTS = *.o + +LIBSOURCES:=*.c +INCLUDEFILES:=*.h + +OBJECTS = $(addsuffix .o, $(basename $(wildcard *.c))) + +libs: banner xemacps_libs clean + +%.o: %.c + ${COMPILER} $(CC_FLAGS) $(ECC_FLAGS) $(INCLUDES) -o $@ $< + +banner: + echo "Compiling emacps" + +xemacps_libs: ${OBJECTS} + $(ARCHIVER) -r ${RELEASEDIR}/${LIB} ${OBJECTS} + +.PHONY: include +include: xemacps_includes + +xemacps_includes: + ${CP} ${INCLUDEFILES} ${INCLUDEDIR} + +clean: + rm -rf ${OBJECTS} diff --git a/XilinxProcessorIPLib/drivers/emacps/src/xemacps.c b/XilinxProcessorIPLib/drivers/emacps/src/xemacps.c new file mode 100755 index 00000000..b1b0fd38 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/src/xemacps.c @@ -0,0 +1,392 @@ +/* $Id: xemacps.c,v 1.1.2.3 2011/05/17 12:00:33 anirudh Exp $ */ +/****************************************************************************** +* +* 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 THE +* XILINX CONSORTIUM 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 xemacps.c +* +* The XEmacPs driver. Functions in this file are the minimum required functions +* for this driver. See xemacps.h for a detailed description of the driver. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a wsy  01/10/10 First release
+* 
+******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xemacps.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +void XEmacPs_StubHandler(void); /* Default handler routine */ + +/************************** Variable Definitions *****************************/ + + +/*****************************************************************************/ +/** +* Initialize a specific XEmacPs instance/driver. The initialization entails: +* - Initialize fields of the XEmacPs instance structure +* - Reset hardware and apply default options +* - Configure the DMA channels +* +* The PHY is setup independently from the device. Use the MII or whatever other +* interface may be present for setup. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* @param CfgPtr is the device configuration structure containing required +* hardware build data. +* @param EffectiveAddress is the base address of the device. If address +* translation is not utilized, this parameter can be passed in using +* CfgPtr->Config.BaseAddress to specify the physical base address. +* +* @return +* - XST_SUCCESS if initialization was successful +* +******************************************************************************/ +int XEmacPs_CfgInitialize(XEmacPs *InstancePtr, XEmacPs_Config * CfgPtr, + u32 EffectiveAddress) +{ + /* Verify arguments */ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(CfgPtr != NULL); + + /* Set device base address and ID */ + InstancePtr->Config.DeviceId = CfgPtr->DeviceId; + InstancePtr->Config.BaseAddress = EffectiveAddress; + + /* Set callbacks to an initial stub routine */ + InstancePtr->SendHandler = (XEmacPs_Handler) XEmacPs_StubHandler; + InstancePtr->RecvHandler = (XEmacPs_Handler) XEmacPs_StubHandler; + InstancePtr->ErrorHandler = (XEmacPs_ErrHandler) XEmacPs_StubHandler; + + /* Reset the hardware and set default options */ + InstancePtr->IsReady = XIL_COMPONENT_IS_READY; + XEmacPs_Reset(InstancePtr); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** +* Start the Ethernet controller as follows: +* - Enable transmitter if XTE_TRANSMIT_ENABLE_OPTION is set +* - Enable receiver if XTE_RECEIVER_ENABLE_OPTION is set +* - Start the SG DMA send and receive channels and enable the device +* interrupt +* +* @param InstancePtr is a pointer to the instance to be worked on. +* +* @return N/A +* +* @note +* Hardware is configured with scatter-gather DMA, the driver expects to start +* the scatter-gather channels and expects that the user has previously set up +* the buffer descriptor lists. +* +* This function makes use of internal resources that are shared between the +* Start, Stop, and Set/ClearOptions functions. So if one task might be setting +* device options while another is trying to start the device, the user is +* required to provide protection of this shared data (typically using a +* semaphore). +* +* This function must not be preempted by an interrupt that may service the +* device. +* +******************************************************************************/ +void XEmacPs_Start(XEmacPs *InstancePtr) +{ + u32 Reg; + + /* Assert bad arguments and conditions */ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid(InstancePtr->RxBdRing.BaseBdAddr != 0); + Xil_AssertVoid(InstancePtr->TxBdRing.BaseBdAddr != 0); + + /* If already started, then there is nothing to do */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + return; + } + + /* Start DMA */ + /* When starting the DMA channels, both transmit and receive sides + * need an initialized BD list. + */ + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_RXQBASE_OFFSET, + InstancePtr->RxBdRing.BaseBdAddr); + + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_TXQBASE_OFFSET, + InstancePtr->TxBdRing.BaseBdAddr); + + /* clear any existed int status */ + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_ISR_OFFSET, + XEMACPS_IXR_ALL_MASK); + + /* Enable transmitter if not already enabled */ + if (InstancePtr->Options & XEMACPS_TRANSMITTER_ENABLE_OPTION) { + Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET); + if (!(Reg & XEMACPS_NWCTRL_TXEN_MASK)) { + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET, + Reg | XEMACPS_NWCTRL_TXEN_MASK); + } + } + + /* Enable receiver if not already enabled */ + if (InstancePtr->Options & XEMACPS_RECEIVER_ENABLE_OPTION) { + Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET); + if (!(Reg & XEMACPS_NWCTRL_RXEN_MASK)) { + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET, + Reg | XEMACPS_NWCTRL_RXEN_MASK); + } + } + + /* Enable TX and RX interrupts */ + XEmacPs_IntEnable(InstancePtr, (XEMACPS_IXR_TX_ERR_MASK | + XEMACPS_IXR_RX_ERR_MASK | XEMACPS_IXR_FRAMERX_MASK | + XEMACPS_IXR_TXCOMPL_MASK)); + + /* Mark as started */ + InstancePtr->IsStarted = XIL_COMPONENT_IS_STARTED; + + return; +} + + +/*****************************************************************************/ +/** +* Gracefully stop the Ethernet MAC as follows: +* - Disable all interrupts from this device +* - Stop DMA channels +* - Disable the tansmitter and receiver +* +* Device options currently in effect are not changed. +* +* This function will disable all interrupts. Default interrupts settings that +* had been enabled will be restored when XEmacPs_Start() is called. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* +* @note +* This function makes use of internal resources that are shared between the +* Start, Stop, SetOptions, and ClearOptions functions. So if one task might be +* setting device options while another is trying to start the device, the user +* is required to provide protection of this shared data (typically using a +* semaphore). +* +* Stopping the DMA channels causes this function to block until the DMA +* operation is complete. +* +******************************************************************************/ +void XEmacPs_Stop(XEmacPs *InstancePtr) +{ + u32 Reg; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* Disable all interrupts */ + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_IDR_OFFSET, + XEMACPS_IXR_ALL_MASK); + + /* Disable the receiver & transmitter */ + Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET); + Reg &= ~XEMACPS_NWCTRL_RXEN_MASK; + Reg &= ~XEMACPS_NWCTRL_TXEN_MASK; + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET, Reg); + + /* Mark as stopped */ + InstancePtr->IsStarted = 0; +} + + +/*****************************************************************************/ +/** +* Perform a graceful reset of the Ethernet MAC. Resets the DMA channels, the +* transmitter, and the receiver. +* +* Steps to reset +* - Stops transmit and receive channels +* - Stops DMA +* - Configure transmit and receive buffer size to default +* - Clear transmit and receive status register and counters +* - Clear all interrupt sources +* - Clear phy (if there is any previously detected) address +* - Clear MAC addresses (1-4) as well as Type IDs and hash value +* +* All options are placed in their default state. Any frames in the +* descriptor lists will remain in the lists. The side effect of doing +* this is that after a reset and following a restart of the device, frames +* were in the list before the reset may be transmitted or received. +* +* The upper layer software is responsible for re-configuring (if necessary) +* and restarting the MAC after the reset. Note also that driver statistics +* are not cleared on reset. It is up to the upper layer software to clear the +* statistics if needed. +* +* When a reset is required, the driver notifies the upper layer software of +* this need through the ErrorHandler callback and specific status codes. +* The upper layer software is responsible for calling this Reset function +* and then re-configuring the device. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* +******************************************************************************/ +void XEmacPs_Reset(XEmacPs *InstancePtr) +{ + u32 Reg; + u8 i; + char EmacPs_zero_MAC[6] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* Stop the device and reset hardware */ + XEmacPs_Stop(InstancePtr); + InstancePtr->Options = XEMACPS_DEFAULT_OPTIONS; + + /* Setup hardware with default values */ + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET, + (XEMACPS_NWCTRL_STATCLR_MASK | + XEMACPS_NWCTRL_MDEN_MASK) & + ~XEMACPS_NWCTRL_LOOPEN_MASK); + + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCFG_OFFSET, + XEMACPS_NWCFG_100_MASK | + XEMACPS_NWCFG_FDEN_MASK | + XEMACPS_NWCFG_UCASTHASHEN_MASK); + + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_DMACR_OFFSET, + ((((XEMACPS_RX_BUF_SIZE / XEMACPS_RX_BUF_UNIT) + + ((XEMACPS_RX_BUF_SIZE % + XEMACPS_RX_BUF_UNIT) ? 1 : 0)) << + XEMACPS_DMACR_RXBUF_SHIFT) & + XEMACPS_DMACR_RXBUF_MASK) | + XEMACPS_DMACR_RXSIZE_MASK | + XEMACPS_DMACR_TXSIZE_MASK); + + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_TXSR_OFFSET, 0x0); + + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_RXQBASE_OFFSET, 0x0); + + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_TXQBASE_OFFSET, 0x0); + + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_RXSR_OFFSET, 0x0); + + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_IDR_OFFSET, + XEMACPS_IXR_ALL_MASK); + + Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_ISR_OFFSET); + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_ISR_OFFSET, + Reg); + + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_PHYMNTNC_OFFSET, 0x0); + + XEmacPs_ClearHash(InstancePtr); + + for (i = 1; i < 5; i++) { + XEmacPs_SetMacAddress(InstancePtr, EmacPs_zero_MAC, i); + XEmacPs_SetTypeIdCheck(InstancePtr, 0x0, i); + } + + /* clear all counters */ + for (i = 0; i < (XEMACPS_LAST_OFFSET - XEMACPS_OCTTXL_OFFSET) / 4; + i++) { + XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_OCTTXL_OFFSET + i * 4); + } + + /* Disable the receiver */ + Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET); + Reg &= ~XEMACPS_NWCTRL_RXEN_MASK; + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET, Reg); + + /* Sync default options with hardware but leave receiver and + * transmitter disabled. They get enabled with XEmacPs_Start() if + * XEMACPS_TRANSMITTER_ENABLE_OPTION and + * XEMACPS_RECEIVER_ENABLE_OPTION are set. + */ + XEmacPs_SetOptions(InstancePtr, InstancePtr->Options & + ~(XEMACPS_TRANSMITTER_ENABLE_OPTION | + XEMACPS_RECEIVER_ENABLE_OPTION)); + + XEmacPs_ClearOptions(InstancePtr, ~InstancePtr->Options); +} + + +/******************************************************************************/ +/** + * This is a stub for the asynchronous callbacks. The stub is here in case the + * upper layer forgot to set the handler(s). On initialization, all handlers are + * set to this callback. It is considered an error for this handler to be + * invoked. + * + ******************************************************************************/ +void XEmacPs_StubHandler(void) +{ + Xil_AssertVoidAlways(); +} diff --git a/XilinxProcessorIPLib/drivers/emacps/src/xemacps.h b/XilinxProcessorIPLib/drivers/emacps/src/xemacps.h new file mode 100755 index 00000000..9fda54c7 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/src/xemacps.h @@ -0,0 +1,719 @@ +/****************************************************************************** +* +* 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 THE +* XILINX CONSORTIUM 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 xemacps.h + * + * The Xilinx Embedded Processor Block Ethernet driver. + * + * For a full description of XEMACPS features, please see the hardware spec. + * This driver supports the following features: + * - Memory mapped access to host interface registers + * - Statistics counter registers for RMON/MIB + * - API for interrupt driven frame transfers for hardware configured DMA + * - Virtual memory support + * - Unicast, broadcast, and multicast receive address filtering + * - Full and half duplex operation + * - Automatic PAD & FCS insertion and stripping + * - Flow control + * - Support up to four 48bit addresses + * - Address checking for four specific 48bit addresses + * - VLAN frame support + * - Pause frame support + * - Large frame support up to 1536 bytes + * - Checksum offload + * + * Driver Description + * + * The device driver enables higher layer software (e.g., an application) to + * communicate to the XEmacPs. The driver handles transmission and reception + * of Ethernet frames, as well as configuration and control. No pre or post + * processing of frame data is performed. The driver does not validate the + * contents of an incoming frame in addition to what has already occurred in + * hardware. + * A single device driver can support multiple devices even when those devices + * have significantly different configurations. + * + * Initialization & Configuration + * + * The XEmacPs_Config structure is used by the driver to configure itself. + * This configuration structure is typically created by the tool-chain based + * on hardware build properties. + * + * The driver instance can be initialized in + * + * - XEmacPs_CfgInitialize(InstancePtr, CfgPtr, EffectiveAddress): Uses a + * configuration structure provided by the caller. If running in a system + * with address translation, the provided virtual memory base address + * replaces the physical address present in the configuration structure. + * + * The device supports DMA only as current development plan. No FIFO mode is + * supported. The driver expects to start the DMA channels and expects that + * the user has set up the buffer descriptor lists. + * + * Interrupts and Asynchronous Callbacks + * + * The driver has no dependencies on the interrupt controller. When an + * interrupt occurs, the handler will perform a small amount of + * housekeeping work, determine the source of the interrupt, and call the + * appropriate callback function. All callbacks are registered by the user + * level application. + * + * Virtual Memory + * + * All virtual to physical memory mappings must occur prior to accessing the + * driver API. + * + * For DMA transactions, user buffers supplied to the driver must be in terms + * of their physical address. + * + * DMA + * + * The DMA engine uses buffer descriptors (BDs) to describe Ethernet frames. + * These BDs are typically chained together into a list the hardware follows + * when transferring data in and out of the packet buffers. Each BD describes + * a memory region containing either a full or partial Ethernet packet. + * + * Interrupt coalescing is not suppoted from this built-in DMA engine. + * + * This API requires the user to understand how the DMA operates. The + * following paragraphs provide some explanation, but the user is encouraged + * to read documentation in xemacps_bdring.h as well as study example code + * that accompanies this driver. + * + * The API is designed to get BDs to and from the DMA engine in the most + * efficient means possible. The first step is to establish a memory region + * to contain all BDs for a specific channel. This is done with + * XEmacPs_BdRingCreate(). This function sets up a BD ring that hardware will + * follow as BDs are processed. The ring will consist of a user defined number + * of BDs which will all be partially initialized. For example on the transmit + * channel, the driver will initialize all BDs' so that they are configured + * for transmit. The more fields that can be permanently setup at + * initialization, then the fewer accesses will be needed to each BD while + * the DMA engine is in operation resulting in better throughput and CPU + * utilization. The best case initialization would require the user to set + * only a frame buffer address and length prior to submitting the BD to the + * engine. + * + * BDs move through the engine with the help of functions + * XEmacPs_BdRingAlloc(), XEmacPs_BdRingToHw(), XEmacPs_BdRingFromHw(), + * and XEmacPs_BdRingFree(). + * All these functions handle BDs that are in place. That is, there are no + * copies of BDs kept anywhere and any BD the user interacts with is an actual + * BD from the same ring hardware accesses. + * + * BDs in the ring go through a series of states as follows: + * 1. Idle. The driver controls BDs in this state. + * 2. The user has data to transfer. XEmacPs_BdRingAlloc() is called to + * reserve BD(s). Once allocated, the user may setup the BD(s) with + * frame buffer address, length, and other attributes. The user controls + * BDs in this state. + * 3. The user submits BDs to the DMA engine with XEmacPs_BdRingToHw. BDs + * in this state are either waiting to be processed by hardware, are in + * process, or have been processed. The DMA engine controls BDs in this + * state. + * 4. Processed BDs are retrieved with XEmacEpv_BdRingFromHw() by the + * user. Once retrieved, the user can examine each BD for the outcome of + * the DMA transfer. The user controls BDs in this state. After examining + * the BDs the user calls XEmacPs_BdRingFree() which places the BDs back + * into state 1. + * + * Each of the four BD accessor functions operate on a set of BDs. A set is + * defined as a segment of the BD ring consisting of one or more BDs. The user + * views the set as a pointer to the first BD along with the number of BDs for + * that set. The set can be navigated by using macros XEmacPs_BdNext(). The + * user must exercise extreme caution when changing BDs in a set as there is + * nothing to prevent doing a mBdNext past the end of the set and modifying a + * BD out of bounds. + * + * XEmacPs_BdRingAlloc() + XEmacPs_BdRingToHw(), as well as + * XEmacPs_BdRingFromHw() + XEmacPs_BdRingFree() are designed to be used in + * tandem. The same BD set retrieved with BdRingAlloc should be the same one + * provided to hardware with BdRingToHw. Same goes with BdRingFromHw and + * BdRIngFree. + * + * Alignment & Data Cache Restrictions + * + * Due to the design of the hardware, all RX buffers, BDs need to be 4-byte + * aligned. Please reference xemacps_bd.h for cache related macros. + * + * DMA Tx: + * + * - If frame buffers exist in cached memory, then they must be flushed + * prior to committing them to hardware. + * + * DMA Rx: + * + * - If frame buffers exist in cached memory, then the cache must be + * invalidated for the memory region containing the frame prior to data + * access + * + * Both cache invalidate/flush are taken care of in driver code. + * + * Buffer Copying + * + * The driver is designed for a zero-copy buffer scheme. That is, the driver + * will not copy buffers. This avoids potential throughput bottlenecks within + * the driver. If byte copying is required, then the transfer will take longer + * to complete. + * + * Checksum Offloading + * + * The Embedded Processor Block Ethernet can be configured to perform IP, TCP + * and UDP checksum offloading in both receive and transmit directions. + * + * IP packets contain a 16-bit checksum field, which is the 16-bit 1s + * complement of the 1s complement sum of all 16-bit words in the header. + * TCP and UDP packets contain a 16-bit checksum field, which is the 16-bit + * 1s complement of the 1s complement sum of all 16-bit words in the header, + * the data and a conceptual pseudo header. + * + * To calculate these checksums in software requires each byte of the packet + * to be read. For TCP and UDP this can use a large amount of processing power. + * Offloading the checksum calculation to hardware can result in significant + * performance improvements. + * + * The transmit checksum offload is only available to use DMA in packet buffer + * mode. This is because the complete frame to be transmitted must be read + * into the packet buffer memory before the checksum can be calculated and + * written to the header at the beginning of the frame. + * + * For IP, TCP or UDP receive checksum offload to be useful, the operating + * system containing the protocol stack must be aware that this offload is + * available so that it can make use of the fact that the hardware has verified + * the checksum. + * + * When receive checksum offloading is enabled in the hardware, the IP header + * checksum is checked, where the packet meets the following criteria: + * + * 1. If present, the VLAN header must be four octets long and the CFI bit + * must not be set. + * 2. Encapsulation must be RFC 894 Ethernet Type Encoding or RFC 1042 SNAP + * encoding. + * 3. IP v4 packet. + * 4. IP header is of a valid length. + * 5. Good IP header checksum. + * 6. No IP fragmentation. + * 7. TCP or UDP packet. + * + * When an IP, TCP or UDP frame is received, the receive buffer descriptor + * gives an indication if the hardware was able to verify the checksums. + * There is also an indication if the frame had SNAP encapsulation. These + * indication bits will replace the type ID match indication bits when the + * receive checksum offload is enabled. + * + * If any of the checksums are verified incorrect by the hardware, the packet + * is discarded and the appropriate statistics counter incremented. + * + * PHY Interfaces + * + * RGMII 1.3 is the only interface supported. + * + * Asserts + * + * Asserts are used within all Xilinx drivers to enforce constraints on + * parameters. Asserts can be turned off on a system-wide basis by defining, + * at compile time, the NDEBUG identifier. By default, asserts are turned on + * and it is recommended that users leave asserts on during development. For + * deployment use -DNDEBUG compiler switch to remove assert code. + * + * @note + * + * Xilinx drivers are typically composed of two parts, one is the driver + * and the other is the adapter. The driver is independent of OS and processor + * and is intended to be highly portable. The adapter is OS-specific and + * facilitates communication between the driver and an OS. + * This driver is intended to be RTOS and processor independent. Any needs for + * dynamic memory management, threads or thread mutual exclusion, or cache + * control must be satisfied bythe layer above this driver. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -------------------------------------------------------
+ * 1.00a wsy  01/10/10 First release
+ * 1.00a asa  11/21/11 The function XEmacPs_BdRingFromHwTx in file
+ *		       xemacps_bdring.c is modified. Earlier it was checking for
+ *		       "BdLimit"(passed argument) number of BDs for finding out
+ *		       which BDs are successfully processed. Now one more check
+ *		       is added. It looks for BDs till the current BD pointer
+ *		       reaches HwTail. By doing this processing time is saved.
+ * 1.00a asa  01/24/12 The function XEmacPs_BdRingFromHwTx in file
+ *		       xemacps_bdring.c is modified. Now start of packet is
+ *		       searched for returning the number of BDs processed.
+ * 1.02a asa  11/05/12 Added a new API for deleting an entry from the HASH
+ *		       registers. Added a new API to set the bust length.
+ *		       Added some new hash-defines.
+ * 1.03a asa  01/23/12 Fix for CR #692702 which updates error handling for
+ *		       Rx errors. Under heavy Rx traffic, there will be a large
+ *		       number of errors related to receive buffer not available.
+ *		       Because of a HW bug (SI #692601), under such heavy errors,
+ *		       the Rx data path can become unresponsive. To reduce the
+ *		       probabilities for hitting this HW bug, the SW writes to
+ *		       bit 18 to flush a packet from Rx DPRAM immediately. The
+ *		       changes for it are done in the function
+ *		       XEmacPs_IntrHandler.
+ * 1.05a asa  09/23/13 Cache operations on BDs are not required and hence
+ *		       removed. It is expected that all BDs are allocated in
+ *		       from uncached area.
+ * 1.06a asa  11/02/13 Changed the value for XEMACPS_RXBUF_LEN_MASK from 0x3fff
+ *				to 0x1fff. This fixes the CR#744902.
+ *			  Made changes in example file xemacps_example.h to fix compilation
+ *			  issues with iarcc compiler.
+ * 2.0   adk  10/12/13 Updated as per the New Tcl API's
+ * 2.1   adk  11/08/14 Fixed the CR#811288. Changes are made in the driver tcl file.
+ * 2.1   bss  09/08/14 Modified driver tcl to fix CR#820349 to export phy
+ *		       address in xparameters.h when GMII to RGMII converter
+ *		       is present in hw.
+ * 2.2   adk  29/10/14 Fixed CR#827686 when PCS/PMA core is configured with
+ *                    1000BASE-X mode export proper values to the xparameters.h
+ *                    file. Changes are made in the driver tcl file.
+ * 
+ * + ****************************************************************************/ + +#ifndef XEMACPS_H /* prevent circular inclusions */ +#define XEMACPS_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files ********************************/ + +#include "xil_types.h" +#include "xil_assert.h" +#include "xstatus.h" +#include "xemacps_hw.h" +#include "xemacps_bd.h" +#include "xemacps_bdring.h" + +/************************** Constant Definitions ****************************/ + +/* + * Device information + */ +#define XEMACPS_DEVICE_NAME "xemacps" +#define XEMACPS_DEVICE_DESC "Xilinx PS 10/100/1000 MAC" + + +/** @name Configuration options + * + * Device configuration options. See the XEmacPs_SetOptions(), + * XEmacPs_ClearOptions() and XEmacPs_GetOptions() for information on how to + * use options. + * + * The default state of the options are noted and are what the device and + * driver will be set to after calling XEmacPs_Reset() or + * XEmacPs_Initialize(). + * + * @{ + */ + +#define XEMACPS_PROMISC_OPTION 0x00000001 +/**< Accept all incoming packets. + * This option defaults to disabled (cleared) */ + +#define XEMACPS_FRAME1536_OPTION 0x00000002 +/**< Frame larger than 1516 support for Tx & Rx. + * This option defaults to disabled (cleared) */ + +#define XEMACPS_VLAN_OPTION 0x00000004 +/**< VLAN Rx & Tx frame support. + * This option defaults to disabled (cleared) */ + +#define XEMACPS_FLOW_CONTROL_OPTION 0x00000010 +/**< Enable recognition of flow control frames on Rx + * This option defaults to enabled (set) */ + +#define XEMACPS_FCS_STRIP_OPTION 0x00000020 +/**< Strip FCS and PAD from incoming frames. Note: PAD from VLAN frames is not + * stripped. + * This option defaults to enabled (set) */ + +#define XEMACPS_FCS_INSERT_OPTION 0x00000040 +/**< Generate FCS field and add PAD automatically for outgoing frames. + * This option defaults to disabled (cleared) */ + +#define XEMACPS_LENTYPE_ERR_OPTION 0x00000080 +/**< Enable Length/Type error checking for incoming frames. When this option is + * set, the MAC will filter frames that have a mismatched type/length field + * and if XEMACPS_REPORT_RXERR_OPTION is set, the user is notified when these + * types of frames are encountered. When this option is cleared, the MAC will + * allow these types of frames to be received. + * + * This option defaults to disabled (cleared) */ + +#define XEMACPS_TRANSMITTER_ENABLE_OPTION 0x00000100 +/**< Enable the transmitter. + * This option defaults to enabled (set) */ + +#define XEMACPS_RECEIVER_ENABLE_OPTION 0x00000200 +/**< Enable the receiver + * This option defaults to enabled (set) */ + +#define XEMACPS_BROADCAST_OPTION 0x00000400 +/**< Allow reception of the broadcast address + * This option defaults to enabled (set) */ + +#define XEMACPS_MULTICAST_OPTION 0x00000800 +/**< Allows reception of multicast addresses programmed into hash + * This option defaults to disabled (clear) */ + +#define XEMACPS_RX_CHKSUM_ENABLE_OPTION 0x00001000 +/**< Enable the RX checksum offload + * This option defaults to enabled (set) */ + +#define XEMACPS_TX_CHKSUM_ENABLE_OPTION 0x00002000 +/**< Enable the TX checksum offload + * This option defaults to enabled (set) */ + + +#define XEMACPS_DEFAULT_OPTIONS \ + (XEMACPS_FLOW_CONTROL_OPTION | \ + XEMACPS_FCS_INSERT_OPTION | \ + XEMACPS_FCS_STRIP_OPTION | \ + XEMACPS_BROADCAST_OPTION | \ + XEMACPS_LENTYPE_ERR_OPTION | \ + XEMACPS_TRANSMITTER_ENABLE_OPTION | \ + XEMACPS_RECEIVER_ENABLE_OPTION | \ + XEMACPS_RX_CHKSUM_ENABLE_OPTION | \ + XEMACPS_TX_CHKSUM_ENABLE_OPTION) + +/**< Default options set when device is initialized or reset */ +/*@}*/ + +/** @name Callback identifiers + * + * These constants are used as parameters to XEmacPs_SetHandler() + * @{ + */ +#define XEMACPS_HANDLER_DMASEND 1 +#define XEMACPS_HANDLER_DMARECV 2 +#define XEMACPS_HANDLER_ERROR 3 +/*@}*/ + +/* Constants to determine the configuration of the hardware device. They are + * used to allow the driver to verify it can operate with the hardware. + */ +#define XEMACPS_MDIO_DIV_DFT MDC_DIV_32 /**< Default MDIO clock divisor */ + +/* The next few constants help upper layers determine the size of memory + * pools used for Ethernet buffers and descriptor lists. + */ +#define XEMACPS_MAC_ADDR_SIZE 6 /* size of Ethernet header */ + +#define XEMACPS_MTU 1500 /* max MTU size of Ethernet frame */ +#define XEMACPS_HDR_SIZE 14 /* size of Ethernet header */ +#define XEMACPS_HDR_VLAN_SIZE 18 /* size of Ethernet header with VLAN */ +#define XEMACPS_TRL_SIZE 4 /* size of Ethernet trailer (FCS) */ +#define XEMACPS_MAX_FRAME_SIZE (XEMACPS_MTU + XEMACPS_HDR_SIZE + \ + XEMACPS_TRL_SIZE) +#define XEMACPS_MAX_VLAN_FRAME_SIZE (XEMACPS_MTU + XEMACPS_HDR_SIZE + \ + XEMACPS_HDR_VLAN_SIZE + XEMACPS_TRL_SIZE) + +/* DMACR Bust length hash defines */ + +#define XEMACPS_SINGLE_BURST 1 +#define XEMACPS_4BYTE_BURST 4 +#define XEMACPS_8BYTE_BURST 8 +#define XEMACPS_16BYTE_BURST 16 + + +/**************************** Type Definitions ******************************/ +/** @name Typedefs for callback functions + * + * These callbacks are invoked in interrupt context. + * @{ + */ +/** + * Callback invoked when frame(s) have been sent or received in interrupt + * driven DMA mode. To set the send callback, invoke XEmacPs_SetHandler(). + * + * @param CallBackRef is user data assigned when the callback was set. + * + * @note + * See xemacps_hw.h for bitmasks definitions and the device hardware spec for + * further information on their meaning. + * + */ +typedef void (*XEmacPs_Handler) (void *CallBackRef); + +/** + * Callback when an asynchronous error occurs. To set this callback, invoke + * XEmacPs_SetHandler() with XEMACPS_HANDLER_ERROR in the HandlerType + * paramter. + * + * @param CallBackRef is user data assigned when the callback was set. + * @param Direction defines either receive or transmit error(s) has occurred. + * @param ErrorWord definition varies with Direction + * + */ +typedef void (*XEmacPs_ErrHandler) (void *CallBackRef, u8 Direction, + u32 ErrorWord); + +/*@}*/ + +/** + * This typedef contains configuration information for a device. + */ +typedef struct { + u16 DeviceId; /**< Unique ID of device */ + u32 BaseAddress;/**< Physical base address of IPIF registers */ +} XEmacPs_Config; + + +/** + * The XEmacPs driver instance data. The user is required to allocate a + * structure of this type for every XEmacPs device in the system. A pointer + * to a structure of this type is then passed to the driver API functions. + */ +typedef struct XEmacPs { + XEmacPs_Config Config; /* Hardware configuration */ + u32 IsStarted; /* Device is currently started */ + u32 IsReady; /* Device is initialized and ready */ + u32 Options; /* Current options word */ + + XEmacPs_BdRing TxBdRing; /* Transmit BD ring */ + XEmacPs_BdRing RxBdRing; /* Receive BD ring */ + + XEmacPs_Handler SendHandler; + XEmacPs_Handler RecvHandler; + void *SendRef; + void *RecvRef; + + XEmacPs_ErrHandler ErrorHandler; + void *ErrorRef; + +} XEmacPs; + + +/***************** Macros (Inline Functions) Definitions ********************/ + +/****************************************************************************/ +/** +* Retrieve the Tx ring object. This object can be used in the various Ring +* API functions. +* +* @param InstancePtr is the DMA channel to operate on. +* +* @return TxBdRing attribute +* +* @note +* C-style signature: +* XEmacPs_BdRing XEmacPs_GetTxRing(XEmacPs *InstancePtr) +* +*****************************************************************************/ +#define XEmacPs_GetTxRing(InstancePtr) ((InstancePtr)->TxBdRing) + +/****************************************************************************/ +/** +* Retrieve the Rx ring object. This object can be used in the various Ring +* API functions. +* +* @param InstancePtr is the DMA channel to operate on. +* +* @return RxBdRing attribute +* +* @note +* C-style signature: +* XEmacPs_BdRing XEmacPs_GetRxRing(XEmacPs *InstancePtr) +* +*****************************************************************************/ +#define XEmacPs_GetRxRing(InstancePtr) ((InstancePtr)->RxBdRing) + +/****************************************************************************/ +/** +* +* Enable interrupts specified in Mask. The corresponding interrupt for +* each bit set to 1 in Mask, will be enabled. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* @param Mask contains a bit mask of interrupts to enable. The mask can +* be formed using a set of bitwise or'd values. +* +* @note +* The state of the transmitter and receiver are not modified by this function. +* C-style signature +* void XEmacPs_IntEnable(XEmacPs *InstancePtr, u32 Mask) +* +*****************************************************************************/ +#define XEmacPs_IntEnable(InstancePtr, Mask) \ + XEmacPs_WriteReg((InstancePtr)->Config.BaseAddress, \ + XEMACPS_IER_OFFSET, \ + (Mask & XEMACPS_IXR_ALL_MASK)); + +/****************************************************************************/ +/** +* +* Disable interrupts specified in Mask. The corresponding interrupt for +* each bit set to 1 in Mask, will be enabled. +* +* @param InstancePtr is a pointer to the instance to be worked on. +* @param Mask contains a bit mask of interrupts to disable. The mask can +* be formed using a set of bitwise or'd values. +* +* @note +* The state of the transmitter and receiver are not modified by this function. +* C-style signature +* void XEmacPs_IntDisable(XEmacPs *InstancePtr, u32 Mask) +* +*****************************************************************************/ +#define XEmacPs_IntDisable(InstancePtr, Mask) \ + XEmacPs_WriteReg((InstancePtr)->Config.BaseAddress, \ + XEMACPS_IDR_OFFSET, \ + (Mask & XEMACPS_IXR_ALL_MASK)); + +/****************************************************************************/ +/** +* +* This macro triggers trasmit circuit to send data currently in TX buffer(s). +* +* @param InstancePtr is a pointer to the XEmacPs instance to be worked on. +* +* @return +* +* @note +* +* Signature: void XEmacPs_Transmit(XEmacPs *InstancePtr) +* +*****************************************************************************/ +#define XEmacPs_Transmit(InstancePtr) \ + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, \ + XEMACPS_NWCTRL_OFFSET, \ + (XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, \ + XEMACPS_NWCTRL_OFFSET) | XEMACPS_NWCTRL_STARTTX_MASK)) + +/****************************************************************************/ +/** +* +* This macro determines if the device is configured with checksum offloading +* on the receive channel +* +* @param InstancePtr is a pointer to the XEmacPs instance to be worked on. +* +* @return +* +* Boolean TRUE if the device is configured with checksum offloading, or +* FALSE otherwise. +* +* @note +* +* Signature: u32 XEmacPs_IsRxCsum(XEmacPs *InstancePtr) +* +*****************************************************************************/ +#define XEmacPs_IsRxCsum(InstancePtr) \ + ((XEmacPs_ReadReg((InstancePtr)->Config.BaseAddress, \ + XEMACPS_NWCFG_OFFSET) & XEMACPS_NWCFG_RXCHKSUMEN_MASK) \ + ? TRUE : FALSE) + +/****************************************************************************/ +/** +* +* This macro determines if the device is configured with checksum offloading +* on the transmit channel +* +* @param InstancePtr is a pointer to the XEmacPs instance to be worked on. +* +* @return +* +* Boolean TRUE if the device is configured with checksum offloading, or +* FALSE otherwise. +* +* @note +* +* Signature: u32 XEmacPs_IsTxCsum(XEmacPs *InstancePtr) +* +*****************************************************************************/ +#define XEmacPs_IsTxCsum(InstancePtr) \ + ((XEmacPs_ReadReg((InstancePtr)->Config.BaseAddress, \ + XEMACPS_DMACR_OFFSET) & XEMACPS_DMACR_TCPCKSUM_MASK) \ + ? TRUE : FALSE) + +/************************** Function Prototypes *****************************/ + +/* + * Initialization functions in xemacps.c + */ +int XEmacPs_CfgInitialize(XEmacPs *InstancePtr, XEmacPs_Config *CfgPtr, + u32 EffectiveAddress); +void XEmacPs_Start(XEmacPs *InstancePtr); +void XEmacPs_Stop(XEmacPs *InstancePtr); +void XEmacPs_Reset(XEmacPs *InstancePtr); + +/* + * Lookup configuration in xemacps_sinit.c + */ +XEmacPs_Config *XEmacPs_LookupConfig(u16 DeviceId); + +/* + * Interrupt-related functions in xemacps_intr.c + * DMA only and FIFO is not supported. This DMA does not support coalescing. + */ +int XEmacPs_SetHandler(XEmacPs *InstancePtr, u32 HandlerType, + void *FuncPtr, void *CallBackRef); +void XEmacPs_IntrHandler(void *InstancePtr); + +/* + * MAC configuration/control functions in XEmacPs_control.c + */ +int XEmacPs_SetOptions(XEmacPs *InstancePtr, u32 Options); +int XEmacPs_ClearOptions(XEmacPs *InstancePtr, u32 Options); +u32 XEmacPs_GetOptions(XEmacPs *InstancePtr); + +int XEmacPs_SetMacAddress(XEmacPs *InstancePtr, void *AddressPtr, u8 Index); +void XEmacPs_GetMacAddress(XEmacPs *InstancePtr, void *AddressPtr, u8 Index); + +int XEmacPs_SetHash(XEmacPs *InstancePtr, void *AddressPtr); +void XEmacPs_ClearHash(XEmacPs *InstancePtr); +void XEmacPs_GetHash(XEmacPs *InstancePtr, void *AddressPtr); + +void XEmacPs_SetMdioDivisor(XEmacPs *InstancePtr, + XEmacPs_MdcDiv Divisor); +void XEmacPs_SetOperatingSpeed(XEmacPs *InstancePtr, u16 Speed); +u16 XEmacPs_GetOperatingSpeed(XEmacPs *InstancePtr); +int XEmacPs_PhyRead(XEmacPs *InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 *PhyDataPtr); +int XEmacPs_PhyWrite(XEmacPs *InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 PhyData); +int XEmacPs_SetTypeIdCheck(XEmacPs *InstancePtr, u32 Id_Check, u8 Index); + +int XEmacPs_SendPausePacket(XEmacPs *InstancePtr); +void XEmacPs_DMABLengthUpdate(XEmacPs *InstancePtr, int BLength); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/emacps/src/xemacps_bd.h b/XilinxProcessorIPLib/drivers/emacps/src/xemacps_bd.h new file mode 100755 index 00000000..32ff68de --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/src/xemacps_bd.h @@ -0,0 +1,728 @@ +/* $Id: xemacps_bd.h,v 1.1.2.1 2011/01/20 03:39:02 sadanan Exp $ */ +/****************************************************************************** +* +* 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 THE +* XILINX CONSORTIUM 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 xemacps_bd.h + * + * This header provides operations to manage buffer descriptors in support + * of scatter-gather DMA. + * + * The API exported by this header defines abstracted macros that allow the + * user to read/write specific BD fields. + * + * Buffer Descriptors + * + * A buffer descriptor (BD) defines a DMA transaction. The macros defined by + * this header file allow access to most fields within a BD to tailor a DMA + * transaction according to user and hardware requirements. See the hardware + * IP DMA spec for more information on BD fields and how they affect transfers. + * + * The XEmacPs_Bd structure defines a BD. The organization of this structure + * is driven mainly by the hardware for use in scatter-gather DMA transfers. + * + * Performance + * + * Limiting I/O to BDs can improve overall performance of the DMA channel. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -------------------------------------------------------
+ * 1.00a wsy  01/10/10 First release
+ * 
+ * + * *************************************************************************** + */ + +#ifndef XEMACPS_BD_H /* prevent circular inclusions */ +#define XEMACPS_BD_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include +#include "xil_types.h" +#include "xil_assert.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/* Minimum BD alignment */ +#define XEMACPS_DMABD_MINIMUM_ALIGNMENT 4 + +/** + * The XEmacPs_Bd is the type for buffer descriptors (BDs). + */ +#define XEMACPS_BD_NUM_WORDS 2 +typedef u32 XEmacPs_Bd[XEMACPS_BD_NUM_WORDS]; + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/*****************************************************************************/ +/** + * Zero out BD fields + * + * @param BdPtr is the BD pointer to operate on + * + * @return Nothing + * + * @note + * C-style signature: + * void XEmacPs_BdClear(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdClear(BdPtr) \ + memset((BdPtr), 0, sizeof(XEmacPs_Bd)) + +/****************************************************************************/ +/** +* +* Read the given Buffer Descriptor word. +* +* @param BaseAddress is the base address of the BD to read +* @param Offset is the word offset to be read +* +* @return The 32-bit value of the field +* +* @note +* C-style signature: +* u32 XEmacPs_BdRead(u32 BaseAddress, u32 Offset) +* +*****************************************************************************/ +#define XEmacPs_BdRead(BaseAddress, Offset) \ + (*(u32*)((u32)(BaseAddress) + (u32)(Offset))) + +/****************************************************************************/ +/** +* +* Write the given Buffer Descriptor word. +* +* @param BaseAddress is the base address of the BD to write +* @param Offset is the word offset to be written +* @param Data is the 32-bit value to write to the field +* +* @return None. +* +* @note +* C-style signature: +* void XEmacPs_BdWrite(u32 BaseAddress, u32 Offset, u32 Data) +* +*****************************************************************************/ +#define XEmacPs_BdWrite(BaseAddress, Offset, Data) \ + (*(u32*)((u32)(BaseAddress) + (u32)(Offset)) = (Data)) + +/*****************************************************************************/ +/** + * Set the BD's Address field (word 0). + * + * @param BdPtr is the BD pointer to operate on + * @param Addr is the value to write to BD's status field. + * + * @note : + * + * C-style signature: + * void XEmacPs_BdSetAddressTx(XEmacPs_Bd* BdPtr, u32 Addr) + * + *****************************************************************************/ +#define XEmacPs_BdSetAddressTx(BdPtr, Addr) \ + (XEmacPs_BdWrite((BdPtr), XEMACPS_BD_ADDR_OFFSET, (u32)(Addr))) + + +/*****************************************************************************/ +/** + * Set the BD's Address field (word 0). + * + * @param BdPtr is the BD pointer to operate on + * @param Addr is the value to write to BD's status field. + * + * @note : Due to some bits are mixed within recevie BD's address field, + * read-modify-write is performed. + * + * C-style signature: + * void XEmacPs_BdSetAddressRx(XEmacPs_Bd* BdPtr, u32 Addr) + * + *****************************************************************************/ +#define XEmacPs_BdSetAddressRx(BdPtr, Addr) \ + XEmacPs_BdWrite((BdPtr), XEMACPS_BD_ADDR_OFFSET, \ + ((XEmacPs_BdRead((BdPtr), XEMACPS_BD_ADDR_OFFSET) & \ + ~XEMACPS_RXBUF_ADD_MASK) | (u32)(Addr))) + + +/*****************************************************************************/ +/** + * Set the BD's Status field (word 1). + * + * @param BdPtr is the BD pointer to operate on + * @param Data is the value to write to BD's status field. + * + * @note + * C-style signature: + * void XEmacPs_BdSetStatus(XEmacPs_Bd* BdPtr, u32 Data) + * + *****************************************************************************/ +#define XEmacPs_BdSetStatus(BdPtr, Data) \ + XEmacPs_BdWrite((BdPtr), XEMACPS_BD_STAT_OFFSET, \ + XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) | Data) + + +/*****************************************************************************/ +/** + * Retrieve the BD's Packet DMA transfer status word (word 1). + * + * @param BdPtr is the BD pointer to operate on + * + * @return Status word + * + * @note + * C-style signature: + * u32 XEmacPs_BdGetStatus(XEmacPs_Bd* BdPtr) + * + * Due to the BD bit layout differences in transmit and receive. User's + * caution is required. + *****************************************************************************/ +#define XEmacPs_BdGetStatus(BdPtr) \ + XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) + + +/*****************************************************************************/ +/** + * Get the address (bits 0..31) of the BD's buffer address (word 0) + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPs_BdGetBufAddr(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdGetBufAddr(BdPtr) \ + (XEmacPs_BdRead((BdPtr), XEMACPS_BD_ADDR_OFFSET)) + + +/*****************************************************************************/ +/** + * Set transfer length in bytes for the given BD. The length must be set each + * time a BD is submitted to hardware. + * + * @param BdPtr is the BD pointer to operate on + * @param LenBytes is the number of bytes to transfer. + * + * @note + * C-style signature: + * void XEmacPs_BdSetLength(XEmacPs_Bd* BdPtr, u32 LenBytes) + * + *****************************************************************************/ +#define XEmacPs_BdSetLength(BdPtr, LenBytes) \ + XEmacPs_BdWrite((BdPtr), XEMACPS_BD_STAT_OFFSET, \ + ((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + ~XEMACPS_TXBUF_LEN_MASK) | (LenBytes))) + + +/*****************************************************************************/ +/** + * Retrieve the BD length field. + * + * For Tx channels, the returned value is the same as that written with + * XEmacPs_BdSetLength(). + * + * For Rx channels, the returned value is the size of the received packet. + * + * @param BdPtr is the BD pointer to operate on + * + * @return Length field processed by hardware or set by + * XEmacPs_BdSetLength(). + * + * @note + * C-style signature: + * u32 XEmacPs_BdGetLength(XEmacPs_Bd* BdPtr) + * XEAMCPS_RXBUF_LEN_MASK is same as XEMACPS_TXBUF_LEN_MASK. + * + *****************************************************************************/ +#define XEmacPs_BdGetLength(BdPtr) \ + (XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + XEMACPS_RXBUF_LEN_MASK) + + +/*****************************************************************************/ +/** + * Test whether the given BD has been marked as the last BD of a packet. + * + * @param BdPtr is the BD pointer to operate on + * + * @return TRUE if BD represents the "Last" BD of a packet, FALSE otherwise + * + * @note + * C-style signature: + * u32 XEmacPs_BdIsLast(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdIsLast(BdPtr) \ + ((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + XEMACPS_RXBUF_EOF_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Tell the DMA engine that the given transmit BD marks the end of the current + * packet to be processed. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * void XEmacPs_BdSetLast(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdSetLast(BdPtr) \ + (XEmacPs_BdWrite((BdPtr), XEMACPS_BD_STAT_OFFSET, \ + XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) | \ + XEMACPS_TXBUF_LAST_MASK)) + + +/*****************************************************************************/ +/** + * Tell the DMA engine that the current packet does not end with the given + * BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * void XEmacPs_BdClearLast(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdClearLast(BdPtr) \ + (XEmacPs_BdWrite((BdPtr), XEMACPS_BD_STAT_OFFSET, \ + XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + ~XEMACPS_TXBUF_LAST_MASK)) + + +/*****************************************************************************/ +/** + * Set this bit to mark the last descriptor in the receive buffer descriptor + * list. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * void XEmacPs_BdSetRxWrap(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdSetRxWrap(BdPtr) \ + (XEmacPs_BdWrite((BdPtr), XEMACPS_BD_ADDR_OFFSET, \ + XEmacPs_BdRead((BdPtr), XEMACPS_BD_ADDR_OFFSET) | \ + XEMACPS_RXBUF_WRAP_MASK)) + + +/*****************************************************************************/ +/** + * Determine the wrap bit of the receive BD which indicates end of the + * BD list. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPs_BdIsRxWrap(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdIsRxWrap(BdPtr) \ + ((XEmacPs_BdRead((BdPtr), XEMACPS_BD_ADDR_OFFSET) & \ + XEMACPS_RXBUF_WRAP_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Sets this bit to mark the last descriptor in the transmit buffer + * descriptor list. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * void XEmacPs_BdSetTxWrap(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdSetTxWrap(BdPtr) \ + (XEmacPs_BdWrite((BdPtr), XEMACPS_BD_STAT_OFFSET, \ + XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) | \ + XEMACPS_TXBUF_WRAP_MASK)) + + +/*****************************************************************************/ +/** + * Determine the wrap bit of the transmit BD which indicates end of the + * BD list. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPs_BdGetTxWrap(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdIsTxWrap(BdPtr) \ + ((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + XEMACPS_TXBUF_WRAP_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/* + * Must clear this bit to enable the MAC to write data to the receive + * buffer. Hardware sets this bit once it has successfully written a frame to + * memory. Once set, software has to clear the bit before the buffer can be + * used again. This macro clear the new bit of the receive BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * void XEmacPs_BdClearRxNew(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdClearRxNew(BdPtr) \ + (XEmacPs_BdWrite((BdPtr), XEMACPS_BD_ADDR_OFFSET, \ + XEmacPs_BdRead((BdPtr), XEMACPS_BD_ADDR_OFFSET) & \ + ~XEMACPS_RXBUF_NEW_MASK)) + + +/*****************************************************************************/ +/** + * Determine the new bit of the receive BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPs_BdIsRxNew(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdIsRxNew(BdPtr) \ + ((XEmacPs_BdRead((BdPtr), XEMACPS_BD_ADDR_OFFSET) & \ + XEMACPS_RXBUF_NEW_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Software sets this bit to disable the buffer to be read by the hardware. + * Hardware sets this bit for the first buffer of a frame once it has been + * successfully transmitted. This macro sets this bit of transmit BD to avoid + * confusion. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * void XEmacPs_BdSetTxUsed(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdSetTxUsed(BdPtr) \ + (XEmacPs_BdWrite((BdPtr), XEMACPS_BD_STAT_OFFSET, \ + XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) | \ + XEMACPS_TXBUF_USED_MASK)) + + +/*****************************************************************************/ +/** + * Software clears this bit to enable the buffer to be read by the hardware. + * Hardware sets this bit for the first buffer of a frame once it has been + * successfully transmitted. This macro clears this bit of transmit BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * void XEmacPs_BdClearTxUsed(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdClearTxUsed(BdPtr) \ + (XEmacPs_BdWrite((BdPtr), XEMACPS_BD_STAT_OFFSET, \ + XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + ~XEMACPS_TXBUF_USED_MASK)) + + +/*****************************************************************************/ +/** + * Determine the used bit of the transmit BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPs_BdIsTxUsed(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdIsTxUsed(BdPtr) \ + ((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + XEMACPS_TXBUF_USED_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine if a frame fails to be transmitted due to too many retries. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPs_BdIsTxRetry(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdIsTxRetry(BdPtr) \ + ((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + XEMACPS_TXBUF_RETRY_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine if a frame fails to be transmitted due to data can not be + * feteched in time or buffers are exhausted. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPs_BdIsTxUrun(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdIsTxUrun(BdPtr) \ + ((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + XEMACPS_TXBUF_URUN_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine if a frame fails to be transmitted due to buffer is exhausted + * mid-frame. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPs_BdIsTxExh(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdIsTxExh(BdPtr) \ + ((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + XEMACPS_TXBUF_EXH_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Sets this bit, no CRC will be appended to the current frame. This control + * bit must be set for the first buffer in a frame and will be ignored for + * the subsequent buffers of a frame. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * This bit must be clear when using the transmit checksum generation offload, + * otherwise checksum generation and substitution will not occur. + * + * C-style signature: + * u32 XEmacPs_BdSetTxNoCRC(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdSetTxNoCRC(BdPtr) \ + (XEmacPs_BdWrite((BdPtr), XEMACPS_BD_STAT_OFFSET, \ + XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) | \ + XEMACPS_TXBUF_NOCRC_MASK)) + + +/*****************************************************************************/ +/** + * Clear this bit, CRC will be appended to the current frame. This control + * bit must be set for the first buffer in a frame and will be ignored for + * the subsequent buffers of a frame. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * This bit must be clear when using the transmit checksum generation offload, + * otherwise checksum generation and substitution will not occur. + * + * C-style signature: + * u32 XEmacPs_BdClearTxNoCRC(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdClearTxNoCRC(BdPtr) \ + (XEmacPs_BdWrite((BdPtr), XEMACPS_BD_STAT_OFFSET, \ + XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + ~XEMACPS_TXBUF_NOCRC_MASK)) + + +/*****************************************************************************/ +/** + * Determine the broadcast bit of the receive BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPs_BdIsRxBcast(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdIsRxBcast(BdPtr) \ + ((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + XEMACPS_RXBUF_BCAST_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine the multicast hash bit of the receive BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPs_BdIsRxMultiHash(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdIsRxMultiHash(BdPtr) \ + ((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + XEMACPS_RXBUF_MULTIHASH_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine the unicast hash bit of the receive BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPs_BdIsRxUniHash(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdIsRxUniHash(BdPtr) \ + ((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + XEMACPS_RXBUF_UNIHASH_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine if the received frame is a VLAN Tagged frame. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPs_BdIsRxVlan(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdIsRxVlan(BdPtr) \ + ((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + XEMACPS_RXBUF_VLAN_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine if the received frame has Type ID of 8100h and null VLAN + * identifier(Priority tag). + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPs_BdIsRxPri(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdIsRxPri(BdPtr) \ + ((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + XEMACPS_RXBUF_PRI_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine if the received frame's Concatenation Format Indicator (CFI) of + * the frames VLANTCI field was set. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPs_BdIsRxCFI(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdIsRxCFI(BdPtr) \ + ((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + XEMACPS_RXBUF_CFI_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine the End Of Frame (EOF) bit of the receive BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPs_BdGetRxEOF(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdIsRxEOF(BdPtr) \ + ((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + XEMACPS_RXBUF_EOF_MASK) ? TRUE : FALSE) + + +/*****************************************************************************/ +/** + * Determine the Start Of Frame (SOF) bit of the receive BD. + * + * @param BdPtr is the BD pointer to operate on + * + * @note + * C-style signature: + * u32 XEmacPs_BdGetRxSOF(XEmacPs_Bd* BdPtr) + * + *****************************************************************************/ +#define XEmacPs_BdIsRxSOF(BdPtr) \ + ((XEmacPs_BdRead((BdPtr), XEMACPS_BD_STAT_OFFSET) & \ + XEMACPS_RXBUF_SOF_MASK) ? TRUE : FALSE) + + +/************************** Function Prototypes ******************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/emacps/src/xemacps_bdring.c b/XilinxProcessorIPLib/drivers/emacps/src/xemacps_bdring.c new file mode 100755 index 00000000..3041c201 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/src/xemacps_bdring.c @@ -0,0 +1,1001 @@ +/* $Id: xemacps_bdring.c,v 1.1.2.1 2011/01/20 03:39:02 sadanan Exp $ */ +/****************************************************************************** +* +* 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 THE +* XILINX CONSORTIUM 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 xemacps_bdring.c +* +* This file implements buffer descriptor ring related functions. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a wsy  01/10/10 First release
+* 1.00a asa  11/21/11 The function XEmacPs_BdRingFromHwTx is modified.
+*		      Earlier it used to search in "BdLimit" number of BDs to
+*		      know which BDs are processed. Now one more check is
+*		      added. It looks for BDs till the current BD pointer
+*		      reaches HwTail. By doing this processing time is saved.
+* 1.00a asa  01/24/12 The function XEmacPs_BdRingFromHwTx in file
+*		      xemacps_bdring.c is modified. Now start of packet is
+*		      searched for returning the number of BDs processed.
+* 1.05a asa  09/23/13 Cache operations on BDs are not required and hence
+*		      removed. It is expected that all BDs are allocated in
+*		      from uncached area. Fix for CR #663885.
+* 
+******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xstatus.h" +#include "xil_cache.h" +#include "xemacps_hw.h" +#include "xemacps_bd.h" +#include "xemacps_bdring.h" + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/**************************************************************************** + * Compute the virtual address of a descriptor from its physical address + * + * @param BdPtr is the physical address of the BD + * + * @returns Virtual address of BdPtr + * + * @note Assume BdPtr is always a valid BD in the ring + ****************************************************************************/ +#define XEMACPS_PHYS_TO_VIRT(BdPtr) \ + ((u32)BdPtr + (RingPtr->BaseBdAddr - RingPtr->PhysBaseAddr)) + +/**************************************************************************** + * Compute the physical address of a descriptor from its virtual address + * + * @param BdPtr is the physical address of the BD + * + * @returns Physical address of BdPtr + * + * @note Assume BdPtr is always a valid BD in the ring + ****************************************************************************/ +#define XEMACPS_VIRT_TO_PHYS(BdPtr) \ + ((u32)BdPtr - (RingPtr->BaseBdAddr - RingPtr->PhysBaseAddr)) + +/**************************************************************************** + * Move the BdPtr argument ahead an arbitrary number of BDs wrapping around + * to the beginning of the ring if needed. + * + * We know if a wrapaound should occur if the new BdPtr is greater than + * the high address in the ring OR if the new BdPtr crosses over the + * 0xFFFFFFFF to 0 boundary. The latter test is a valid one since we do not + * allow a BD space to span this boundary. + * + * @param RingPtr is the ring BdPtr appears in + * @param BdPtr on input is the starting BD position and on output is the + * final BD position + * @param NumBd is the number of BD spaces to increment + * + ****************************************************************************/ +#define XEMACPS_RING_SEEKAHEAD(RingPtr, BdPtr, NumBd) \ + { \ + u32 Addr = (u32)BdPtr; \ + \ + Addr += ((RingPtr)->Separation * NumBd); \ + if ((Addr > (RingPtr)->HighBdAddr) || ((u32)BdPtr > Addr)) \ + { \ + Addr -= (RingPtr)->Length; \ + } \ + \ + BdPtr = (XEmacPs_Bd*)Addr; \ + } + +/**************************************************************************** + * Move the BdPtr argument backwards an arbitrary number of BDs wrapping + * around to the end of the ring if needed. + * + * We know if a wrapaound should occur if the new BdPtr is less than + * the base address in the ring OR if the new BdPtr crosses over the + * 0xFFFFFFFF to 0 boundary. The latter test is a valid one since we do not + * allow a BD space to span this boundary. + * + * @param RingPtr is the ring BdPtr appears in + * @param BdPtr on input is the starting BD position and on output is the + * final BD position + * @param NumBd is the number of BD spaces to increment + * + ****************************************************************************/ +#define XEMACPS_RING_SEEKBACK(RingPtr, BdPtr, NumBd) \ + { \ + u32 Addr = (u32)BdPtr; \ + \ + Addr -= ((RingPtr)->Separation * NumBd); \ + if ((Addr < (RingPtr)->BaseBdAddr) || ((u32)BdPtr < Addr)) \ + { \ + Addr += (RingPtr)->Length; \ + } \ + \ + BdPtr = (XEmacPs_Bd*)Addr; \ + } + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Definitions *****************************/ + +/*****************************************************************************/ +/** + * Using a memory segment allocated by the caller, create and setup the BD list + * for the given DMA channel. + * + * @param RingPtr is the instance to be worked on. + * @param PhysAddr is the physical base address of user memory region. + * @param VirtAddr is the virtual base address of the user memory region. If + * address translation is not being utilized, then VirtAddr should be + * equivalent to PhysAddr. + * @param Alignment governs the byte alignment of individual BDs. This function + * will enforce a minimum alignment of 4 bytes with no maximum as long + * as it is specified as a power of 2. + * @param BdCount is the number of BDs to setup in the user memory region. It + * is assumed the region is large enough to contain the BDs. + * + * @return + * + * - XST_SUCCESS if initialization was successful + * - XST_NO_FEATURE if the provided instance is a non DMA type + * channel. + * - XST_INVALID_PARAM under any of the following conditions: + * 1) PhysAddr and/or VirtAddr are not aligned to the given Alignment + * parameter; + * 2) Alignment parameter does not meet minimum requirements or is not a + * power of 2 value; + * 3) BdCount is 0. + * - XST_DMA_SG_LIST_ERROR if the memory segment containing the list spans + * over address 0x00000000 in virtual address space. + * + * @note + * Make sure to pass in the right alignment value. + *****************************************************************************/ +int XEmacPs_BdRingCreate(XEmacPs_BdRing * RingPtr, u32 PhysAddr, + u32 VirtAddr, u32 Alignment, unsigned BdCount) +{ + unsigned i; + u32 BdVirtAddr; + u32 BdPhyAddr; + + /* In case there is a failure prior to creating list, make sure the + * following attributes are 0 to prevent calls to other functions + * from doing anything. + */ + RingPtr->AllCnt = 0; + RingPtr->FreeCnt = 0; + RingPtr->HwCnt = 0; + RingPtr->PreCnt = 0; + RingPtr->PostCnt = 0; + + /* Make sure Alignment parameter meets minimum requirements */ + if (Alignment < XEMACPS_DMABD_MINIMUM_ALIGNMENT) { + return (XST_INVALID_PARAM); + } + + /* Make sure Alignment is a power of 2 */ + if ((Alignment - 1) & Alignment) { + return (XST_INVALID_PARAM); + } + + /* Make sure PhysAddr and VirtAddr are on same Alignment */ + if ((PhysAddr % Alignment) || (VirtAddr % Alignment)) { + return (XST_INVALID_PARAM); + } + + /* Is BdCount reasonable? */ + if (BdCount == 0) { + return (XST_INVALID_PARAM); + } + + /* Figure out how many bytes will be between the start of adjacent BDs */ + RingPtr->Separation = + (sizeof(XEmacPs_Bd) + (Alignment - 1)) & ~(Alignment - 1); + + /* Must make sure the ring doesn't span address 0x00000000. If it does, + * then the next/prev BD traversal macros will fail. + */ + if (VirtAddr > (VirtAddr + (RingPtr->Separation * BdCount) - 1)) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Initial ring setup: + * - Clear the entire space + * - Setup each BD's BDA field with the physical address of the next BD + */ + memset((void *) VirtAddr, 0, (RingPtr->Separation * BdCount)); + + BdVirtAddr = VirtAddr; + BdPhyAddr = PhysAddr + RingPtr->Separation; + for (i = 1; i < BdCount; i++) { + BdVirtAddr += RingPtr->Separation; + BdPhyAddr += RingPtr->Separation; + } + + /* Setup and initialize pointers and counters */ + RingPtr->RunState = XST_DMA_SG_IS_STOPPED; + RingPtr->BaseBdAddr = VirtAddr; + RingPtr->PhysBaseAddr = PhysAddr; + RingPtr->HighBdAddr = BdVirtAddr; + RingPtr->Length = + RingPtr->HighBdAddr - RingPtr->BaseBdAddr + RingPtr->Separation; + RingPtr->AllCnt = BdCount; + RingPtr->FreeCnt = BdCount; + RingPtr->FreeHead = (XEmacPs_Bd *) VirtAddr; + RingPtr->PreHead = (XEmacPs_Bd *) VirtAddr; + RingPtr->HwHead = (XEmacPs_Bd *) VirtAddr; + RingPtr->HwTail = (XEmacPs_Bd *) VirtAddr; + RingPtr->PostHead = (XEmacPs_Bd *) VirtAddr; + RingPtr->BdaRestart = (XEmacPs_Bd *) PhysAddr; + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Clone the given BD into every BD in the list. + * every field of the source BD is replicated in every BD of the list. + * + * This function can be called only when all BDs are in the free group such as + * they are immediately after initialization with XEmacPs_BdRingCreate(). + * This prevents modification of BDs while they are in use by hardware or the + * user. + * + * @param RingPtr is the pointer of BD ring instance to be worked on. + * @param SrcBdPtr is the source BD template to be cloned into the list. This + * BD will be modified. + * @param Direction is either XEMACPS_SEND or XEMACPS_RECV that indicates + * which direction. + * + * @return + * - XST_SUCCESS if the list was modified. + * - XST_DMA_SG_NO_LIST if a list has not been created. + * - XST_DMA_SG_LIST_ERROR if some of the BDs in this channel are under + * hardware or user control. + * - XST_DEVICE_IS_STARTED if the DMA channel has not been stopped. + * + *****************************************************************************/ +int XEmacPs_BdRingClone(XEmacPs_BdRing * RingPtr, XEmacPs_Bd * SrcBdPtr, + u8 Direction) +{ + unsigned i; + u32 CurBd; + + /* Can't do this function if there isn't a ring */ + if (RingPtr->AllCnt == 0) { + return (XST_DMA_SG_NO_LIST); + } + + /* Can't do this function with the channel running */ + if (RingPtr->RunState == XST_DMA_SG_IS_STARTED) { + return (XST_DEVICE_IS_STARTED); + } + + /* Can't do this function with some of the BDs in use */ + if (RingPtr->FreeCnt != RingPtr->AllCnt) { + return (XST_DMA_SG_LIST_ERROR); + } + + if ((Direction != XEMACPS_SEND) && (Direction != XEMACPS_RECV)) { + return (XST_INVALID_PARAM); + } + + /* Starting from the top of the ring, save BD.Next, overwrite the entire + * BD with the template, then restore BD.Next + */ + for (i = 0, CurBd = (u32) RingPtr->BaseBdAddr; + i < RingPtr->AllCnt; i++, CurBd += RingPtr->Separation) { + memcpy((void *)CurBd, SrcBdPtr, sizeof(XEmacPs_Bd)); + } + + CurBd -= RingPtr->Separation; + + if (Direction == XEMACPS_RECV) { + XEmacPs_BdSetRxWrap(CurBd); + } + else { + XEmacPs_BdSetTxWrap(CurBd); + } + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Reserve locations in the BD list. The set of returned BDs may be modified + * in preparation for future DMA transaction(s). Once the BDs are ready to be + * submitted to hardware, the user must call XEmacPs_BdRingToHw() in the same + * order which they were allocated here. Example: + * + *
+ *        NumBd = 2;
+ *        Status = XEmacPs_BdRingAlloc(MyRingPtr, NumBd, &MyBdSet);
+ *
+ *        if (Status != XST_SUCCESS)
+ *        {
+ *            // Not enough BDs available for the request
+ *        }
+ *
+ *        CurBd = MyBdSet;
+ *        for (i=0; i
+ *
+ * A more advanced use of this function may allocate multiple sets of BDs.
+ * They must be allocated and given to hardware in the correct sequence:
+ * 
+ *        // Legal
+ *        XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1);
+ *        XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1);
+ *
+ *        // Legal
+ *        XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1);
+ *        XEmacPs_BdRingAlloc(MyRingPtr, NumBd2, &MySet2);
+ *        XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1);
+ *        XEmacPs_BdRingToHw(MyRingPtr, NumBd2, MySet2);
+ *
+ *        // Not legal
+ *        XEmacPs_BdRingAlloc(MyRingPtr, NumBd1, &MySet1);
+ *        XEmacPs_BdRingAlloc(MyRingPtr, NumBd2, &MySet2);
+ *        XEmacPs_BdRingToHw(MyRingPtr, NumBd2, MySet2);
+ *        XEmacPs_BdRingToHw(MyRingPtr, NumBd1, MySet1);
+ * 
+ * + * Use the API defined in xemacps_bd.h to modify individual BDs. Traversal + * of the BD set can be done using XEmacPs_BdRingNext() and + * XEmacPs_BdRingPrev(). + * + * @param RingPtr is a pointer to the BD ring instance to be worked on. + * @param NumBd is the number of BDs to allocate + * @param BdSetPtr is an output parameter, it points to the first BD available + * for modification. + * + * @return + * - XST_SUCCESS if the requested number of BDs was returned in the BdSetPtr + * parameter. + * - XST_FAILURE if there were not enough free BDs to satisfy the request. + * + * @note This function should not be preempted by another XEmacPs_Bd function + * call that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + * @note Do not modify more BDs than the number requested with the NumBd + * parameter. Doing so will lead to data corruption and system + * instability. + * + *****************************************************************************/ +int XEmacPs_BdRingAlloc(XEmacPs_BdRing * RingPtr, unsigned NumBd, + XEmacPs_Bd ** BdSetPtr) +{ + /* Enough free BDs available for the request? */ + if (RingPtr->FreeCnt < NumBd) { + return (XST_FAILURE); + } + + /* Set the return argument and move FreeHead forward */ + *BdSetPtr = RingPtr->FreeHead; + XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->FreeHead, NumBd); + RingPtr->FreeCnt -= NumBd; + RingPtr->PreCnt += NumBd; + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** + * Fully or partially undo an XEmacPs_BdRingAlloc() operation. Use this + * function if all the BDs allocated by XEmacPs_BdRingAlloc() could not be + * transferred to hardware with XEmacPs_BdRingToHw(). + * + * This function helps out in situations when an unrelated error occurs after + * BDs have been allocated but before they have been given to hardware. + * An example of this type of error would be an OS running out of resources. + * + * This function is not the same as XEmacPs_BdRingFree(). The Free function + * returns BDs to the free list after they have been processed by hardware, + * while UnAlloc returns them before being processed by hardware. + * + * There are two scenarios where this function can be used. Full UnAlloc or + * Partial UnAlloc. A Full UnAlloc means all the BDs Alloc'd will be returned: + * + *
+ *    Status = XEmacPs_BdRingAlloc(MyRingPtr, 10, &BdPtr);
+ *        ...
+ *    if (Error)
+ *    {
+ *        Status = XEmacPs_BdRingUnAlloc(MyRingPtr, 10, &BdPtr);
+ *    }
+ * 
+ * + * A partial UnAlloc means some of the BDs Alloc'd will be returned: + * + *
+ *    Status = XEmacPs_BdRingAlloc(MyRingPtr, 10, &BdPtr);
+ *    BdsLeft = 10;
+ *    CurBdPtr = BdPtr;
+ *
+ *    while (BdsLeft)
+ *    {
+ *       if (Error)
+ *       {
+ *          Status = XEmacPs_BdRingUnAlloc(MyRingPtr, BdsLeft, CurBdPtr);
+ *       }
+ *
+ *       CurBdPtr = XEmacPs_BdRingNext(MyRingPtr, CurBdPtr);
+ *       BdsLeft--;
+ *    }
+ * 
+ * + * A partial UnAlloc must include the last BD in the list that was Alloc'd. + * + * @param RingPtr is a pointer to the instance to be worked on. + * @param NumBd is the number of BDs to allocate + * @param BdSetPtr is an output parameter, it points to the first BD available + * for modification. + * + * @return + * - XST_SUCCESS if the BDs were unallocated. + * - XST_FAILURE if NumBd parameter was greater that the number of BDs in + * the preprocessing state. + * + * @note This function should not be preempted by another XEmacPs_Bd function + * call that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + *****************************************************************************/ +int XEmacPs_BdRingUnAlloc(XEmacPs_BdRing * RingPtr, unsigned NumBd, + XEmacPs_Bd * BdSetPtr) +{ + (void)BdSetPtr; + + /* Enough BDs in the free state for the request? */ + if (RingPtr->PreCnt < NumBd) { + return (XST_FAILURE); + } + + /* Set the return argument and move FreeHead backward */ + XEMACPS_RING_SEEKBACK(RingPtr, RingPtr->FreeHead, NumBd); + RingPtr->FreeCnt += NumBd; + RingPtr->PreCnt -= NumBd; + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Enqueue a set of BDs to hardware that were previously allocated by + * XEmacPs_BdRingAlloc(). Once this function returns, the argument BD set goes + * under hardware control. Any changes made to these BDs after this point will + * corrupt the BD list leading to data corruption and system instability. + * + * The set will be rejected if the last BD of the set does not mark the end of + * a packet (see XEmacPs_BdSetLast()). + * + * @param RingPtr is a pointer to the instance to be worked on. + * @param NumBd is the number of BDs in the set. + * @param BdSetPtr is the first BD of the set to commit to hardware. + * + * @return + * - XST_SUCCESS if the set of BDs was accepted and enqueued to hardware. + * - XST_FAILURE if the set of BDs was rejected because the last BD of the set + * did not have its "last" bit set. + * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with + * XEmacPs_BdRingAlloc(). + * + * @note This function should not be preempted by another XEmacPs_Bd function + * call that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + *****************************************************************************/ +int XEmacPs_BdRingToHw(XEmacPs_BdRing * RingPtr, unsigned NumBd, + XEmacPs_Bd * BdSetPtr) +{ + XEmacPs_Bd *CurBdPtr; + unsigned i; + + /* if no bds to process, simply return. */ + if (0 == NumBd) + return (XST_SUCCESS); + + /* Make sure we are in sync with XEmacPs_BdRingAlloc() */ + if ((RingPtr->PreCnt < NumBd) || (RingPtr->PreHead != BdSetPtr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + CurBdPtr = BdSetPtr; + for (i = 0; i < NumBd; i++) { + CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr); + } + + /* Adjust ring pointers & counters */ + XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->PreHead, NumBd); + RingPtr->PreCnt -= NumBd; + + RingPtr->HwTail = CurBdPtr; + RingPtr->HwCnt += NumBd; + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Returns a set of BD(s) that have been processed by hardware. The returned + * BDs may be examined to determine the outcome of the DMA transaction(s). + * Once the BDs have been examined, the user must call XEmacPs_BdRingFree() + * in the same order which they were retrieved here. Example: + * + *
+ *        NumBd = XEmacPs_BdRingFromHwTx(MyRingPtr, MaxBd, &MyBdSet);
+ *
+ *        if (NumBd == 0)
+ *        {
+ *           // hardware has nothing ready for us yet
+ *        }
+ *
+ *        CurBd = MyBdSet;
+ *        for (i=0; i
+ *
+ * A more advanced use of this function may allocate multiple sets of BDs.
+ * They must be retrieved from hardware and freed in the correct sequence:
+ * 
+ *        // Legal
+ *        XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1);
+ *        XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
+ *
+ *        // Legal
+ *        XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1);
+ *        XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd2, &MySet2);
+ *        XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
+ *        XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2);
+ *
+ *        // Not legal
+ *        XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd1, &MySet1);
+ *        XEmacPs_BdRingFromHwTx(MyRingPtr, NumBd2, &MySet2);
+ *        XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2);
+ *        XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
+ * 
+ * + * If hardware has only partially completed a packet spanning multiple BDs, + * then none of the BDs for that packet will be included in the results. + * + * @param RingPtr is a pointer to the instance to be worked on. + * @param BdLimit is the maximum number of BDs to return in the set. + * @param BdSetPtr is an output parameter, it points to the first BD available + * for examination. + * + * @return + * The number of BDs processed by hardware. A value of 0 indicates that no + * data is available. No more than BdLimit BDs will be returned. + * + * @note Treat BDs returned by this function as read-only. + * + * @note This function should not be preempted by another XEmacPs_Bd function + * call that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + *****************************************************************************/ +unsigned XEmacPs_BdRingFromHwTx(XEmacPs_BdRing * RingPtr, unsigned BdLimit, + XEmacPs_Bd ** BdSetPtr) +{ + XEmacPs_Bd *CurBdPtr; + u32 BdStr = 0; + unsigned BdCount; + unsigned BdPartialCount; + unsigned int Sop = 0; + + + CurBdPtr = RingPtr->HwHead; + BdCount = 0; + BdPartialCount = 0; + + /* If no BDs in work group, then there's nothing to search */ + if (RingPtr->HwCnt == 0) { + *BdSetPtr = NULL; + return (0); + } + + if (BdLimit > RingPtr->HwCnt) + BdLimit = RingPtr->HwCnt; + + /* Starting at HwHead, keep moving forward in the list until: + * - A BD is encountered with its new/used bit set which means + * hardware has not completed processing of that BD. + * - RingPtr->HwTail is reached and RingPtr->HwCnt is reached. + * - The number of requested BDs has been processed + */ + while (BdCount < BdLimit) { + /* Read the status */ + BdStr = XEmacPs_BdRead(CurBdPtr, XEMACPS_BD_STAT_OFFSET); + + if ((Sop == 0) && (BdStr & XEMACPS_TXBUF_USED_MASK)) + Sop = 1; + + if (Sop == 1) { + BdCount++; + BdPartialCount++; + } + + /* hardware has processed this BD so check the "last" bit. + * If it is clear, then there are more BDs for the current + * packet. Keep a count of these partial packet BDs. + */ + if ((Sop == 1) && (BdStr & XEMACPS_TXBUF_LAST_MASK)) { + Sop = 0; + BdPartialCount = 0; + } + + /* Move on to next BD in work group */ + CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr); + } + + /* Subtract off any partial packet BDs found */ + BdCount -= BdPartialCount; + + /* If BdCount is non-zero then BDs were found to return. Set return + * parameters, update pointers and counters, return success + */ + if (BdCount > 0) { + *BdSetPtr = RingPtr->HwHead; + RingPtr->HwCnt -= BdCount; + RingPtr->PostCnt += BdCount; + XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount); + return (BdCount); + } + else { + *BdSetPtr = NULL; + return (0); + } +} + + +/*****************************************************************************/ +/** + * Returns a set of BD(s) that have been processed by hardware. The returned + * BDs may be examined to determine the outcome of the DMA transaction(s). + * Once the BDs have been examined, the user must call XEmacPs_BdRingFree() + * in the same order which they were retrieved here. Example: + * + *
+ *        NumBd = XEmacPs_BdRingFromHwRx(MyRingPtr, MaxBd, &MyBdSet);
+ *
+ *        if (NumBd == 0)
+ *        {
+ *           // hardware has nothing ready for us yet
+ *        }
+ *
+ *        CurBd = MyBdSet;
+ *        for (i=0; i
+ *
+ * A more advanced use of this function may allocate multiple sets of BDs.
+ * They must be retrieved from hardware and freed in the correct sequence:
+ * 
+ *        // Legal
+ *        XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1);
+ *        XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
+ *
+ *        // Legal
+ *        XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1);
+ *        XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd2, &MySet2);
+ *        XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
+ *        XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2);
+ *
+ *        // Not legal
+ *        XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd1, &MySet1);
+ *        XEmacPs_BdRingFromHwRx(MyRingPtr, NumBd2, &MySet2);
+ *        XEmacPs_BdRingFree(MyRingPtr, NumBd2, MySet2);
+ *        XEmacPs_BdRingFree(MyRingPtr, NumBd1, MySet1);
+ * 
+ * + * If hardware has only partially completed a packet spanning multiple BDs, + * then none of the BDs for that packet will be included in the results. + * + * @param RingPtr is a pointer to the instance to be worked on. + * @param BdLimit is the maximum number of BDs to return in the set. + * @param BdSetPtr is an output parameter, it points to the first BD available + * for examination. + * + * @return + * The number of BDs processed by hardware. A value of 0 indicates that no + * data is available. No more than BdLimit BDs will be returned. + * + * @note Treat BDs returned by this function as read-only. + * + * @note This function should not be preempted by another XEmacPs_Bd function + * call that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + *****************************************************************************/ +unsigned XEmacPs_BdRingFromHwRx(XEmacPs_BdRing * RingPtr, unsigned BdLimit, + XEmacPs_Bd ** BdSetPtr) +{ + XEmacPs_Bd *CurBdPtr; + u32 BdStr = 0; + unsigned BdCount; + unsigned BdPartialCount; + + CurBdPtr = RingPtr->HwHead; + BdCount = 0; + BdPartialCount = 0; + + /* If no BDs in work group, then there's nothing to search */ + if (RingPtr->HwCnt == 0) { + *BdSetPtr = NULL; + return (0); + } + + /* Starting at HwHead, keep moving forward in the list until: + * - A BD is encountered with its new/used bit set which means + * hardware has completed processing of that BD. + * - RingPtr->HwTail is reached and RingPtr->HwCnt is reached. + * - The number of requested BDs has been processed + */ + while (BdCount < BdLimit) { + + /* Read the status */ + BdStr = XEmacPs_BdRead(CurBdPtr, XEMACPS_BD_STAT_OFFSET); + + if (!(XEmacPs_BdIsRxNew(CurBdPtr))) { + break; + } + + BdCount++; + + /* hardware has processed this BD so check the "last" bit. If + * it is clear, then there are more BDs for the current packet. + * Keep a count of these partial packet BDs. + */ + if (BdStr & XEMACPS_RXBUF_EOF_MASK) { + BdPartialCount = 0; + } + else { + BdPartialCount++; + } + + /* Move on to next BD in work group */ + CurBdPtr = XEmacPs_BdRingNext(RingPtr, CurBdPtr); + } + + /* Subtract off any partial packet BDs found */ + BdCount -= BdPartialCount; + + /* If BdCount is non-zero then BDs were found to return. Set return + * parameters, update pointers and counters, return success + */ + if (BdCount > 0) { + *BdSetPtr = RingPtr->HwHead; + RingPtr->HwCnt -= BdCount; + RingPtr->PostCnt += BdCount; + XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount); + return (BdCount); + } + else { + *BdSetPtr = NULL; + return (0); + } +} + + +/*****************************************************************************/ +/** + * Frees a set of BDs that had been previously retrieved with + * XEmacPs_BdRingFromHw(). + * + * @param RingPtr is a pointer to the instance to be worked on. + * @param NumBd is the number of BDs to free. + * @param BdSetPtr is the head of a list of BDs returned by + * XEmacPs_BdRingFromHw(). + * + * @return + * - XST_SUCCESS if the set of BDs was freed. + * - XST_DMA_SG_LIST_ERROR if this function was called out of sequence with + * XEmacPs_BdRingFromHw(). + * + * @note This function should not be preempted by another XEmacPs_Bd function + * call that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + *****************************************************************************/ +int XEmacPs_BdRingFree(XEmacPs_BdRing * RingPtr, unsigned NumBd, + XEmacPs_Bd * BdSetPtr) +{ + /* if no bds to process, simply return. */ + if (0 == NumBd) + return (XST_SUCCESS); + + /* Make sure we are in sync with XEmacPs_BdRingFromHw() */ + if ((RingPtr->PostCnt < NumBd) || (RingPtr->PostHead != BdSetPtr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Update pointers and counters */ + RingPtr->FreeCnt += NumBd; + RingPtr->PostCnt -= NumBd; + XEMACPS_RING_SEEKAHEAD(RingPtr, RingPtr->PostHead, NumBd); + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Check the internal data structures of the BD ring for the provided channel. + * The following checks are made: + * + * - Is the BD ring linked correctly in physical address space. + * - Do the internal pointers point to BDs in the ring. + * - Do the internal counters add up. + * + * The channel should be stopped prior to calling this function. + * + * @param RingPtr is a pointer to the instance to be worked on. + * @param Direction is either XEMACPS_SEND or XEMACPS_RECV that indicates + * which direction. + * + * @return + * - XST_SUCCESS if the set of BDs was freed. + * - XST_DMA_SG_NO_LIST if the list has not been created. + * - XST_IS_STARTED if the channel is not stopped. + * - XST_DMA_SG_LIST_ERROR if a problem is found with the internal data + * structures. If this value is returned, the channel should be reset to + * avoid data corruption or system instability. + * + * @note This function should not be preempted by another XEmacPs_Bd function + * call that modifies the BD space. It is the caller's responsibility to + * provide a mutual exclusion mechanism. + * + *****************************************************************************/ +int XEmacPs_BdRingCheck(XEmacPs_BdRing * RingPtr, u8 Direction) +{ + u32 AddrV, AddrP; + unsigned i; + + if ((Direction != XEMACPS_SEND) && (Direction != XEMACPS_RECV)) { + return (XST_INVALID_PARAM); + } + + /* Is the list created */ + if (RingPtr->AllCnt == 0) { + return (XST_DMA_SG_NO_LIST); + } + + /* Can't check if channel is running */ + if (RingPtr->RunState == XST_DMA_SG_IS_STARTED) { + return (XST_IS_STARTED); + } + + /* RunState doesn't make sense */ + else if (RingPtr->RunState != XST_DMA_SG_IS_STOPPED) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Verify internal pointers point to correct memory space */ + AddrV = (u32) RingPtr->FreeHead; + if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + AddrV = (u32) RingPtr->PreHead; + if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + AddrV = (u32) RingPtr->HwHead; + if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + AddrV = (u32) RingPtr->HwTail; + if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + AddrV = (u32) RingPtr->PostHead; + if ((AddrV < RingPtr->BaseBdAddr) || (AddrV > RingPtr->HighBdAddr)) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Verify internal counters add up */ + if ((RingPtr->HwCnt + RingPtr->PreCnt + RingPtr->FreeCnt + + RingPtr->PostCnt) != RingPtr->AllCnt) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Verify BDs are linked correctly */ + AddrV = RingPtr->BaseBdAddr; + AddrP = RingPtr->PhysBaseAddr + RingPtr->Separation; + + for (i = 1; i < RingPtr->AllCnt; i++) { + /* Check BDA for this BD. It should point to next physical addr */ + if (XEmacPs_BdRead(AddrV, XEMACPS_BD_ADDR_OFFSET) != AddrP) { + return (XST_DMA_SG_LIST_ERROR); + } + + /* Move on to next BD */ + AddrV += RingPtr->Separation; + AddrP += RingPtr->Separation; + } + + /* Last BD should have wrap bit set */ + if (XEMACPS_SEND == Direction) { + if (!XEmacPs_BdIsTxWrap(AddrV)) { + return (XST_DMA_SG_LIST_ERROR); + } + } + else { /* XEMACPS_RECV */ + if (!XEmacPs_BdIsRxWrap(AddrV)) { + return (XST_DMA_SG_LIST_ERROR); + } + } + + /* No problems found */ + return (XST_SUCCESS); +} diff --git a/XilinxProcessorIPLib/drivers/emacps/src/xemacps_bdring.h b/XilinxProcessorIPLib/drivers/emacps/src/xemacps_bdring.h new file mode 100755 index 00000000..80c7981c --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/src/xemacps_bdring.h @@ -0,0 +1,233 @@ +/* $Id: xemacps_bdring.h,v 1.1.2.1 2011/01/20 03:39:02 sadanan Exp $ */ +/****************************************************************************** +* +* 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 THE +* XILINX CONSORTIUM 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 xemacps_bdring.h +* +* The Xiline EmacPs Buffer Descriptor ring driver. This is part of EmacPs +* DMA functionalities. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a wsy  01/10/10 First release
+* 
+* +******************************************************************************/ + +#ifndef XEMACPS_BDRING_H /* prevent curcular inclusions */ +#define XEMACPS_BDRING_H /* by using protection macros */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/**************************** Type Definitions *******************************/ + +/** This is an internal structure used to maintain the DMA list */ +typedef struct { + u32 PhysBaseAddr;/**< Physical address of 1st BD in list */ + u32 BaseBdAddr; /**< Virtual address of 1st BD in list */ + u32 HighBdAddr; /**< Virtual address of last BD in the list */ + u32 Length; /**< Total size of ring in bytes */ + u32 RunState; /**< Flag to indicate DMA is started */ + u32 Separation; /**< Number of bytes between the starting address + of adjacent BDs */ + XEmacPs_Bd *FreeHead; + /**< First BD in the free group */ + XEmacPs_Bd *PreHead;/**< First BD in the pre-work group */ + XEmacPs_Bd *HwHead; /**< First BD in the work group */ + XEmacPs_Bd *HwTail; /**< Last BD in the work group */ + XEmacPs_Bd *PostHead; + /**< First BD in the post-work group */ + XEmacPs_Bd *BdaRestart; + /**< BDA to load when channel is started */ + unsigned HwCnt; /**< Number of BDs in work group */ + unsigned PreCnt; /**< Number of BDs in pre-work group */ + unsigned FreeCnt; /**< Number of allocatable BDs in the free group */ + unsigned PostCnt; /**< Number of BDs in post-work group */ + unsigned AllCnt; /**< Total Number of BDs for channel */ +} XEmacPs_BdRing; + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/*****************************************************************************/ +/** +* Use this macro at initialization time to determine how many BDs will fit +* in a BD list within the given memory constraints. +* +* The results of this macro can be provided to XEmacPs_BdRingCreate(). +* +* @param Alignment specifies what byte alignment the BDs must fall on and +* must be a power of 2 to get an accurate calculation (32, 64, 128,...) +* @param Bytes is the number of bytes to be used to store BDs. +* +* @return Number of BDs that can fit in the given memory area +* +* @note +* C-style signature: +* u32 XEmacPs_BdRingCntCalc(u32 Alignment, u32 Bytes) +* +******************************************************************************/ +#define XEmacPs_BdRingCntCalc(Alignment, Bytes) \ + (u32)((Bytes) / ((sizeof(XEmacPs_Bd) + ((Alignment)-1)) & \ + ~((Alignment)-1))) + +/*****************************************************************************/ +/** +* Use this macro at initialization time to determine how many bytes of memory +* is required to contain a given number of BDs at a given alignment. +* +* @param Alignment specifies what byte alignment the BDs must fall on. This +* parameter must be a power of 2 to get an accurate calculation (32, 64, +* 128,...) +* @param NumBd is the number of BDs to calculate memory size requirements for +* +* @return The number of bytes of memory required to create a BD list with the +* given memory constraints. +* +* @note +* C-style signature: +* u32 XEmacPs_BdRingMemCalc(u32 Alignment, u32 NumBd) +* +******************************************************************************/ +#define XEmacPs_BdRingMemCalc(Alignment, NumBd) \ + (u32)((sizeof(XEmacPs_Bd) + ((Alignment)-1)) & \ + ~((Alignment)-1)) * (NumBd) + +/****************************************************************************/ +/** +* Return the total number of BDs allocated by this channel with +* XEmacPs_BdRingCreate(). +* +* @param RingPtr is the DMA channel to operate on. +* +* @return The total number of BDs allocated for this channel. +* +* @note +* C-style signature: +* u32 XEmacPs_BdRingGetCnt(XEmacPs_BdRing* RingPtr) +* +*****************************************************************************/ +#define XEmacPs_BdRingGetCnt(RingPtr) ((RingPtr)->AllCnt) + +/****************************************************************************/ +/** +* Return the number of BDs allocatable with XEmacPs_BdRingAlloc() for pre- +* processing. +* +* @param RingPtr is the DMA channel to operate on. +* +* @return The number of BDs currently allocatable. +* +* @note +* C-style signature: +* u32 XEmacPs_BdRingGetFreeCnt(XEmacPs_BdRing* RingPtr) +* +*****************************************************************************/ +#define XEmacPs_BdRingGetFreeCnt(RingPtr) ((RingPtr)->FreeCnt) + +/****************************************************************************/ +/** +* Return the next BD from BdPtr in a list. +* +* @param RingPtr is the DMA channel to operate on. +* @param BdPtr is the BD to operate on. +* +* @return The next BD in the list relative to the BdPtr parameter. +* +* @note +* C-style signature: +* XEmacPs_Bd *XEmacPs_BdRingNext(XEmacPs_BdRing* RingPtr, +* XEmacPs_Bd *BdPtr) +* +*****************************************************************************/ +#define XEmacPs_BdRingNext(RingPtr, BdPtr) \ + (((u32)(BdPtr) >= (RingPtr)->HighBdAddr) ? \ + (XEmacPs_Bd*)(RingPtr)->BaseBdAddr : \ + (XEmacPs_Bd*)((u32)(BdPtr) + (RingPtr)->Separation)) + +/****************************************************************************/ +/** +* Return the previous BD from BdPtr in the list. +* +* @param RingPtr is the DMA channel to operate on. +* @param BdPtr is the BD to operate on +* +* @return The previous BD in the list relative to the BdPtr parameter. +* +* @note +* C-style signature: +* XEmacPs_Bd *XEmacPs_BdRingPrev(XEmacPs_BdRing* RingPtr, +* XEmacPs_Bd *BdPtr) +* +*****************************************************************************/ +#define XEmacPs_BdRingPrev(RingPtr, BdPtr) \ + (((u32)(BdPtr) <= (RingPtr)->BaseBdAddr) ? \ + (XEmacPs_Bd*)(RingPtr)->HighBdAddr : \ + (XEmacPs_Bd*)((u32)(BdPtr) - (RingPtr)->Separation)) + +/************************** Function Prototypes ******************************/ + +/* + * Scatter gather DMA related functions in xemacps_bdring.c + */ +int XEmacPs_BdRingCreate(XEmacPs_BdRing * RingPtr, u32 PhysAddr, + u32 VirtAddr, u32 Alignment, unsigned BdCount); +int XEmacPs_BdRingClone(XEmacPs_BdRing * RingPtr, XEmacPs_Bd * SrcBdPtr, + u8 Direction); +int XEmacPs_BdRingAlloc(XEmacPs_BdRing * RingPtr, unsigned NumBd, + XEmacPs_Bd ** BdSetPtr); +int XEmacPs_BdRingUnAlloc(XEmacPs_BdRing * RingPtr, unsigned NumBd, + XEmacPs_Bd * BdSetPtr); +int XEmacPs_BdRingToHw(XEmacPs_BdRing * RingPtr, unsigned NumBd, + XEmacPs_Bd * BdSetPtr); +int XEmacPs_BdRingFree(XEmacPs_BdRing * RingPtr, unsigned NumBd, + XEmacPs_Bd * BdSetPtr); +unsigned XEmacPs_BdRingFromHwTx(XEmacPs_BdRing * RingPtr, unsigned BdLimit, + XEmacPs_Bd ** BdSetPtr); +unsigned XEmacPs_BdRingFromHwRx(XEmacPs_BdRing * RingPtr, unsigned BdLimit, + XEmacPs_Bd ** BdSetPtr); +int XEmacPs_BdRingCheck(XEmacPs_BdRing * RingPtr, u8 Direction); + +#ifdef __cplusplus +} +#endif + + +#endif /* end of protection macros */ diff --git a/XilinxProcessorIPLib/drivers/emacps/src/xemacps_control.c b/XilinxProcessorIPLib/drivers/emacps/src/xemacps_control.c new file mode 100755 index 00000000..67d55955 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/src/xemacps_control.c @@ -0,0 +1,1075 @@ +/* $Id: xemacps_control.c,v 1.1.2.1 2011/01/20 03:39:02 sadanan Exp $ */ +/****************************************************************************** +* +* Copyright (C) 2009 - 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 THE +* XILINX CONSORTIUM 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 xemacps_control.c + * + * Functions in this file implement general purpose command and control related + * functionality. See xemacps.h for a detailed description of the driver. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -------------------------------------------------------
+ * 1.00a wsy  01/10/10 First release
+ * 1.02a asa  11/05/12 Added a new API for deleting an entry from the HASH
+ *					   register. Added a new API for setting the BURST length
+ *					   in DMACR register.
+ * 
+ *****************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xemacps.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Definitions *****************************/ + + +/*****************************************************************************/ +/** + * Set the MAC address for this driver/device. The address is a 48-bit value. + * The device must be stopped before calling this function. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param AddressPtr is a pointer to a 6-byte MAC address. + * @param Index is a index to which MAC (1-4) address. + * + * @return + * - XST_SUCCESS if the MAC address was set successfully + * - XST_DEVICE_IS_STARTED if the device has not yet been stopped + * + *****************************************************************************/ +int XEmacPs_SetMacAddress(XEmacPs *InstancePtr, void *AddressPtr, u8 Index) +{ + u32 MacAddr; + u8 *Aptr = (u8 *) AddressPtr; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(AddressPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid((Index <= XEMACPS_MAX_MAC_ADDR) && (Index > 0)); + + /* Be sure device has been stopped */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + return (XST_DEVICE_IS_STARTED); + } + + /* Index ranges 1 to 4, for offset calculation is 0 to 3. */ + Index--; + + /* Set the MAC bits [31:0] in BOT */ + MacAddr = Aptr[0]; + MacAddr |= Aptr[1] << 8; + MacAddr |= Aptr[2] << 16; + MacAddr |= Aptr[3] << 24; + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + (XEMACPS_LADDR1L_OFFSET + Index * 8), MacAddr); + + /* There are reserved bits in TOP so don't affect them */ + MacAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + (XEMACPS_LADDR1H_OFFSET + (Index * 8))); + + MacAddr &= ~XEMACPS_LADDR_MACH_MASK; + + /* Set MAC bits [47:32] in TOP */ + MacAddr |= Aptr[4]; + MacAddr |= Aptr[5] << 8; + + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + (XEMACPS_LADDR1H_OFFSET + (Index * 8)), MacAddr); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Get the MAC address for this driver/device. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param AddressPtr is an output parameter, and is a pointer to a buffer into + * which the current MAC address will be copied. + * @param Index is a index to which MAC (1-4) address. + * + *****************************************************************************/ +void XEmacPs_GetMacAddress(XEmacPs *InstancePtr, void *AddressPtr, u8 Index) +{ + u32 MacAddr; + u8 *Aptr = (u8 *) AddressPtr; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(AddressPtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid((Index <= XEMACPS_MAX_MAC_ADDR) && (Index > 0)); + + /* Index ranges 1 to 4, for offset calculation is 0 to 3. */ + Index--; + + MacAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + (XEMACPS_LADDR1L_OFFSET + (Index * 8))); + 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 TOP */ + MacAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + (XEMACPS_LADDR1H_OFFSET + (Index * 8))); + Aptr[4] = (u8) MacAddr; + Aptr[5] = (u8) (MacAddr >> 8); +} + + +/*****************************************************************************/ +/** + * Set 48-bit MAC addresses in hash table. + * The device must be stopped before calling this function. + * + * The hash address register is 64 bits long and takes up two locations in + * the memory map. The least significant bits are stored in hash register + * bottom and the most significant bits in hash register top. + * + * The unicast hash enable and the multicast hash enable bits in the network + * configuration register enable the reception of hash matched frames. The + * destination address is reduced to a 6 bit index into the 64 bit hash + * register using the following hash function. The hash function is an XOR + * of every sixth bit of the destination address. + * + *
+ * hash_index[05] = da[05]^da[11]^da[17]^da[23]^da[29]^da[35]^da[41]^da[47]
+ * hash_index[04] = da[04]^da[10]^da[16]^da[22]^da[28]^da[34]^da[40]^da[46]
+ * hash_index[03] = da[03]^da[09]^da[15]^da[21]^da[27]^da[33]^da[39]^da[45]
+ * hash_index[02] = da[02]^da[08]^da[14]^da[20]^da[26]^da[32]^da[38]^da[44]
+ * hash_index[01] = da[01]^da[07]^da[13]^da[19]^da[25]^da[31]^da[37]^da[43]
+ * hash_index[00] = da[00]^da[06]^da[12]^da[18]^da[24]^da[30]^da[36]^da[42]
+ * 
+ * + * da[0] represents the least significant bit of the first byte received, + * that is, the multicast/unicast indicator, and da[47] represents the most + * significant bit of the last byte received. + * + * If the hash index points to a bit that is set in the hash register then + * the frame will be matched according to whether the frame is multicast + * or unicast. + * + * A multicast match will be signaled if the multicast hash enable bit is + * set, da[0] is logic 1 and the hash index points to a bit set in the hash + * register. + * + * A unicast match will be signaled if the unicast hash enable bit is set, + * da[0] is logic 0 and the hash index points to a bit set in the hash + * register. + * + * To receive all multicast frames, the hash register should be set with + * all ones and the multicast hash enable bit should be set in the network + * configuration register. + * + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param AddressPtr is a pointer to a 6-byte MAC address. + * + * @return + * - XST_SUCCESS if the HASH MAC address was set successfully + * - XST_DEVICE_IS_STARTED if the device has not yet been stopped + * - XST_INVALID_PARAM if the HASH MAC address passed in does not meet + * requirement after calculation + * + * @note + * Having Aptr be unsigned type prevents the following operations from sign + * extending. + *****************************************************************************/ +int XEmacPs_SetHash(XEmacPs *InstancePtr, void *AddressPtr) +{ + u32 HashAddr; + u8 *Aptr = (u8 *) AddressPtr; + u8 Temp1, Temp2, Temp3, Temp4, Temp5, Temp6, Temp7, Temp8; + int Result; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(AddressPtr != 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); + } + Temp1 = Aptr[0] & 0x3F; + Temp2 = ((Aptr[0] >> 6) & 0x3) | ((Aptr[1] & 0xF) << 2); + Temp3 = ((Aptr[1] >> 4) & 0xF) | ((Aptr[2] & 0x3) << 4); + Temp4 = ((Aptr[2] >> 2) & 0x3F); + Temp5 = Aptr[3] & 0x3F; + Temp6 = ((Aptr[3] >> 6) & 0x3) | ((Aptr[4] & 0xF) << 2); + Temp7 = ((Aptr[4] >> 4) & 0xF) | ((Aptr[5] & 0x3) << 4); + Temp8 = ((Aptr[5] >> 2) & 0x3F); + + Result = Temp1 ^ Temp2 ^ Temp3 ^ Temp4 ^ Temp5 ^ Temp6 ^ Temp7 ^ Temp8; + + if (Result >= XEMACPS_MAX_HASH_BITS) { + return (XST_INVALID_PARAM); + } + + if (Result < 32) { + HashAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_HASHL_OFFSET); + HashAddr |= (1 << Result); + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_HASHL_OFFSET, HashAddr); + } else { + HashAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_HASHH_OFFSET); + HashAddr |= (1 << (Result - 32)); + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_HASHH_OFFSET, HashAddr); + } + + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** + * Delete 48-bit MAC addresses in hash table. + * The device must be stopped before calling this function. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param AddressPtr is a pointer to a 6-byte MAC address. + * + * @return + * - XST_SUCCESS if the HASH MAC address was deleted successfully + * - XST_DEVICE_IS_STARTED if the device has not yet been stopped + * - XST_INVALID_PARAM if the HASH MAC address passed in does not meet + * requirement after calculation + * + * @note + * Having Aptr be unsigned type prevents the following operations from sign + * extending. + *****************************************************************************/ +int XEmacPs_DeleteHash(XEmacPs *InstancePtr, void *AddressPtr) +{ + u32 HashAddr; + u8 *Aptr = (u8 *) AddressPtr; + u8 Temp1, Temp2, Temp3, Temp4, Temp5, Temp6, Temp7, Temp8; + int Result; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(AddressPtr != 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); + } + Temp1 = Aptr[0] & 0x3F; + Temp2 = ((Aptr[0] >> 6) & 0x3) | ((Aptr[1] & 0xF) << 2); + Temp3 = ((Aptr[1] >> 4) & 0xF) | ((Aptr[2] & 0x3) << 4); + Temp4 = ((Aptr[2] >> 2) & 0x3F); + Temp5 = Aptr[3] & 0x3F; + Temp6 = ((Aptr[3] >> 6) & 0x3) | ((Aptr[4] & 0xF) << 2); + Temp7 = ((Aptr[4] >> 4) & 0xF) | ((Aptr[5] & 0x3) << 4); + Temp8 = ((Aptr[5] >> 2) & 0x3F); + + Result = Temp1 ^ Temp2 ^ Temp3 ^ Temp4 ^ Temp5 ^ Temp6 ^ Temp7 ^ Temp8; + + if (Result >= XEMACPS_MAX_HASH_BITS) { + return (XST_INVALID_PARAM); + } + + if (Result < 32) { + HashAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_HASHL_OFFSET); + HashAddr &= (~(1 << Result)); + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_HASHL_OFFSET, HashAddr); + } else { + HashAddr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_HASHH_OFFSET); + HashAddr &= (~(1 << (Result - 32))); + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_HASHH_OFFSET, HashAddr); + } + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Clear the Hash registers for the mac address pointed by AddressPtr. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * + *****************************************************************************/ +void XEmacPs_ClearHash(XEmacPs *InstancePtr) +{ + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_HASHL_OFFSET, 0x0); + + /* write bits [63:32] in TOP */ + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_HASHH_OFFSET, 0x0); +} + + +/*****************************************************************************/ +/** + * Get the Hash address for this driver/device. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param AddressPtr is an output parameter, and is a pointer to a buffer into + * which the current HASH MAC address will be copied. + * + *****************************************************************************/ +void XEmacPs_GetHash(XEmacPs *InstancePtr, void *AddressPtr) +{ + u32 *Aptr = (u32 *) AddressPtr; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(AddressPtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Aptr[0] = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_HASHL_OFFSET); + + /* Read Hash bits [63:32] in TOP */ + Aptr[1] = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_HASHH_OFFSET); +} + + +/*****************************************************************************/ +/** + * Set the Type ID match for this driver/device. The register is a 32-bit + * value. The device must be stopped before calling this function. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param Id_Check is type ID to be configured. + * @param Index is a index to which Type ID (1-4). + * + * @return + * - XST_SUCCESS if the MAC address was set successfully + * - XST_DEVICE_IS_STARTED if the device has not yet been stopped + * + *****************************************************************************/ +int XEmacPs_SetTypeIdCheck(XEmacPs *InstancePtr, u32 Id_Check, u8 Index) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertNonvoid((Index <= XEMACPS_MAX_TYPE_ID) && (Index > 0)); + + /* Be sure device has been stopped */ + if (InstancePtr->IsStarted == XIL_COMPONENT_IS_STARTED) { + return (XST_DEVICE_IS_STARTED); + } + + /* Index ranges 1 to 4, for offset calculation is 0 to 3. */ + Index--; + + /* Set the ID bits in MATCHx register */ + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + (XEMACPS_MATCH1_OFFSET + (Index * 4)), Id_Check); + + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** + * Set options for the driver/device. The driver should be stopped with + * XEmacPs_Stop() before changing options. + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param Options are the options to set. Multiple options can be set by OR'ing + * XTE_*_OPTIONS constants together. Options not specified are not + * affected. + * + * @return + * - XST_SUCCESS if the options were set successfully + * - XST_DEVICE_IS_STARTED if the device has not yet been stopped + * + * @note + * See xemacps.h for a description of the available options. + * + *****************************************************************************/ +int XEmacPs_SetOptions(XEmacPs *InstancePtr, u32 Options) +{ + u32 Reg; /* Generic register contents */ + u32 RegNetCfg; /* Reflects original contents of NET_CONFIG */ + u32 RegNewNetCfg; /* Reflects new contents of NET_CONFIG */ + + 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); + } + + /* Many of these options will change the NET_CONFIG registers. + * To reduce the amount of IO to the device, group these options here + * and change them all at once. + */ + + /* Grab current register contents */ + RegNetCfg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCFG_OFFSET); + RegNewNetCfg = RegNetCfg; + + /* + * It is configured to max 1536. + */ + if (Options & XEMACPS_FRAME1536_OPTION) { + RegNewNetCfg |= (XEMACPS_NWCFG_1536RXEN_MASK); + } + + /* Turn on VLAN packet only, only VLAN tagged will be accepted */ + if (Options & XEMACPS_VLAN_OPTION) { + RegNewNetCfg |= XEMACPS_NWCFG_NVLANDISC_MASK; + } + + /* Turn on FCS stripping on receive packets */ + if (Options & XEMACPS_FCS_STRIP_OPTION) { + RegNewNetCfg |= XEMACPS_NWCFG_FCSREM_MASK; + } + + /* Turn on length/type field checking on receive packets */ + if (Options & XEMACPS_LENTYPE_ERR_OPTION) { + RegNewNetCfg |= XEMACPS_NWCFG_LENGTHERRDSCRD_MASK; + } + + /* Turn on flow control */ + if (Options & XEMACPS_FLOW_CONTROL_OPTION) { + RegNewNetCfg |= XEMACPS_NWCFG_PAUSEEN_MASK; + } + + /* Turn on promiscuous frame filtering (all frames are received) */ + if (Options & XEMACPS_PROMISC_OPTION) { + RegNewNetCfg |= XEMACPS_NWCFG_COPYALLEN_MASK; + } + + /* Allow broadcast address reception */ + if (Options & XEMACPS_BROADCAST_OPTION) { + RegNewNetCfg &= ~XEMACPS_NWCFG_BCASTDI_MASK; + } + + /* Allow multicast address filtering */ + if (Options & XEMACPS_MULTICAST_OPTION) { + RegNewNetCfg |= XEMACPS_NWCFG_MCASTHASHEN_MASK; + } + + /* enable RX checksum offload */ + if (Options & XEMACPS_RX_CHKSUM_ENABLE_OPTION) { + RegNewNetCfg |= XEMACPS_NWCFG_RXCHKSUMEN_MASK; + } + + /* Officially change the NET_CONFIG registers if it needs to be + * modified. + */ + if (RegNetCfg != RegNewNetCfg) { + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCFG_OFFSET, RegNewNetCfg); + } + + /* Enable TX checksum offload */ + if (Options & XEMACPS_TX_CHKSUM_ENABLE_OPTION) { + Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_DMACR_OFFSET); + Reg |= XEMACPS_DMACR_TCPCKSUM_MASK; + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_DMACR_OFFSET, Reg); + } + + /* Enable transmitter */ + if (Options & XEMACPS_TRANSMITTER_ENABLE_OPTION) { + Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET); + Reg |= XEMACPS_NWCTRL_TXEN_MASK; + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET, Reg); + } + + /* Enable receiver */ + if (Options & XEMACPS_RECEIVER_ENABLE_OPTION) { + Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET); + Reg |= XEMACPS_NWCTRL_RXEN_MASK; + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET, Reg); + } + + /* The remaining options not handled here are managed elsewhere in the + * driver. No register modifications are needed at this time. Reflecting + * the option in InstancePtr->Options is good enough for now. + */ + + /* Set options word to its new value */ + InstancePtr->Options |= Options; + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Clear options for the driver/device + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param Options are the options to clear. Multiple options can be cleared by + * OR'ing XEMACPS_*_OPTIONS constants together. Options not specified + * are not affected. + * + * @return + * - XST_SUCCESS if the options were set successfully + * - XST_DEVICE_IS_STARTED if the device has not yet been stopped + * + * @note + * See xemacps.h for a description of the available options. + * + *****************************************************************************/ +int XEmacPs_ClearOptions(XEmacPs *InstancePtr, u32 Options) +{ + u32 Reg; /* Generic */ + u32 RegNetCfg; /* Reflects original contents of NET_CONFIG */ + u32 RegNewNetCfg; /* Reflects new contents of NET_CONFIG */ + + 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); + } + + /* Many of these options will change the NET_CONFIG registers. + * To reduce the amount of IO to the device, group these options here + * and change them all at once. + */ + + /* Grab current register contents */ + RegNetCfg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCFG_OFFSET); + RegNewNetCfg = RegNetCfg; + + /* There is only RX configuration!? + * It is configured in two different length, upto 1536 and 10240 bytes + */ + if (Options & XEMACPS_FRAME1536_OPTION) { + RegNewNetCfg &= ~XEMACPS_NWCFG_1536RXEN_MASK; + } + + /* Turn off VLAN packet only */ + if (Options & XEMACPS_VLAN_OPTION) { + RegNewNetCfg &= ~XEMACPS_NWCFG_NVLANDISC_MASK; + } + + /* Turn off FCS stripping on receive packets */ + if (Options & XEMACPS_FCS_STRIP_OPTION) { + RegNewNetCfg &= ~XEMACPS_NWCFG_FCSREM_MASK; + } + + /* Turn off length/type field checking on receive packets */ + if (Options & XEMACPS_LENTYPE_ERR_OPTION) { + RegNewNetCfg &= ~XEMACPS_NWCFG_LENGTHERRDSCRD_MASK; + } + + /* Turn off flow control */ + if (Options & XEMACPS_FLOW_CONTROL_OPTION) { + RegNewNetCfg &= ~XEMACPS_NWCFG_PAUSEEN_MASK; + } + + /* Turn off promiscuous frame filtering (all frames are received) */ + if (Options & XEMACPS_PROMISC_OPTION) { + RegNewNetCfg &= ~XEMACPS_NWCFG_COPYALLEN_MASK; + } + + /* Disallow broadcast address filtering => broadcast reception */ + if (Options & XEMACPS_BROADCAST_OPTION) { + RegNewNetCfg |= XEMACPS_NWCFG_BCASTDI_MASK; + } + + /* Disallow multicast address filtering */ + if (Options & XEMACPS_MULTICAST_OPTION) { + RegNewNetCfg &= ~XEMACPS_NWCFG_MCASTHASHEN_MASK; + } + + /* Disable RX checksum offload */ + if (Options & XEMACPS_RX_CHKSUM_ENABLE_OPTION) { + RegNewNetCfg &= ~XEMACPS_NWCFG_RXCHKSUMEN_MASK; + } + + /* Officially change the NET_CONFIG registers if it needs to be + * modified. + */ + if (RegNetCfg != RegNewNetCfg) { + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCFG_OFFSET, RegNewNetCfg); + } + + /* Disable TX checksum offload */ + if (Options & XEMACPS_TX_CHKSUM_ENABLE_OPTION) { + Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_DMACR_OFFSET); + Reg &= ~XEMACPS_DMACR_TCPCKSUM_MASK; + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_DMACR_OFFSET, Reg); + } + + /* Disable transmitter */ + if (Options & XEMACPS_TRANSMITTER_ENABLE_OPTION) { + Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET); + Reg &= ~XEMACPS_NWCTRL_TXEN_MASK; + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET, Reg); + } + + /* Disable receiver */ + if (Options & XEMACPS_RECEIVER_ENABLE_OPTION) { + Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET); + Reg &= ~XEMACPS_NWCTRL_RXEN_MASK; + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET, Reg); + } + + /* The remaining options not handled here are managed elsewhere in the + * driver. No register modifications are needed at this time. Reflecting + * option in InstancePtr->Options is good enough for now. + */ + + /* Set options word to its new value */ + InstancePtr->Options &= ~Options; + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** + * Get current option settings + * + * @param InstancePtr is a pointer to the instance to be worked on. + * + * @return + * A bitmask of XTE_*_OPTION constants. Any bit set to 1 is to be interpreted + * as a set opion. + * + * @note + * See xemacps.h for a description of the available options. + * + *****************************************************************************/ +u32 XEmacPs_GetOptions(XEmacPs *InstancePtr) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + return (InstancePtr->Options); +} + + +/*****************************************************************************/ +/** + * Send a pause packet + * + * @param InstancePtr is a pointer to the instance to be worked on. + * + * @return + * - XST_SUCCESS if pause frame transmission was initiated + * - XST_DEVICE_IS_STOPPED if the device has not been started. + * + *****************************************************************************/ +int XEmacPs_SendPausePacket(XEmacPs *InstancePtr) +{ + u32 Reg; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* Make sure device is ready for this operation */ + if (InstancePtr->IsStarted != XIL_COMPONENT_IS_STARTED) { + return (XST_DEVICE_IS_STOPPED); + } + + /* Send flow control frame */ + Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET); + Reg |= XEMACPS_NWCTRL_PAUSETX_MASK; + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET, Reg); + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** + * XEmacPs_GetOperatingSpeed gets the current operating link speed. This may + * be the value set by XEmacPs_SetOperatingSpeed() or a hardware default. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * + * @return XEmacPs_GetOperatingSpeed returns the link speed in units of + * megabits per second. + * + * @note + * + *****************************************************************************/ +u16 XEmacPs_GetOperatingSpeed(XEmacPs *InstancePtr) +{ + u32 Reg; + + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCFG_OFFSET); + + if (Reg & XEMACPS_NWCFG_1000_MASK) { + return (1000); + } else { + if (Reg & XEMACPS_NWCFG_100_MASK) { + return (100); + } else { + return (10); + } + } +} + + +/*****************************************************************************/ +/** + * XEmacPs_SetOperatingSpeed sets the current operating link speed. For any + * traffic to be passed, this speed must match the current MII/GMII/SGMII/RGMII + * link speed. + * + * @param InstancePtr references the TEMAC channel on which to operate. + * @param Speed is the speed to set in units of Mbps. Valid values are 10, 100, + * or 1000. XEmacPs_SetOperatingSpeed ignores invalid values. + * + * @note + * + *****************************************************************************/ +void XEmacPs_SetOperatingSpeed(XEmacPs *InstancePtr, u16 Speed) +{ + u32 Reg; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid((Speed == 10) || (Speed == 100) || (Speed == 1000)); + + Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCFG_OFFSET); + Reg &= ~(XEMACPS_NWCFG_1000_MASK | XEMACPS_NWCFG_100_MASK); + + switch (Speed) { + case 10: + break; + + case 100: + Reg |= XEMACPS_NWCFG_100_MASK; + break; + + case 1000: + Reg |= XEMACPS_NWCFG_1000_MASK; + break; + + default: + return; + } + + /* Set register and return */ + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCFG_OFFSET, Reg); +} + + +/*****************************************************************************/ +/** + * Set the MDIO clock divisor. + * + * Calculating the divisor: + * + *
+ *              f[HOSTCLK]
+ *   f[MDC] = -----------------
+ *            (1 + Divisor) * 2
+ * 
+ * + * where f[HOSTCLK] is the bus clock frequency in MHz, and f[MDC] is the + * MDIO clock frequency in MHz to the PHY. Typically, f[MDC] should not + * exceed 2.5 MHz. Some PHYs can tolerate faster speeds which means faster + * access. Here is the table to show values to generate MDC, + * + *
+ * 000 : divide pclk by   8 (pclk up to  20 MHz)
+ * 001 : divide pclk by  16 (pclk up to  40 MHz)
+ * 010 : divide pclk by  32 (pclk up to  80 MHz)
+ * 011 : divide pclk by  48 (pclk up to 120 MHz)
+ * 100 : divide pclk by  64 (pclk up to 160 MHz)
+ * 101 : divide pclk by  96 (pclk up to 240 MHz)
+ * 110 : divide pclk by 128 (pclk up to 320 MHz)
+ * 111 : divide pclk by 224 (pclk up to 540 MHz)
+ * 
+ * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param Divisor is the divisor to set. Range is 0b000 to 0b111. + * + *****************************************************************************/ +void XEmacPs_SetMdioDivisor(XEmacPs *InstancePtr, XEmacPs_MdcDiv Divisor) +{ + u32 Reg; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + Xil_AssertVoid(Divisor <= 0x7); /* only last three bits are valid */ + + Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCFG_OFFSET); + /* clear these three bits, could be done with mask */ + Reg &= ~XEMACPS_NWCFG_MDCCLKDIV_MASK; + + Reg |= (Divisor << XEMACPS_NWCFG_MDC_SHIFT_MASK); + + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCFG_OFFSET, Reg); + +} + + +/*****************************************************************************/ +/** +* Read the current value of the PHY register indicated by the PhyAddress and +* the RegisterNum parameters. The MAC provides the driver with the ability to +* talk to a PHY that adheres to the Media Independent Interface (MII) as +* defined in the IEEE 802.3 standard. +* +* Prior to PHY access with this function, the user should have setup the MDIO +* clock with XEmacPs_SetMdioDivisor(). +* +* @param InstancePtr is a pointer to the XEmacPs instance to be worked on. +* @param PhyAddress is the address of the PHY to be read (supports multiple +* PHYs) +* @param RegisterNum is the register number, 0-31, of the specific PHY register +* to read +* @param PhyDataPtr is an output parameter, and points to a 16-bit buffer into +* which the current value of the register will be copied. +* +* @return +* +* - XST_SUCCESS if the PHY was read from successfully +* - XST_EMAC_MII_BUSY if there is another PHY operation in progress +* +* @note +* +* This function is not thread-safe. The user must provide mutually exclusive +* access to this function if there are to be multiple threads that can call it. +* +* There is the possibility that this function will not return if the hardware +* is broken (i.e., it never sets the status bit indicating that the read is +* done). If this is of concern to the user, the user should provide a mechanism +* suitable to their needs for recovery. +* +* For the duration of this function, all host interface reads and writes are +* blocked to the current XEmacPs instance. +* +******************************************************************************/ +int XEmacPs_PhyRead(XEmacPs *InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 *PhyDataPtr) +{ + u32 Mgtcr; + volatile u32 Ipisr; + + Xil_AssertNonvoid(InstancePtr != NULL); + + /* Make sure no other PHY operation is currently in progress */ + if (!(XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWSR_OFFSET) & + XEMACPS_NWSR_MDIOIDLE_MASK)) { + return (XST_EMAC_MII_BUSY); + } + + /* Construct Mgtcr mask for the operation */ + Mgtcr = XEMACPS_PHYMNTNC_OP_MASK | XEMACPS_PHYMNTNC_OP_R_MASK | + (PhyAddress << XEMACPS_PHYMNTNC_PHYAD_SHIFT_MASK) | + (RegisterNum << XEMACPS_PHYMNTNC_PHREG_SHIFT_MASK); + + /* Write Mgtcr and wait for completion */ + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_PHYMNTNC_OFFSET, Mgtcr); + + do { + Ipisr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWSR_OFFSET); + } while ((Ipisr & XEMACPS_NWSR_MDIOIDLE_MASK) == 0); + + /* Read data */ + *PhyDataPtr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_PHYMNTNC_OFFSET); + + return (XST_SUCCESS); +} + + +/*****************************************************************************/ +/** +* Write data to the specified PHY register. The Ethernet driver does not +* require the device to be stopped before writing to the PHY. Although it is +* probably a good idea to stop the device, it is the responsibility of the +* application to deem this necessary. The MAC provides the driver with the +* ability to talk to a PHY that adheres to the Media Independent Interface +* (MII) as defined in the IEEE 802.3 standard. +* +* Prior to PHY access with this function, the user should have setup the MDIO +* clock with XEmacPs_SetMdioDivisor(). +* +* @param InstancePtr is a pointer to the XEmacPs instance to be worked on. +* @param PhyAddress is the address of the PHY to be written (supports multiple +* PHYs) +* @param RegisterNum is the register number, 0-31, of the specific PHY register +* to write +* @param PhyData is the 16-bit value that will be written to the register +* +* @return +* +* - XST_SUCCESS if the PHY was written to successfully. Since there is no error +* status from the MAC on a write, the user should read the PHY to verify the +* write was successful. +* - XST_EMAC_MII_BUSY if there is another PHY operation in progress +* +* @note +* +* This function is not thread-safe. The user must provide mutually exclusive +* access to this function if there are to be multiple threads that can call it. +* +* There is the possibility that this function will not return if the hardware +* is broken (i.e., it never sets the status bit indicating that the write is +* done). If this is of concern to the user, the user should provide a mechanism +* suitable to their needs for recovery. +* +* For the duration of this function, all host interface reads and writes are +* blocked to the current XEmacPs instance. +* +******************************************************************************/ +int XEmacPs_PhyWrite(XEmacPs *InstancePtr, u32 PhyAddress, + u32 RegisterNum, u16 PhyData) +{ + u32 Mgtcr; + volatile u32 Ipisr; + + Xil_AssertNonvoid(InstancePtr != NULL); + + /* Make sure no other PHY operation is currently in progress */ + if (!(XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWSR_OFFSET) & + XEMACPS_NWSR_MDIOIDLE_MASK)) { + return (XST_EMAC_MII_BUSY); + } + + /* Construct Mgtcr mask for the operation */ + Mgtcr = XEMACPS_PHYMNTNC_OP_MASK | XEMACPS_PHYMNTNC_OP_W_MASK | + (PhyAddress << XEMACPS_PHYMNTNC_PHYAD_SHIFT_MASK) | + (RegisterNum << XEMACPS_PHYMNTNC_PHREG_SHIFT_MASK) | PhyData; + + /* Write Mgtcr and wait for completion */ + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_PHYMNTNC_OFFSET, Mgtcr); + + do { + Ipisr = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWSR_OFFSET); + } while ((Ipisr & XEMACPS_NWSR_MDIOIDLE_MASK) == 0); + + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** +* API to update the Burst length in the DMACR register. +* +* @param InstancePtr is a pointer to the XEmacPs instance to be worked on. +* @param BLength is the length in bytes for the dma burst. +* +* @return None +* +******************************************************************************/ +void XEmacPs_DMABLengthUpdate(XEmacPs *InstancePtr, int BLength) +{ + u32 Reg; + u32 RegUpdateVal = 0; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid((BLength == XEMACPS_SINGLE_BURST) || + (BLength == XEMACPS_4BYTE_BURST) || + (BLength == XEMACPS_8BYTE_BURST) || + (BLength == XEMACPS_16BYTE_BURST)); + + switch (BLength) { + case XEMACPS_SINGLE_BURST: + RegUpdateVal = XEMACPS_DMACR_SINGLE_AHB_BURST; + break; + + case XEMACPS_4BYTE_BURST: + RegUpdateVal = XEMACPS_DMACR_INCR4_AHB_BURST; + break; + + case XEMACPS_8BYTE_BURST: + RegUpdateVal = XEMACPS_DMACR_INCR8_AHB_BURST; + break; + + case XEMACPS_16BYTE_BURST: + RegUpdateVal = XEMACPS_DMACR_INCR16_AHB_BURST; + break; + + default: + break; + } + Reg = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_DMACR_OFFSET); + + Reg &= (~XEMACPS_DMACR_BLENGTH_MASK); + Reg |= RegUpdateVal; + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_DMACR_OFFSET, + Reg); +} \ No newline at end of file diff --git a/XilinxProcessorIPLib/drivers/emacps/src/xemacps_g.c b/XilinxProcessorIPLib/drivers/emacps/src/xemacps_g.c new file mode 100755 index 00000000..5ed59361 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/src/xemacps_g.c @@ -0,0 +1,90 @@ +/* $Id: xemacps_g.c,v 1.1.2.1 2011/01/20 03:39:02 sadanan Exp $ */ +/****************************************************************************** +* +* 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 THE +* XILINX CONSORTIUM 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 xemacps_g.c +* +* This file contains a configuration table that specifies the configuration of +* ethernet devices in the system. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -----------------------------------------------
+* 1.00a wsy  01/10/10 First release
+* 2.00  hk   22/01/14 Added check for picking second instance
+* 
+* +* @internal +* +* This configuration table contains entries that are modified at runtime by the +* driver. This table reflects only the hardware configuration of the device. +* This emac configuration table contains software information in addition to +* hardware configuration. +* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xemacps.h" + +/************************** Constant Definitions *****************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Prototypes ******************************/ + +/* + * The configuration table for emacps device + */ + +XEmacPs_Config XEmacPs_ConfigTable[XPAR_XEMACPS_NUM_INSTANCES] = { + { + XPAR_XEMACPS_0_DEVICE_ID, /* Device ID */ + XPAR_XEMACPS_0_BASEADDR /* Device base address */ + }, +#ifdef XPAR_XEMACPS_1_DEVICE_ID + { + XPAR_XEMACPS_1_DEVICE_ID, /* Device ID */ + XPAR_XEMACPS_1_BASEADDR /* Device base address */ + } +#endif +}; diff --git a/XilinxProcessorIPLib/drivers/emacps/src/xemacps_hw.c b/XilinxProcessorIPLib/drivers/emacps/src/xemacps_hw.c new file mode 100755 index 00000000..290f27da --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/src/xemacps_hw.c @@ -0,0 +1,119 @@ +/****************************************************************************** +* +* 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 THE +* XILINX CONSORTIUM 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 xemacps_hw.c +* +* This file contains the implementation of the ethernet interface reset sequence +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.05a kpc  28/06/13 First release
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xemacps_hw.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ +/** +* This function perform the reset sequence to the given emacps interface by +* configuring the appropriate control bits in the emacps specifc registers. +* the emacps reset squence involves the following steps +* Disable all the interuupts +* Clear the status registers +* Disable Rx and Tx engines +* Update the Tx and Rx descriptor queue registers with reset values +* Update the other relevant control registers with reset value +* +* @param BaseAddress of the interface +* +* @return N/A +* +* @note +* This function will not modify the slcr registers that are relavant for +* emacps controller +******************************************************************************/ +void XEmacPs_ResetHw(u32 BaseAddr) +{ + u32 RegVal = 0; + + /* Disable the interrupts */ + XEmacPs_WriteReg(BaseAddr,XEMACPS_IDR_OFFSET,0x0); + + /* Stop transmission,disable loopback and Stop tx and Rx engines */ + RegVal = XEmacPs_ReadReg(BaseAddr,XEMACPS_NWCTRL_OFFSET); + RegVal &= ~(XEMACPS_NWCTRL_TXEN_MASK| + XEMACPS_NWCTRL_RXEN_MASK| + XEMACPS_NWCTRL_HALTTX_MASK| + XEMACPS_NWCTRL_LOOPEN_MASK); + /* Clear the statistic registers, flush the packets in DPRAM*/ + RegVal |= (XEMACPS_NWCTRL_STATCLR_MASK| + XEMACPS_NWCTRL_FLUSH_DPRAM_MASK); + XEmacPs_WriteReg(BaseAddr,XEMACPS_NWCTRL_OFFSET,RegVal); + /* Clear the interrupt status */ + XEmacPs_WriteReg(BaseAddr,XEMACPS_ISR_OFFSET,XEMACPS_IXR_ALL_MASK); + /* Clear the tx status */ + XEmacPs_WriteReg(BaseAddr,XEMACPS_TXSR_OFFSET,XEMACPS_TXSR_ERROR_MASK| + XEMACPS_TXSR_TXCOMPL_MASK| + XEMACPS_TXSR_TXGO_MASK); + /* Clear the rx status */ + XEmacPs_WriteReg(BaseAddr,XEMACPS_RXSR_OFFSET, + XEMACPS_RXSR_FRAMERX_MASK); + /* Clear the tx base address */ + XEmacPs_WriteReg(BaseAddr,XEMACPS_TXQBASE_OFFSET,0x0); + /* Clear the rx base address */ + XEmacPs_WriteReg(BaseAddr,XEMACPS_RXQBASE_OFFSET,0x0); + /* Update the network config register with reset value */ + XEmacPs_WriteReg(BaseAddr,XEMACPS_NWCFG_OFFSET,XEMACPS_NWCFG_RESET_MASK); + /* Update the hash address registers with reset value */ + XEmacPs_WriteReg(BaseAddr,XEMACPS_HASHL_OFFSET,0x0); + XEmacPs_WriteReg(BaseAddr,XEMACPS_HASHH_OFFSET,0x0); +} diff --git a/XilinxProcessorIPLib/drivers/emacps/src/xemacps_hw.h b/XilinxProcessorIPLib/drivers/emacps/src/xemacps_hw.h new file mode 100755 index 00000000..faba5942 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/src/xemacps_hw.h @@ -0,0 +1,596 @@ +/****************************************************************************** +* +* 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 THE +* XILINX CONSORTIUM 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 xemacps_hw.h +* +* This header file contains identifiers and low-level driver functions (or +* macros) that can be used to access the PS Ethernet MAC (XEmacPs) device. +* High-level driver functions are defined in xemacps.h. +* +* @note +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a wsy  01/10/10 First release.
+* 1.02a asa  11/05/12 Added hash defines for DMACR burst length configuration.
+* 1.05a kpc  28/06/13 Added XEmacPs_ResetHw function prototype
+* 1.06a asa  11/02/13 Changed the value for XEMACPS_RXBUF_LEN_MASK from 0x3fff
+*					  to 0x1fff. This fixes the CR#744902.
+* 
+* +******************************************************************************/ + +#ifndef XEMACPS_HW_H /* prevent circular inclusions */ +#define XEMACPS_HW_H /* by using protection macros */ + +/***************************** Include Files *********************************/ + +#include "xil_types.h" +#include "xil_assert.h" +#include "xil_io.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/************************** Constant Definitions *****************************/ + +#define XEMACPS_MAX_MAC_ADDR 4 /**< Maxmum number of mac address + supported */ +#define XEMACPS_MAX_TYPE_ID 4 /**< Maxmum number of type id supported */ +#define XEMACPS_BD_ALIGNMENT 4 /**< Minimum buffer descriptor alignment + on the local bus */ +#define XEMACPS_RX_BUF_ALIGNMENT 4 /**< Minimum buffer alignment when using + options that impose alignment + restrictions on the buffer data on + the local bus */ + +/** @name Direction identifiers + * + * These are used by several functions and callbacks that need + * to specify whether an operation specifies a send or receive channel. + * @{ + */ +#define XEMACPS_SEND 1 /**< send direction */ +#define XEMACPS_RECV 2 /**< receive direction */ +/*@}*/ + +/** @name MDC clock division + * currently supporting 8, 16, 32, 48, 64, 96, 128, 224. + * @{ + */ +typedef enum { MDC_DIV_8 = 0, MDC_DIV_16, MDC_DIV_32, MDC_DIV_48, + MDC_DIV_64, MDC_DIV_96, MDC_DIV_128, MDC_DIV_224 +} XEmacPs_MdcDiv; + +/*@}*/ + +#define XEMACPS_RX_BUF_SIZE 1536 /**< Specify the receive buffer size in + bytes, 64, 128, ... 10240 */ +#define XEMACPS_RX_BUF_UNIT 64 /**< Number of receive buffer bytes as a + unit, this is HW setup */ + +#define XEMACPS_MAX_RXBD 128 /**< Size of RX buffer descriptor queues */ +#define XEMACPS_MAX_TXBD 128 /**< Size of TX buffer descriptor queues */ + +#define XEMACPS_MAX_HASH_BITS 64 /**< Maximum value for hash bits. 2**6 */ + +/* Register offset definitions. Unless otherwise noted, register access is + * 32 bit. Names are self explained here. + */ + +#define XEMACPS_NWCTRL_OFFSET 0x00000000 /**< Network Control reg */ +#define XEMACPS_NWCFG_OFFSET 0x00000004 /**< Network Config reg */ +#define XEMACPS_NWSR_OFFSET 0x00000008 /**< Network Status reg */ + +#define XEMACPS_DMACR_OFFSET 0x00000010 /**< DMA Control reg */ +#define XEMACPS_TXSR_OFFSET 0x00000014 /**< TX Status reg */ +#define XEMACPS_RXQBASE_OFFSET 0x00000018 /**< RX Q Base address reg */ +#define XEMACPS_TXQBASE_OFFSET 0x0000001C /**< TX Q Base address reg */ +#define XEMACPS_RXSR_OFFSET 0x00000020 /**< RX Status reg */ + +#define XEMACPS_ISR_OFFSET 0x00000024 /**< Interrupt Status reg */ +#define XEMACPS_IER_OFFSET 0x00000028 /**< Interrupt Enable reg */ +#define XEMACPS_IDR_OFFSET 0x0000002C /**< Interrupt Disable reg */ +#define XEMACPS_IMR_OFFSET 0x00000030 /**< Interrupt Mask reg */ + +#define XEMACPS_PHYMNTNC_OFFSET 0x00000034 /**< Phy Maintaince reg */ +#define XEMACPS_RXPAUSE_OFFSET 0x00000038 /**< RX Pause Time reg */ +#define XEMACPS_TXPAUSE_OFFSET 0x0000003C /**< TX Pause Time reg */ + +#define XEMACPS_HASHL_OFFSET 0x00000080 /**< Hash Low address reg */ +#define XEMACPS_HASHH_OFFSET 0x00000084 /**< Hash High address reg */ + +#define XEMACPS_LADDR1L_OFFSET 0x00000088 /**< Specific1 addr low reg */ +#define XEMACPS_LADDR1H_OFFSET 0x0000008C /**< Specific1 addr high reg */ +#define XEMACPS_LADDR2L_OFFSET 0x00000090 /**< Specific2 addr low reg */ +#define XEMACPS_LADDR2H_OFFSET 0x00000094 /**< Specific2 addr high reg */ +#define XEMACPS_LADDR3L_OFFSET 0x00000098 /**< Specific3 addr low reg */ +#define XEMACPS_LADDR3H_OFFSET 0x0000009C /**< Specific3 addr high reg */ +#define XEMACPS_LADDR4L_OFFSET 0x000000A0 /**< Specific4 addr low reg */ +#define XEMACPS_LADDR4H_OFFSET 0x000000A4 /**< Specific4 addr high reg */ + +#define XEMACPS_MATCH1_OFFSET 0x000000A8 /**< Type ID1 Match reg */ +#define XEMACPS_MATCH2_OFFSET 0x000000AC /**< Type ID2 Match reg */ +#define XEMACPS_MATCH3_OFFSET 0x000000B0 /**< Type ID3 Match reg */ +#define XEMACPS_MATCH4_OFFSET 0x000000B4 /**< Type ID4 Match reg */ + +#define XEMACPS_STRETCH_OFFSET 0x000000BC /**< IPG Stretch reg */ + +#define XEMACPS_OCTTXL_OFFSET 0x00000100 /**< Octects transmitted Low + reg */ +#define XEMACPS_OCTTXH_OFFSET 0x00000104 /**< Octects transmitted High + reg */ + +#define XEMACPS_TXCNT_OFFSET 0x00000108 /**< Error-free Frmaes + transmitted counter */ +#define XEMACPS_TXBCCNT_OFFSET 0x0000010C /**< Error-free Broadcast + Frames counter*/ +#define XEMACPS_TXMCCNT_OFFSET 0x00000110 /**< Error-free Multicast + Frame counter */ +#define XEMACPS_TXPAUSECNT_OFFSET 0x00000114 /**< Pause Frames Transmitted + Counter */ +#define XEMACPS_TX64CNT_OFFSET 0x00000118 /**< Error-free 64 byte Frames + Transmitted counter */ +#define XEMACPS_TX65CNT_OFFSET 0x0000011C /**< Error-free 65-127 byte + Frames Transmitted + counter */ +#define XEMACPS_TX128CNT_OFFSET 0x00000120 /**< Error-free 128-255 byte + Frames Transmitted + counter*/ +#define XEMACPS_TX256CNT_OFFSET 0x00000124 /**< Error-free 256-511 byte + Frames transmitted + counter */ +#define XEMACPS_TX512CNT_OFFSET 0x00000128 /**< Error-free 512-1023 byte + Frames transmitted + counter */ +#define XEMACPS_TX1024CNT_OFFSET 0x0000012C /**< Error-free 1024-1518 byte + Frames transmitted + counter */ +#define XEMACPS_TX1519CNT_OFFSET 0x00000130 /**< Error-free larger than + 1519 byte Frames + transmitted counter */ +#define XEMACPS_TXURUNCNT_OFFSET 0x00000134 /**< TX under run error + counter */ + +#define XEMACPS_SNGLCOLLCNT_OFFSET 0x00000138 /**< Single Collision Frame + Counter */ +#define XEMACPS_MULTICOLLCNT_OFFSET 0x0000013C /**< Multiple Collision Frame + Counter */ +#define XEMACPS_EXCESSCOLLCNT_OFFSET 0x00000140 /**< Excessive Collision Frame + Counter */ +#define XEMACPS_LATECOLLCNT_OFFSET 0x00000144 /**< Late Collision Frame + Counter */ +#define XEMACPS_TXDEFERCNT_OFFSET 0x00000148 /**< Deferred Transmission + Frame Counter */ +#define XEMACPS_TXCSENSECNT_OFFSET 0x0000014C /**< Transmit Carrier Sense + Error Counter */ + +#define XEMACPS_OCTRXL_OFFSET 0x00000150 /**< Octects Received register + Low */ +#define XEMACPS_OCTRXH_OFFSET 0x00000154 /**< Octects Received register + High */ + +#define XEMACPS_RXCNT_OFFSET 0x00000158 /**< Error-free Frames + Received Counter */ +#define XEMACPS_RXBROADCNT_OFFSET 0x0000015C /**< Error-free Broadcast + Frames Received Counter */ +#define XEMACPS_RXMULTICNT_OFFSET 0x00000160 /**< Error-free Multicast + Frames Received Counter */ +#define XEMACPS_RXPAUSECNT_OFFSET 0x00000164 /**< Pause Frames + Received Counter */ +#define XEMACPS_RX64CNT_OFFSET 0x00000168 /**< Error-free 64 byte Frames + Received Counter */ +#define XEMACPS_RX65CNT_OFFSET 0x0000016C /**< Error-free 65-127 byte + Frames Received Counter */ +#define XEMACPS_RX128CNT_OFFSET 0x00000170 /**< Error-free 128-255 byte + Frames Received Counter */ +#define XEMACPS_RX256CNT_OFFSET 0x00000174 /**< Error-free 256-512 byte + Frames Received Counter */ +#define XEMACPS_RX512CNT_OFFSET 0x00000178 /**< Error-free 512-1023 byte + Frames Received Counter */ +#define XEMACPS_RX1024CNT_OFFSET 0x0000017C /**< Error-free 1024-1518 byte + Frames Received Counter */ +#define XEMACPS_RX1519CNT_OFFSET 0x00000180 /**< Error-free 1519-max byte + Frames Received Counter */ +#define XEMACPS_RXUNDRCNT_OFFSET 0x00000184 /**< Undersize Frames Received + Counter */ +#define XEMACPS_RXOVRCNT_OFFSET 0x00000188 /**< Oversize Frames Received + Counter */ +#define XEMACPS_RXJABCNT_OFFSET 0x0000018C /**< Jabbers Received + Counter */ +#define XEMACPS_RXFCSCNT_OFFSET 0x00000190 /**< Frame Check Sequence + Error Counter */ +#define XEMACPS_RXLENGTHCNT_OFFSET 0x00000194 /**< Length Field Error + Counter */ +#define XEMACPS_RXSYMBCNT_OFFSET 0x00000198 /**< Symbol Error Counter */ +#define XEMACPS_RXALIGNCNT_OFFSET 0x0000019C /**< Alignment Error Counter */ +#define XEMACPS_RXRESERRCNT_OFFSET 0x000001A0 /**< Receive Resource Error + Counter */ +#define XEMACPS_RXORCNT_OFFSET 0x000001A4 /**< Receive Overrun Counter */ +#define XEMACPS_RXIPCCNT_OFFSET 0x000001A8 /**< IP header Checksum Error + Counter */ +#define XEMACPS_RXTCPCCNT_OFFSET 0x000001AC /**< TCP Checksum Error + Counter */ +#define XEMACPS_RXUDPCCNT_OFFSET 0x000001B0 /**< UDP Checksum Error + Counter */ +#define XEMACPS_LAST_OFFSET 0x000001B4 /**< Last statistic counter + offset, for clearing */ + +#define XEMACPS_1588_SEC_OFFSET 0x000001D0 /**< 1588 second counter */ +#define XEMACPS_1588_NANOSEC_OFFSET 0x000001D4 /**< 1588 nanosecond counter */ +#define XEMACPS_1588_ADJ_OFFSET 0x000001D8 /**< 1588 nanosecond + adjustment counter */ +#define XEMACPS_1588_INC_OFFSET 0x000001DC /**< 1588 nanosecond + increment counter */ +#define XEMACPS_PTP_TXSEC_OFFSET 0x000001E0 /**< 1588 PTP transmit second + counter */ +#define XEMACPS_PTP_TXNANOSEC_OFFSET 0x000001E4 /**< 1588 PTP transmit + nanosecond counter */ +#define XEMACPS_PTP_RXSEC_OFFSET 0x000001E8 /**< 1588 PTP receive second + counter */ +#define XEMACPS_PTP_RXNANOSEC_OFFSET 0x000001EC /**< 1588 PTP receive + nanosecond counter */ +#define XEMACPS_PTPP_TXSEC_OFFSET 0x000001F0 /**< 1588 PTP peer transmit + second counter */ +#define XEMACPS_PTPP_TXNANOSEC_OFFSET 0x000001F4 /**< 1588 PTP peer transmit + nanosecond counter */ +#define XEMACPS_PTPP_RXSEC_OFFSET 0x000001F8 /**< 1588 PTP peer receive + second counter */ +#define XEMACPS_PTPP_RXNANOSEC_OFFSET 0x000001FC /**< 1588 PTP peer receive + nanosecond counter */ + +/* Define some bit positions for registers. */ + +/** @name network control register bit definitions + * @{ + */ +#define XEMACPS_NWCTRL_FLUSH_DPRAM_MASK 0x00040000 /**< Flush a packet from + Rx SRAM */ +#define XEMACPS_NWCTRL_ZEROPAUSETX_MASK 0x00000800 /**< Transmit zero quantum + pause frame */ +#define XEMACPS_NWCTRL_PAUSETX_MASK 0x00000800 /**< Transmit pause frame */ +#define XEMACPS_NWCTRL_HALTTX_MASK 0x00000400 /**< Halt transmission + after current frame */ +#define XEMACPS_NWCTRL_STARTTX_MASK 0x00000200 /**< Start tx (tx_go) */ + +#define XEMACPS_NWCTRL_STATWEN_MASK 0x00000080 /**< Enable writing to + stat counters */ +#define XEMACPS_NWCTRL_STATINC_MASK 0x00000040 /**< Increment statistic + registers */ +#define XEMACPS_NWCTRL_STATCLR_MASK 0x00000020 /**< Clear statistic + registers */ +#define XEMACPS_NWCTRL_MDEN_MASK 0x00000010 /**< Enable MDIO port */ +#define XEMACPS_NWCTRL_TXEN_MASK 0x00000008 /**< Enable transmit */ +#define XEMACPS_NWCTRL_RXEN_MASK 0x00000004 /**< Enable receive */ +#define XEMACPS_NWCTRL_LOOPEN_MASK 0x00000002 /**< local loopback */ +/*@}*/ + +/** @name network configuration register bit definitions + * @{ + */ +#define XEMACPS_NWCFG_BADPREAMBEN_MASK 0x20000000 /**< disable rejection of + non-standard preamble */ +#define XEMACPS_NWCFG_IPDSTRETCH_MASK 0x10000000 /**< enable transmit IPG */ +#define XEMACPS_NWCFG_FCSIGNORE_MASK 0x04000000 /**< disable rejection of + FCS error */ +#define XEMACPS_NWCFG_HDRXEN_MASK 0x02000000 /**< RX half duplex */ +#define XEMACPS_NWCFG_RXCHKSUMEN_MASK 0x01000000 /**< enable RX checksum + offload */ +#define XEMACPS_NWCFG_PAUSECOPYDI_MASK 0x00800000 /**< Do not copy pause + Frames to memory */ +#define XEMACPS_NWCFG_MDC_SHIFT_MASK 18 /**< shift bits for MDC */ +#define XEMACPS_NWCFG_MDCCLKDIV_MASK 0x001C0000 /**< MDC Mask PCLK divisor */ +#define XEMACPS_NWCFG_FCSREM_MASK 0x00020000 /**< Discard FCS from + received frames */ +#define XEMACPS_NWCFG_LENGTHERRDSCRD_MASK 0x00010000 +/**< RX length error discard */ +#define XEMACPS_NWCFG_RXOFFS_MASK 0x0000C000 /**< RX buffer offset */ +#define XEMACPS_NWCFG_PAUSEEN_MASK 0x00002000 /**< Enable pause RX */ +#define XEMACPS_NWCFG_RETRYTESTEN_MASK 0x00001000 /**< Retry test */ +#define XEMACPS_NWCFG_EXTADDRMATCHEN_MASK 0x00000200 +/**< External address match enable */ +#define XEMACPS_NWCFG_1000_MASK 0x00000400 /**< 1000 Mbps */ +#define XEMACPS_NWCFG_1536RXEN_MASK 0x00000100 /**< Enable 1536 byte + frames reception */ +#define XEMACPS_NWCFG_UCASTHASHEN_MASK 0x00000080 /**< Receive unicast hash + frames */ +#define XEMACPS_NWCFG_MCASTHASHEN_MASK 0x00000040 /**< Receive multicast hash + frames */ +#define XEMACPS_NWCFG_BCASTDI_MASK 0x00000020 /**< Do not receive + broadcast frames */ +#define XEMACPS_NWCFG_COPYALLEN_MASK 0x00000010 /**< Copy all frames */ +#define XEMACPS_NWCFG_JUMBO_MASK 0x00000008 /**< Jumbo frames */ +#define XEMACPS_NWCFG_NVLANDISC_MASK 0x00000004 /**< Receive only VLAN + frames */ +#define XEMACPS_NWCFG_FDEN_MASK 0x00000002 /**< full duplex */ +#define XEMACPS_NWCFG_100_MASK 0x00000001 /**< 100 Mbps */ +#define XEMACPS_NWCFG_RESET_MASK 0x00080000 /**< reset value */ +/*@}*/ + +/** @name network status register bit definitaions + * @{ + */ +#define XEMACPS_NWSR_MDIOIDLE_MASK 0x00000004 /**< PHY management idle */ +#define XEMACPS_NWSR_MDIO_MASK 0x00000002 /**< Status of mdio_in */ +/*@}*/ + + +/** @name MAC address register word 1 mask + * @{ + */ +#define XEMACPS_LADDR_MACH_MASK 0x0000FFFF /**< Address bits[47:32] + bit[31:0] are in BOTTOM */ +/*@}*/ + + +/** @name DMA control register bit definitions + * @{ + */ +#define XEMACPS_DMACR_RXBUF_MASK 0x00FF0000 /**< Mask bit for RX buffer + size */ +#define XEMACPS_DMACR_RXBUF_SHIFT 16 /**< Shift bit for RX buffer + size */ +#define XEMACPS_DMACR_TCPCKSUM_MASK 0x00000800 /**< enable/disable TX + checksum offload */ +#define XEMACPS_DMACR_TXSIZE_MASK 0x00000400 /**< TX buffer memory size */ +#define XEMACPS_DMACR_RXSIZE_MASK 0x00000300 /**< RX buffer memory size */ +#define XEMACPS_DMACR_ENDIAN_MASK 0x00000080 /**< endian configuration */ +#define XEMACPS_DMACR_BLENGTH_MASK 0x0000001F /**< buffer burst length */ +#define XEMACPS_DMACR_SINGLE_AHB_BURST 0x00000001 /**< single AHB bursts */ +#define XEMACPS_DMACR_INCR4_AHB_BURST 0x00000004 /**< 4 bytes AHB bursts */ +#define XEMACPS_DMACR_INCR8_AHB_BURST 0x00000008 /**< 8 bytes AHB bursts */ +#define XEMACPS_DMACR_INCR16_AHB_BURST 0x00000010 /**< 16 bytes AHB bursts */ +/*@}*/ + +/** @name transmit status register bit definitions + * @{ + */ +#define XEMACPS_TXSR_HRESPNOK_MASK 0x00000100 /**< Transmit hresp not OK */ +#define XEMACPS_TXSR_URUN_MASK 0x00000040 /**< Transmit underrun */ +#define XEMACPS_TXSR_TXCOMPL_MASK 0x00000020 /**< Transmit completed OK */ +#define XEMACPS_TXSR_BUFEXH_MASK 0x00000010 /**< Transmit buffs exhausted + mid frame */ +#define XEMACPS_TXSR_TXGO_MASK 0x00000008 /**< Status of go flag */ +#define XEMACPS_TXSR_RXOVR_MASK 0x00000004 /**< Retry limit exceeded */ +#define XEMACPS_TXSR_FRAMERX_MASK 0x00000002 /**< Collision tx frame */ +#define XEMACPS_TXSR_USEDREAD_MASK 0x00000001 /**< TX buffer used bit set */ + +#define XEMACPS_TXSR_ERROR_MASK (XEMACPS_TXSR_HRESPNOK_MASK | \ + XEMACPS_TXSR_URUN_MASK | \ + XEMACPS_TXSR_BUFEXH_MASK | \ + XEMACPS_TXSR_RXOVR_MASK | \ + XEMACPS_TXSR_FRAMERX_MASK | \ + XEMACPS_TXSR_USEDREAD_MASK) +/*@}*/ + +/** + * @name receive status register bit definitions + * @{ + */ +#define XEMACPS_RXSR_HRESPNOK_MASK 0x00000008 /**< Receive hresp not OK */ +#define XEMACPS_RXSR_RXOVR_MASK 0x00000004 /**< Receive overrun */ +#define XEMACPS_RXSR_FRAMERX_MASK 0x00000002 /**< Frame received OK */ +#define XEMACPS_RXSR_BUFFNA_MASK 0x00000001 /**< RX buffer used bit set */ + +#define XEMACPS_RXSR_ERROR_MASK (XEMACPS_RXSR_HRESPNOK_MASK | \ + XEMACPS_RXSR_RXOVR_MASK | \ + XEMACPS_RXSR_BUFFNA_MASK) +/*@}*/ + +/** + * @name interrupts bit definitions + * Bits definitions are same in XEMACPS_ISR_OFFSET, + * XEMACPS_IER_OFFSET, XEMACPS_IDR_OFFSET, and XEMACPS_IMR_OFFSET + * @{ + */ +#define XEMACPS_IXR_PTPPSTX_MASK 0x02000000 /**< PTP Psync transmitted */ +#define XEMACPS_IXR_PTPPDRTX_MASK 0x01000000 /**< PTP Pdelay_req + transmitted */ +#define XEMACPS_IXR_PTPSTX_MASK 0x00800000 /**< PTP Sync transmitted */ +#define XEMACPS_IXR_PTPDRTX_MASK 0x00400000 /**< PTP Delay_req transmitted + */ +#define XEMACPS_IXR_PTPPSRX_MASK 0x00200000 /**< PTP Psync received */ +#define XEMACPS_IXR_PTPPDRRX_MASK 0x00100000 /**< PTP Pdelay_req received */ +#define XEMACPS_IXR_PTPSRX_MASK 0x00080000 /**< PTP Sync received */ +#define XEMACPS_IXR_PTPDRRX_MASK 0x00040000 /**< PTP Delay_req received */ +#define XEMACPS_IXR_PAUSETX_MASK 0x00004000 /**< Pause frame transmitted */ +#define XEMACPS_IXR_PAUSEZERO_MASK 0x00002000 /**< Pause time has reached + zero */ +#define XEMACPS_IXR_PAUSENZERO_MASK 0x00001000 /**< Pause frame received */ +#define XEMACPS_IXR_HRESPNOK_MASK 0x00000800 /**< hresp not ok */ +#define XEMACPS_IXR_RXOVR_MASK 0x00000400 /**< Receive overrun occurred */ +#define XEMACPS_IXR_TXCOMPL_MASK 0x00000080 /**< Frame transmitted ok */ +#define XEMACPS_IXR_TXEXH_MASK 0x00000040 /**< Transmit err occurred or + no buffers*/ +#define XEMACPS_IXR_RETRY_MASK 0x00000020 /**< Retry limit exceeded */ +#define XEMACPS_IXR_URUN_MASK 0x00000010 /**< Transmit underrun */ +#define XEMACPS_IXR_TXUSED_MASK 0x00000008 /**< Tx buffer used bit read */ +#define XEMACPS_IXR_RXUSED_MASK 0x00000004 /**< Rx buffer used bit read */ +#define XEMACPS_IXR_FRAMERX_MASK 0x00000002 /**< Frame received ok */ +#define XEMACPS_IXR_MGMNT_MASK 0x00000001 /**< PHY management complete */ +#define XEMACPS_IXR_ALL_MASK 0x00007FFF /**< Everything! */ + +#define XEMACPS_IXR_TX_ERR_MASK (XEMACPS_IXR_TXEXH_MASK | \ + XEMACPS_IXR_RETRY_MASK | \ + XEMACPS_IXR_URUN_MASK | \ + XEMACPS_IXR_TXUSED_MASK) + + +#define XEMACPS_IXR_RX_ERR_MASK (XEMACPS_IXR_HRESPNOK_MASK | \ + XEMACPS_IXR_RXUSED_MASK | \ + XEMACPS_IXR_RXOVR_MASK) + +/*@}*/ + +/** @name PHY Maintenance bit definitions + * @{ + */ +#define XEMACPS_PHYMNTNC_OP_MASK 0x40020000 /**< operation mask bits */ +#define XEMACPS_PHYMNTNC_OP_R_MASK 0x20000000 /**< read operation */ +#define XEMACPS_PHYMNTNC_OP_W_MASK 0x10000000 /**< write operation */ +#define XEMACPS_PHYMNTNC_ADDR_MASK 0x0F800000 /**< Address bits */ +#define XEMACPS_PHYMNTNC_REG_MASK 0x007C0000 /**< register bits */ +#define XEMACPS_PHYMNTNC_DATA_MASK 0x00000FFF /**< data bits */ +#define XEMACPS_PHYMNTNC_PHYAD_SHIFT_MASK 23 /**< Shift bits for PHYAD */ +#define XEMACPS_PHYMNTNC_PHREG_SHIFT_MASK 18 /**< Shift bits for PHREG */ +/*@}*/ + +/* Transmit buffer descriptor status words offset + * @{ + */ +#define XEMACPS_BD_ADDR_OFFSET 0x00000000 /**< word 0/addr of BDs */ +#define XEMACPS_BD_STAT_OFFSET 0x00000004 /**< word 1/status of BDs */ +/* + * @} + */ + +/* Transmit buffer descriptor status words bit positions. + * Transmit buffer descriptor consists of two 32-bit registers, + * the first - word0 contains a 32-bit address pointing to the location of + * the transmit data. + * The following register - word1, consists of various information to control + * the XEmacPs transmit process. After transmit, this is updated with status + * information, whether the frame was transmitted OK or why it had failed. + * @{ + */ +#define XEMACPS_TXBUF_USED_MASK 0x80000000 /**< Used bit. */ +#define XEMACPS_TXBUF_WRAP_MASK 0x40000000 /**< Wrap bit, last descriptor */ +#define XEMACPS_TXBUF_RETRY_MASK 0x20000000 /**< Retry limit exceeded */ +#define XEMACPS_TXBUF_URUN_MASK 0x10000000 /**< Transmit underrun occurred */ +#define XEMACPS_TXBUF_EXH_MASK 0x08000000 /**< Buffers exhausted */ +#define XEMACPS_TXBUF_TCP_MASK 0x04000000 /**< Late collision. */ +#define XEMACPS_TXBUF_NOCRC_MASK 0x00010000 /**< No CRC */ +#define XEMACPS_TXBUF_LAST_MASK 0x00008000 /**< Last buffer */ +#define XEMACPS_TXBUF_LEN_MASK 0x00003FFF /**< Mask for length field */ +/* + * @} + */ + +/* Receive buffer descriptor status words bit positions. + * Receive buffer descriptor consists of two 32-bit registers, + * the first - word0 contains a 32-bit word aligned address pointing to the + * address of the buffer. The lower two bits make up the wrap bit indicating + * the last descriptor and the ownership bit to indicate it has been used by + * the XEmacPs. + * The following register - word1, contains status information regarding why + * the frame was received (the filter match condition) as well as other + * useful info. + * @{ + */ +#define XEMACPS_RXBUF_BCAST_MASK 0x80000000 /**< Broadcast frame */ +#define XEMACPS_RXBUF_MULTIHASH_MASK 0x40000000 /**< Multicast hashed frame */ +#define XEMACPS_RXBUF_UNIHASH_MASK 0x20000000 /**< Unicast hashed frame */ +#define XEMACPS_RXBUF_EXH_MASK 0x08000000 /**< buffer exhausted */ +#define XEMACPS_RXBUF_AMATCH_MASK 0x06000000 /**< Specific address + matched */ +#define XEMACPS_RXBUF_IDFOUND_MASK 0x01000000 /**< Type ID matched */ +#define XEMACPS_RXBUF_IDMATCH_MASK 0x00C00000 /**< ID matched mask */ +#define XEMACPS_RXBUF_VLAN_MASK 0x00200000 /**< VLAN tagged */ +#define XEMACPS_RXBUF_PRI_MASK 0x00100000 /**< Priority tagged */ +#define XEMACPS_RXBUF_VPRI_MASK 0x000E0000 /**< Vlan priority */ +#define XEMACPS_RXBUF_CFI_MASK 0x00010000 /**< CFI frame */ +#define XEMACPS_RXBUF_EOF_MASK 0x00008000 /**< End of frame. */ +#define XEMACPS_RXBUF_SOF_MASK 0x00004000 /**< Start of frame. */ +#define XEMACPS_RXBUF_LEN_MASK 0x00001FFF /**< Mask for length field */ + +#define XEMACPS_RXBUF_WRAP_MASK 0x00000002 /**< Wrap bit, last BD */ +#define XEMACPS_RXBUF_NEW_MASK 0x00000001 /**< Used bit.. */ +#define XEMACPS_RXBUF_ADD_MASK 0xFFFFFFFC /**< Mask for address */ +/* + * @} + */ + +/* + * Define appropriate I/O access method to mempry mapped I/O or other + * intarfce if necessary. + */ + +#define XEmacPs_In32 Xil_In32 +#define XEmacPs_Out32 Xil_Out32 + + +/****************************************************************************/ +/** +* +* Read the given register. +* +* @param BaseAddress is the base address of the device +* @param RegOffset is the register offset to be read +* +* @return The 32-bit value of the register +* +* @note +* C-style signature: +* u32 XEmacPs_ReadReg(u32 BaseAddress, u32 RegOffset) +* +*****************************************************************************/ +#define XEmacPs_ReadReg(BaseAddress, RegOffset) \ + XEmacPs_In32((BaseAddress) + (RegOffset)) + + +/****************************************************************************/ +/** +* +* Write the given register. +* +* @param BaseAddress is the base address of the device +* @param RegOffset is the register offset to be written +* @param Data is the 32-bit value to write to the register +* +* @return None. +* +* @note +* C-style signature: +* void XEmacPs_WriteReg(u32 BaseAddress, u32 RegOffset, +* u32 Data) +* +*****************************************************************************/ +#define XEmacPs_WriteReg(BaseAddress, RegOffset, Data) \ + XEmacPs_Out32((BaseAddress) + (RegOffset), (Data)) + +/************************** Function Prototypes *****************************/ +/* + * Perform reset operation to the emacps interface + */ +void XEmacPs_ResetHw(u32 BaseAddr); + +#ifdef __cplusplus + } +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/emacps/src/xemacps_intr.c b/XilinxProcessorIPLib/drivers/emacps/src/xemacps_intr.c new file mode 100755 index 00000000..20a35486 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/src/xemacps_intr.c @@ -0,0 +1,220 @@ +/* $Id: xemacps_intr.c,v 1.1.2.1 2011/01/20 03:39:02 sadanan Exp $ */ +/****************************************************************************** +* +* 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 THE +* XILINX CONSORTIUM 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 xemacps_intr.c +* +* Functions in this file implement general purpose interrupt processing related +* functionality. See xemacps.h for a detailed description of the driver. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a wsy  01/10/10 First release
+* 1.03a asa  01/24/13 Fix for CR #692702 which updates error handling for
+*		      Rx errors. Under heavy Rx traffic, there will be a large
+*		      number of errors related to receive buffer not available.
+*		      Because of a HW bug (SI #692601), under such heavy errors,
+*		      the Rx data path can become unresponsive. To reduce the
+*		      probabilities for hitting this HW bug, the SW writes to
+*		      bit 18 to flush a packet from Rx DPRAM immediately. The
+*		      changes for it are done in the function
+*		      XEmacPs_IntrHandler.
+* 
+******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xemacps.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + + +/************************** Variable Definitions *****************************/ + + +/*****************************************************************************/ +/** + * Install an asynchronious handler function for the given HandlerType: + * + * @param InstancePtr is a pointer to the instance to be worked on. + * @param HandlerType indicates what interrupt handler type is. + * XEMACPS_HANDLER_DMASEND, XEMACPS_HANDLER_DMARECV and + * XEMACPS_HANDLER_ERROR. + * @param FuncPtr is the pointer to the callback function + * @param CallBackRef is the upper layer callback reference passed back when + * when the callback function is invoked. + * + * @return + * + * None. + * + * @note + * There is no assert on the CallBackRef since the driver doesn't know what + * it is. + * + *****************************************************************************/ +int XEmacPs_SetHandler(XEmacPs *InstancePtr, u32 HandlerType, + void *FuncPtr, void *CallBackRef) +{ + Xil_AssertNonvoid(InstancePtr != NULL); + Xil_AssertNonvoid(FuncPtr != NULL); + Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + switch (HandlerType) { + case XEMACPS_HANDLER_DMASEND: + InstancePtr->SendHandler = (XEmacPs_Handler) FuncPtr; + InstancePtr->SendRef = CallBackRef; + break; + case XEMACPS_HANDLER_DMARECV: + InstancePtr->RecvHandler = (XEmacPs_Handler) FuncPtr; + InstancePtr->RecvRef = CallBackRef; + break; + case XEMACPS_HANDLER_ERROR: + InstancePtr->ErrorHandler = (XEmacPs_ErrHandler) FuncPtr; + InstancePtr->ErrorRef = CallBackRef; + break; + default: + return (XST_INVALID_PARAM); + } + return (XST_SUCCESS); +} + +/*****************************************************************************/ +/** +* Master interrupt handler for EMAC driver. This routine will query the +* status of the device, bump statistics, and invoke user callbacks. +* +* This routine must be connected to an interrupt controller using OS/BSP +* specific methods. +* +* @param XEmacPsPtr is a pointer to the XEMACPS instance that has caused the +* interrupt. +* +******************************************************************************/ +void XEmacPs_IntrHandler(void *XEmacPsPtr) +{ + u32 RegISR; + u32 RegSR; + u32 RegCtrl; + XEmacPs *InstancePtr = (XEmacPs *) XEmacPsPtr; + + Xil_AssertVoid(InstancePtr != NULL); + Xil_AssertVoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); + + /* This ISR will try to handle as many interrupts as it can in a single + * call. However, in most of the places where the user's error handler + * is called, this ISR exits because it is expected that the user will + * reset the device in nearly all instances. + */ + RegISR = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_ISR_OFFSET); + + /* Clear the interrupt status register */ + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, XEMACPS_ISR_OFFSET, + RegISR); + + /* Receive complete interrupt */ + if (RegISR & (XEMACPS_IXR_FRAMERX_MASK)) { + /* Clear RX status register RX complete indication but preserve + * error bits if there is any */ + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_RXSR_OFFSET, + XEMACPS_RXSR_FRAMERX_MASK | + XEMACPS_RXSR_BUFFNA_MASK); + InstancePtr->RecvHandler(InstancePtr->RecvRef); + } + + /* Transmit complete interrupt */ + if (RegISR & (XEMACPS_IXR_TXCOMPL_MASK)) { + /* Clear TX status register TX complete indication but preserve + * error bits if there is any */ + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_TXSR_OFFSET, + XEMACPS_TXSR_TXCOMPL_MASK | + XEMACPS_TXSR_USEDREAD_MASK); + InstancePtr->SendHandler(InstancePtr->SendRef); + } + + /* Receive error conditions interrupt */ + if (RegISR & (XEMACPS_IXR_RX_ERR_MASK)) { + /* Clear RX status register */ + RegSR = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_RXSR_OFFSET); + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_RXSR_OFFSET, RegSR); + + /* Fix for CR # 692702. Write to bit 18 of net_ctrl + * register to flush a packet out of Rx SRAM upon + * an error for receive buffer not available. */ + if (RegISR & XEMACPS_IXR_RXUSED_MASK) { + RegCtrl = + XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET); + RegCtrl |= XEMACPS_NWCTRL_FLUSH_DPRAM_MASK; + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_NWCTRL_OFFSET, RegCtrl); + } + InstancePtr->ErrorHandler(InstancePtr->ErrorRef, XEMACPS_RECV, + RegSR); + } + + /* When XEMACPS_IXR_TXCOMPL_MASK is flaged, XEMACPS_IXR_TXUSED_MASK + * will be asserted the same time. + * Have to distinguish this bit to handle the real error condition. + */ + /* Transmit error conditions interrupt */ + if (RegISR & (XEMACPS_IXR_TX_ERR_MASK) && + !(RegISR & (XEMACPS_IXR_TXCOMPL_MASK))) { + /* Clear TX status register */ + RegSR = XEmacPs_ReadReg(InstancePtr->Config.BaseAddress, + XEMACPS_TXSR_OFFSET); + XEmacPs_WriteReg(InstancePtr->Config.BaseAddress, + XEMACPS_TXSR_OFFSET, RegSR); + InstancePtr->ErrorHandler(InstancePtr->ErrorRef, XEMACPS_SEND, + RegSR); + } + +} diff --git a/XilinxProcessorIPLib/drivers/emacps/src/xemacps_sinit.c b/XilinxProcessorIPLib/drivers/emacps/src/xemacps_sinit.c new file mode 100755 index 00000000..0110e1b4 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/emacps/src/xemacps_sinit.c @@ -0,0 +1,93 @@ +/* $Id: xemacps_sinit.c,v 1.1.2.1 2011/01/20 03:39:02 sadanan Exp $ */ +/****************************************************************************** +* +* 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 THE +* XILINX CONSORTIUM 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 xemacps_sinit.c +* +* This file contains lookup method by device ID when success, it returns +* pointer to config table to be used to initialize the device. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a wsy  01/10/10 New
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xemacps.h" + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ +/** +* Lookup the device configuration based on the unique device ID. The table +* contains the configuration info for each device in the system. +* +* @param DeviceId is the unique device ID of the device being looked up. +* +* @return +* A pointer to the configuration table entry corresponding to the given +* device ID, or NULL if no match is found. +* +******************************************************************************/ +XEmacPs_Config *XEmacPs_LookupConfig(u16 DeviceId) +{ + extern XEmacPs_Config XEmacPs_ConfigTable[]; + XEmacPs_Config *CfgPtr = NULL; + int i; + + for (i = 0; i < XPAR_XEMACPS_NUM_INSTANCES; i++) { + if (XEmacPs_ConfigTable[i].DeviceId == DeviceId) { + CfgPtr = &XEmacPs_ConfigTable[i]; + break; + } + } + + return (CfgPtr); +}