diff --git a/XilinxProcessorIPLib/drivers/axidma/data/axidma.mdd b/XilinxProcessorIPLib/drivers/axidma/data/axidma.mdd new file mode 100755 index 00000000..567dd98c --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/data/axidma.mdd @@ -0,0 +1,43 @@ +############################################################################### +# +# 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. +# +############################################################################## + +OPTION psf_version = 2.1; + +BEGIN driver axidma + + OPTION supported_peripherals = (axi_dma_v[3-9]_[0-9][0-9]_[a-z] axi_dma_v[3-9]_[0-9]); + OPTION driver_state = ACTIVE; + OPTION copyfiles = all; + OPTION VERSION = 8.1; + OPTION NAME = axidma; + +END driver diff --git a/XilinxProcessorIPLib/drivers/axidma/data/axidma.tcl b/XilinxProcessorIPLib/drivers/axidma/data/axidma.tcl new file mode 100755 index 00000000..e2c19e91 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/data/axidma.tcl @@ -0,0 +1,208 @@ +############################################################################### +# +# 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. +# +# MODIFICATION HISTORY: +# Ver Who Date Changes +# -------- ------ -------- ---------------------------------------------------- +# 8.0 adk 12/10/13 Updated as per the New Tcl API's +############################################################################## + +#uses "xillib.tcl" + +set periph_ninstances 0 + +proc generate {drv_handle} { + xdefine_include_file $drv_handle "xparameters.h" "XAxiDma" "NUM_INSTANCES" "DEVICE_ID" "C_BASEADDR" "C_HIGHADDR" "C_SG_INCLUDE_STSCNTRL_STRM" "C_INCLUDE_MM2S_DRE" "C_INCLUDE_S2MM_DRE" "C_INCLUDE_MM2S" "C_INCLUDE_S2MM" "C_M_AXI_MM2S_DATA_WIDTH" "C_M_AXI_S2MM_DATA_WIDTH" "C_INCLUDE_SG" "C_ENABLE_MULTI_CHANNEL" "C_NUM_MM2S_CHANNELS" "C_NUM_S2MM_CHANNELS" "C_MM2S_BURST_SIZE" "C_S2MM_BURST_SIZE" "C_MICRO_DMA" + xdefine_canonical_xpars $drv_handle "xparameters.h" "AxiDma" "DEVICE_ID" "C_BASEADDR" "C_SG_INCLUDE_STSCNTRL_STRM" "C_INCLUDE_MM2S" "C_INCLUDE_MM2S_DRE" "C_M_AXI_MM2S_DATA_WIDTH" "C_INCLUDE_S2MM" "C_INCLUDE_S2MM_DRE" "C_M_AXI_S2MM_DATA_WIDTH" "C_INCLUDE_SG" "C_ENABLE_MULTI_CHANNEL" "C_NUM_MM2S_CHANNELS" "C_NUM_S2MM_CHANNELS" "C_MM2S_BURST_SIZE" "C_S2MM_BURST_SIZE" "C_MICRO_DMA" + xdefine_config_file $drv_handle "xaxidma_g.c" "XAxiDma" "DEVICE_ID" "C_BASEADDR" "C_SG_INCLUDE_STSCNTRL_STRM" "C_INCLUDE_MM2S" "C_INCLUDE_MM2S_DRE" "C_M_AXI_MM2S_DATA_WIDTH" "C_INCLUDE_S2MM" "C_INCLUDE_S2MM_DRE" "C_M_AXI_S2MM_DATA_WIDTH" "C_INCLUDE_SG" "C_NUM_MM2S_CHANNELS" "C_NUM_S2MM_CHANNELS" "C_MM2S_BURST_SIZE" "C_S2MM_BURST_SIZE" "C_MICRO_DMA" +} + +# +# Given a list of arguments, define them all in an include file. +# Handles mpd and mld parameters, as well as the special parameters NUM_INSTANCES, +# DEVICE_ID +# Will not work for a processor. +# + +proc xdefine_dma_include_file {drv_handle file_name drv_string args} { + # Open include file + set file_handle [xopen_include_file $file_name] + + # Get all peripherals connected to this driver + set periphs [xget_sw_iplist_for_driver $drv_handle] + + # Handle special cases + set arg "NUM_INSTANCES" + set posn [lsearch -exact $args $arg] + if {$posn > -1} { + puts $file_handle "/* Definitions for driver [string toupper [get_property NAME $drv_handle]] */" + # Define NUM_INSTANCES + puts $file_handle "#define [xget_dname $drv_string $arg] [llength $periphs]" + set args [lreplace $args $posn $posn] + } + # Check if it is a driver parameter + + lappend newargs + foreach arg $args { + set value [get_property CONFIG.$arg $drv_handle] + if {[llength $value] == 0} { + lappend newargs $arg + } else { + puts $file_handle "#define [xget_dname $drv_string $arg] [get_property CONFIG.$arg $drv_handle]" + } + } + set args $newargs + + # Print all parameters for all peripherals + set device_id 0 + foreach periph $periphs { + puts $file_handle "" + puts $file_handle "/* Definitions for peripheral [string toupper [get_property NAME $periph]] */" + foreach arg $args { + if {[string compare -nocase "DEVICE_ID" $arg] == 0} { + set value $device_id + incr device_id + } else { + set value [xget_param_value $periph $arg] + if {[string compare -nocase $arg "C_INCLUDE_SG"] == 0} { + if {[llength $value] == 0} { + set value 1 + } + } else { + if {[llength $value] == 0} { + set value 0 + } + } + if {[string compare -nocase $arg "C_MICRO_DMA"] == 0} { + if {[llength $value] == 0} { + set value 1 + } + } else { + if {[llength $value] == 0} { + set value 0 + } + } + } + + set value [xformat_addr_string $value $arg] + if {[string compare -nocase "HW_VER" $arg] == 0} { + puts $file_handle "#define [xget_name $periph $arg] \"$value\"" + } else { + puts $file_handle "#define [xget_name $periph $arg] $value" + } + } + puts $file_handle "" + } + puts $file_handle "\n/******************************************************************/\n" + close $file_handle +} + +#----------------------------------------------------------------------------- +# xdefine_canonical_xpars - Used to print out canonical defines for a driver. +# Given a list of arguments, define each as a canonical constant name, using +# the driver name, in an include file. +#----------------------------------------------------------------------------- +proc xdefine_axidma_canonical_xpars {drv_handle file_name drv_string args} { + # Open include file + set file_handle [xopen_include_file $file_name] + + # Get all the peripherals connected to this driver + set periphs [xget_sw_iplist_for_driver $drv_handle] + + # Get the names of all the peripherals connected to this driver + foreach periph $periphs { + set peripheral_name [string toupper [get_property NAME $periph]] + lappend peripherals $peripheral_name + } + + # Get possible canonical names for all the peripherals connected to this + # driver + set device_id 0 + foreach periph $periphs { + set canonical_name [string toupper [format "%s_%s" $drv_string $device_id]] + lappend canonicals $canonical_name + + # Create a list of IDs of the peripherals whose hardware instance name + # doesn't match the canonical name. These IDs can be used later to + # generate canonical definitions + if { [lsearch $peripherals $canonical_name] < 0 } { + lappend indices $device_id + } + incr device_id + } + + set i 0 + foreach periph $periphs { + set periph_name [string toupper [get_property NAME $periph]] + + # Generate canonical definitions only for the peripherals whose + # canonical name is not the same as hardware instance name + if { [lsearch $canonicals $periph_name] < 0 } { + puts $file_handle "/* Canonical definitions for peripheral $periph_name */" + set canonical_name [format "%s_%s" $drv_string [lindex $indices $i]] + + foreach arg $args { + set lvalue [xget_dname $canonical_name $arg] + # The commented out rvalue is the name of the instance-specific constant + # set rvalue [xget_name $periph $arg] + # The rvalue set below is the actual value of the parameter + set rvalue [xget_param_value $periph $arg] + + if {[string compare -nocase $arg "C_INCLUDE_SG"] == 0} { + if {[llength $rvalue] == 0} { + set rvalue 1 + } + } else { + if {[llength $rvalue] == 0} { + set rvalue 0 + } + } + if {[string compare -nocase $arg "C_MICRO_DMA"] == 0} { + if {[llength $rvalue] == 0} { + set rvalue 1 + } + } else { + if {[llength $rvalue] == 0} { + set rvalue 0 + } + } + set rvalue [xformat_addr_string $rvalue $arg] + + puts $file_handle "#define $lvalue $rvalue" + + } + puts $file_handle "" + incr i + } + } + + puts $file_handle "\n/******************************************************************/\n" + close $file_handle +} diff --git a/XilinxProcessorIPLib/drivers/axidma/examples/index.html b/XilinxProcessorIPLib/drivers/axidma/examples/index.html new file mode 100755 index 00000000..a0cd0166 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/examples/index.html @@ -0,0 +1,22 @@ + + + + + +Driver example applications + + + +

Example Applications for the driver axidma_v8_0

+
+ +

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

+ + diff --git a/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_example_sg_intr.c b/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_example_sg_intr.c new file mode 100644 index 00000000..a69e6b85 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_example_sg_intr.c @@ -0,0 +1,1203 @@ +/****************************************************************************** +* +* (c) Copyright 2010-2013 Xilinx, Inc. All rights reserved. +* +* This file contains confidential and proprietary information of Xilinx, Inc. +* and is protected under U.S. and international copyright and other +* intellectual property laws. +* +* DISCLAIMER +* This disclaimer is not a license and does not grant any rights to the +* materials distributed herewith. Except as otherwise provided in a valid +* license issued to you by Xilinx, and to the maximum extent permitted by +* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL +* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, +* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF +* MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; +* and (2) Xilinx shall not be liable (whether in contract or tort, including +* negligence, or under any other theory of liability) for any loss or damage +* of any kind or nature related to, arising under or in connection with these +* materials, including for any direct, or any indirect, special, incidental, +* or consequential loss or damage (including loss of data, profits, goodwill, +* or any type of loss or damage suffered as a result of any action brought by +* a third party) even if such damage or loss was reasonably foreseeable or +* Xilinx had been advised of the possibility of the same. +* +* CRITICAL APPLICATIONS +* Xilinx products are not designed or intended to be fail-safe, or for use in +* any application requiring fail-safe performance, such as life-support or +* safety devices or systems, Class III medical devices, nuclear facilities, +* applications related to the deployment of airbags, or any other applications +* that could lead to death, personal injury, or severe property or +* environmental damage (individually and collectively, "Critical +* Applications"). Customer assumes the sole risk and liability of any use of +* Xilinx products in Critical Applications, subject only to applicable laws +* and regulations governing limitations on product liability. +* +* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE +* AT ALL TIMES. +* +******************************************************************************/ +/*****************************************************************************/ +/** + * + * @file xaxidma_example_sg_intr.c + * + * This file demonstrates how to use the xaxidma driver on the Xilinx AXI + * DMA core (AXIDMA) to transfer packets in interrupt mode when the AXIDMA + * core is configured in Scatter Gather Mode + * + * We show how to do multiple packets transfers, as well as how to do multiple + * BDs per packet transfers. + * + * This code assumes a loopback hardware widget is connected to the AXI DMA + * core for data packet loopback. + * + * To see the debug print, you need a Uart16550 or uartlite in your system, + * and please set "-DDEBUG" in your compiler options. You need to rebuild your + * software executable. + * + * Make sure that MEMORY_BASE is defined properly as per the HW system. The + * h/w system built in Area mode has a maximum DDR memory limit of 64MB. In + * throughput mode, it is 512MB. These limits are need to ensured for + * proper operation of this code. + * + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -------------------------------------------------------
+ * 1.00a jz   05/18/10 First release
+ * 2.00a jz   08/10/10 Second release, added in xaxidma_g.c, xaxidma_sinit.c,
+ *		       		   updated tcl file, added xaxidma_porting_guide.h, removed
+ *		         	   workaround for endianness
+ * 4.00a rkv  02/22/11 Name of the file has been changed for naming consistency
+ *		       		   Added interrupt support for Zynq.
+ * 5.00a srt  03/05/12 Added Flushing and Invalidation of Caches to fix CRs
+ *		       		   648103, 648701.
+ *		       		   Added V7 DDR Base Address to fix CR 649405.
+ * 6.00a srt  01/24/12 Changed API calls to support MCDMA driver.
+ * 7.00a srt  06/18/12 API calls are reverted back for backward compatibility.
+ * 7.01a srt  11/02/12 Buffer sizes (Tx and Rx) are modified to meet maximum
+ *		       DDR memory limit of the h/w system built with Area mode
+ * 7.02a srt  03/01/13 Updated DDR base address for IPI designs (CR 703656).
+ *
+ * 
+ * + * *************************************************************************** + */ +/***************************** Include Files *********************************/ +#include "xaxidma.h" +#include "xparameters.h" +#include "xil_exception.h" +#include "xdebug.h" + +#ifdef XPAR_UARTNS550_0_BASEADDR +#include "xuartns550_l.h" /* to use uartns550 */ +#endif + +#ifndef DEBUG +extern void xil_printf(const char *format, ...); +#endif + +#ifdef XPAR_INTC_0_DEVICE_ID + #include "xintc.h" +#else + #include "xscugic.h" +#endif + +/******************** Constant Definitions **********************************/ +/* + * Device hardware build related constants. + */ + +#define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID + +#ifdef XPAR_V6DDR_0_S_AXI_BASEADDR +#define DDR_BASE_ADDR XPAR_V6DDR_0_S_AXI_BASEADDR +#elif XPAR_S6DDR_0_S0_AXI_BASEADDR +#define DDR_BASE_ADDR XPAR_S6DDR_0_S0_AXI_BASEADDR +#elif XPAR_AXI_7SDDR_0_S_AXI_BASEADDR +#define DDR_BASE_ADDR XPAR_AXI_7SDDR_0_S_AXI_BASEADDR +#elif XPAR_MIG7SERIES_0_BASEADDR +#define DDR_BASE_ADDR XPAR_MIG7SERIES_0_BASEADDR +#endif + +#ifndef DDR_BASE_ADDR +#warning CHECK FOR THE VALID DDR ADDRESS IN XPARAMETERS.H, \ + DEFAULT SET TO 0x01000000 +#define MEM_BASE_ADDR 0x01000000 +#else +#define MEM_BASE_ADDR (DDR_BASE_ADDR + 0x1000000) +#endif + +#ifdef XPAR_INTC_0_DEVICE_ID +#define RX_INTR_ID XPAR_INTC_0_AXIDMA_0_S2MM_INTROUT_VEC_ID +#define TX_INTR_ID XPAR_INTC_0_AXIDMA_0_MM2S_INTROUT_VEC_ID +#else +#define RX_INTR_ID XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID +#define TX_INTR_ID XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID +#endif + +#define RX_BD_SPACE_BASE (MEM_BASE_ADDR) +#define RX_BD_SPACE_HIGH (MEM_BASE_ADDR + 0x0000FFFF) +#define TX_BD_SPACE_BASE (MEM_BASE_ADDR + 0x00010000) +#define TX_BD_SPACE_HIGH (MEM_BASE_ADDR + 0x0001FFFF) +#define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000) +#define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00300000) +#define RX_BUFFER_HIGH (MEM_BASE_ADDR + 0x004FFFFF) + +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#else +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#endif + +/* Timeout loop counter for reset + */ +#define RESET_TIMEOUT_COUNTER 10000 + +/* + * Buffer and Buffer Descriptor related constant definition + */ +#define MAX_PKT_LEN 0x100 + +/* + * Number of BDs in the transfer example + * We show how to submit multiple BDs for one transmit. + * The receive side gets one completion per transfer. + */ +#define NUMBER_OF_BDS_PER_PKT 12 +#define NUMBER_OF_PKTS_TO_TRANSFER 11 +#define NUMBER_OF_BDS_TO_TRANSFER (NUMBER_OF_PKTS_TO_TRANSFER * \ + NUMBER_OF_BDS_PER_PKT) + +/* The interrupt coalescing threshold and delay timer threshold + * Valid range is 1 to 255 + * + * We set the coalescing threshold to be the total number of packets. + * The receive side will only get one completion interrupt for this example. + */ +#define COALESCING_COUNT NUMBER_OF_PKTS_TO_TRANSFER +#define DELAY_TIMER_COUNT 100 + +#ifdef XPAR_INTC_0_DEVICE_ID + #define INTC XIntc + #define INTC_HANDLER XIntc_InterruptHandler +#else + #define INTC XScuGic + #define INTC_HANDLER XScuGic_InterruptHandler +#endif + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ +#ifdef XPAR_UARTNS550_0_BASEADDR +static void Uart550_Setup(void); +#endif + +static int CheckData(int Length, u8 StartValue); +static void TxCallBack(XAxiDma_BdRing * TxRingPtr); +static void TxIntrHandler(void *Callback); +static void RxCallBack(XAxiDma_BdRing * RxRingPtr); +static void RxIntrHandler(void *Callback); + + + +static int SetupIntrSystem(INTC * IntcInstancePtr, + XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId); +static void DisableIntrSystem(INTC * IntcInstancePtr, + u16 TxIntrId, u16 RxIntrId); + +static int RxSetup(XAxiDma * AxiDmaInstPtr); +static int TxSetup(XAxiDma * AxiDmaInstPtr); +static int SendPacket(XAxiDma * AxiDmaInstPtr); + +/************************** Variable Definitions *****************************/ +/* + * Device instance definitions + */ +XAxiDma AxiDma; + + +static INTC Intc; /* Instance of the Interrupt Controller */ + +/* + * Flags interrupt handlers use to notify the application context the events. + */ +volatile int TxDone; +volatile int RxDone; +volatile int Error; + +/* + * Buffer for transmit packet. Must be 32-bit aligned to be used by DMA. + */ +u32 *Packet = (u32 *) TX_BUFFER_BASE; + +/*****************************************************************************/ +/** +* +* Main function +* +* This function is the main entry of the interrupt test. It does the following: +* - Set up the output terminal if UART16550 is in the hardware build +* - Initialize the DMA engine +* - Set up Tx and Rx channels +* - Set up the interrupt system for the Tx and Rx interrupts +* - Submit a transfer +* - Wait for the transfer to finish +* - Check transfer status +* - Disable Tx and Rx interrupts +* - Print test status and exit +* +* @param None +* +* @return - XST_SUCCESS if tests pass +* - XST_FAILURE if fails. +* +* @note None. +* +******************************************************************************/ +int main(void) +{ + int Status; + XAxiDma_Config *Config; + + /* Initial setup for Uart16550 */ +#ifdef XPAR_UARTNS550_0_BASEADDR + + Uart550_Setup(); + +#endif + + xil_printf("\r\n--- Entering main() --- \r\n"); + + Config = XAxiDma_LookupConfig(DMA_DEV_ID); + if (!Config) { + xil_printf("No config found for %d\r\n", DMA_DEV_ID); + + return XST_FAILURE; + } + + /* Initialize DMA engine */ + XAxiDma_CfgInitialize(&AxiDma, Config); + + if(!XAxiDma_HasSg(&AxiDma)) { + xil_printf("Device configured as Simple mode \r\n"); + return XST_FAILURE; + } + + /* Set up TX/RX channels to be ready to transmit and receive packets */ + Status = TxSetup(&AxiDma); + + if (Status != XST_SUCCESS) { + + xil_printf("Failed TX setup\r\n"); + return XST_FAILURE; + } + + Status = RxSetup(&AxiDma); + if (Status != XST_SUCCESS) { + + xil_printf("Failed RX setup\r\n"); + return XST_FAILURE; + } + + /* Set up Interrupt system */ + Status = SetupIntrSystem(&Intc, &AxiDma, TX_INTR_ID, RX_INTR_ID); + if (Status != XST_SUCCESS) { + + xil_printf("Failed intr setup\r\n"); + return XST_FAILURE; + } + + /* Initialize flags before start transfer test */ + TxDone = 0; + RxDone = 0; + Error = 0; + + /* Send a packet */ + Status = SendPacket(&AxiDma); + if (Status != XST_SUCCESS) { + + xil_printf("Failed send packet\r\n"); + return XST_FAILURE; + } + + /* + * Wait TX done and RX done + */ + while (((TxDone < NUMBER_OF_BDS_TO_TRANSFER) || + (RxDone < NUMBER_OF_BDS_TO_TRANSFER)) && !Error) { + /* NOP */ + } + + if (Error) { + xil_printf("Failed test transmit%s done, " + "receive%s done\r\n", TxDone? "":" not", + RxDone? "":" not"); + + goto Done; + + }else { + + /* + * Test finished, check data + */ + Status = CheckData(MAX_PKT_LEN * NUMBER_OF_BDS_TO_TRANSFER, + 0xC); + if (Status != XST_SUCCESS) { + + xil_printf("Data check failed\r\n"); + + goto Done; + } + + xil_printf("AXI DMA SG interrupt Test passed\r\n"); + } + + /* Disable TX and RX Ring interrupts and return success */ + + DisableIntrSystem(&Intc, TX_INTR_ID, RX_INTR_ID); + +Done: + + xil_printf("--- Exiting main() --- \r\n"); + + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +#ifdef XPAR_UARTNS550_0_BASEADDR +/*****************************************************************************/ +/* +* +* Uart16550 setup routine, need to set baudrate to 9600 and data bits to 8 +* +* @param None +* +* @return None +* +* @note None. +* +******************************************************************************/ +static void Uart550_Setup(void) +{ + + XUartNs550_SetBaud(XPAR_UARTNS550_0_BASEADDR, + XPAR_XUARTNS550_CLOCK_HZ, 9600); + + XUartNs550_SetLineControlReg(XPAR_UARTNS550_0_BASEADDR, + XUN_LCR_8_DATA_BITS); +} +#endif + +/*****************************************************************************/ +/* +* +* This function checks data buffer after the DMA transfer is finished. +* +* We use the static tx/rx buffers. +* +* @param Length is the length to check +* @param StartValue is the starting value of the first byte +* +* @return - XST_SUCCESS if validation is successful +* - XST_FAILURE if validation fails. +* +* @note None. +* +******************************************************************************/ +static int CheckData(int Length, u8 StartValue) +{ + u8 *RxPacket; + int Index = 0; + u8 Value; + + RxPacket = (u8 *) RX_BUFFER_BASE; + Value = StartValue; + + /* Invalidate the DestBuffer before receiving the data, in case the + * Data Cache is enabled + */ + Xil_DCacheInvalidateRange((u32)RxPacket, Length); + + for(Index = 0; Index < Length; Index++) { + if (RxPacket[Index] != Value) { + xil_printf("Data error %d: %x/%x\r\n", + Index, RxPacket[Index], Value); + + return XST_FAILURE; + } + Value = (Value + 1) & 0xFF; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/* +* +* This is the DMA TX callback function to be called by TX interrupt handler. +* This function handles BDs finished by hardware. +* +* @param TxRingPtr is a pointer to TX channel of the DMA engine. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void TxCallBack(XAxiDma_BdRing * TxRingPtr) +{ + int BdCount; + u32 BdSts; + XAxiDma_Bd *BdPtr; + XAxiDma_Bd *BdCurPtr; + int Status; + int Index; + + /* Get all processed BDs from hardware */ + BdCount = XAxiDma_BdRingFromHw(TxRingPtr, XAXIDMA_ALL_BDS, &BdPtr); + + /* Handle the BDs */ + BdCurPtr = BdPtr; + for (Index = 0; Index < BdCount; Index++) { + + /* + * Check the status in each BD + * If error happens, the DMA engine will be halted after this + * BD processing stops. + */ + BdSts = XAxiDma_BdGetSts(BdCurPtr); + if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) || + (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) { + + Error = 1; + break; + } + + /* + * Here we don't need to do anything. But if a RTOS is being + * used, we may need to free the packet buffer attached to + * the processed BD + */ + + /* Find the next processed BD */ + BdCurPtr = XAxiDma_BdRingNext(TxRingPtr, BdCurPtr); + } + + /* Free all processed BDs for future transmission */ + Status = XAxiDma_BdRingFree(TxRingPtr, BdCount, BdPtr); + if (Status != XST_SUCCESS) { + Error = 1; + } + + if(!Error) { + + TxDone += BdCount; + } +} + +/*****************************************************************************/ +/* +* +* This is the DMA TX Interrupt handler function. +* +* It gets the interrupt status from the hardware, acknowledges it, and if any +* error happens, it resets the hardware. Otherwise, if a completion interrupt +* presents, then it calls the callback function. +* +* @param Callback is a pointer to TX channel of the DMA engine. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void TxIntrHandler(void *Callback) +{ + XAxiDma_BdRing *TxRingPtr = (XAxiDma_BdRing *) Callback; + u32 IrqStatus; + int TimeOut; + + /* Read pending interrupts */ + IrqStatus = XAxiDma_BdRingGetIrq(TxRingPtr); + + /* Acknowledge pending interrupts */ + XAxiDma_BdRingAckIrq(TxRingPtr, IrqStatus); + + /* If no interrupt is asserted, we do not do anything + */ + if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) { + + return; + } + + /* + * If error interrupt is asserted, raise error flag, reset the + * hardware to recover from the error, and return with no further + * processing. + */ + if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) { + + XAxiDma_BdRingDumpRegs(TxRingPtr); + + Error = 1; + + /* + * Reset should never fail for transmit channel + */ + XAxiDma_Reset(&AxiDma); + + TimeOut = RESET_TIMEOUT_COUNTER; + + while (TimeOut) { + if (XAxiDma_ResetIsDone(&AxiDma)) { + break; + } + + TimeOut -= 1; + } + + return; + } + + /* + * If Transmit done interrupt is asserted, call TX call back function + * to handle the processed BDs and raise the according flag + */ + if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) { + TxCallBack(TxRingPtr); + } +} + +/*****************************************************************************/ +/* +* +* This is the DMA RX callback function called by the RX interrupt handler. +* This function handles finished BDs by hardware, attaches new buffers to those +* BDs, and give them back to hardware to receive more incoming packets +* +* @param RxRingPtr is a pointer to RX channel of the DMA engine. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void RxCallBack(XAxiDma_BdRing * RxRingPtr) +{ + int BdCount; + XAxiDma_Bd *BdPtr; + XAxiDma_Bd *BdCurPtr; + u32 BdSts; + int Index; + + /* Get finished BDs from hardware */ + BdCount = XAxiDma_BdRingFromHw(RxRingPtr, XAXIDMA_ALL_BDS, &BdPtr); + + BdCurPtr = BdPtr; + for (Index = 0; Index < BdCount; Index++) { + + /* + * Check the flags set by the hardware for status + * If error happens, processing stops, because the DMA engine + * is halted after this BD. + */ + BdSts = XAxiDma_BdGetSts(BdCurPtr); + if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) || + (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) { + Error = 1; + break; + } + + /* Find the next processed BD */ + BdCurPtr = XAxiDma_BdRingNext(RxRingPtr, BdCurPtr); + RxDone += 1; + } + +} + +/*****************************************************************************/ +/* +* +* This is the DMA RX interrupt handler function +* +* It gets the interrupt status from the hardware, acknowledges it, and if any +* error happens, it resets the hardware. Otherwise, if a completion interrupt +* presents, then it calls the callback function. +* +* @param Callback is a pointer to RX channel of the DMA engine. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void RxIntrHandler(void *Callback) +{ + XAxiDma_BdRing *RxRingPtr = (XAxiDma_BdRing *) Callback; + u32 IrqStatus; + int TimeOut; + + /* Read pending interrupts */ + IrqStatus = XAxiDma_BdRingGetIrq(RxRingPtr); + + /* Acknowledge pending interrupts */ + XAxiDma_BdRingAckIrq(RxRingPtr, IrqStatus); + + /* + * If no interrupt is asserted, we do not do anything + */ + if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) { + return; + } + + /* + * If error interrupt is asserted, raise error flag, reset the + * hardware to recover from the error, and return with no further + * processing. + */ + if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) { + + XAxiDma_BdRingDumpRegs(RxRingPtr); + + Error = 1; + + /* Reset could fail and hang + * NEED a way to handle this or do not call it?? + */ + XAxiDma_Reset(&AxiDma); + + TimeOut = RESET_TIMEOUT_COUNTER; + + while (TimeOut) { + if(XAxiDma_ResetIsDone(&AxiDma)) { + break; + } + + TimeOut -= 1; + } + + return; + } + + /* + * If completion interrupt is asserted, call RX call back function + * to handle the processed BDs and then raise the according flag. + */ + if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) { + RxCallBack(RxRingPtr); + } +} + +/*****************************************************************************/ +/* +* +* This function setups the interrupt system so interrupts can occur for the +* DMA, it assumes INTC component exists in the hardware system. +* +* @param IntcInstancePtr is a pointer to the instance of the INTC. +* @param AxiDmaPtr is a pointer to the instance of the DMA engine +* @param TxIntrId is the TX channel Interrupt ID. +* @param RxIntrId is the RX channel Interrupt ID. +* +* @return +* - XST_SUCCESS if successful, +* - XST_FAILURE.if not succesful +* +* @note None. +* +******************************************************************************/ + +static int SetupIntrSystem(INTC * IntcInstancePtr, + XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId) +{ + XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(AxiDmaPtr); + XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxRing(AxiDmaPtr); + int Status; + +#ifdef XPAR_INTC_0_DEVICE_ID + + /* Initialize the interrupt controller and connect the ISRs */ + Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID); + if (Status != XST_SUCCESS) { + + xil_printf("Failed init intc\r\n"); + return XST_FAILURE; + } + + Status = XIntc_Connect(IntcInstancePtr, TxIntrId, + (XInterruptHandler) TxIntrHandler, TxRingPtr); + if (Status != XST_SUCCESS) { + + xil_printf("Failed tx connect intc\r\n"); + return XST_FAILURE; + } + + Status = XIntc_Connect(IntcInstancePtr, RxIntrId, + (XInterruptHandler) RxIntrHandler, RxRingPtr); + if (Status != XST_SUCCESS) { + + xil_printf("Failed rx connect intc\r\n"); + return XST_FAILURE; + } + + /* Start the interrupt controller */ + Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE); + if (Status != XST_SUCCESS) { + + xil_printf("Failed to start intc\r\n"); + return XST_FAILURE; + } + + XIntc_Enable(IntcInstancePtr, TxIntrId); + XIntc_Enable(IntcInstancePtr, RxIntrId); + +#else + + XScuGic_Config *IntcConfig; + + + /* + * Initialize the interrupt controller driver so that it is ready to + * use. + */ + IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); + if (NULL == IntcConfig) { + return XST_FAILURE; + } + + Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, + IntcConfig->CpuBaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + XScuGic_SetPriorityTriggerType(IntcInstancePtr, TxIntrId, 0xA0, 0x3); + + XScuGic_SetPriorityTriggerType(IntcInstancePtr, RxIntrId, 0xA0, 0x3); + /* + * Connect the device driver handler that will be called when an + * interrupt for the device occurs, the handler defined above performs + * the specific interrupt processing for the device. + */ + Status = XScuGic_Connect(IntcInstancePtr, TxIntrId, + (Xil_InterruptHandler)TxIntrHandler, + TxRingPtr); + if (Status != XST_SUCCESS) { + return Status; + } + + Status = XScuGic_Connect(IntcInstancePtr, RxIntrId, + (Xil_InterruptHandler)RxIntrHandler, + RxRingPtr); + if (Status != XST_SUCCESS) { + return Status; + } + + XScuGic_Enable(IntcInstancePtr, TxIntrId); + XScuGic_Enable(IntcInstancePtr, RxIntrId); +#endif + + /* Enable interrupts from the hardware */ + + Xil_ExceptionInit(); + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler)INTC_HANDLER, + (void *)IntcInstancePtr); + + Xil_ExceptionEnable(); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function disables the interrupts for DMA engine. +* +* @param IntcInstancePtr is the pointer to the INTC component instance +* @param TxIntrId is interrupt ID associated w/ DMA TX channel +* @param RxIntrId is interrupt ID associated w/ DMA RX channel +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void DisableIntrSystem(INTC * IntcInstancePtr, + u16 TxIntrId, u16 RxIntrId) +{ +#ifdef XPAR_INTC_0_DEVICE_ID + /* Disconnect the interrupts for the DMA TX and RX channels */ + XIntc_Disconnect(IntcInstancePtr, TxIntrId); + XIntc_Disconnect(IntcInstancePtr, RxIntrId); +#else + XScuGic_Disconnect(IntcInstancePtr, TxIntrId); + XScuGic_Disconnect(IntcInstancePtr, RxIntrId); +#endif +} + +/*****************************************************************************/ +/* +* +* This function sets up RX channel of the DMA engine to be ready for packet +* reception +* +* @param AxiDmaInstPtr is the pointer to the instance of the DMA engine. +* +* @return - XST_SUCCESS if the setup is successful. +* - XST_FAILURE if fails. +* +* @note None. +* +******************************************************************************/ +static int RxSetup(XAxiDma * AxiDmaInstPtr) +{ + XAxiDma_BdRing *RxRingPtr; + int Status; + XAxiDma_Bd BdTemplate; + XAxiDma_Bd *BdPtr; + XAxiDma_Bd *BdCurPtr; + int BdCount; + int FreeBdCount; + u32 RxBufferPtr; + int Index; + + RxRingPtr = XAxiDma_GetRxRing(&AxiDma); + + /* Disable all RX interrupts before RxBD space setup */ + XAxiDma_BdRingIntDisable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* Setup Rx BD space */ + BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, + RX_BD_SPACE_HIGH - RX_BD_SPACE_BASE + 1); + + Status = XAxiDma_BdRingCreate(RxRingPtr, RX_BD_SPACE_BASE, + RX_BD_SPACE_BASE, + XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount); + if (Status != XST_SUCCESS) { + xil_printf("Rx bd create failed with %d\r\n", Status); + return XST_FAILURE; + } + + /* + * Setup a BD template for the Rx channel. Then copy it to every RX BD. + */ + XAxiDma_BdClear(&BdTemplate); + Status = XAxiDma_BdRingClone(RxRingPtr, &BdTemplate); + if (Status != XST_SUCCESS) { + xil_printf("Rx bd clone failed with %d\r\n", Status); + return XST_FAILURE; + } + + /* Attach buffers to RxBD ring so we are ready to receive packets */ + FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr); + + Status = XAxiDma_BdRingAlloc(RxRingPtr, FreeBdCount, &BdPtr); + if (Status != XST_SUCCESS) { + xil_printf("Rx bd alloc failed with %d\r\n", Status); + return XST_FAILURE; + } + + BdCurPtr = BdPtr; + RxBufferPtr = RX_BUFFER_BASE; + + for (Index = 0; Index < FreeBdCount; Index++) { + + Status = XAxiDma_BdSetBufAddr(BdCurPtr, RxBufferPtr); + if (Status != XST_SUCCESS) { + xil_printf("Rx set buffer addr %x on BD %x failed %d\r\n", + (unsigned int)RxBufferPtr, + (unsigned int)BdCurPtr, Status); + + return XST_FAILURE; + } + + Status = XAxiDma_BdSetLength(BdCurPtr, MAX_PKT_LEN, + RxRingPtr->MaxTransferLen); + if (Status != XST_SUCCESS) { + xil_printf("Rx set length %d on BD %x failed %d\r\n", + MAX_PKT_LEN, (unsigned int)BdCurPtr, Status); + + return XST_FAILURE; + } + + /* Receive BDs do not need to set anything for the control + * The hardware will set the SOF/EOF bits per stream status + */ + XAxiDma_BdSetCtrl(BdCurPtr, 0); + + XAxiDma_BdSetId(BdCurPtr, RxBufferPtr); + + RxBufferPtr += MAX_PKT_LEN; + BdCurPtr = XAxiDma_BdRingNext(RxRingPtr, BdCurPtr); + } + + /* + * Set the coalescing threshold, so only one receive interrupt + * occurs for this example + * + * If you would like to have multiple interrupts to happen, change + * the COALESCING_COUNT to be a smaller value + */ + Status = XAxiDma_BdRingSetCoalesce(RxRingPtr, COALESCING_COUNT, + DELAY_TIMER_COUNT); + if (Status != XST_SUCCESS) { + xil_printf("Rx set coalesce failed with %d\r\n", Status); + return XST_FAILURE; + } + + Status = XAxiDma_BdRingToHw(RxRingPtr, FreeBdCount, BdPtr); + if (Status != XST_SUCCESS) { + xil_printf("Rx ToHw failed with %d\r\n", Status); + return XST_FAILURE; + } + + /* Enable all RX interrupts */ + XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* Start RX DMA channel */ + Status = XAxiDma_BdRingStart(RxRingPtr); + if (Status != XST_SUCCESS) { + xil_printf("Rx start BD ring failed with %d\r\n", Status); + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/* +* +* This function sets up the TX channel of a DMA engine to be ready for packet +* transmission. +* +* @param AxiDmaInstPtr is the pointer to the instance of the DMA engine. +* +* @return - XST_SUCCESS if the setup is successful. +* - XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +static int TxSetup(XAxiDma * AxiDmaInstPtr) +{ + XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(&AxiDma); + XAxiDma_Bd BdTemplate; + int Status; + u32 BdCount; + + /* Disable all TX interrupts before TxBD space setup */ + XAxiDma_BdRingIntDisable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* Setup TxBD space */ + BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, + (u32)TX_BD_SPACE_HIGH - (u32)TX_BD_SPACE_BASE + 1); + + Status = XAxiDma_BdRingCreate(TxRingPtr, TX_BD_SPACE_BASE, + TX_BD_SPACE_BASE, + XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount); + if (Status != XST_SUCCESS) { + + xil_printf("Failed create BD ring\r\n"); + return XST_FAILURE; + } + + /* + * Like the RxBD space, we create a template and set all BDs to be the + * same as the template. The sender has to set up the BDs as needed. + */ + XAxiDma_BdClear(&BdTemplate); + Status = XAxiDma_BdRingClone(TxRingPtr, &BdTemplate); + if (Status != XST_SUCCESS) { + + xil_printf("Failed clone BDs\r\n"); + return XST_FAILURE; + } + + /* + * Set the coalescing threshold, so only one transmit interrupt + * occurs for this example + * + * If you would like to have multiple interrupts to happen, change + * the COALESCING_COUNT to be a smaller value + */ + Status = XAxiDma_BdRingSetCoalesce(TxRingPtr, COALESCING_COUNT, + DELAY_TIMER_COUNT); + if (Status != XST_SUCCESS) { + + xil_printf("Failed set coalescing" + " %d/%d\r\n",COALESCING_COUNT, DELAY_TIMER_COUNT); + return XST_FAILURE; + } + + /* Enable all TX interrupts */ + XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* Start the TX channel */ + Status = XAxiDma_BdRingStart(TxRingPtr); + if (Status != XST_SUCCESS) { + + xil_printf("Failed bd start\r\n"); + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/* +* +* This function non-blockingly transmits all packets through the DMA engine. +* +* @param AxiDmaInstPtr points to the DMA engine instance +* +* @return +* - XST_SUCCESS if the DMA accepts all the packets successfully, +* - XST_FAILURE if error occurs +* +* @note None. +* +******************************************************************************/ +static int SendPacket(XAxiDma * AxiDmaInstPtr) +{ + XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(AxiDmaInstPtr); + u8 *TxPacket; + u8 Value; + XAxiDma_Bd *BdPtr, *BdCurPtr; + int Status; + int Index, Pkts; + u32 BufferAddr; + + /* + * Each packet is limited to TxRingPtr->MaxTransferLen + * + * This will not be the case if hardware has store and forward built in + */ + if (MAX_PKT_LEN * NUMBER_OF_BDS_PER_PKT > + TxRingPtr->MaxTransferLen) { + + xil_printf("Invalid total per packet transfer length for the " + "packet %d/%d\r\n", + MAX_PKT_LEN * NUMBER_OF_BDS_PER_PKT, + TxRingPtr->MaxTransferLen); + + return XST_INVALID_PARAM; + } + + TxPacket = (u8 *) Packet; + + Value = 0xC; + + for(Index = 0; Index < MAX_PKT_LEN * NUMBER_OF_BDS_TO_TRANSFER; + Index ++) { + TxPacket[Index] = Value; + + Value = (Value + 1) & 0xFF; + } + + /* Flush the SrcBuffer before the DMA transfer, in case the Data Cache + * is enabled + */ + Xil_DCacheFlushRange((u32)TxPacket, MAX_PKT_LEN * + NUMBER_OF_BDS_TO_TRANSFER); + + Status = XAxiDma_BdRingAlloc(TxRingPtr, NUMBER_OF_BDS_TO_TRANSFER, + &BdPtr); + if (Status != XST_SUCCESS) { + + xil_printf("Failed bd alloc\r\n"); + return XST_FAILURE; + } + + BufferAddr = (u32) Packet; + BdCurPtr = BdPtr; + + /* + * Set up the BD using the information of the packet to transmit + * Each transfer has NUMBER_OF_BDS_PER_PKT BDs + */ + for(Index = 0; Index < NUMBER_OF_PKTS_TO_TRANSFER; Index++) { + + for(Pkts = 0; Pkts < NUMBER_OF_BDS_PER_PKT; Pkts++) { + u32 CrBits = 0; + + Status = XAxiDma_BdSetBufAddr(BdCurPtr, BufferAddr); + if (Status != XST_SUCCESS) { + xil_printf("Tx set buffer addr %x on BD %x failed %d\r\n", + (unsigned int)BufferAddr, + (unsigned int)BdCurPtr, Status); + + return XST_FAILURE; + } + + Status = XAxiDma_BdSetLength(BdCurPtr, MAX_PKT_LEN, + TxRingPtr->MaxTransferLen); + if (Status != XST_SUCCESS) { + xil_printf("Tx set length %d on BD %x failed %d\r\n", + MAX_PKT_LEN, (unsigned int)BdCurPtr, Status); + + return XST_FAILURE; + } + + if (Pkts == 0) { + /* The first BD has SOF set + */ + CrBits |= XAXIDMA_BD_CTRL_TXSOF_MASK; + +#if (XPAR_AXIDMA_0_SG_INCLUDE_STSCNTRL_STRM == 1) + /* The first BD has total transfer length set + * in the last APP word, this is for the + * loopback widget + */ + Status = XAxiDma_BdSetAppWord(BdCurPtr, + XAXIDMA_LAST_APPWORD, + MAX_PKT_LEN * NUMBER_OF_BDS_PER_PKT); + + if (Status != XST_SUCCESS) { + xil_printf("Set app word failed with %d\r\n", + Status); + } +#endif + } + + if(Pkts == (NUMBER_OF_BDS_PER_PKT - 1)) { + /* The last BD should have EOF and IOC set + */ + CrBits |= XAXIDMA_BD_CTRL_TXEOF_MASK; + } + + XAxiDma_BdSetCtrl(BdCurPtr, CrBits); + XAxiDma_BdSetId(BdCurPtr, BufferAddr); + + BufferAddr += MAX_PKT_LEN; + BdCurPtr = XAxiDma_BdRingNext(TxRingPtr, BdCurPtr); + } + } + + /* Give the BD to hardware */ + Status = XAxiDma_BdRingToHw(TxRingPtr, NUMBER_OF_BDS_TO_TRANSFER, + BdPtr); + if (Status != XST_SUCCESS) { + + xil_printf("Failed to hw, length %d\r\n", + (int)XAxiDma_BdGetLength(BdPtr, + TxRingPtr->MaxTransferLen)); + + return XST_FAILURE; + } + + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_example_sg_poll.c b/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_example_sg_poll.c new file mode 100644 index 00000000..73b0178d --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_example_sg_poll.c @@ -0,0 +1,688 @@ +/****************************************************************************** +* +* (c) Copyright 2010-2013 Xilinx, Inc. All rights reserved. +* +* This file contains confidential and proprietary information of Xilinx, Inc. +* and is protected under U.S. and international copyright and other +* intellectual property laws. +* +* DISCLAIMER +* This disclaimer is not a license and does not grant any rights to the +* materials distributed herewith. Except as otherwise provided in a valid +* license issued to you by Xilinx, and to the maximum extent permitted by +* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL +* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, +* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF +* MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; +* and (2) Xilinx shall not be liable (whether in contract or tort, including +* negligence, or under any other theory of liability) for any loss or damage +* of any kind or nature related to, arising under or in connection with these +* materials, including for any direct, or any indirect, special, incidental, +* or consequential loss or damage (including loss of data, profits, goodwill, +* or any type of loss or damage suffered as a result of any action brought by +* a third party) even if such damage or loss was reasonably foreseeable or +* Xilinx had been advised of the possibility of the same. +* +* CRITICAL APPLICATIONS +* Xilinx products are not designed or intended to be fail-safe, or for use in +* any application requiring fail-safe performance, such as life-support or +* safety devices or systems, Class III medical devices, nuclear facilities, +* applications related to the deployment of airbags, or any other applications +* that could lead to death, personal injury, or severe property or +* environmental damage (individually and collectively, "Critical +* Applications"). Customer assumes the sole risk and liability of any use of +* Xilinx products in Critical Applications, subject only to applicable laws +* and regulations governing limitations on product liability. +* +* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE +* AT ALL TIMES. +* +******************************************************************************/ +/*****************************************************************************/ +/** + * + * @file xaxidma_example_sg_poll.c + * + * This file demonstrates how to use the xaxidma driver on the Xilinx AXI + * DMA core (AXIDMA) to transfer packets in polling mode when the AXIDMA + * core is configured in Scatter Gather Mode. + * + * This code assumes a loopback hardware widget is connected to the AXI DMA + * core for data packet loopback. + * + * To see the debug print, you need a Uart16550 or uartlite in your system, + * and please set "-DDEBUG" in your compiler options. You need to rebuild your + * software executable. + * + * Make sure that MEMORY_BASE is defined properly as per the HW system. The + * h/w system built in Area mode has a maximum DDR memory limit of 64MB. In + * throughput mode, it is 512MB. These limits are need to ensured for + * proper operation of this code. + * + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -------------------------------------------------------
+ * 1.00a jz   05/17/10 First release
+ * 2.00a jz   08/10/10 Second release, added in xaxidma_g.c, xaxidma_sinit.c,
+ *                     updated tcl file, added xaxidma_porting_guide.h, removed
+ *                     workaround for endianness
+ * 4.00a rkv  02/22/11 Name of the file has been changed for naming consistency
+ *       	       	   Added interrupt support for ARM.
+ * 5.00a srt  03/05/12 Added Flushing and Invalidation of Caches to fix CRs
+ *		       		   648103, 648701.
+ *		       		   Added V7 DDR Base Address to fix CR 649405.
+ * 6.00a srt  03/27/12 Changed API calls to support MCDMA driver.
+ * 7.00a srt  06/18/12 API calls are reverted back for backward compatibility.
+ * 7.01a srt  11/02/12 Buffer sizes (Tx and Rx) are modified to meet maximum
+ *		       DDR memory limit of the h/w system built with Area mode
+ * 7.02a srt  03/01/13 Updated DDR base address for IPI designs (CR 703656).
+ *
+ * 
+ * + * *************************************************************************** + */ +/***************************** Include Files *********************************/ +#include "xaxidma.h" +#include "xparameters.h" +#include "xdebug.h" + +#if defined(XPAR_UARTNS550_0_BASEADDR) +#include "xuartns550_l.h" /* to use uartns550 */ +#endif + +#if (!defined(DEBUG)) +extern void xil_printf(const char *format, ...); +#endif + +/******************** Constant Definitions **********************************/ + +/* + * Device hardware build related constants. + */ + +#define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID + +#ifdef XPAR_V6DDR_0_S_AXI_BASEADDR +#define DDR_BASE_ADDR XPAR_V6DDR_0_S_AXI_BASEADDR +#elif XPAR_S6DDR_0_S0_AXI_BASEADDR +#define DDR_BASE_ADDR XPAR_S6DDR_0_S0_AXI_BASEADDR +#elif XPAR_AXI_7SDDR_0_S_AXI_BASEADDR +#define DDR_BASE_ADDR XPAR_AXI_7SDDR_0_S_AXI_BASEADDR +#elif XPAR_MIG7SERIES_0_BASEADDR +#define DDR_BASE_ADDR XPAR_MIG7SERIES_0_BASEADDR +#endif + +#ifndef DDR_BASE_ADDR +#warning CHECK FOR THE VALID DDR ADDRESS IN XPARAMETERS.H, \ + DEFAULT SET TO 0x01000000 +#define MEM_BASE_ADDR 0x01000000 +#else +#define MEM_BASE_ADDR (DDR_BASE_ADDR + 0x1000000) +#endif + +#define TX_BD_SPACE_BASE (MEM_BASE_ADDR) +#define TX_BD_SPACE_HIGH (MEM_BASE_ADDR + 0x00000FFF) +#define RX_BD_SPACE_BASE (MEM_BASE_ADDR + 0x00001000) +#define RX_BD_SPACE_HIGH (MEM_BASE_ADDR + 0x00001FFF) +#define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000) +#define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00300000) +#define RX_BUFFER_HIGH (MEM_BASE_ADDR + 0x004FFFFF) + + +#define MAX_PKT_LEN 0x20 + +#define TEST_START_VALUE 0xC + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ +#if defined(XPAR_UARTNS550_0_BASEADDR) +static void Uart550_Setup(void); +#endif + +static int RxSetup(XAxiDma * AxiDmaInstPtr); +static int TxSetup(XAxiDma * AxiDmaInstPtr); +static int SendPacket(XAxiDma * AxiDmaInstPtr); +static int CheckData(void); +static int CheckDmaResult(XAxiDma * AxiDmaInstPtr); + +/************************** Variable Definitions *****************************/ +/* + * Device instance definitions + */ +XAxiDma AxiDma; + +/* + * Buffer for transmit packet. Must be 32-bit aligned to be used by DMA. + */ +u32 *Packet = (u32 *) TX_BUFFER_BASE; + +/*****************************************************************************/ +/** +* +* Main function +* +* This function is the main entry of the tests on DMA core. It sets up +* DMA engine to be ready to receive and send packets, then a packet is +* transmitted and will be verified after it is received via the DMA loopback +* widget. +* +* @param None +* +* @return +* - XST_SUCCESS if test passes +* - XST_FAILURE if test fails. +* +* @note None. +* +******************************************************************************/ +int main(void) +{ + int Status; + XAxiDma_Config *Config; + +#if defined(XPAR_UARTNS550_0_BASEADDR) + + Uart550_Setup(); + +#endif + + xil_printf("\r\n--- Entering main() --- \r\n"); + + Config = XAxiDma_LookupConfig(DMA_DEV_ID); + if (!Config) { + xil_printf("No config found for %d\r\n", DMA_DEV_ID); + + return XST_FAILURE; + } + + /* Initialize DMA engine */ + Status = XAxiDma_CfgInitialize(&AxiDma, Config); + if (Status != XST_SUCCESS) { + xil_printf("Initialization failed %d\r\n", Status); + return XST_FAILURE; + } + + if(!XAxiDma_HasSg(&AxiDma)) { + xil_printf("Device configured as Simple mode \r\n"); + + return XST_FAILURE; + } + + Status = TxSetup(&AxiDma); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + Status = RxSetup(&AxiDma); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* Send a packet */ + Status = SendPacket(&AxiDma); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* Check DMA transfer result */ + Status = CheckDmaResult(&AxiDma); + + xil_printf("AXI DMA SG Polling Test %s\r\n", + (Status == XST_SUCCESS)? "passed":"failed"); + + xil_printf("--- Exiting main() --- \r\n"); + + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +#if defined(XPAR_UARTNS550_0_BASEADDR) +/*****************************************************************************/ +/* +* +* Uart16550 setup routine, need to set baudrate to 9600, and data bits to 8 +* +* @param None +* +* @return None +* +* @note None. +* +******************************************************************************/ +static void Uart550_Setup(void) +{ + + /* Set the baudrate to be predictable + */ + XUartNs550_SetBaud(XPAR_UARTNS550_0_BASEADDR, + XPAR_XUARTNS550_CLOCK_HZ, 9600); + + XUartNs550_SetLineControlReg(XPAR_UARTNS550_0_BASEADDR, + XUN_LCR_8_DATA_BITS); + +} +#endif + +/*****************************************************************************/ +/** +* +* This function sets up RX channel of the DMA engine to be ready for packet +* reception +* +* @param AxiDmaInstPtr is the pointer to the instance of the DMA engine. +* +* @return XST_SUCCESS if the setup is successful, XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +static int RxSetup(XAxiDma * AxiDmaInstPtr) +{ + XAxiDma_BdRing *RxRingPtr; + int Delay = 0; + int Coalesce = 1; + int Status; + XAxiDma_Bd BdTemplate; + XAxiDma_Bd *BdPtr; + XAxiDma_Bd *BdCurPtr; + u32 BdCount; + u32 FreeBdCount; + u32 RxBufferPtr; + int Index; + + RxRingPtr = XAxiDma_GetRxRing(&AxiDma); + + /* Disable all RX interrupts before RxBD space setup */ + + XAxiDma_BdRingIntDisable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* Set delay and coalescing */ + XAxiDma_BdRingSetCoalesce(RxRingPtr, Coalesce, Delay); + + /* Setup Rx BD space */ + BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, + RX_BD_SPACE_HIGH - RX_BD_SPACE_BASE + 1); + + Status = XAxiDma_BdRingCreate(RxRingPtr, RX_BD_SPACE_BASE, + RX_BD_SPACE_BASE, + XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount); + + if (Status != XST_SUCCESS) { + xil_printf("RX create BD ring failed %d\r\n", Status); + + return XST_FAILURE; + } + + /* + * Setup an all-zero BD as the template for the Rx channel. + */ + XAxiDma_BdClear(&BdTemplate); + + Status = XAxiDma_BdRingClone(RxRingPtr, &BdTemplate); + if (Status != XST_SUCCESS) { + xil_printf("RX clone BD failed %d\r\n", Status); + + return XST_FAILURE; + } + + /* Attach buffers to RxBD ring so we are ready to receive packets */ + + FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr); + + Status = XAxiDma_BdRingAlloc(RxRingPtr, FreeBdCount, &BdPtr); + if (Status != XST_SUCCESS) { + xil_printf("RX alloc BD failed %d\r\n", Status); + + return XST_FAILURE; + } + + BdCurPtr = BdPtr; + RxBufferPtr = RX_BUFFER_BASE; + for (Index = 0; Index < FreeBdCount; Index++) { + Status = XAxiDma_BdSetBufAddr(BdCurPtr, RxBufferPtr); + + if (Status != XST_SUCCESS) { + xil_printf("Set buffer addr %x on BD %x failed %d\r\n", + (unsigned int)RxBufferPtr, + (unsigned int)BdCurPtr, Status); + + return XST_FAILURE; + } + + Status = XAxiDma_BdSetLength(BdCurPtr, MAX_PKT_LEN, + RxRingPtr->MaxTransferLen); + if (Status != XST_SUCCESS) { + xil_printf("Rx set length %d on BD %x failed %d\r\n", + MAX_PKT_LEN, (unsigned int)BdCurPtr, Status); + + return XST_FAILURE; + } + + /* Receive BDs do not need to set anything for the control + * The hardware will set the SOF/EOF bits per stream status + */ + XAxiDma_BdSetCtrl(BdCurPtr, 0); + XAxiDma_BdSetId(BdCurPtr, RxBufferPtr); + + RxBufferPtr += MAX_PKT_LEN; + BdCurPtr = XAxiDma_BdRingNext(RxRingPtr, BdCurPtr); + } + + /* Clear the receive buffer, so we can verify data + */ + memset((void *)RX_BUFFER_BASE, 0, MAX_PKT_LEN); + + Status = XAxiDma_BdRingToHw(RxRingPtr, FreeBdCount, + BdPtr); + if (Status != XST_SUCCESS) { + xil_printf("RX submit hw failed %d\r\n", Status); + + return XST_FAILURE; + } + + /* Start RX DMA channel */ + Status = XAxiDma_BdRingStart(RxRingPtr); + if (Status != XST_SUCCESS) { + xil_printf("RX start hw failed %d\r\n", Status); + + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function sets up the TX channel of a DMA engine to be ready for packet +* transmission +* +* @param AxiDmaInstPtr is the instance pointer to the DMA engine. +* +* @return XST_SUCCESS if the setup is successful, XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +static int TxSetup(XAxiDma * AxiDmaInstPtr) +{ + XAxiDma_BdRing *TxRingPtr; + XAxiDma_Bd BdTemplate; + int Delay = 0; + int Coalesce = 1; + int Status; + u32 BdCount; + + TxRingPtr = XAxiDma_GetTxRing(&AxiDma); + + /* Disable all TX interrupts before TxBD space setup */ + + XAxiDma_BdRingIntDisable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* Set TX delay and coalesce */ + XAxiDma_BdRingSetCoalesce(TxRingPtr, Coalesce, Delay); + + /* Setup TxBD space */ + BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, + TX_BD_SPACE_HIGH - TX_BD_SPACE_BASE + 1); + + Status = XAxiDma_BdRingCreate(TxRingPtr, TX_BD_SPACE_BASE, + TX_BD_SPACE_BASE, + XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount); + if (Status != XST_SUCCESS) { + xil_printf("failed create BD ring in txsetup\r\n"); + + return XST_FAILURE; + } + + /* + * We create an all-zero BD as the template. + */ + XAxiDma_BdClear(&BdTemplate); + + Status = XAxiDma_BdRingClone(TxRingPtr, &BdTemplate); + if (Status != XST_SUCCESS) { + xil_printf("failed bdring clone in txsetup %d\r\n", Status); + + return XST_FAILURE; + } + + /* Start the TX channel */ + Status = XAxiDma_BdRingStart(TxRingPtr); + if (Status != XST_SUCCESS) { + xil_printf("failed start bdring txsetup %d\r\n", Status); + + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function transmits one packet non-blockingly through the DMA engine. +* +* @param AxiDmaInstPtr points to the DMA engine instance +* +* @return - XST_SUCCESS if the DMA accepts the packet successfully, +* - XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +static int SendPacket(XAxiDma * AxiDmaInstPtr) +{ + XAxiDma_BdRing *TxRingPtr; + u8 *TxPacket; + u8 Value; + XAxiDma_Bd *BdPtr; + int Status; + int Index; + + TxRingPtr = XAxiDma_GetTxRing(AxiDmaInstPtr); + + /* Create pattern in the packet to transmit */ + TxPacket = (u8 *) Packet; + + Value = TEST_START_VALUE; + + for(Index = 0; Index < MAX_PKT_LEN; Index ++) { + TxPacket[Index] = Value; + + Value = (Value + 1) & 0xFF; + } + + /* Flush the SrcBuffer before the DMA transfer, in case the Data Cache + * is enabled + */ + Xil_DCacheFlushRange((u32)TxPacket, MAX_PKT_LEN); + + + /* Allocate a BD */ + Status = XAxiDma_BdRingAlloc(TxRingPtr, 1, &BdPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* Set up the BD using the information of the packet to transmit */ + Status = XAxiDma_BdSetBufAddr(BdPtr, (u32) Packet); + if (Status != XST_SUCCESS) { + xil_printf("Tx set buffer addr %x on BD %x failed %d\r\n", + (unsigned int)Packet, (unsigned int)BdPtr, Status); + + return XST_FAILURE; + } + + Status = XAxiDma_BdSetLength(BdPtr, MAX_PKT_LEN, + TxRingPtr->MaxTransferLen); + if (Status != XST_SUCCESS) { + xil_printf("Tx set length %d on BD %x failed %d\r\n", + MAX_PKT_LEN, (unsigned int)BdPtr, Status); + + return XST_FAILURE; + } + +#if (XPAR_AXIDMA_0_SG_INCLUDE_STSCNTRL_STRM == 1) + Status = XAxiDma_BdSetAppWord(BdPtr, + XAXIDMA_LAST_APPWORD, MAX_PKT_LEN); + + /* If Set app length failed, it is not fatal + */ + if (Status != XST_SUCCESS) { + xil_printf("Set app word failed with %d\r\n", Status); + } +#endif + + /* For single packet, both SOF and EOF are to be set + */ + XAxiDma_BdSetCtrl(BdPtr, XAXIDMA_BD_CTRL_TXEOF_MASK | + XAXIDMA_BD_CTRL_TXSOF_MASK); + + XAxiDma_BdSetId(BdPtr, (u32) Packet); + + /* Give the BD to DMA to kick off the transmission. */ + Status = XAxiDma_BdRingToHw(TxRingPtr, 1, BdPtr); + if (Status != XST_SUCCESS) { + xil_printf("to hw failed %d\r\n", Status); + return XST_FAILURE; + } + + + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/* +* +* This function checks data buffer after the DMA transfer is finished. +* +* @param None +* +* @return - XST_SUCCESS if validation is successful +* - XST_FAILURE if validation is failure. +* +* @note None. +* +******************************************************************************/ +static int CheckData(void) +{ + u8 *RxPacket; + int Index = 0; + u8 Value; + + + RxPacket = (u8 *) RX_BUFFER_BASE; + Value = TEST_START_VALUE; + + /* Invalidate the DestBuffer before receiving the data, in case the + * Data Cache is enabled + */ + Xil_DCacheInvalidateRange((u32)RxPacket, MAX_PKT_LEN); + + for(Index = 0; Index < MAX_PKT_LEN; Index++) { + if (RxPacket[Index] != Value) { + xil_printf("Data error %d: %x/%x\r\n", + Index, (unsigned int)RxPacket[Index], + (unsigned int)Value); + + return XST_FAILURE; + } + Value = (Value + 1) & 0xFF; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function waits until the DMA transaction is finished, checks data, +* and cleans up. +* +* @param None +* +* @return - XST_SUCCESS if DMA transfer is successful and data is correct, +* - XST_FAILURE if fails. +* +* @note None. +* +******************************************************************************/ +static int CheckDmaResult(XAxiDma * AxiDmaInstPtr) +{ + XAxiDma_BdRing *TxRingPtr; + XAxiDma_BdRing *RxRingPtr; + XAxiDma_Bd *BdPtr; + int ProcessedBdCount; + int FreeBdCount; + int Status; + + TxRingPtr = XAxiDma_GetTxRing(AxiDmaInstPtr); + RxRingPtr = XAxiDma_GetRxRing(AxiDmaInstPtr); + + /* Wait until the one BD TX transaction is done */ + while ((ProcessedBdCount = XAxiDma_BdRingFromHw(TxRingPtr, + XAXIDMA_ALL_BDS, + &BdPtr)) == 0) { + } + + /* Free all processed TX BDs for future transmission */ + Status = XAxiDma_BdRingFree(TxRingPtr, ProcessedBdCount, BdPtr); + if (Status != XST_SUCCESS) { + xil_printf("Failed to free %d tx BDs %d\r\n", + ProcessedBdCount, Status); + return XST_FAILURE; + } + + /* Wait until the data has been received by the Rx channel */ + while ((ProcessedBdCount = XAxiDma_BdRingFromHw(RxRingPtr, + XAXIDMA_ALL_BDS, + &BdPtr)) == 0) { + } + + /* Check received data */ + if (CheckData() != XST_SUCCESS) { + + return XST_FAILURE; + } + + /* Free all processed RX BDs for future transmission */ + Status = XAxiDma_BdRingFree(RxRingPtr, ProcessedBdCount, BdPtr); + if (Status != XST_SUCCESS) { + xil_printf("Failed to free %d rx BDs %d\r\n", + ProcessedBdCount, Status); + return XST_FAILURE; + } + + /* Return processed BDs to RX channel so we are ready to receive new + * packets: + * - Allocate all free RX BDs + * - Pass the BDs to RX channel + */ + FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr); + Status = XAxiDma_BdRingAlloc(RxRingPtr, FreeBdCount, &BdPtr); + if (Status != XST_SUCCESS) { + xil_printf("bd alloc failed\r\n"); + return XST_FAILURE; + } + + Status = XAxiDma_BdRingToHw(RxRingPtr, FreeBdCount, BdPtr); + if (Status != XST_SUCCESS) { + xil_printf("Submit %d rx BDs failed %d\r\n", FreeBdCount, Status); + return XST_FAILURE; + } + + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_example_simple_intr.c b/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_example_simple_intr.c new file mode 100644 index 00000000..5a42ca63 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_example_simple_intr.c @@ -0,0 +1,748 @@ +/****************************************************************************** +* +* (c) Copyright 2010-2013 Xilinx, Inc. All rights reserved. +* +* This file contains confidential and proprietary information of Xilinx, Inc. +* and is protected under U.S. and international copyright and other +* intellectual property laws. +* +* DISCLAIMER +* This disclaimer is not a license and does not grant any rights to the +* materials distributed herewith. Except as otherwise provided in a valid +* license issued to you by Xilinx, and to the maximum extent permitted by +* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL +* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, +* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF +* MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; +* and (2) Xilinx shall not be liable (whether in contract or tort, including +* negligence, or under any other theory of liability) for any loss or damage +* of any kind or nature related to, arising under or in connection with these +* materials, including for any direct, or any indirect, special, incidental, +* or consequential loss or damage (including loss of data, profits, goodwill, +* or any type of loss or damage suffered as a result of any action brought by +* a third party) even if such damage or loss was reasonably foreseeable or +* Xilinx had been advised of the possibility of the same. +* +* CRITICAL APPLICATIONS +* Xilinx products are not designed or intended to be fail-safe, or for use in +* any application requiring fail-safe performance, such as life-support or +* safety devices or systems, Class III medical devices, nuclear facilities, +* applications related to the deployment of airbags, or any other applications +* that could lead to death, personal injury, or severe property or +* environmental damage (individually and collectively, "Critical +* Applications"). Customer assumes the sole risk and liability of any use of +* Xilinx products in Critical Applications, subject only to applicable laws +* and regulations governing limitations on product liability. +* +* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE +* AT ALL TIMES. +* +******************************************************************************/ +/*****************************************************************************/ +/** + * + * @file xaxidma_example_simple_intr.c + * + * This file demonstrates how to use the xaxidma driver on the Xilinx AXI + * DMA core (AXIDMA) to transfer packets.in interrupt mode when the AXIDMA core + * is configured in simple mode + * + * This code assumes a loopback hardware widget is connected to the AXI DMA + * core for data packet loopback. + * + * To see the debug print, you need a Uart16550 or uartlite in your system, + * and please set "-DDEBUG" in your compiler options. You need to rebuild your + * software executable. + * + * Make sure that MEMORY_BASE is defined properly as per the HW system. The + * h/w system built in Area mode has a maximum DDR memory limit of 64MB. In + * throughput mode, it is 512MB. These limits are need to ensured for + * proper operation of this code. + * + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -------------------------------------------------------
+ * 4.00a rkv  02/22/11 New example created for simple DMA, this example is for
+ *       	       simple DMA,Added interrupt support for Zynq.
+ * 4.00a srt  08/04/11 Changed a typo in the RxIntrHandler, changed
+ *		       XAXIDMA_DMA_TO_DEVICE to XAXIDMA_DEVICE_TO_DMA
+ * 5.00a srt  03/06/12 Added Flushing and Invalidation of Caches to fix CRs
+ *		       648103, 648701.
+ *		       Added V7 DDR Base Address to fix CR 649405.
+ * 6.00a srt  03/27/12 Changed API calls to support MCDMA driver.
+ * 7.00a srt  06/18/12 API calls are reverted back for backward compatibility.
+ * 7.01a srt  11/02/12 Buffer sizes (Tx and Rx) are modified to meet maximum
+ *		       DDR memory limit of the h/w system built with Area mode
+ * 7.02a srt  03/01/13 Updated DDR base address for IPI designs (CR 703656).
+ *
+ * 
+ * + * *************************************************************************** + */ + +/***************************** Include Files *********************************/ + +#include "xaxidma.h" +#include "xparameters.h" +#include "xil_exception.h" +#include "xdebug.h" + +#ifdef XPAR_UARTNS550_0_BASEADDR +#include "xuartns550_l.h" /* to use uartns550 */ +#endif + + +#ifdef XPAR_INTC_0_DEVICE_ID + #include "xintc.h" +#else + #include "xscugic.h" +#endif + +/************************** Constant Definitions *****************************/ + +/* + * Device hardware build related constants. + */ + +#define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID + +#ifdef XPAR_V6DDR_0_S_AXI_BASEADDR +#define DDR_BASE_ADDR XPAR_V6DDR_0_S_AXI_BASEADDR +#elif XPAR_S6DDR_0_S0_AXI_BASEADDR +#define DDR_BASE_ADDR XPAR_S6DDR_0_S0_AXI_BASEADDR +#elif XPAR_AXI_7SDDR_0_S_AXI_BASEADDR +#define DDR_BASE_ADDR XPAR_AXI_7SDDR_0_S_AXI_BASEADDR +#elif XPAR_MIG7SERIES_0_BASEADDR +#define DDR_BASE_ADDR XPAR_MIG7SERIES_0_BASEADDR +#endif + +#ifndef DDR_BASE_ADDR +#warning CHECK FOR THE VALID DDR ADDRESS IN XPARAMETERS.H, \ + DEFAULT SET TO 0x01000000 +#define MEM_BASE_ADDR 0x01000000 +#else +#define MEM_BASE_ADDR (DDR_BASE_ADDR + 0x1000000) +#endif + +#ifdef XPAR_INTC_0_DEVICE_ID +#define RX_INTR_ID XPAR_INTC_0_AXIDMA_0_S2MM_INTROUT_VEC_ID +#define TX_INTR_ID XPAR_INTC_0_AXIDMA_0_MM2S_INTROUT_VEC_ID +#else +#define RX_INTR_ID XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID +#define TX_INTR_ID XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID +#endif + +#define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000) +#define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00300000) +#define RX_BUFFER_HIGH (MEM_BASE_ADDR + 0x004FFFFF) + +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#else +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#endif + +#ifdef XPAR_INTC_0_DEVICE_ID + #define INTC XIntc + #define INTC_HANDLER XIntc_InterruptHandler +#else + #define INTC XScuGic + #define INTC_HANDLER XScuGic_InterruptHandler +#endif + + +/* Timeout loop counter for reset + */ +#define RESET_TIMEOUT_COUNTER 10000 + +#define TEST_START_VALUE 0xC +/* + * Buffer and Buffer Descriptor related constant definition + */ +#define MAX_PKT_LEN 0x100 + +#define NUMBER_OF_TRANSFERS 10 + +/* The interrupt coalescing threshold and delay timer threshold + * Valid range is 1 to 255 + * + * We set the coalescing threshold to be the total number of packets. + * The receive side will only get one completion interrupt for this example. + */ + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ +#ifndef DEBUG +extern void xil_printf(const char *format, ...); +#endif + +#ifdef XPAR_UARTNS550_0_BASEADDR +static void Uart550_Setup(void); +#endif + +static int CheckData(int Length, u8 StartValue); +static void TxIntrHandler(void *Callback); +static void RxIntrHandler(void *Callback); + + + + +static int SetupIntrSystem(INTC * IntcInstancePtr, + XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId); +static void DisableIntrSystem(INTC * IntcInstancePtr, + u16 TxIntrId, u16 RxIntrId); + + + +/************************** Variable Definitions *****************************/ +/* + * Device instance definitions + */ + + +static XAxiDma AxiDma; /* Instance of the XAxiDma */ + +static INTC Intc; /* Instance of the Interrupt Controller */ + +/* + * Flags interrupt handlers use to notify the application context the events. + */ +volatile int TxDone; +volatile int RxDone; +volatile int Error; + +/*****************************************************************************/ +/** +* +* Main function +* +* This function is the main entry of the interrupt test. It does the following: +* Set up the output terminal if UART16550 is in the hardware build +* Initialize the DMA engine +* Set up Tx and Rx channels +* Set up the interrupt system for the Tx and Rx interrupts +* Submit a transfer +* Wait for the transfer to finish +* Check transfer status +* Disable Tx and Rx interrupts +* Print test status and exit +* +* @param None +* +* @return +* - XST_SUCCESS if example finishes successfully +* - XST_FAILURE if example fails. +* +* @note None. +* +******************************************************************************/ +int main(void) +{ + int Status; + XAxiDma_Config *Config; + int Tries = NUMBER_OF_TRANSFERS; + int Index; + u8 *TxBufferPtr; + u8 *RxBufferPtr; + u8 Value; + + TxBufferPtr = (u8 *)TX_BUFFER_BASE ; + RxBufferPtr = (u8 *)RX_BUFFER_BASE; + /* Initial setup for Uart16550 */ +#ifdef XPAR_UARTNS550_0_BASEADDR + + Uart550_Setup(); + +#endif + + xil_printf("\r\n--- Entering main() --- \r\n"); + + Config = XAxiDma_LookupConfig(DMA_DEV_ID); + if (!Config) { + xil_printf("No config found for %d\r\n", DMA_DEV_ID); + + return XST_FAILURE; + } + + /* Initialize DMA engine */ + Status = XAxiDma_CfgInitialize(&AxiDma, Config); + + if (Status != XST_SUCCESS) { + xil_printf("Initialization failed %d\r\n", Status); + return XST_FAILURE; + } + + if(XAxiDma_HasSg(&AxiDma)){ + xil_printf("Device configured as SG mode \r\n"); + return XST_FAILURE; + } + + /* Set up Interrupt system */ + Status = SetupIntrSystem(&Intc, &AxiDma, TX_INTR_ID, RX_INTR_ID); + if (Status != XST_SUCCESS) { + + xil_printf("Failed intr setup\r\n"); + return XST_FAILURE; + } + + /* Disable all interrupts before setup */ + + XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK, + XAXIDMA_DMA_TO_DEVICE); + + XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK, + XAXIDMA_DEVICE_TO_DMA); + + /* Enable all interrupts */ + XAxiDma_IntrEnable(&AxiDma, XAXIDMA_IRQ_ALL_MASK, + XAXIDMA_DMA_TO_DEVICE); + + + XAxiDma_IntrEnable(&AxiDma, XAXIDMA_IRQ_ALL_MASK, + XAXIDMA_DEVICE_TO_DMA); + + /* Initialize flags before start transfer test */ + TxDone = 0; + RxDone = 0; + Error = 0; + + Value = TEST_START_VALUE; + + for(Index = 0; Index < MAX_PKT_LEN; Index ++) { + TxBufferPtr[Index] = Value; + + Value = (Value + 1) & 0xFF; + } + + /* Flush the SrcBuffer before the DMA transfer, in case the Data Cache + * is enabled + */ + Xil_DCacheFlushRange((u32)TxBufferPtr, MAX_PKT_LEN); + + /* Send a packet */ + for(Index = 0; Index < Tries; Index ++) { + + Status = XAxiDma_SimpleTransfer(&AxiDma,(u32) RxBufferPtr, + MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA); + + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + Status = XAxiDma_SimpleTransfer(&AxiDma,(u32) TxBufferPtr, + MAX_PKT_LEN, XAXIDMA_DMA_TO_DEVICE); + + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + /* + * Wait TX done and RX done + */ + while (!TxDone && !RxDone && !Error) { + /* NOP */ + } + + if (Error) { + xil_printf("Failed test transmit%s done, " + "receive%s done\r\n", TxDone? "":" not", + RxDone? "":" not"); + + goto Done; + + } + + /* + * Test finished, check data + */ + Status = CheckData(MAX_PKT_LEN, 0xC); + if (Status != XST_SUCCESS) { + xil_printf("Data check failed\r\n"); + goto Done; + } + } + + + xil_printf("AXI DMA interrupt example test passed\r\n"); + + + /* Disable TX and RX Ring interrupts and return success */ + + DisableIntrSystem(&Intc, TX_INTR_ID, RX_INTR_ID); + +Done: + xil_printf("--- Exiting main() --- \r\n"); + + return XST_SUCCESS; +} + +#ifdef XPAR_UARTNS550_0_BASEADDR +/*****************************************************************************/ +/* +* +* Uart16550 setup routine, need to set baudrate to 9600 and data bits to 8 +* +* @param None +* +* @return None +* +* @note None. +* +******************************************************************************/ +static void Uart550_Setup(void) +{ + + XUartNs550_SetBaud(XPAR_UARTNS550_0_BASEADDR, + XPAR_XUARTNS550_CLOCK_HZ, 9600); + + XUartNs550_SetLineControlReg(XPAR_UARTNS550_0_BASEADDR, + XUN_LCR_8_DATA_BITS); +} +#endif + +/*****************************************************************************/ +/* +* +* This function checks data buffer after the DMA transfer is finished. +* +* We use the static tx/rx buffers. +* +* @param Length is the length to check +* @param StartValue is the starting value of the first byte +* +* @return +* - XST_SUCCESS if validation is successful +* - XST_FAILURE if validation is failure. +* +* @note None. +* +******************************************************************************/ +static int CheckData(int Length, u8 StartValue) +{ + u8 *RxPacket; + int Index = 0; + u8 Value; + + RxPacket = (u8 *) RX_BUFFER_BASE; + Value = StartValue; + + /* Invalidate the DestBuffer before receiving the data, in case the + * Data Cache is enabled + */ + Xil_DCacheInvalidateRange((u32)RxPacket, Length); + + for(Index = 0; Index < Length; Index++) { + if (RxPacket[Index] != Value) { + xil_printf("Data error %d: %x/%x\r\n", + Index, RxPacket[Index], Value); + + return XST_FAILURE; + } + Value = (Value + 1) & 0xFF; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/* +* +* This is the DMA TX Interrupt handler function. +* +* It gets the interrupt status from the hardware, acknowledges it, and if any +* error happens, it resets the hardware. Otherwise, if a completion interrupt +* is present, then sets the TxDone.flag +* +* @param Callback is a pointer to TX channel of the DMA engine. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void TxIntrHandler(void *Callback) +{ + + u32 IrqStatus; + int TimeOut; + XAxiDma *AxiDmaInst = (XAxiDma *)Callback; + + /* Read pending interrupts */ + IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DMA_TO_DEVICE); + + /* Acknowledge pending interrupts */ + + + XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DMA_TO_DEVICE); + + /* + * If no interrupt is asserted, we do not do anything + */ + if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) { + + return; + } + + /* + * If error interrupt is asserted, raise error flag, reset the + * hardware to recover from the error, and return with no further + * processing. + */ + if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) { + + Error = 1; + + /* + * Reset should never fail for transmit channel + */ + XAxiDma_Reset(AxiDmaInst); + + TimeOut = RESET_TIMEOUT_COUNTER; + + while (TimeOut) { + if (XAxiDma_ResetIsDone(AxiDmaInst)) { + break; + } + + TimeOut -= 1; + } + + return; + } + + /* + * If Completion interrupt is asserted, then set the TxDone flag + */ + if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) { + + TxDone = 1; + } +} + +/*****************************************************************************/ +/* +* +* This is the DMA RX interrupt handler function +* +* It gets the interrupt status from the hardware, acknowledges it, and if any +* error happens, it resets the hardware. Otherwise, if a completion interrupt +* is present, then it sets the RxDone flag. +* +* @param Callback is a pointer to RX channel of the DMA engine. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void RxIntrHandler(void *Callback) +{ + u32 IrqStatus; + int TimeOut; + XAxiDma *AxiDmaInst = (XAxiDma *)Callback; + + /* Read pending interrupts */ + IrqStatus = XAxiDma_IntrGetIrq(AxiDmaInst, XAXIDMA_DEVICE_TO_DMA); + + /* Acknowledge pending interrupts */ + XAxiDma_IntrAckIrq(AxiDmaInst, IrqStatus, XAXIDMA_DEVICE_TO_DMA); + + /* + * If no interrupt is asserted, we do not do anything + */ + if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) { + return; + } + + /* + * If error interrupt is asserted, raise error flag, reset the + * hardware to recover from the error, and return with no further + * processing. + */ + if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) { + + Error = 1; + + /* Reset could fail and hang + * NEED a way to handle this or do not call it?? + */ + XAxiDma_Reset(AxiDmaInst); + + TimeOut = RESET_TIMEOUT_COUNTER; + + while (TimeOut) { + if(XAxiDma_ResetIsDone(AxiDmaInst)) { + break; + } + + TimeOut -= 1; + } + + return; + } + + /* + * If completion interrupt is asserted, then set RxDone flag + */ + if ((IrqStatus & XAXIDMA_IRQ_IOC_MASK)) { + + RxDone = 1; + } +} + +/*****************************************************************************/ +/* +* +* This function setups the interrupt system so interrupts can occur for the +* DMA, it assumes INTC component exists in the hardware system. +* +* @param IntcInstancePtr is a pointer to the instance of the INTC. +* @param AxiDmaPtr is a pointer to the instance of the DMA engine +* @param TxIntrId is the TX channel Interrupt ID. +* @param RxIntrId is the RX channel Interrupt ID. +* +* @return +* - XST_SUCCESS if successful, +* - XST_FAILURE.if not succesful +* +* @note None. +* +******************************************************************************/ +static int SetupIntrSystem(INTC * IntcInstancePtr, + XAxiDma * AxiDmaPtr, u16 TxIntrId, u16 RxIntrId) +{ + int Status; + +#ifdef XPAR_INTC_0_DEVICE_ID + + /* Initialize the interrupt controller and connect the ISRs */ + Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID); + if (Status != XST_SUCCESS) { + + xil_printf("Failed init intc\r\n"); + return XST_FAILURE; + } + + Status = XIntc_Connect(IntcInstancePtr, TxIntrId, + (XInterruptHandler) TxIntrHandler, AxiDmaPtr); + if (Status != XST_SUCCESS) { + + xil_printf("Failed tx connect intc\r\n"); + return XST_FAILURE; + } + + Status = XIntc_Connect(IntcInstancePtr, RxIntrId, + (XInterruptHandler) RxIntrHandler, AxiDmaPtr); + if (Status != XST_SUCCESS) { + + xil_printf("Failed rx connect intc\r\n"); + return XST_FAILURE; + } + + /* Start the interrupt controller */ + Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE); + if (Status != XST_SUCCESS) { + + xil_printf("Failed to start intc\r\n"); + return XST_FAILURE; + } + + XIntc_Enable(IntcInstancePtr, TxIntrId); + XIntc_Enable(IntcInstancePtr, RxIntrId); + +#else + + XScuGic_Config *IntcConfig; + + + /* + * Initialize the interrupt controller driver so that it is ready to + * use. + */ + IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); + if (NULL == IntcConfig) { + return XST_FAILURE; + } + + Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, + IntcConfig->CpuBaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + XScuGic_SetPriorityTriggerType(IntcInstancePtr, TxIntrId, 0xA0, 0x3); + + XScuGic_SetPriorityTriggerType(IntcInstancePtr, RxIntrId, 0xA0, 0x3); + /* + * Connect the device driver handler that will be called when an + * interrupt for the device occurs, the handler defined above performs + * the specific interrupt processing for the device. + */ + Status = XScuGic_Connect(IntcInstancePtr, TxIntrId, + (Xil_InterruptHandler)TxIntrHandler, + AxiDmaPtr); + if (Status != XST_SUCCESS) { + return Status; + } + + Status = XScuGic_Connect(IntcInstancePtr, RxIntrId, + (Xil_InterruptHandler)RxIntrHandler, + AxiDmaPtr); + if (Status != XST_SUCCESS) { + return Status; + } + + XScuGic_Enable(IntcInstancePtr, TxIntrId); + XScuGic_Enable(IntcInstancePtr, RxIntrId); + + +#endif + + /* Enable interrupts from the hardware */ + + Xil_ExceptionInit(); + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler)INTC_HANDLER, + (void *)IntcInstancePtr); + + Xil_ExceptionEnable(); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function disables the interrupts for DMA engine. +* +* @param IntcInstancePtr is the pointer to the INTC component instance +* @param TxIntrId is interrupt ID associated w/ DMA TX channel +* @param RxIntrId is interrupt ID associated w/ DMA RX channel +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void DisableIntrSystem(INTC * IntcInstancePtr, + u16 TxIntrId, u16 RxIntrId) +{ +#ifdef XPAR_INTC_0_DEVICE_ID + /* Disconnect the interrupts for the DMA TX and RX channels */ + XIntc_Disconnect(IntcInstancePtr, TxIntrId); + XIntc_Disconnect(IntcInstancePtr, RxIntrId); +#else + XScuGic_Disconnect(IntcInstancePtr, TxIntrId); + XScuGic_Disconnect(IntcInstancePtr, RxIntrId); +#endif +} diff --git a/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_example_simple_poll.c b/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_example_simple_poll.c new file mode 100644 index 00000000..a9ef0700 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_example_simple_poll.c @@ -0,0 +1,357 @@ +/****************************************************************************** +* +* (c) Copyright 2010-2013 Xilinx, Inc. All rights reserved. +* +* This file contains confidential and proprietary information of Xilinx, Inc. +* and is protected under U.S. and international copyright and other +* intellectual property laws. +* +* DISCLAIMER +* This disclaimer is not a license and does not grant any rights to the +* materials distributed herewith. Except as otherwise provided in a valid +* license issued to you by Xilinx, and to the maximum extent permitted by +* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL +* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, +* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF +* MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; +* and (2) Xilinx shall not be liable (whether in contract or tort, including +* negligence, or under any other theory of liability) for any loss or damage +* of any kind or nature related to, arising under or in connection with these +* materials, including for any direct, or any indirect, special, incidental, +* or consequential loss or damage (including loss of data, profits, goodwill, +* or any type of loss or damage suffered as a result of any action brought by +* a third party) even if such damage or loss was reasonably foreseeable or +* Xilinx had been advised of the possibility of the same. +* +* CRITICAL APPLICATIONS +* Xilinx products are not designed or intended to be fail-safe, or for use in +* any application requiring fail-safe performance, such as life-support or +* safety devices or systems, Class III medical devices, nuclear facilities, +* applications related to the deployment of airbags, or any other applications +* that could lead to death, personal injury, or severe property or +* environmental damage (individually and collectively, "Critical +* Applications"). Customer assumes the sole risk and liability of any use of +* Xilinx products in Critical Applications, subject only to applicable laws +* and regulations governing limitations on product liability. +* +* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE +* AT ALL TIMES. +* +******************************************************************************/ +/*****************************************************************************/ +/** + * + * @file xaxidma_example_simple_poll.c + * + * This file demonstrates how to use the xaxidma driver on the Xilinx AXI + * DMA core (AXIDMA) to transfer packets in polling mode when the AXI DMA core + * is configured in simple mode. + * + * This code assumes a loopback hardware widget is connected to the AXI DMA + * core for data packet loopback. + * + * To see the debug print, you need a Uart16550 or uartlite in your system, + * and please set "-DDEBUG" in your compiler options. You need to rebuild your + * software executable. + * + * Make sure that MEMORY_BASE is defined properly as per the HW system. The + * h/w system built in Area mode has a maximum DDR memory limit of 64MB. In + * throughput mode, it is 512MB. These limits are need to ensured for + * proper operation of this code. + * + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -------------------------------------------------------
+ * 4.00a rkv  02/22/11 New example created for simple DMA, this example is for
+ *       	       simple DMA
+ * 5.00a srt  03/06/12 Added Flushing and Invalidation of Caches to fix CRs
+ *		       648103, 648701.
+ *		       Added V7 DDR Base Address to fix CR 649405.
+ * 6.00a srt  03/27/12 Changed API calls to support MCDMA driver.
+ * 7.00a srt  06/18/12 API calls are reverted back for backward compatibility.
+ * 7.01a srt  11/02/12 Buffer sizes (Tx and Rx) are modified to meet maximum
+ *		       DDR memory limit of the h/w system built with Area mode
+ * 7.02a srt  03/01/13 Updated DDR base address for IPI designs (CR 703656).
+ *
+ * 
+ * + * *************************************************************************** + + */ +/***************************** Include Files *********************************/ +#include "xaxidma.h" +#include "xparameters.h" +#include "xdebug.h" + +#if defined(XPAR_UARTNS550_0_BASEADDR) +#include "xuartns550_l.h" /* to use uartns550 */ +#endif + +/******************** Constant Definitions **********************************/ + +/* + * Device hardware build related constants. + */ + +#define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID + +#ifdef XPAR_V6DDR_0_S_AXI_BASEADDR +#define DDR_BASE_ADDR XPAR_V6DDR_0_S_AXI_BASEADDR +#elif XPAR_S6DDR_0_S0_AXI_BASEADDR +#define DDR_BASE_ADDR XPAR_S6DDR_0_S0_AXI_BASEADDR +#elif XPAR_AXI_7SDDR_0_S_AXI_BASEADDR +#define DDR_BASE_ADDR XPAR_AXI_7SDDR_0_S_AXI_BASEADDR +#elif XPAR_MIG7SERIES_0_BASEADDR +#define DDR_BASE_ADDR XPAR_MIG7SERIES_0_BASEADDR +#endif + +#ifndef DDR_BASE_ADDR +#warning CHECK FOR THE VALID DDR ADDRESS IN XPARAMETERS.H, \ + DEFAULT SET TO 0x01000000 +#define MEM_BASE_ADDR 0x01000000 +#else +#define MEM_BASE_ADDR (DDR_BASE_ADDR + 0x1000000) +#endif + +#define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000) +#define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00300000) +#define RX_BUFFER_HIGH (MEM_BASE_ADDR + 0x004FFFFF) + +#define MAX_PKT_LEN 0x20 + +#define TEST_START_VALUE 0xC + +#define NUMBER_OF_TRANSFERS 10 + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ + +#if (!defined(DEBUG)) +extern void xil_printf(const char *format, ...); +#endif + +int XAxiDma_SimplePollExample(u16 DeviceId); +static int CheckData(void); + +/************************** Variable Definitions *****************************/ +/* + * Device instance definitions + */ +XAxiDma AxiDma; + + +/*****************************************************************************/ +/* +* The entry point for this example. It invokes the example function, +* and reports the execution status. +* +* @param None. +* +* @return +* - XST_SUCCESS if example finishes successfully +* - XST_FAILURE if example fails. +* +* @note None. +* +******************************************************************************/ +int main() +{ + int Status; + + xil_printf("\r\n--- Entering main() --- \r\n"); + + /* Run the poll example for simple transfer */ + Status = XAxiDma_SimplePollExample(DMA_DEV_ID); + + if (Status != XST_SUCCESS) { + + xil_printf("XAxiDma_SimplePollExample: Failed\r\n"); + return XST_FAILURE; + } + + xil_printf("XAxiDma_SimplePollExample: Passed\r\n"); + + xil_printf("--- Exiting main() --- \r\n"); + + return XST_SUCCESS; + +} + +#if defined(XPAR_UARTNS550_0_BASEADDR) +/*****************************************************************************/ +/* +* +* Uart16550 setup routine, need to set baudrate to 9600, and data bits to 8 +* +* @param None. +* +* @return None +* +* @note None. +* +******************************************************************************/ +static void Uart550_Setup(void) +{ + + /* Set the baudrate to be predictable + */ + XUartNs550_SetBaud(XPAR_UARTNS550_0_BASEADDR, + XPAR_XUARTNS550_CLOCK_HZ, 9600); + + XUartNs550_SetLineControlReg(XPAR_UARTNS550_0_BASEADDR, + XUN_LCR_8_DATA_BITS); + +} +#endif + +/*****************************************************************************/ +/** +* The example to do the simple transfer through polling. The constant +* NUMBER_OF_TRANSFERS defines how many times a simple transfer is repeated. +* +* @param DeviceId is the Device Id of the XAxiDma instance +* +* @return +* - XST_SUCCESS if example finishes successfully +* - XST_FAILURE if error occurs +* +* @note None +* +* +******************************************************************************/ +int XAxiDma_SimplePollExample(u16 DeviceId) +{ + XAxiDma_Config *CfgPtr; + int Status; + int Tries = NUMBER_OF_TRANSFERS; + int Index; + u8 *TxBufferPtr; + u8 *RxBufferPtr; + u8 Value; + + TxBufferPtr = (u8 *)TX_BUFFER_BASE ; + RxBufferPtr = (u8 *)RX_BUFFER_BASE; + + /* Initialize the XAxiDma device. + */ + CfgPtr = XAxiDma_LookupConfig(DeviceId); + if (!CfgPtr) { + xil_printf("No config found for %d\r\n", DeviceId); + return XST_FAILURE; + } + + Status = XAxiDma_CfgInitialize(&AxiDma, CfgPtr); + if (Status != XST_SUCCESS) { + xil_printf("Initialization failed %d\r\n", Status); + return XST_FAILURE; + } + + if(XAxiDma_HasSg(&AxiDma)){ + xil_printf("Device configured as SG mode \r\n"); + return XST_FAILURE; + } + + /* Disable interrupts, we use polling mode + */ + XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK, + XAXIDMA_DEVICE_TO_DMA); + XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK, + XAXIDMA_DMA_TO_DEVICE); + + Value = TEST_START_VALUE; + + for(Index = 0; Index < MAX_PKT_LEN; Index ++) { + TxBufferPtr[Index] = Value; + + Value = (Value + 1) & 0xFF; + } + /* Flush the SrcBuffer before the DMA transfer, in case the Data Cache + * is enabled + */ + Xil_DCacheFlushRange((u32)TxBufferPtr, MAX_PKT_LEN); + + for(Index = 0; Index < Tries; Index ++) { + + + Status = XAxiDma_SimpleTransfer(&AxiDma,(u32) RxBufferPtr, + MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA); + + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + Status = XAxiDma_SimpleTransfer(&AxiDma,(u32) TxBufferPtr, + MAX_PKT_LEN, XAXIDMA_DMA_TO_DEVICE); + + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + while ((XAxiDma_Busy(&AxiDma,XAXIDMA_DEVICE_TO_DMA)) || + (XAxiDma_Busy(&AxiDma,XAXIDMA_DMA_TO_DEVICE))) { + /* Wait */ + } + + Status = CheckData(); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + } + + /* Test finishes successfully + */ + return XST_SUCCESS; +} + + + +/*****************************************************************************/ +/* +* +* This function checks data buffer after the DMA transfer is finished. +* +* @param None +* +* @return +* - XST_SUCCESS if validation is successful. +* - XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +static int CheckData(void) +{ + u8 *RxPacket; + int Index = 0; + u8 Value; + + RxPacket = (u8 *) RX_BUFFER_BASE; + Value = TEST_START_VALUE; + + /* Invalidate the DestBuffer before receiving the data, in case the + * Data Cache is enabled + */ + Xil_DCacheInvalidateRange((u32)RxPacket, MAX_PKT_LEN); + + for(Index = 0; Index < MAX_PKT_LEN; Index++) { + if (RxPacket[Index] != Value) { + xil_printf("Data error %d: %x/%x\r\n", + Index, (unsigned int)RxPacket[Index], + (unsigned int)Value); + + return XST_FAILURE; + } + Value = (Value + 1) & 0xFF; + } + + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_multichan_sg_intr.c b/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_multichan_sg_intr.c new file mode 100644 index 00000000..7006756e --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_multichan_sg_intr.c @@ -0,0 +1,1317 @@ +/****************************************************************************** +* +* (c) Copyright 2010-2013 Xilinx, Inc. All rights reserved. +* +* This file contains confidential and proprietary information of Xilinx, Inc. +* and is protected under U.S. and international copyright and other +* intellectual property laws. +* +* DISCLAIMER +* This disclaimer is not a license and does not grant any rights to the +* materials distributed herewith. Except as otherwise provided in a valid +* license issued to you by Xilinx, and to the maximum extent permitted by +* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL +* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, +* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF +* MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; +* and (2) Xilinx shall not be liable (whether in contract or tort, including +* negligence, or under any other theory of liability) for any loss or damage +* of any kind or nature related to, arising under or in connection with these +* materials, including for any direct, or any indirect, special, incidental, +* or consequential loss or damage (including loss of data, profits, goodwill, +* or any type of loss or damage suffered as a result of any action brought by +* a third party) even if such damage or loss was reasonably foreseeable or +* Xilinx had been advised of the possibility of the same. +* +* CRITICAL APPLICATIONS +* Xilinx products are not designed or intended to be fail-safe, or for use in +* any application requiring fail-safe performance, such as life-support or +* safety devices or systems, Class III medical devices, nuclear facilities, +* applications related to the deployment of airbags, or any other applications +* that could lead to death, personal injury, or severe property or +* environmental damage (individually and collectively, "Critical +* Applications"). Customer assumes the sole risk and liability of any use of +* Xilinx products in Critical Applications, subject only to applicable laws +* and regulations governing limitations on product liability. +* +* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE +* AT ALL TIMES. +* +******************************************************************************/ +/*****************************************************************************/ +/** + * + * @file xaximcdma_example_sg_intr.c + * + * This file demonstrates how to use the xaxidma driver on the Xilinx AXI + * DMA core v6_00_a (AXIDMA) to transfer packets in interrupt mode for + * Multiple Channel capability. + * Thi example is designed to work only when AXIDMA core is configured + * in Scatter Gather Mode and Multiple Channel mode. + * + * We show how to do multiple packets transfers, as well as how to do multiple + * BDs per packet transfers. + * + * This code is tested only with two channels on both Tx and Rx. + * This code assumes a loopback hardware widget is connected to the AXI DMA + * core for data packet loopback. The loopback widget is configured in a way + * that, when a packet is transmitted on "Tx Channel 0" it will be received + * on the "Rx channel 1" and if "Tx Channel 1" it is on Rx Channel 0. + * Both the cases are included in this example. + * + * To see the debug print, you need a Uart16550 or uartlite in your system, + * and please set "-DDEBUG" in your compiler options. You need to rebuild your + * software executable. + * + * Make sure that MEMORY_BASE is defined properly as per the HW system. The + * h/w system built in Area mode has a maximum DDR memory limit of 64MB. In + * throughput mode, it is 512MB. These limits are need to ensured for + * proper operation of this code. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -------------------------------------------------------
+ * 1.00a srt  03/27/12 First release
+ * 2.00a srt  06/18/12 API calls are reverted back for backward compatibility.
+ * 2.01a srt  11/02/12 Buffer sizes (Tx and Rx) are modified to meet maximum
+ *		       DDR memory limit of the h/w system built with Area mode
+ * 7.02a srt  03/01/13 Updated DDR base address for IPI designs (CR 703656).
+ *
+ * 
+ * + * *************************************************************************** + */ +/***************************** Include Files *********************************/ +#include "xaxidma.h" +#include "xparameters.h" +#include "xil_exception.h" +#include "xdebug.h" +#include "xaxidma_bd.h" + +#ifdef XPAR_UARTNS550_0_BASEADDR +#include "xuartns550_l.h" /* to use uartns550 */ +#endif + +#ifndef DEBUG +extern void xil_printf(const char *format, ...); +#endif + +#ifdef XPAR_INTC_0_DEVICE_ID + #include "xintc.h" +#else + #include "xscugic.h" +#endif + +/******************** Constant Definitions **********************************/ +/* + * Device hardware build related constants. + */ + +#define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID + +#ifdef XPAR_V6DDR_0_S_AXI_BASEADDR +#define DDR_BASE_ADDR XPAR_V6DDR_0_S_AXI_BASEADDR +#elif XPAR_S6DDR_0_S0_AXI_BASEADDR +#define DDR_BASE_ADDR XPAR_S6DDR_0_S0_AXI_BASEADDR +#elif XPAR_AXI_7SDDR_0_S_AXI_BASEADDR +#define DDR_BASE_ADDR XPAR_AXI_7SDDR_0_S_AXI_BASEADDR +#elif XPAR_MIG7SERIES_0_BASEADDR +#define DDR_BASE_ADDR XPAR_MIG7SERIES_0_BASEADDR +#endif + +#ifndef DDR_BASE_ADDR +#warning CHECK FOR THE VALID DDR ADDRESS IN XPARAMETERS.H, \ + DEFAULT SET TO 0x01000000 +#define MEM_BASE_ADDR 0x01000000 +#else +#define MEM_BASE_ADDR (DDR_BASE_ADDR + 0x1000000) +#endif + +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#else +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#endif + +#ifdef XPAR_INTC_0_DEVICE_ID +#define RX_INTR_ID XPAR_INTC_0_AXIDMA_0_S2MM_INTROUT_VEC_ID +#define TX_INTR_ID XPAR_INTC_0_AXIDMA_0_MM2S_INTROUT_VEC_ID +#else +#define RX_INTR_ID XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_VEC_ID +#define TX_INTR_ID XPAR_FABRIC_AXIDMA_0_MM2S_INTROUT_VEC_ID +#endif + +#define RX_BD_SPACE_BASE (MEM_BASE_ADDR) +#define RX_BD_SPACE_HIGH (MEM_BASE_ADDR + 0x0000FFFF) +#define TX_BD_SPACE_BASE (MEM_BASE_ADDR + 0x00040000) +#define TX_BD_SPACE_HIGH (MEM_BASE_ADDR + 0x0004FFFF) +#define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000) +#define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00300000) +#define RX_BUFFER_HIGH (MEM_BASE_ADDR + 0x004FFFFF) + +#ifdef XPAR_INTC_0_DEVICE_ID +#define INTC_DEVICE_ID XPAR_INTC_0_DEVICE_ID +#else +#define INTC_DEVICE_ID XPAR_SCUGIC_SINGLE_DEVICE_ID +#endif + +/* Timeout loop counter for reset + */ +#define RESET_TIMEOUT_COUNTER 10000 + +/* + * Number of BDs in the transfer example + * We show how to submit multiple BDs for one transmit. + * The receive side gets one completion per transfer. + */ +#define NUMBER_OF_BDS_PER_PKT 2 +#define NUMBER_OF_PKTS_TO_TRANSFER 1 +#define NUMBER_OF_BDS_TO_TRANSFER (NUMBER_OF_PKTS_TO_TRANSFER * \ + NUMBER_OF_BDS_PER_PKT) +#define MAX_BD_COUNT 1024 + +/* The interrupt coalescing threshold and delay timer threshold + * Valid range is 1 + * + * Note: Coalescing threshold configured for more than one is not + * supported by the AXIDMA IP v6_00_a. + */ +#define COALESCING_COUNT 1 +#define DELAY_TIMER_COUNT 100 + +#ifdef XPAR_INTC_0_DEVICE_ID + #define INTC XIntc + #define INTC_HANDLER XIntc_InterruptHandler +#else + #define INTC XScuGic + #define INTC_HANDLER XScuGic_InterruptHandler +#endif + +/* + * Packet Data Values + */ +#define PACKET0_DATA 0x1 +#define PACKET1_DATA 0xC + +/* + * MCDMA Values + */ +#define TID0 0x0 /* Stream identifier 0 */ +#define TDEST0 0x0 /* Coarse Routing info for stream 0 */ +#define TID1 0x1 /* Stream identifier 1 */ +#define TDEST1 0x1 /* Coarse Routing info for stream 1 */ +#define TUSER 0x0 /* User defined sideband signaling */ +#define ARCACHE 0x3 /* Cache type */ +#define ARUSER 0x0 /* Sideband signals */ +#define VSIZE 0x4 /* Vsize */ +#define STRIDE 0x20 /* Stride control */ +#define HSIZE 0x100 /* Hsize */ + +/* + * Buffer and Buffer Descriptor related constant definition + */ +#define MAX_PKT_LEN VSIZE * STRIDE + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ +#ifdef XPAR_UARTNS550_0_BASEADDR +static void Uart550_Setup(void); +#endif + +static int CheckData(int Length, u8 *RxPacket, u8 StartValue); +static void TxCallBack(XAxiDma * AxiDmaInstPtr); +static void TxIntrHandler(void *Callback); +static void RxCallBack(XAxiDma * AxiDmaInstPtr); +static void RxIntrHandler(void *Callback); +extern void XaxiDma_DumpBd(XAxiDma_Bd *BdPtr); + +static int SetupIntrSystem(INTC * IntcInstancePtr, + XAxiDma * AxiDmaPtr, u16 TxIntrId, + u16 RxIntrId, int RingIndex); +static void DisableIntrSystem(INTC * IntcInstancePtr, + u16 TxIntrId, u16 RxIntrId); + +static int RxSetup(XAxiDma * AxiDmaInstPtr); +static int TxSetup(XAxiDma * AxiDmaInstPtr); +static int SendPacket(XAxiDma * AxiDmaInstPtr, + u8 TDest, u8 TId, u8 Value); + +/************************** Variable Definitions *****************************/ +/* + * Device instance definitions + */ +XAxiDma AxiDma; + + +static INTC Intc; /* Instance of the Interrupt Controller */ + +/* + * Flags interrupt handlers use to notify the application context the events. + */ +volatile int TxDone; +volatile int RxDone; +volatile int Error; + +/* + * Buffer for transmit packet. Must be 32-bit aligned to be used by DMA. + */ +u32 *Packet = (u32 *) TX_BUFFER_BASE; + +/* + * Buffer for Receive packet. Must be 32-bit aligned to be used by DMA. + */ +u8 *RxPacket0 = (u8 *) RX_BUFFER_BASE; +u8 *RxPacket1 = (u8 *) (RX_BUFFER_BASE + MAX_BD_COUNT + * MAX_PKT_LEN); + +/*****************************************************************************/ +/** +* +* Main function +* +* This function is the main entry of the interrupt test. It does the following: +* - Set up the output terminal if UART16550 is in the hardware build +* - Initialize the DMA engine +* - Set up Tx and Rx channels +* - Set up the interrupt system for the Tx and Rx interrupts +* - Submit a transfer +* - Wait for the transfer to finish +* - Check transfer status +* - Disable Tx and Rx interrupts +* - Print test status and exit +* +* @param None +* +* @return - XST_SUCCESS if tests pass +* - XST_FAILURE if fails. +* +* @note None. +* +******************************************************************************/ +int main(void) +{ + int Status; + XAxiDma_Config *Config; + + /* Initial setup for Uart16550 */ +#ifdef XPAR_UARTNS550_0_BASEADDR + + Uart550_Setup(); + +#endif + + xil_printf("\r\n--- Entering main() --- \r\n"); + + Config = XAxiDma_LookupConfig(DMA_DEV_ID); + if (!Config) { + xil_printf("No config found for %d\r\n", DMA_DEV_ID); + + return XST_FAILURE; + } + + /* Initialize DMA engine */ + XAxiDma_CfgInitialize(&AxiDma, Config); + + if(!XAxiDma_HasSg(&AxiDma)) { + xil_printf("Device configured as Simple mode \r\n"); + return XST_FAILURE; + } + + /* Set up TX/RX channels to be ready to transmit and receive packets */ + Status = TxSetup(&AxiDma); + if (Status != XST_SUCCESS) { + + xil_printf("Failed TX setup\r\n"); + return XST_FAILURE; + } + + Status = RxSetup(&AxiDma); + if (Status != XST_SUCCESS) { + xil_printf("Failed RX setup\r\n"); + return XST_FAILURE; + } + + /* Set up Interrupt system */ + Status = SetupIntrSystem(&Intc, &AxiDma, TX_INTR_ID, + RX_INTR_ID, 1); + if (Status != XST_SUCCESS) { + xil_printf("Failed intr setup\r\n"); + return XST_FAILURE; + } + + /* Initialize flags before start transfer test */ + TxDone = 0; + RxDone = 0; + Error = 0; + + /* Send a packet */ + Status = SendPacket(&AxiDma, TDEST0, TID0, PACKET0_DATA); + if (Status != XST_SUCCESS) { + xil_printf("Failed send packet\r\n"); + return XST_FAILURE; + } + + /* + * Wait TX done and RX done + */ + while (((TxDone < NUMBER_OF_BDS_TO_TRANSFER) || + (RxDone < NUMBER_OF_BDS_TO_TRANSFER)) && !Error) { + /* NOP */ + } + + if (Error) { + xil_printf("Failed test transmit%s done, " + "receive%s done\r\n", TxDone? "":" not", + RxDone? "":" not"); + goto Done; + }else { + /* + * Test finished, check data + */ + Status = CheckData(MAX_PKT_LEN * NUMBER_OF_BDS_TO_TRANSFER, + RxPacket1, PACKET0_DATA); + if (Status != XST_SUCCESS) { + xil_printf("Data check failed\r\n"); + goto Done; + } + } + + xil_printf("Sent Packet with Tdest 0 Successfully\n\r"); + + /* Initialize flags before start transfer test */ + TxDone = 0; + RxDone = 0; + Error = 0; + + /* Send a packet */ + Status = SendPacket(&AxiDma, TDEST1, TID1, PACKET1_DATA); + if (Status != XST_SUCCESS) { + xil_printf("Failed send packet\r\n"); + return XST_FAILURE; + } + + /* + * Wait TX done and RX done + */ + while (((TxDone < NUMBER_OF_BDS_TO_TRANSFER) || + (RxDone < NUMBER_OF_BDS_TO_TRANSFER)) && !Error) { + /* NOP */ + } + + + if (Error) { + xil_printf("Failed test transmit%s done, " + "receive%s done\r\n", TxDone? "":" not", + RxDone? "":" not"); + goto Done; + }else { + /* + * Test finished, check data + */ + Status = CheckData(MAX_PKT_LEN * NUMBER_OF_BDS_TO_TRANSFER, + RxPacket0, PACKET1_DATA); + if (Status != XST_SUCCESS) { + xil_printf("Data check failed\r\n"); + goto Done; + } + } + + /* Disable TX and RX Ring interrupts and return success */ + DisableIntrSystem(&Intc, TX_INTR_ID, RX_INTR_ID); + + xil_printf("Sent Packet with Tdest 1 Successfully\n\r"); + + xil_printf("AXI DMA SG interrupt Test passed\r\n"); + +Done: + + xil_printf("--- Exiting main() --- \r\n"); + + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +#ifdef XPAR_UARTNS550_0_BASEADDR +/*****************************************************************************/ +/* +* +* Uart16550 setup routine, need to set baudrate to 9600 and data bits to 8 +* +* @param None +* +* @return None +* +* @note None. +* +******************************************************************************/ +static void Uart550_Setup(void) +{ + + XUartNs550_SetBaud(XPAR_UARTNS550_0_BASEADDR, + XPAR_XUARTNS550_CLOCK_HZ, 9600); + + XUartNs550_SetLineControlReg(XPAR_UARTNS550_0_BASEADDR, + XUN_LCR_8_DATA_BITS); +} +#endif + +/*****************************************************************************/ +/* +* +* This function checks data buffer after the DMA transfer is finished. +* +* We use the static tx/rx buffers. +* +* @param Length is the length to check +* @param StartValue is the starting value of the first byte +* +* @return - XST_SUCCESS if validation is successful +* - XST_FAILURE if validation fails. +* +* @note None. +* +******************************************************************************/ +static int CheckData(int Length, u8 *RxPacket, u8 StartValue) +{ + int Index = 0; + u8 Value; + + Value = StartValue; + + /* Invalidate the DestBuffer before receiving the data, in case the + * Data Cache is enabled + */ + Xil_DCacheInvalidateRange((u32)RxPacket, Length); + + for(Index = 0; Index < Length; Index++) { + if (RxPacket[Index] != Value) { + xil_printf("Data error %d: %x/%x\r\n", + Index, RxPacket[Index], Value); + + return XST_FAILURE; + } + Value = (Value + 1) & 0xFF; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/* +* +* This is the DMA TX callback function to be called by TX interrupt handler. +* This function handles BDs finished by hardware. +* +* @param TxRingPtr is a pointer to TX channel of the DMA engine. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void TxCallBack(XAxiDma *AxiDmaPtr) +{ + int BdCount; + u32 BdSts; + XAxiDma_Bd *BdPtr; + XAxiDma_Bd *BdCurPtr; + int Status; + int Index; + XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(AxiDmaPtr); + + /* Get all processed BDs from hardware */ + BdCount = XAxiDma_BdRingFromHw(TxRingPtr, XAXIDMA_ALL_BDS, &BdPtr); + + /* Handle the BDs */ + BdCurPtr = BdPtr; + for (Index = 0; Index < BdCount; Index++) { + + /* + * Check the status in each BD + * If error happens, the DMA engine will be halted after this + * BD processing stops. + */ + BdSts = XAxiDma_BdGetSts(BdCurPtr); + if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) || + (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) { + + Error = 1; + break; + } + + /* + * Here we don't need to do anything. But if a RTOS is being + * used, we may need to free the packet buffer attached to + * the processed BD + */ + + /* Find the next processed BD */ + BdCurPtr = XAxiDma_BdRingNext(TxRingPtr, BdCurPtr); + } + + /* Free all processed BDs for future transmission */ + Status = XAxiDma_BdRingFree(TxRingPtr, BdCount, BdPtr); + if (Status != XST_SUCCESS) { + Error = 1; + } + + if(!Error) { + TxDone += BdCount; + } +} + +/*****************************************************************************/ +/* +* +* This is the DMA TX Interrupt handler function. +* +* It gets the interrupt status from the hardware, acknowledges it, and if any +* error happens, it resets the hardware. Otherwise, if a completion interrupt +* presents, then it calls the callback function. +* +* @param Callback is a pointer to TX channel of the DMA engine. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void TxIntrHandler(void *Callback) +{ + XAxiDma *AxiDmaPtr = (XAxiDma *) Callback; + XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(AxiDmaPtr); + u32 IrqStatus; + int TimeOut; + + /* Read pending interrupts */ + IrqStatus = XAxiDma_BdRingGetIrq(TxRingPtr); + + /* Acknowledge pending interrupts */ + XAxiDma_BdRingAckIrq(TxRingPtr, IrqStatus); + + /* If no interrupt is asserted, we do not do anything + */ + if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) { + + return; + } + + /* + * If error interrupt is asserted, raise error flag, reset the + * hardware to recover from the error, and return with no further + * processing. + */ + if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) { + + Error = 1; + + /* + * Reset should never fail for transmit channel + */ + XAxiDma_Reset(&AxiDma); + + TimeOut = RESET_TIMEOUT_COUNTER; + + while (TimeOut) { + if (XAxiDma_ResetIsDone(&AxiDma)) { + break; + } + + TimeOut -= 1; + } + + return; + } + + /* + * If Transmit done interrupt is asserted, call TX call back function + * to handle the processed BDs and raise the according flag + */ + if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) { + TxCallBack(AxiDmaPtr); + } +} + +/*****************************************************************************/ +/* +* +* This is the DMA RX callback function called by the RX interrupt handler. +* This function handles finished BDs by hardware, attaches new buffers to those +* BDs, and give them back to hardware to receive more incoming packets +* +* @param RxRingPtr is a pointer to RX channel of the DMA engine. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void RxCallBack(XAxiDma *AxiDmaPtr) +{ + int BdCount; + XAxiDma_Bd *BdPtr; + XAxiDma_Bd *BdCurPtr; + u32 BdSts; + int Index; + int RingIndex; + XAxiDma_BdRing *RxRingPtr; + + for (RingIndex = 0; + RingIndex < AxiDmaPtr->RxNumChannels; RingIndex++) { + + RxRingPtr = XAxiDma_GetRxIndexRing(AxiDmaPtr, RingIndex); + BdCount = XAxiDma_BdRingFromHw(RxRingPtr, XAXIDMA_ALL_BDS, &BdPtr); + + BdCurPtr = BdPtr; + for (Index = 0; Index < BdCount; Index++) { + + /* + * Check the flags set by the hardware for status + * If error happens, processing stops, because the DMA engine + * is halted after this BD. + */ + BdSts = XAxiDma_BdGetSts(BdCurPtr); + if ((BdSts & XAXIDMA_BD_STS_ALL_ERR_MASK) || + (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK))) { + Error = 1; + break; + } + + /* Find the next processed BD */ + BdCurPtr = XAxiDma_BdRingNext(RxRingPtr, BdCurPtr); + RxDone += 1; + } + } +} + +/*****************************************************************************/ +/* +* +* This is the DMA RX interrupt handler function +* +* It gets the interrupt status from the hardware, acknowledges it, and if any +* error happens, it resets the hardware. Otherwise, if a completion interrupt +* presents, then it calls the callback function. +* +* @param Callback is a pointer to RX channel of the DMA engine. +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void RxIntrHandler(void *Callback) +{ + XAxiDma *AxiDmaPtr = (XAxiDma *) Callback; + + XAxiDma_BdRing *RxRingPtr = XAxiDma_GetRxIndexRing(AxiDmaPtr, 0); + + u32 IrqStatus; + int TimeOut; + + + /* Read pending interrupts */ + IrqStatus = XAxiDma_BdRingGetIrq(RxRingPtr); + + /* Acknowledge pending interrupts */ + XAxiDma_BdRingAckIrq(RxRingPtr, IrqStatus); + + /* + * If no interrupt is asserted, we do not do anything + */ + if (!(IrqStatus & XAXIDMA_IRQ_ALL_MASK)) { + return; + } + + /* + * If error interrupt is asserted, raise error flag, reset the + * hardware to recover from the error, and return with no further + * processing. + */ + if ((IrqStatus & XAXIDMA_IRQ_ERROR_MASK)) { + + Error = 1; + + /* Reset could fail and hang + * NEED a way to handle this or do not call it?? + */ + XAxiDma_Reset(&AxiDma); + + TimeOut = RESET_TIMEOUT_COUNTER; + + while (TimeOut) { + if(XAxiDma_ResetIsDone(&AxiDma)) { + break; + } + + TimeOut -= 1; + } + + return; + } + + /* + * If completion interrupt is asserted, call RX call back function + * to handle the processed BDs and then raise the according flag. + */ + if ((IrqStatus & (XAXIDMA_IRQ_DELAY_MASK | XAXIDMA_IRQ_IOC_MASK))) { + RxCallBack(AxiDmaPtr); + } +} + +/*****************************************************************************/ +/* +* +* This function setups the interrupt system so interrupts can occur for the +* DMA, it assumes INTC component exists in the hardware system. +* +* @param IntcInstancePtr is a pointer to the instance of the INTC. +* @param AxiDmaPtr is a pointer to the instance of the DMA engine +* @param TxIntrId is the TX channel Interrupt ID. +* @param RxIntrId is the RX channel Interrupt ID. +* +* @return +* - XST_SUCCESS if successful, +* - XST_FAILURE.if not succesful +* +* @note None. +* +******************************************************************************/ + +static int SetupIntrSystem(INTC * IntcInstancePtr, + XAxiDma * AxiDmaPtr, u16 TxIntrId, + u16 RxIntrId, int RingIndex) +{ + int Status; + +#ifdef XPAR_INTC_0_DEVICE_ID + + /* Initialize the interrupt controller and connect the ISRs */ + Status = XIntc_Initialize(IntcInstancePtr, INTC_DEVICE_ID); + if (Status != XST_SUCCESS) { + + xil_printf("Failed init intc\r\n"); + return XST_FAILURE; + } + + Status = XIntc_Connect(IntcInstancePtr, TxIntrId, + (XInterruptHandler) TxIntrHandler, AxiDmaPtr); + if (Status != XST_SUCCESS) { + + xil_printf("Failed tx connect intc\r\n"); + return XST_FAILURE; + } + + Status = XIntc_Connect(IntcInstancePtr, RxIntrId, + (XInterruptHandler) RxIntrHandler, AxiDmaPtr); + if (Status != XST_SUCCESS) { + + xil_printf("Failed rx connect intc\r\n"); + return XST_FAILURE; + } + + /* Start the interrupt controller */ + Status = XIntc_Start(IntcInstancePtr, XIN_REAL_MODE); + if (Status != XST_SUCCESS) { + + xil_printf("Failed to start intc\r\n"); + return XST_FAILURE; + } + + XIntc_Enable(IntcInstancePtr, TxIntrId); + XIntc_Enable(IntcInstancePtr, RxIntrId); + +#else + + XScuGic_Config *IntcConfig; + + + /* + * Initialize the interrupt controller driver so that it is ready to + * use. + */ + IntcConfig = XScuGic_LookupConfig(INTC_DEVICE_ID); + if (NULL == IntcConfig) { + return XST_FAILURE; + } + + Status = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, + IntcConfig->CpuBaseAddress); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + + XScuGic_SetPriorityTriggerType(IntcInstancePtr, TxIntrId, 0xA0, 0x3); + + XScuGic_SetPriorityTriggerType(IntcInstancePtr, RxIntrId, 0xA0, 0x3); + /* + * Connect the device driver handler that will be called when an + * interrupt for the device occurs, the handler defined above performs + * the specific interrupt processing for the device. + */ + Status = XScuGic_Connect(IntcInstancePtr, TxIntrId, + (Xil_InterruptHandler)TxIntrHandler, + AxiDmaPtr); + if (Status != XST_SUCCESS) { + return Status; + } + + Status = XScuGic_Connect(IntcInstancePtr, RxIntrId, + (Xil_InterruptHandler)RxIntrHandler, + AxiDmaPtr); + if (Status != XST_SUCCESS) { + return Status; + } + + XScuGic_Enable(IntcInstancePtr, TxIntrId); + XScuGic_Enable(IntcInstancePtr, RxIntrId); +#endif + + /* Enable interrupts from the hardware */ + + Xil_ExceptionInit(); + Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, + (Xil_ExceptionHandler)INTC_HANDLER, + (void *)IntcInstancePtr); + + Xil_ExceptionEnable(); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function disables the interrupts for DMA engine. +* +* @param IntcInstancePtr is the pointer to the INTC component instance +* @param TxIntrId is interrupt ID associated w/ DMA TX channel +* @param RxIntrId is interrupt ID associated w/ DMA RX channel +* +* @return None. +* +* @note None. +* +******************************************************************************/ +static void DisableIntrSystem(INTC * IntcInstancePtr, + u16 TxIntrId, u16 RxIntrId) +{ +#ifdef XPAR_INTC_0_DEVICE_ID + /* Disconnect the interrupts for the DMA TX and RX channels */ + XIntc_Disconnect(IntcInstancePtr, TxIntrId); + XIntc_Disconnect(IntcInstancePtr, RxIntrId); +#else + XScuGic_Disconnect(IntcInstancePtr, TxIntrId); + XScuGic_Disconnect(IntcInstancePtr, RxIntrId); +#endif +} + +/*****************************************************************************/ +/* +* +* This function sets up RX channel of the DMA engine to be ready for packet +* reception +* +* @param AxiDmaInstPtr is the pointer to the instance of the DMA engine. +* +* @return - XST_SUCCESS if the setup is successful. +* - XST_FAILURE if fails. +* +* @note None. +* +******************************************************************************/ +static int RxSetup(XAxiDma * AxiDmaInstPtr) +{ + XAxiDma_BdRing *RxRingPtr; + int Status; + XAxiDma_Bd BdTemplate; + XAxiDma_Bd *BdPtr; + XAxiDma_Bd *BdCurPtr; + int BdCount; + int FreeBdCount; + u32 RxBufferPtr; + u32 RxBdSpacePtr; + int Index; + int RingIndex; + + RxBufferPtr = RX_BUFFER_BASE; + RxBdSpacePtr = RX_BD_SPACE_BASE; + + for (RingIndex = 0; + RingIndex < AxiDmaInstPtr->RxNumChannels; RingIndex++) { + + RxRingPtr = XAxiDma_GetRxIndexRing(&AxiDma, RingIndex); + + /* Disable all RX interrupts before RxBD space setup */ + XAxiDma_BdRingIntDisable(RxRingPtr, + XAXIDMA_IRQ_ALL_MASK); + + /* Setup Rx BD space */ + BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, + RX_BD_SPACE_HIGH - RX_BD_SPACE_BASE + 1); + + Status = XAxiDma_BdRingCreate(RxRingPtr, + RxBdSpacePtr, + RxBdSpacePtr, + XAXIDMA_BD_MINIMUM_ALIGNMENT, + BdCount); + if (Status != XST_SUCCESS) { + xil_printf("Rx bd create failed with %d\r\n", + Status); + return XST_FAILURE; + } + + /* + * Setup a BD template for the Rx channel. Then copy it + * to every RX BD. + */ + XAxiDma_BdClear(&BdTemplate); + Status = XAxiDma_BdRingClone(RxRingPtr, + &BdTemplate); + if (Status != XST_SUCCESS) { + xil_printf("Rx bd clone failed with %d\r\n", + Status); + return XST_FAILURE; + } + + /* Attach buffers to RxBD ring so we are ready to receive packets */ + FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr); + + Status = XAxiDma_BdRingAlloc(RxRingPtr, + FreeBdCount, &BdPtr); + if (Status != XST_SUCCESS) { + xil_printf("Rx bd alloc failed with %d\r\n", + Status); + return XST_FAILURE; + } + + BdCurPtr = BdPtr; + + for (Index = 0; Index < FreeBdCount; Index++) { + + Status = XAxiDma_BdSetBufAddr(BdCurPtr, RxBufferPtr); + if (Status != XST_SUCCESS) { + xil_printf("Rx set buffer addr %x on BD %x failed %d\r\n", + (unsigned int)RxBufferPtr, + (unsigned int)BdCurPtr, Status); + + return XST_FAILURE; + } + + Status = XAxiDma_BdSetLength(BdCurPtr, HSIZE, + RxRingPtr->MaxTransferLen); + if (Status != XST_SUCCESS) { + xil_printf("Rx set length %d on BD %x failed %d\r\n", + MAX_PKT_LEN, (unsigned int)BdCurPtr, Status); + + return XST_FAILURE; + } + + /* Receive BDs do not need to set anything for the control + * The hardware will set the SOF/EOF bits per stream status + */ + XAxiDma_BdSetCtrl(BdCurPtr, 0); + XAxiDma_BdSetId(BdCurPtr, RxBufferPtr); + XAxiDma_BdSetARCache(BdCurPtr, ARCACHE); + XAxiDma_BdSetARUser(BdCurPtr, ARUSER); + XAxiDma_BdSetVSize(BdCurPtr, VSIZE); + XAxiDma_BdSetStride(BdCurPtr, STRIDE); + + RxBufferPtr += MAX_PKT_LEN; + BdCurPtr = XAxiDma_BdRingNext(RxRingPtr, BdCurPtr); + } + + /* + * Set the coalescing threshold, so only one receive interrupt + * occurs for this example + * + * If you would like to have multiple interrupts to happen, change + * the COALESCING_COUNT to be a smaller value + */ + Status = XAxiDma_BdRingSetCoalesce(RxRingPtr, COALESCING_COUNT, + DELAY_TIMER_COUNT); + if (Status != XST_SUCCESS) { + xil_printf("Rx set coalesce failed with %d\r\n", Status); + return XST_FAILURE; + } + + Status = XAxiDma_BdRingToHw(RxRingPtr, FreeBdCount, BdPtr); + if (Status != XST_SUCCESS) { + xil_printf("Rx ToHw failed with %d\r\n", Status); + return XST_FAILURE; + } + + /* Enable all RX interrupts */ + XAxiDma_BdRingIntEnable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* Start RX DMA channel */ + Status = XAxiDma_UpdateBdRingCDesc(RxRingPtr); + if (Status != XST_SUCCESS) { + xil_printf("Failed bd start %x\r\n", Status); + return XST_FAILURE; + } + + RxBdSpacePtr += BdCount * sizeof(XAxiDma_Bd); + + } + + for (RingIndex = 0; + RingIndex < AxiDmaInstPtr->RxNumChannels; RingIndex++) { + RxRingPtr = XAxiDma_GetRxIndexRing(&AxiDma, RingIndex); + Status = XAxiDma_StartBdRingHw(RxRingPtr); + if (Status != XST_SUCCESS) { + xil_printf("Rx start BD ring failed with %d\r\n", Status); + return XST_FAILURE; + } + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/* +* +* This function sets up the TX channel of a DMA engine to be ready for packet +* transmission. +* +* @param AxiDmaInstPtr is the pointer to the instance of the DMA engine. +* +* @return - XST_SUCCESS if the setup is successful. +* - XST_FAILURE otherwise. +* +* @note None. +* +******************************************************************************/ +static int TxSetup(XAxiDma * AxiDmaInstPtr) +{ + XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(&AxiDma); + XAxiDma_Bd BdTemplate; + int Status; + u32 BdCount; + + u32 TxBdSpacePtr = TX_BD_SPACE_BASE; + + /* Disable all TX interrupts before TxBD space setup */ + XAxiDma_BdRingIntDisable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* Setup TxBD space */ + BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, + (u32)TX_BD_SPACE_HIGH - (u32)TX_BD_SPACE_BASE + 1); + + Status = XAxiDma_BdRingCreate(TxRingPtr, TxBdSpacePtr, + TxBdSpacePtr, + XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount); + if (Status != XST_SUCCESS) { + + xil_printf("Failed create BD ring\r\n"); + return XST_FAILURE; + } + + /* + * Like the RxBD space, we create a template and set all BDs to be the + * same as the template. The sender has to set up the BDs as needed. + */ + XAxiDma_BdClear(&BdTemplate); + Status = XAxiDma_BdRingClone(TxRingPtr, &BdTemplate); + if (Status != XST_SUCCESS) { + + xil_printf("Failed clone BDs\r\n"); + return XST_FAILURE; + } + + /* + * Set the coalescing threshold, so only one transmit interrupt + * occurs for this example + * + * If you would like to have multiple interrupts to happen, change + * the COALESCING_COUNT to be a smaller value + */ + Status = XAxiDma_BdRingSetCoalesce(TxRingPtr, COALESCING_COUNT, + DELAY_TIMER_COUNT); + if (Status != XST_SUCCESS) { + + xil_printf("Failed set coalescing" + " %d/%d\r\n",COALESCING_COUNT, DELAY_TIMER_COUNT); + return XST_FAILURE; + } + + /* Enable all TX interrupts */ + XAxiDma_BdRingIntEnable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* Start the TX channel */ + Status = XAxiDma_UpdateBdRingCDesc(TxRingPtr); + if (Status != XST_SUCCESS) { + + xil_printf("Failed bd start %x\r\n", Status); + return XST_FAILURE; + } + + Status = XAxiDma_StartBdRingHw(TxRingPtr); + if (Status != XST_SUCCESS) { + + xil_printf("Failed bd start %x\r\n", Status); + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/* +* +* This function non-blockingly transmits all packets through the DMA engine. +* +* @param AxiDmaInstPtr points to the DMA engine instance +* +* @return +* - XST_SUCCESS if the DMA accepts all the packets successfully, +* - XST_FAILURE if error occurs +* +* @note None. +* +******************************************************************************/ +static int SendPacket(XAxiDma * AxiDmaInstPtr, u8 TDest, u8 TId, u8 Value) +{ + XAxiDma_BdRing *TxRingPtr = XAxiDma_GetTxRing(AxiDmaInstPtr); + u8 *TxPacket; + XAxiDma_Bd *BdPtr, *BdCurPtr; + int Status; + int Index, Pkts; + u32 BufferAddr; + + /* + * Each packet is limited to TxRingPtr->MaxTransferLen + * + * This will not be the case if hardware has store and forward built in + */ + if (MAX_PKT_LEN * NUMBER_OF_BDS_PER_PKT > TxRingPtr->MaxTransferLen) { + + xil_printf("Invalid total per packet transfer length for the " + "packet %d/%d\r\n", + MAX_PKT_LEN * NUMBER_OF_BDS_PER_PKT, + TxRingPtr->MaxTransferLen); + + return XST_INVALID_PARAM; + } + + TxPacket = (u8 *) Packet; + + for(Index = 0; Index < MAX_PKT_LEN * NUMBER_OF_BDS_TO_TRANSFER; + Index ++) { + TxPacket[Index] = Value; + + Value = (Value + 1) & 0xFF; + } + + /* Flush the SrcBuffer before the DMA transfer, in case the Data Cache + * is enabled + */ + Xil_DCacheFlushRange((u32)TxPacket, MAX_PKT_LEN * + NUMBER_OF_BDS_TO_TRANSFER); + + Status = XAxiDma_BdRingAlloc(TxRingPtr, + NUMBER_OF_BDS_TO_TRANSFER, + &BdPtr); + if (Status != XST_SUCCESS) { + + xil_printf("Failed bd alloc\r\n"); + return XST_FAILURE; + } + + BufferAddr = (u32) TxPacket; + BdCurPtr = BdPtr; + + /* + * Set up the BD using the information of the packet to transmit + * Each transfer has NUMBER_OF_BDS_PER_PKT BDs + */ + for(Index = 0; Index < NUMBER_OF_PKTS_TO_TRANSFER; Index++) { + + for(Pkts = 0; Pkts < NUMBER_OF_BDS_PER_PKT; Pkts++) { + u32 CrBits = 0; + + Status = XAxiDma_BdSetBufAddr(BdCurPtr, BufferAddr); + if (Status != XST_SUCCESS) { + xil_printf("Tx set buffer addr %x on BD %x failed %d\r\n", + (unsigned int)BufferAddr, + (unsigned int)BdCurPtr, Status); + + return XST_FAILURE; + } + + Status = XAxiDma_BdSetLength(BdCurPtr, HSIZE, + TxRingPtr->MaxTransferLen); + if (Status != XST_SUCCESS) { + xil_printf("Tx set length %d on BD %x failed %d\r\n", + MAX_PKT_LEN, (unsigned int)BdCurPtr, Status); + + return XST_FAILURE; + } + + if (Pkts == 0) { + /* The first BD has SOF set + */ + CrBits |= XAXIDMA_BD_CTRL_TXSOF_MASK; + +#if (XPAR_AXIDMA_0_SG_INCLUDE_STSCNTRL_STRM == 1) + /* The first BD has total transfer length set + * in the last APP word, this is for the + * loopback widget + */ + Status = XAxiDma_BdSetAppWord(BdCurPtr, + XAXIDMA_LAST_APPWORD, + MAX_PKT_LEN * NUMBER_OF_BDS_PER_PKT); + + if (Status != XST_SUCCESS) { + xil_printf("Set app word failed with %d\r\n", + Status); + } +#endif + } + + if(Pkts == (NUMBER_OF_BDS_PER_PKT - 1)) { + /* The last BD should have EOF and IOC set + */ + CrBits |= XAXIDMA_BD_CTRL_TXEOF_MASK; + } + + XAxiDma_BdSetCtrl(BdCurPtr, CrBits); + XAxiDma_BdSetId(BdCurPtr, BufferAddr); + XAxiDma_BdSetTId(BdCurPtr, TId); + XAxiDma_BdSetTDest(BdCurPtr, TDest); + XAxiDma_BdSetTUser(BdCurPtr, TUSER); + XAxiDma_BdSetARCache(BdCurPtr, ARCACHE); + XAxiDma_BdSetARUser(BdCurPtr, ARUSER); + XAxiDma_BdSetVSize(BdCurPtr, VSIZE); + XAxiDma_BdSetStride(BdCurPtr, STRIDE); + + BufferAddr += MAX_PKT_LEN; + BdCurPtr = XAxiDma_BdRingNext(TxRingPtr, BdCurPtr); + } + } + + /* Give the BD to hardware */ + Status = XAxiDma_BdRingToHw(TxRingPtr, NUMBER_OF_BDS_TO_TRANSFER, + BdPtr); + if (Status != XST_SUCCESS) { + + xil_printf("Failed to hw, length %d\r\n", + (int)XAxiDma_BdGetLength(BdPtr, + TxRingPtr->MaxTransferLen)); + + return XST_FAILURE; + } + + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_poll_multi_pkts.c b/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_poll_multi_pkts.c new file mode 100644 index 00000000..5610f28a --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/examples/xaxidma_poll_multi_pkts.c @@ -0,0 +1,696 @@ +/****************************************************************************** +* +* (c) Copyright 2010-2013 Xilinx, Inc. All rights reserved. +* +* This file contains confidential and proprietary information of Xilinx, Inc. +* and is protected under U.S. and international copyright and other +* intellectual property laws. +* +* DISCLAIMER +* This disclaimer is not a license and does not grant any rights to the +* materials distributed herewith. Except as otherwise provided in a valid +* license issued to you by Xilinx, and to the maximum extent permitted by +* applicable law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL +* FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, +* IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES OF +* MERCHANTABILITY, NON-INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; +* and (2) Xilinx shall not be liable (whether in contract or tort, including +* negligence, or under any other theory of liability) for any loss or damage +* of any kind or nature related to, arising under or in connection with these +* materials, including for any direct, or any indirect, special, incidental, +* or consequential loss or damage (including loss of data, profits, goodwill, +* or any type of loss or damage suffered as a result of any action brought by +* a third party) even if such damage or loss was reasonably foreseeable or +* Xilinx had been advised of the possibility of the same. +* +* CRITICAL APPLICATIONS +* Xilinx products are not designed or intended to be fail-safe, or for use in +* any application requiring fail-safe performance, such as life-support or +* safety devices or systems, Class III medical devices, nuclear facilities, +* applications related to the deployment of airbags, or any other applications +* that could lead to death, personal injury, or severe property or +* environmental damage (individually and collectively, "Critical +* Applications"). Customer assumes the sole risk and liability of any use of +* Xilinx products in Critical Applications, subject only to applicable laws +* and regulations governing limitations on product liability. +* +* THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE +* AT ALL TIMES. +* +******************************************************************************/ +/*****************************************************************************/ +/** + * + * @file xaxidma_poll_multi_pkts.c + * + * This file demonstrates how to use the xaxidma driver on the Xilinx AXI + * DMA core (AXIDMA) to transfer multiple packets in polling mode when the + * AXI DMA core is configured in Scatter Gather Mode. + * + * This code assumes a loopback hardware widget is connected to the AXI DMA + * core for data packet loopback. + * + * To see the debug print, you need a Uart16550 or uartlite in your system, + * and please set "-DDEBUG" in your compiler options. You need to rebuild your + * software executable. + * + * Make sure that MEMORY_BASE is defined properly as per the HW system. The + * h/w system built in Area mode has a maximum DDR memory limit of 64MB. In + * throughput mode, it is 512MB. These limits are need to ensured for + * proper operation of this code. + * + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -------------------------------------------------------
+ * 1.00a jz   05/17/10 First release
+ * 2.00a jz   08/10/10 Second release, added in xaxidma_g.c, xaxidma_sinit.c,
+ *		       updated tcl file, added xaxidma_porting_guide.h, removed
+ *		       workaround for endianness
+ * 4.00a rkv  02/22/11 Name of the file has been changed for naming consistency
+ * 5.00a srt  03/06/12 Added Flushing and Invalidation of Caches to fix CRs
+ *		       648103, 648701.
+ *		       Added V7 DDR Base Address to fix CR 649405.
+ * 6.00a srt  03/27/12 Changed API calls to support MCDMA driver.
+ * 7.00a srt  06/18/12 API calls are reverted back for backward compatibility.
+ * 7.02a srt  03/01/13 Updated DDR base address for IPI designs (CR 703656).
+ *
+ * 
+ * + * *************************************************************************** + */ +/***************************** Include Files *********************************/ +#include "xaxidma.h" +#include "xparameters.h" +#include "xdebug.h" + +#if defined(XPAR_UARTNS550_0_BASEADDR) +#include "xuartns550_l.h" /* to use uartns550 */ +#endif + +#ifndef DEBUG +extern void xil_printf(const char *format, ...); +#endif + +/******************** Constant Definitions **********************************/ + +/*********************** TEMPORARY ******************************************/ +/* + * Device hardware build related constants. + */ +#define DMA_BASE_ADDR XPAR_AXIDMA_0_BASEADDR +#define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID + +#ifdef XPAR_V6DDR_0_S_AXI_BASEADDR +#define DDR_BASE_ADDR XPAR_V6DDR_0_S_AXI_BASEADDR +#elif XPAR_S6DDR_0_S0_AXI_BASEADDR +#define DDR_BASE_ADDR XPAR_S6DDR_0_S0_AXI_BASEADDR +#elif XPAR_AXI_7SDDR_0_S_AXI_BASEADDR +#define DDR_BASE_ADDR XPAR_AXI_7SDDR_0_S_AXI_BASEADDR +#elif XPAR_MIG7SERIES_0_BASEADDR +#define DDR_BASE_ADDR XPAR_MIG7SERIES_0_BASEADDR +#endif + +#ifndef DDR_BASE_ADDR +#warning CHECK FOR THE VALID DDR ADDRESS IN XPARAMETERS.H, \ + DEFAULT SET TO 0x01000000 +#define MEM_BASE_ADDR 0x01000000 +#else +#define MEM_BASE_ADDR (DDR_BASE_ADDR + 0x1000000) +#endif + +#define TX_BD_SPACE_BASE (MEM_BASE_ADDR) +#define TX_BD_SPACE_HIGH (MEM_BASE_ADDR + 0x00000FFF) +#define RX_BD_SPACE_BASE (MEM_BASE_ADDR + 0x00001000) +#define RX_BD_SPACE_HIGH (MEM_BASE_ADDR + 0x00001FFF) +#define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00020000) +#define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00030000) +#define RX_BUFFER_HIGH (MEM_BASE_ADDR + 0x0003FFFF) + +#define MAX_PKT_LEN 0x200 +#define NUMBER_OF_PACKETS 0x10 +#define TEST_START_VALUE 0xC + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ +#if defined(XPAR_UARTNS550_0_BASEADDR) +static void Uart550_Setup(void); +#endif + +static int RxSetup(XAxiDma * AxiDmaInstPtr); +static int TxSetup(XAxiDma * AxiDmaInstPtr); +static int SendPackets(XAxiDma * AxiDmaInstPtr); +static int CheckData(void); +static int CheckDmaResult(XAxiDma * AxiDmaInstPtr); + +/************************** Variable Definitions *****************************/ +/* + * Device instance definitions + */ +XAxiDma AxiDma; + +/* + * Buffer for transmit packet. + */ +u32 *Packet = (u32 *) TX_BUFFER_BASE; + +static XAxiDma_Bd *LastRxBdPtr = NULL; + +/*****************************************************************************/ +/** +* +* Main function +* +* This function is the main entry of the tests on DMA core. It sets up +* DMA engine to be ready to receive and send packets, then a packet is +* transmitted and will be verified after it is received via the DMA loopback +* widget. +* +* @param None +* +* @return - XST_SUCCESS if test pass, +* - XST_FAILURE if test fails +* +* @note None. +* +******************************************************************************/ +int main(void) +{ + int Status; + XAxiDma_Config *Config; + +#if defined(XPAR_UARTNS550_0_BASEADDR) + + Uart550_Setup(); + +#endif + + xil_printf("\r\n--- Entering main() --- \r\n"); + + Config = XAxiDma_LookupConfig(DMA_DEV_ID); + if (!Config) { + xil_printf("No config found for %d\r\n", DMA_DEV_ID); + + return XST_FAILURE; + } + + /* Initialize DMA engine */ + Status = XAxiDma_CfgInitialize(&AxiDma, Config); + if (Status != XST_SUCCESS) { + xil_printf("Initialization failed %d\r\n", Status); + + return XST_FAILURE; + } + + if(!XAxiDma_HasSg(&AxiDma)) { + xil_printf("Device configured as simple mode \r\n"); + + return XST_FAILURE; + } + + Status = TxSetup(&AxiDma); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + Status = RxSetup(&AxiDma); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* Send packets */ + Status = SendPackets(&AxiDma); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* Check DMA transfer result */ + + Status = CheckDmaResult(&AxiDma); + + xil_printf("Test %s\r\n", + (Status == XST_SUCCESS)? "passed":"failed"); + + xil_printf("--- Exiting main() --- \r\n"); + + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + + +#if defined(XPAR_UARTNS550_0_BASEADDR) +/*****************************************************************************/ +/* +* +* Uart16550 setup routine, need to set baudrate to 9600 and data bits to 8 +* +* @param None +* +* @return None +* +* @note None. +* + +******************************************************************************/ +static void Uart550_Setup(void) +{ + /* Set the baudrate to be predictable + */ + XUartNs550_SetBaud(XPAR_UARTNS550_0_BASEADDR, + XPAR_XUARTNS550_CLOCK_HZ, 9600); + + XUartNs550_SetLineControlReg(XPAR_UARTNS550_0_BASEADDR, + XUN_LCR_8_DATA_BITS); + +} +#endif + +/*****************************************************************************/ +/** +* +* This function sets up RX channel of the DMA engine to be ready for packet +* reception +* +* @param AxiDmaInstPtr is the pointer to the instance of the DMA engine. +* +* @return - XST_SUCCESS if the setup is successful +* - XST_FAILURE if setup is failure +* +* @note None. +* +******************************************************************************/ +static int RxSetup(XAxiDma * AxiDmaInstPtr) +{ + XAxiDma_BdRing *RxRingPtr; + int Delay = 0; + int Coalesce = 1; + int Status; + XAxiDma_Bd BdTemplate; + XAxiDma_Bd *BdPtr; + XAxiDma_Bd *BdCurPtr; + u32 BdCount; + u32 FreeBdCount; + u32 RxBufferPtr; + int i; + + RxRingPtr = XAxiDma_GetRxRing(&AxiDma); + + /* Disable all RX interrupts before RxBD space setup */ + + XAxiDma_BdRingIntDisable(RxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* Set delay and coalescing */ + XAxiDma_BdRingSetCoalesce(RxRingPtr, Coalesce, Delay); + + /* Setup Rx BD space */ + BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, + RX_BD_SPACE_HIGH - RX_BD_SPACE_BASE + 1); + + Status = XAxiDma_BdRingCreate(RxRingPtr, RX_BD_SPACE_BASE, + RX_BD_SPACE_BASE, + XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount); + + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* + * Setup an all-zero BD as the template for the Rx channel. + */ + XAxiDma_BdClear(&BdTemplate); + + Status = XAxiDma_BdRingClone(RxRingPtr, &BdTemplate); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* Attach buffers to RxBD ring so we are ready to receive packets + */ + FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr); + Status = XAxiDma_BdRingAlloc(RxRingPtr, FreeBdCount, &BdPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + BdCurPtr = BdPtr; + RxBufferPtr = RX_BUFFER_BASE; + + for (i = 0; i < FreeBdCount; i++) { + + Status = XAxiDma_BdSetBufAddr(BdCurPtr, RxBufferPtr); + if (Status != XST_SUCCESS) { + xil_printf("Rx set buffer addr %x on BD %x failed %d\r\n", + (unsigned int)RxBufferPtr, (unsigned int)BdCurPtr, + Status); + + return XST_FAILURE; + } + + Status = XAxiDma_BdSetLength(BdCurPtr, MAX_PKT_LEN, + RxRingPtr->MaxTransferLen); + if (Status != XST_SUCCESS) { + xil_printf("Rx set length %d on BD %x failed %d\r\n", + MAX_PKT_LEN, (unsigned int)BdCurPtr, Status); + + return XST_FAILURE; + } + + /* Receive BDs do not need to set anything for the control + * The hardware will set the SOF/EOF bits per stream status + */ + XAxiDma_BdSetCtrl(BdPtr, 0); + XAxiDma_BdSetId(BdCurPtr, RxBufferPtr); + RxBufferPtr += MAX_PKT_LEN; + + if (i == (FreeBdCount - 1)) { + LastRxBdPtr = BdCurPtr; + } + + BdCurPtr = XAxiDma_BdRingNext(RxRingPtr, BdCurPtr); + } + + Status = XAxiDma_BdRingToHw(RxRingPtr, FreeBdCount, BdPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* Start RX DMA channel */ + Status = XAxiDma_BdRingStart(RxRingPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function sets up the TX channel of a DMA engine to be ready for packet +* transmission +* +* @param AxiDmaInstPtr is the instance pointer to the DMA engine. +* +* @return - XST_SUCCESS if the setup is successful +* - XST_FAILURE if setup is failure +* +* @note None. +* +******************************************************************************/ +static int TxSetup(XAxiDma * AxiDmaInstPtr) +{ + XAxiDma_BdRing *TxRingPtr; + XAxiDma_Bd BdTemplate; + int Delay = 0; + int Coalesce = 1; + int Status; + u32 BdCount; + + TxRingPtr = XAxiDma_GetTxRing(&AxiDma); + + /* Disable all TX interrupts before Tx BD space setup */ + + XAxiDma_BdRingIntDisable(TxRingPtr, XAXIDMA_IRQ_ALL_MASK); + + /* Set TX delay and coalesce */ + XAxiDma_BdRingSetCoalesce(TxRingPtr, Coalesce, Delay); + + /* Setup Tx BD space */ + BdCount = XAxiDma_BdRingCntCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, + TX_BD_SPACE_HIGH - TX_BD_SPACE_BASE + 1); + + Status = XAxiDma_BdRingCreate(TxRingPtr, TX_BD_SPACE_BASE, + TX_BD_SPACE_BASE, + XAXIDMA_BD_MINIMUM_ALIGNMENT, BdCount); + if (Status != XST_SUCCESS) { + xil_printf("failed create BD ring in txsetup\r\n"); + + return XST_FAILURE; + } + + /* + * We create an all-zero BD as the template. + */ + XAxiDma_BdClear(&BdTemplate); + + Status = XAxiDma_BdRingClone(TxRingPtr, &BdTemplate); + if (Status != XST_SUCCESS) { + xil_printf("failed bdring clone in txsetup %d\r\n", Status); + + return XST_FAILURE; + } + + /* Start the TX channel */ + Status = XAxiDma_BdRingStart(TxRingPtr); + if (Status != XST_SUCCESS) { + xil_printf("failed start bdring txsetup %d\r\n", Status); + + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function transmits packets non-blockingly through the DMA engine. +* +* @param AxiDmaInstPtr points to the DMA engine instance +* +* @return - XST_SUCCESS if the DMA accepts the packet successfully, +* - XST_FAILURE if failure. +* +* @note None. +* +******************************************************************************/ +static int SendPackets(XAxiDma * AxiDmaInstPtr) +{ + XAxiDma_BdRing *TxRingPtr; + u8 *TxPacket; + u8 Value; + XAxiDma_Bd *BdPtr; + int Status; + int i; + u32 BufAddr; + XAxiDma_Bd *CurBdPtr; + + /* Create pattern in the packet to transmit + */ + TxPacket = (u8 *) Packet; + + Value = TEST_START_VALUE; + + for(i = 0; i < MAX_PKT_LEN * NUMBER_OF_PACKETS; i ++) { + TxPacket[i] = Value; + + Value = (Value + 1) & 0xFF; + } + + /* Flush the SrcBuffer before the DMA transfer, in case the Data Cache + * is enabled + */ + Xil_DCacheFlushRange((u32)TxPacket, MAX_PKT_LEN * + NUMBER_OF_PACKETS); + + TxRingPtr = XAxiDma_GetTxRing(AxiDmaInstPtr); + + /* Allocate BDs */ + Status = XAxiDma_BdRingAlloc(TxRingPtr, NUMBER_OF_PACKETS, &BdPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* Set up the BDs using the information of the packet to transmit */ + BufAddr = (u32)Packet; + CurBdPtr = BdPtr; + + for (i = 0; i < NUMBER_OF_PACKETS; i++) { + u32 CrBits = 0; + + Status = XAxiDma_BdSetBufAddr(CurBdPtr, BufAddr); + if (Status != XST_SUCCESS) { + xil_printf("Tx set buffer addr %x on BD %x failed %d\r\n", + (unsigned int)BufAddr, (unsigned int)CurBdPtr, Status); + + return XST_FAILURE; + } + + Status = XAxiDma_BdSetLength(CurBdPtr, MAX_PKT_LEN, + TxRingPtr->MaxTransferLen); + if (Status != XST_SUCCESS) { + xil_printf("Tx set length %d on BD %x failed %d\r\n", + MAX_PKT_LEN, (unsigned int)CurBdPtr, Status); + + return XST_FAILURE; + } + + if (i == 0) { + CrBits |= XAXIDMA_BD_CTRL_TXSOF_MASK; + +#if (XPAR_AXIDMA_0_SG_INCLUDE_STSCNTRL_STRM == 1) + /* The first BD has total transfer length set in + * the last APP word, this is for the loopback widget + */ + Status = XAxiDma_BdSetAppWord(CurBdPtr, + XAXIDMA_LAST_APPWORD, + MAX_PKT_LEN * NUMBER_OF_PACKETS); + + if (Status != XST_SUCCESS) { + xil_printf("Set app word failed with %d\r\n", + Status); + } +#endif + } + if (i == (NUMBER_OF_PACKETS - 1)) { + CrBits |= XAXIDMA_BD_CTRL_TXEOF_MASK; + XAxiDma_BdSetCtrl(CurBdPtr, + XAXIDMA_BD_CTRL_TXEOF_MASK); + } + XAxiDma_BdSetCtrl(CurBdPtr, CrBits); + + XAxiDma_BdSetId(CurBdPtr, BufAddr); + + BufAddr += MAX_PKT_LEN; + CurBdPtr = XAxiDma_BdRingNext(TxRingPtr, CurBdPtr); + } + + /* Give the BD to DMA to kick off the transmission. */ + Status = XAxiDma_BdRingToHw(TxRingPtr, NUMBER_OF_PACKETS, BdPtr); + if (Status != XST_SUCCESS) { + xil_printf("to hw failed %d\r\n", Status); + + return XST_FAILURE; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function checks data buffer after the DMA transfer is finished. +* +* @param None +* +* @return - XST_SUCCESS if validation is successful +* - XST_FAILURE if validation is failure. +* +* @note None. +* +******************************************************************************/ +static int CheckData(void) +{ + u8 *RxPacket; + int i = 0; + u8 Value; + + RxPacket = (u8 *) RX_BUFFER_BASE; + Value = TEST_START_VALUE; + + /* Invalidate the DestBuffer before receiving the data, in case the + * Data Cache is enabled + */ + Xil_DCacheInvalidateRange((u32)RxPacket, MAX_PKT_LEN * + NUMBER_OF_PACKETS); + + for(i = 0; i < MAX_PKT_LEN * NUMBER_OF_PACKETS; i++) { + if (RxPacket[i] != Value) { + xil_printf("Data error %d: %x/%x\r\n", + i, (unsigned int)RxPacket[i], (unsigned int)Value); + + return XST_FAILURE; + } + Value = (Value + 1) & 0xFF; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* +* This function delays until the DMA transaction is finished, checks data, +* and cleans up. +* +* @param AxiDmaInstPtr points to the DMA engine instance +* +* @return - XST_SUCCESS if DMA transfer is successful and data is correct +* - XST_FAILURE if failure +* +* @note None. +* +******************************************************************************/ +static int CheckDmaResult(XAxiDma * AxiDmaInstPtr) +{ + XAxiDma_BdRing *TxRingPtr; + XAxiDma_BdRing *RxRingPtr; + XAxiDma_Bd *BdPtr; + u32 ProcessedBdCount = 0; + u32 FreeBdCount; + int Status; + + TxRingPtr = XAxiDma_GetTxRing(AxiDmaInstPtr); + RxRingPtr = XAxiDma_GetRxRing(AxiDmaInstPtr); + + /* Wait until the TX transactions are done */ + while (ProcessedBdCount < NUMBER_OF_PACKETS) { + ProcessedBdCount += XAxiDma_BdRingFromHw(TxRingPtr, + XAXIDMA_ALL_BDS, &BdPtr); + } + + /* Free all processed TX BDs for future transmission */ + Status = XAxiDma_BdRingFree(TxRingPtr, ProcessedBdCount, BdPtr); + if (Status != XST_SUCCESS) { + return XST_FAILURE; + } + + /* Wait until the data has been received by the Rx channel */ + ProcessedBdCount = 0; + + while (ProcessedBdCount < NUMBER_OF_PACKETS) { + + ProcessedBdCount += XAxiDma_BdRingFromHw(RxRingPtr, + XAXIDMA_ALL_BDS, &BdPtr); + } + + + /* Check received data */ + if (CheckData() != XST_SUCCESS) { + + return XST_FAILURE; + } + + /* Free all processed RX BDs for future transmission */ + Status = XAxiDma_BdRingFree(RxRingPtr, ProcessedBdCount, BdPtr); + if (Status != XST_SUCCESS) { + xil_printf("free bd failed\r\n"); + return XST_FAILURE; + } + + /* Return processed BDs to RX channel so we are ready to receive new + * packets: + * - Allocate all free RX BDs + * - Pass the BDs to RX channel + */ + FreeBdCount = XAxiDma_BdRingGetFreeCnt(RxRingPtr); + Status = XAxiDma_BdRingAlloc(RxRingPtr, FreeBdCount, &BdPtr); + if (Status != XST_SUCCESS) { + xil_printf("bd alloc failed\r\n"); + return XST_FAILURE; + } + + Status = XAxiDma_BdRingToHw(RxRingPtr, FreeBdCount, BdPtr); + + return Status; +} diff --git a/XilinxProcessorIPLib/drivers/axidma/src/Makefile b/XilinxProcessorIPLib/drivers/axidma/src/Makefile new file mode 100644 index 00000000..f4e121b7 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/src/Makefile @@ -0,0 +1,27 @@ +COMPILER= +ARCHIVER= +CP=cp +COMPILER_FLAGS= +EXTRA_COMPILER_FLAGS= +LIB=libxil.a + +RELEASEDIR=../../../lib +INCLUDEDIR=../../../include +INCLUDES=-I${INCLUDEDIR} + +OUTS = *.o + +LIBSOURCES=*.c +INCLUDEFILES=*.h + +libs: + echo "Compiling axidma" + $(COMPILER) $(COMPILER_FLAGS) $(EXTRA_COMPILER_FLAGS) $(INCLUDES) $(LIBSOURCES) + $(ARCHIVER) -r ${RELEASEDIR}/${LIB} ${OUTS} + make clean + +include: + ${CP} $(INCLUDEFILES) $(INCLUDEDIR) + +clean: + rm -rf $(OUTS) diff --git a/XilinxProcessorIPLib/drivers/axidma/src/xaxidma.c b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma.c new file mode 100644 index 00000000..16ab1af0 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma.c @@ -0,0 +1,953 @@ +/****************************************************************************** +* +* 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 xaxidma.c +* +* This file implements DMA engine-wise initialization and control functions. +* For more information on the implementation of this driver, see xaxidma.h. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a jz   05/18/10 First release
+* 2.00a jz   08/10/10 Second release, added in xaxidma_g.c, xaxidma_sinit.c,
+*                     updated tcl file, added xaxidma_porting_guide.h
+* 3.00a jz   11/22/10 Support IP core parameters change
+* 4.00a rkv  02/22/11 Added support for simple DMA mode
+*		      New API added for simple DMA mode are
+*			- XAxiDma_Busy
+*			- XAxiDma_SimpleTransfer
+* 6.00a srt  01/24/12 Added support for Multi-Channel DMA mode.
+*		      - Changed APIs:
+*			* XAxiDma_Start(XAxiDma * InstancePtr, int RingIndex)
+*			* XAxiDma_Started(XAxiDma * InstancePtr, int RingIndex)
+*			* XAxiDma_Pause(XAxiDma * InstancePtr, int RingIndex)
+*			* XAxiDma_Resume(XAxiDma * InstancePtr, int RingIndex)
+*			* XAxiDma_SimpleTransfer(XAxiDma *InstancePtr,
+*        					u32 BuffAddr, u32 Length,
+*						int Direction, int RingIndex)
+*		      - New API:
+*			* XAxiDma_SelectKeyHole(XAxiDma *InstancePtr,
+*						int Direction, int Select)
+* 7.00a srt  06/18/12  All the APIs changed in v6_00_a are reverted back for
+*		       backward compatibility.
+* 7.01a srt  10/26/12  Fixed issue with driver as it fails with IP version
+*		       < 6.00a as the parameter C_NUM_*_CHANNELS is not
+*		       applicable.
+* 8.0   srt  01/29/14  Added support for Micro DMA Mode and Cyclic mode of
+*		       operations.
+*		      - New API:
+*			* XAxiDma_SelectCyclicMode(XAxiDma *InstancePtr,
+*						int Direction, int Select)
+*
+* 
+******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xaxidma.h" + +/************************** Constant Definitions *****************************/ + +/* Loop counter to check reset done + */ +#define XAXIDMA_RESET_TIMEOUT 500 + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ + + +/************************** Function Prototypes ******************************/ +static int XAxiDma_Start(XAxiDma * InstancePtr); +static int XAxiDma_Started(XAxiDma * InstancePtr); + +/************************** Variable Definitions *****************************/ + +/*****************************************************************************/ +/** + * This function initializes a DMA engine. This function must be called + * prior to using a DMA engine. Initializing a engine includes setting + * up the register base address, setting up the instance data, and ensuring the + * hardware is in a quiescent state. + * + * @param InstancePtr is a pointer to the DMA engine instance to be + * worked on. + * @param Config is a pointer to an XAxiDma_Config structure. It contains + * the information about the hardware build, including base + * address,and whether status control stream (StsCntrlStrm), MM2S + * and S2MM are included in the build. + * + * @return + * - XST_SUCCESS for successful initialization + * - XST_INVALID_PARAM if pointer to the configuration structure + * is NULL + * - XST_DMA_ERROR if reset operation failed at the end of + * initialization + * + * @note We assume the hardware building tool will check and error out + * for a hardware build that has no transfer channels. + *****************************************************************************/ +int XAxiDma_CfgInitialize(XAxiDma * InstancePtr, XAxiDma_Config *Config) +{ + u32 BaseAddr; + int TimeOut; + int Index; + u32 MaxTransferLen; + + InstancePtr->Initialized = 0; + + if(!Config) { + return XST_INVALID_PARAM; + } + + BaseAddr = Config->BaseAddr; + + /* Setup the instance */ + memset(InstancePtr, 0, sizeof(XAxiDma)); + InstancePtr->RegBase = BaseAddr; + + /* Get hardware setting information from the configuration structure + */ + InstancePtr->HasMm2S = Config->HasMm2S; + InstancePtr->HasS2Mm = Config->HasS2Mm; + + InstancePtr->HasSg = Config->HasSg; + + InstancePtr->MicroDmaMode = Config->MicroDmaMode; + + /* Get the number of channels */ + InstancePtr->TxNumChannels = Config->Mm2sNumChannels; + InstancePtr->RxNumChannels = Config->S2MmNumChannels; + + /* This condition is for IP version < 6.00a */ + if (!InstancePtr->TxNumChannels) + InstancePtr->TxNumChannels = 1; + if (!InstancePtr->RxNumChannels) + InstancePtr->RxNumChannels = 1; + + if ((InstancePtr->RxNumChannels > 1) || + (InstancePtr->TxNumChannels > 1)) { + MaxTransferLen = + XAXIDMA_MCHAN_MAX_TRANSFER_LEN; + } + else { + MaxTransferLen = + XAXIDMA_MAX_TRANSFER_LEN; + } + + /* Initialize the ring structures */ + InstancePtr->TxBdRing.RunState = AXIDMA_CHANNEL_HALTED; + InstancePtr->TxBdRing.IsRxChannel = 0; + if (!InstancePtr->MicroDmaMode) { + InstancePtr->TxBdRing.MaxTransferLen = MaxTransferLen; + } + else { + /* In MicroDMA mode, Maximum length that can be transferred + * is '(Memory Data Width / 4) * Burst Size' + */ + InstancePtr->TxBdRing.MaxTransferLen = + ((Config->Mm2SDataWidth / 4) * + Config->Mm2SBurstSize); + } + InstancePtr->TxBdRing.RingIndex = 0; + + for (Index = 0; Index < InstancePtr->RxNumChannels; Index++) { + InstancePtr->RxBdRing[Index].RunState + = AXIDMA_CHANNEL_HALTED; + InstancePtr->RxBdRing[Index].IsRxChannel = 1; + InstancePtr->RxBdRing[Index].RingIndex = Index; + } + + if (InstancePtr->HasMm2S) { + InstancePtr->TxBdRing.ChanBase = + BaseAddr + XAXIDMA_TX_OFFSET; + InstancePtr->TxBdRing.HasStsCntrlStrm = + Config->HasStsCntrlStrm; + InstancePtr->TxBdRing.HasDRE = Config->HasMm2SDRE; + InstancePtr->TxBdRing.DataWidth = + ((unsigned int)Config->Mm2SDataWidth >> 3); + } + + if (InstancePtr->HasS2Mm) { + for (Index = 0; + Index < InstancePtr->RxNumChannels; Index++) { + InstancePtr->RxBdRing[Index].ChanBase = + BaseAddr + XAXIDMA_RX_OFFSET; + InstancePtr->RxBdRing[Index].HasStsCntrlStrm = + Config->HasStsCntrlStrm; + InstancePtr->RxBdRing[Index].HasDRE = + Config->HasS2MmDRE; + InstancePtr->RxBdRing[Index].DataWidth = + ((unsigned int)Config->S2MmDataWidth >> 3); + + if (!InstancePtr->MicroDmaMode) { + InstancePtr->RxBdRing[Index].MaxTransferLen = + MaxTransferLen; + } + else { + /* In MicroDMA mode, Maximum length that can be transferred + * is '(Memory Data Width / 4) * Burst Size' + */ + InstancePtr->RxBdRing[Index].MaxTransferLen = + ((Config->S2MmDataWidth / 4) * + Config->S2MmBurstSize); + } + } + } + + /* Reset the engine so the hardware starts from a known state + */ + XAxiDma_Reset(InstancePtr); + + /* At the initialization time, hardware should finish reset quickly + */ + TimeOut = XAXIDMA_RESET_TIMEOUT; + + while (TimeOut) { + + if(XAxiDma_ResetIsDone(InstancePtr)) { + break; + } + + TimeOut -= 1; + + } + + if (!TimeOut) { + xdbg_printf(XDBG_DEBUG_ERROR, "Failed reset in" + "initialize\r\n"); + + /* Need system hard reset to recover + */ + InstancePtr->Initialized = 0; + return XST_DMA_ERROR; + } + + /* Initialization is successful + */ + InstancePtr->Initialized = 1; + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** +* Reset both TX and RX channels of a DMA engine. +* +* Reset one channel resets the whole AXI DMA engine. +* +* Any DMA transaction in progress will finish gracefully before engine starts +* reset. Any other transactions that have been submitted to hardware will be +* discarded by the hardware. +* +* @param InstancePtr is a pointer to the DMA engine instance to be +* worked on. +* +* @return None +* +* @note After the reset: +* - All interrupts are disabled. +* - Engine is halted +* +******************************************************************************/ +void XAxiDma_Reset(XAxiDma * InstancePtr) +{ + u32 RegBase; + XAxiDma_BdRing *TxRingPtr; + XAxiDma_BdRing *RxRingPtr; + int RingIndex; + + TxRingPtr = XAxiDma_GetTxRing(InstancePtr); + + /* Save the locations of current BDs both rings are working on + * before the reset so later we can resume the rings smoothly. + */ + if(XAxiDma_HasSg(InstancePtr)){ + XAxiDma_BdRingSnapShotCurrBd(TxRingPtr); + + for (RingIndex = 0; RingIndex < InstancePtr->RxNumChannels; + RingIndex++) { + RxRingPtr = XAxiDma_GetRxIndexRing(InstancePtr, + RingIndex); + XAxiDma_BdRingSnapShotCurrBd(RxRingPtr); + } + } + + /* Reset + */ + if (InstancePtr->HasMm2S) { + RegBase = InstancePtr->RegBase + XAXIDMA_TX_OFFSET; + } + else { + RegBase = InstancePtr->RegBase + XAXIDMA_RX_OFFSET; + } + + XAxiDma_WriteReg(RegBase, XAXIDMA_CR_OFFSET, XAXIDMA_CR_RESET_MASK); + + /* Set TX/RX Channel state */ + if (InstancePtr->HasMm2S) { + TxRingPtr->RunState = AXIDMA_CHANNEL_HALTED; + } + + for (RingIndex = 0; RingIndex < InstancePtr->RxNumChannels; + RingIndex++) { + RxRingPtr = XAxiDma_GetRxIndexRing(InstancePtr, RingIndex); + if (InstancePtr->HasS2Mm) { + RxRingPtr->RunState = AXIDMA_CHANNEL_HALTED; + } + } +} + +/*****************************************************************************/ +/** +* +* Check whether reset is done +* +* @param InstancePtr is a pointer to the DMA engine instance to be +* worked on. +* +* @return +* - 1 if reset is done. +* - 0 if reset is not done +* +* @note None +* +******************************************************************************/ +int XAxiDma_ResetIsDone(XAxiDma * InstancePtr) +{ + u32 RegisterValue; + XAxiDma_BdRing *TxRingPtr; + XAxiDma_BdRing *RxRingPtr; + + TxRingPtr = XAxiDma_GetTxRing(InstancePtr); + RxRingPtr = XAxiDma_GetRxRing(InstancePtr); + + /* Check transmit channel + */ + if (InstancePtr->HasMm2S) { + RegisterValue = XAxiDma_ReadReg(TxRingPtr->ChanBase, + XAXIDMA_CR_OFFSET); + + /* Reset is done when the reset bit is low + */ + if(RegisterValue & XAXIDMA_CR_RESET_MASK) { + + return 0; + } + } + + /* Check receive channel + */ + if (InstancePtr->HasS2Mm) { + RegisterValue = XAxiDma_ReadReg(RxRingPtr->ChanBase, + XAXIDMA_CR_OFFSET); + + /* Reset is done when the reset bit is low + */ + if(RegisterValue & XAXIDMA_CR_RESET_MASK) { + + return 0; + } + } + + return 1; +} +/*****************************************************************************/ +/* +* Start the DMA engine. +* +* Start a halted engine. Processing of BDs is not started. +* +* @param InstancePtr is a pointer to the DMA engine instance to be +* worked on. +* +* @return +* - XST_SUCCESS for success +* - XST_NOT_SGDMA if the driver instance has not been initialized +* - XST_DMA_ERROR if starting the hardware channel fails +* +* @note None +* +*****************************************************************************/ +static int XAxiDma_Start(XAxiDma * InstancePtr) +{ + XAxiDma_BdRing *TxRingPtr; + XAxiDma_BdRing *RxRingPtr; + int Status; + int RingIndex = 0; + + if (!InstancePtr->Initialized) { + + xdbg_printf(XDBG_DEBUG_ERROR, "Start: Driver not initialized " + "%d\r\n", InstancePtr->Initialized); + + return XST_NOT_SGDMA; + } + + if (InstancePtr->HasMm2S) { + TxRingPtr = XAxiDma_GetTxRing(InstancePtr); + + if (TxRingPtr->RunState == AXIDMA_CHANNEL_HALTED) { + + /* Start the channel + */ + if(XAxiDma_HasSg(InstancePtr)) { + Status = XAxiDma_BdRingStart(TxRingPtr); + if (Status != XST_SUCCESS) { + xdbg_printf(XDBG_DEBUG_ERROR, + "Start hw tx channel failed %d\r\n", + Status); + + return XST_DMA_ERROR; + } + } + else { + XAxiDma_WriteReg(TxRingPtr->ChanBase, + XAXIDMA_CR_OFFSET, + XAxiDma_ReadReg(TxRingPtr->ChanBase, + XAXIDMA_CR_OFFSET) + | XAXIDMA_CR_RUNSTOP_MASK); + } + TxRingPtr->RunState = AXIDMA_CHANNEL_NOT_HALTED; + } + } + + if (InstancePtr->HasS2Mm) { + + for (RingIndex = 0; RingIndex < InstancePtr->RxNumChannels; + RingIndex++) { + RxRingPtr = XAxiDma_GetRxIndexRing(InstancePtr, + RingIndex); + + if (RxRingPtr->RunState != AXIDMA_CHANNEL_HALTED) { + return XST_SUCCESS; + } + + /* Start the channel + */ + if(XAxiDma_HasSg(InstancePtr)) { + Status = XAxiDma_BdRingStart(RxRingPtr); + if (Status != XST_SUCCESS) { + xdbg_printf(XDBG_DEBUG_ERROR, + "Start hw tx channel failed %d\r\n", + Status); + + return XST_DMA_ERROR; + } + } + else { + XAxiDma_WriteReg(RxRingPtr->ChanBase, + XAXIDMA_CR_OFFSET, + XAxiDma_ReadReg(RxRingPtr->ChanBase, + XAXIDMA_CR_OFFSET) | + XAXIDMA_CR_RUNSTOP_MASK); + } + + RxRingPtr->RunState = AXIDMA_CHANNEL_NOT_HALTED; + } + } + + return XST_SUCCESS; +} +/*****************************************************************************/ +/** +* Pause DMA transactions on both channels. +* +* If the engine is running and doing transfers, this function does not stop +* the DMA transactions immediately, because then hardware will throw away +* our previously queued transfers. All submitted transfers will finish. +* Transfers submitted after this function will not start until +* XAxiDma_BdRingStart() or XAxiDma_Resume() is called. +* +* @param InstancePtr is a pointer to the DMA engine instance to be +* worked on. +* +* @return +* - XST_SUCCESS if successful +* - XST_NOT_SGDMA, if the driver instance is not initialized +* +* @note None +* +*****************************************************************************/ +int XAxiDma_Pause(XAxiDma * InstancePtr) +{ + XAxiDma_BdRing *TxRingPtr; + XAxiDma_BdRing *RxRingPtr; + int RingIndex = 0; + + if (!InstancePtr->Initialized) { + + xdbg_printf(XDBG_DEBUG_ERROR, "Pause: Driver not initialized" + " %d\r\n",InstancePtr->Initialized); + + return XST_NOT_SGDMA; + } + + if (InstancePtr->HasMm2S) { + TxRingPtr = XAxiDma_GetTxRing(InstancePtr); + + /* If channel is halted, then we do not need to do anything + */ + if(!XAxiDma_HasSg(InstancePtr)) { + XAxiDma_WriteReg(TxRingPtr->ChanBase, + XAXIDMA_CR_OFFSET, + XAxiDma_ReadReg(TxRingPtr->ChanBase, + XAXIDMA_CR_OFFSET) + & ~XAXIDMA_CR_RUNSTOP_MASK); + } + + TxRingPtr->RunState = AXIDMA_CHANNEL_HALTED; + } + + if (InstancePtr->HasS2Mm) { + for (RingIndex = 0; RingIndex < InstancePtr->RxNumChannels; + RingIndex++) { + RxRingPtr = XAxiDma_GetRxIndexRing(InstancePtr, RingIndex); + + /* If channel is halted, then we do not need to do anything + */ + + if(!XAxiDma_HasSg(InstancePtr) && !RingIndex) { + XAxiDma_WriteReg(RxRingPtr->ChanBase, + XAXIDMA_CR_OFFSET, + XAxiDma_ReadReg(RxRingPtr->ChanBase, + XAXIDMA_CR_OFFSET) + & ~XAXIDMA_CR_RUNSTOP_MASK); + } + + RxRingPtr->RunState = AXIDMA_CHANNEL_HALTED; + } + } + + return XST_SUCCESS; + +} + +/*****************************************************************************/ +/** +* Resume DMA transactions on both channels. +* +* @param InstancePtr is a pointer to the DMA engine instance to be +* worked on. +* +* @return +* - XST_SUCCESS for success +* - XST_NOT_SGDMA if the driver instance has not been initialized +* - XST_DMA_ERROR if one of the channels fails to start +* +* @note None +* +*****************************************************************************/ +int XAxiDma_Resume(XAxiDma * InstancePtr) +{ + XAxiDma_BdRing *TxRingPtr; + XAxiDma_BdRing *RxRingPtr; + int Status; + int RingIndex = 0; + + if (!InstancePtr->Initialized) { + + xdbg_printf(XDBG_DEBUG_ERROR, "Resume: Driver not initialized" + " %d\r\n",InstancePtr->Initialized); + + return XST_NOT_SGDMA; + } + + /* If the DMA engine is not running, start it. Start may fail. + */ + if (!XAxiDma_Started(InstancePtr)) { + Status = XAxiDma_Start(InstancePtr); + + if (Status != XST_SUCCESS) { + xdbg_printf(XDBG_DEBUG_ERROR, "Resume: failed to start" + " engine %d\r\n", Status); + + return Status; + } + } + + /* Mark the state to be not halted + */ + if (InstancePtr->HasMm2S) { + TxRingPtr = XAxiDma_GetTxRing(InstancePtr); + + if(XAxiDma_HasSg(InstancePtr)) { + Status = XAxiDma_BdRingStart(TxRingPtr); + if (Status != XST_SUCCESS) { + xdbg_printf(XDBG_DEBUG_ERROR, "Resume: failed" + " to start tx ring %d\r\n", Status); + + return XST_DMA_ERROR; + } + } + + TxRingPtr->RunState = AXIDMA_CHANNEL_NOT_HALTED; + } + + if (InstancePtr->HasS2Mm) { + for (RingIndex = 0 ; RingIndex < InstancePtr->RxNumChannels; + RingIndex++) { + RxRingPtr = XAxiDma_GetRxIndexRing(InstancePtr, RingIndex); + + if(XAxiDma_HasSg(InstancePtr)) { + Status = XAxiDma_BdRingStart(RxRingPtr); + if (Status != XST_SUCCESS) { + xdbg_printf(XDBG_DEBUG_ERROR, "Resume: failed" + "to start rx ring %d\r\n", Status); + + return XST_DMA_ERROR; + } + } + + RxRingPtr->RunState = AXIDMA_CHANNEL_NOT_HALTED; + } + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/* +* Check whether the DMA engine is started. +* +* @param InstancePtr is a pointer to the DMA engine instance to be +* worked on. +* +* @return +* - 1 if engine is started +* - 0 otherwise. +* +* @note None +* +*****************************************************************************/ +static int XAxiDma_Started(XAxiDma * InstancePtr) +{ + XAxiDma_BdRing *TxRingPtr; + XAxiDma_BdRing *RxRingPtr; + + if (!InstancePtr->Initialized) { + + xdbg_printf(XDBG_DEBUG_ERROR, "Started: Driver not initialized" + " %d\r\n",InstancePtr->Initialized); + + return 0; + } + + if (InstancePtr->HasMm2S) { + TxRingPtr = XAxiDma_GetTxRing(InstancePtr); + + if (!XAxiDma_BdRingHwIsStarted(TxRingPtr)) { + xdbg_printf(XDBG_DEBUG_ERROR, + "Started: tx ring not started\r\n"); + + return 0; + } + } + + if (InstancePtr->HasS2Mm) { + RxRingPtr = XAxiDma_GetRxRing(InstancePtr); + + if (!XAxiDma_BdRingHwIsStarted(RxRingPtr)) { + xdbg_printf(XDBG_DEBUG_ERROR, + "Started: rx ring not started\r\n"); + + return 0; + } + } + + return 1; +} + +/*****************************************************************************/ +/** + * This function checks whether specified DMA channel is busy + * + * @param InstancePtr is the driver instance we are working on + * + * @param Direction is DMA transfer direction, valid values are + * - XAXIDMA_DMA_TO_DEVICE. + * - XAXIDMA_DEVICE_TO_DMA. + * + * @return - TRUE if channel is busy + * - FALSE if channel is idle + * + * @note None. + * + *****************************************************************************/ +u32 XAxiDma_Busy(XAxiDma *InstancePtr, int Direction) +{ + + return ((XAxiDma_ReadReg(InstancePtr->RegBase + + (XAXIDMA_RX_OFFSET * Direction), + XAXIDMA_SR_OFFSET) & + XAXIDMA_IDLE_MASK) ? FALSE : TRUE); +} + + +/*****************************************************************************/ +/** + * This function Enable or Disable KeyHole Feature + * + * @param InstancePtr is the driver instance we are working on + * + * @param Direction is DMA transfer direction, valid values are + * - XAXIDMA_DMA_TO_DEVICE. + * - XAXIDMA_DEVICE_TO_DMA. + * @Select Select is the option to enable (TRUE) or disable (FALSE). + * + * @return - XST_SUCCESS for success + * + * @note None. + * + *****************************************************************************/ +int XAxiDma_SelectKeyHole(XAxiDma *InstancePtr, int Direction, int Select) +{ + u32 Value; + + Value = XAxiDma_ReadReg(InstancePtr->RegBase + + (XAXIDMA_RX_OFFSET * Direction), + XAXIDMA_CR_OFFSET); + + if (Select) + Value |= XAXIDMA_CR_KEYHOLE_MASK; + else + Value &= ~XAXIDMA_CR_KEYHOLE_MASK; + + XAxiDma_WriteReg(InstancePtr->RegBase + + (XAXIDMA_RX_OFFSET * Direction), + XAXIDMA_CR_OFFSET, Value); + + return XST_SUCCESS; + +} + +/*****************************************************************************/ +/** + * This function Enable or Disable Cyclic Mode Feature + * + * @param InstancePtr is the driver instance we are working on + * + * @param Direction is DMA transfer direction, valid values are + * - XAXIDMA_DMA_TO_DEVICE. + * - XAXIDMA_DEVICE_TO_DMA. + * @Select Select is the option to enable (TRUE) or disable (FALSE). + * + * @return - XST_SUCCESS for success + * + * @note None. + * + *****************************************************************************/ +int XAxiDma_SelectCyclicMode(XAxiDma *InstancePtr, int Direction, int Select) +{ + u32 Value; + + Value = XAxiDma_ReadReg(InstancePtr->RegBase + + (XAXIDMA_RX_OFFSET * Direction), + XAXIDMA_CR_OFFSET); + + if (Select) + Value |= XAXIDMA_CR_CYCLIC_MASK; + else + Value &= ~XAXIDMA_CR_CYCLIC_MASK; + + XAxiDma_WriteReg(InstancePtr->RegBase + + (XAXIDMA_RX_OFFSET * Direction), + XAXIDMA_CR_OFFSET, Value); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** + * This function does one simple transfer submission + * + * It checks in the following sequence: + * - if engine is busy, cannot submit + * - if engine is in SG mode , cannot submit + * + * @param InstancePtr is the pointer to the driver instance + * @param BuffAddr is the address of the source/destination buffer + * @param Length is the length of the transfer + * @param Direction is DMA transfer direction, valid values are + * - XAXIDMA_DMA_TO_DEVICE. + * - XAXIDMA_DEVICE_TO_DMA. + + * @return + * - XST_SUCCESS for success of submission + * - XST_FAILURE for submission failure, maybe caused by: + * Another simple transfer is still going + * - XST_INVALID_PARAM if:Length out of valid range [1:8M] + * Or, address not aligned when DRE is not built in + * + * @note This function is used only when system is configured as + * Simple mode. + * + *****************************************************************************/ +int XAxiDma_SimpleTransfer(XAxiDma *InstancePtr, u32 BuffAddr, u32 Length, + int Direction) +{ + u32 WordBits; + int RingIndex = 0; + + /* If Scatter Gather is included then, cannot submit + */ + if (XAxiDma_HasSg(InstancePtr)) { + xdbg_printf(XDBG_DEBUG_ERROR, "Simple DMA mode is not" + " supported\r\n"); + + return XST_FAILURE; + } + + if(Direction == XAXIDMA_DMA_TO_DEVICE){ + if ((Length < 1) || + (Length > InstancePtr->TxBdRing.MaxTransferLen)) { + return XST_INVALID_PARAM; + } + + if (!InstancePtr->HasMm2S) { + xdbg_printf(XDBG_DEBUG_ERROR, "MM2S channel is not" + "supported\r\n"); + + return XST_FAILURE; + } + + /* If the engine is doing transfer, cannot submit + */ + + if(!(XAxiDma_ReadReg(InstancePtr->TxBdRing.ChanBase, + XAXIDMA_SR_OFFSET) & XAXIDMA_HALTED_MASK)) { + if (XAxiDma_Busy(InstancePtr,Direction)) { + xdbg_printf(XDBG_DEBUG_ERROR, + "Engine is busy\r\n"); + return XST_FAILURE; + } + } + + if (!InstancePtr->MicroDmaMode) { + WordBits = (u32)((InstancePtr->TxBdRing.DataWidth) - 1); + } + else { + WordBits = XAXIDMA_MICROMODE_MIN_BUF_ALIGN; + } + + if ((BuffAddr & WordBits)) { + + if (!InstancePtr->TxBdRing.HasDRE) { + xdbg_printf(XDBG_DEBUG_ERROR, + "Unaligned transfer without" + " DRE %x\r\n",(unsigned int)BuffAddr); + + return XST_INVALID_PARAM; + } + } + + + XAxiDma_WriteReg(InstancePtr->TxBdRing.ChanBase, + XAXIDMA_SRCADDR_OFFSET, BuffAddr); + + XAxiDma_WriteReg(InstancePtr->TxBdRing.ChanBase, + XAXIDMA_CR_OFFSET, + XAxiDma_ReadReg( + InstancePtr->TxBdRing.ChanBase, + XAXIDMA_CR_OFFSET)| XAXIDMA_CR_RUNSTOP_MASK); + + /* Writing to the BTT register starts the transfer + */ + XAxiDma_WriteReg(InstancePtr->TxBdRing.ChanBase, + XAXIDMA_BUFFLEN_OFFSET, Length); + } + else if(Direction == XAXIDMA_DEVICE_TO_DMA){ + if ((Length < 1) || + (Length > + InstancePtr->RxBdRing[RingIndex].MaxTransferLen)) { + return XST_INVALID_PARAM; + } + + + if (!InstancePtr->HasS2Mm) { + xdbg_printf(XDBG_DEBUG_ERROR, "S2MM channel is not" + " supported\r\n"); + + return XST_FAILURE; + } + + if(!(XAxiDma_ReadReg(InstancePtr->RxBdRing[RingIndex].ChanBase, + XAXIDMA_SR_OFFSET) & XAXIDMA_HALTED_MASK)) { + if (XAxiDma_Busy(InstancePtr,Direction)) { + xdbg_printf(XDBG_DEBUG_ERROR, + "Engine is busy\r\n"); + return XST_FAILURE; + } + } + + if (!InstancePtr->MicroDmaMode) { + WordBits = + (u32)((InstancePtr->RxBdRing[RingIndex].DataWidth) - 1); + } + else { + WordBits = XAXIDMA_MICROMODE_MIN_BUF_ALIGN; + } + + if ((BuffAddr & WordBits)) { + + if (!InstancePtr->RxBdRing[RingIndex].HasDRE) { + xdbg_printf(XDBG_DEBUG_ERROR, + "Unaligned transfer without" + " DRE %x\r\n", (unsigned int)BuffAddr); + + return XST_INVALID_PARAM; + } + } + + + XAxiDma_WriteReg(InstancePtr->RxBdRing[RingIndex].ChanBase, + XAXIDMA_DESTADDR_OFFSET, BuffAddr); + + XAxiDma_WriteReg(InstancePtr->RxBdRing[RingIndex].ChanBase, + XAXIDMA_CR_OFFSET, + XAxiDma_ReadReg(InstancePtr->RxBdRing[RingIndex].ChanBase, + XAXIDMA_CR_OFFSET)| XAXIDMA_CR_RUNSTOP_MASK); + /* Writing to the BTT register starts the transfer + */ + XAxiDma_WriteReg(InstancePtr->RxBdRing[RingIndex].ChanBase, + XAXIDMA_BUFFLEN_OFFSET, Length); + + } + + return XST_SUCCESS; +} diff --git a/XilinxProcessorIPLib/drivers/axidma/src/xaxidma.h b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma.h new file mode 100644 index 00000000..644220e3 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma.h @@ -0,0 +1,727 @@ +/****************************************************************************** +* +* 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 xaxidma.h +* +* This is the driver API for the AXI DMA engine. +* +* For a full description of DMA features, please see the hardware spec. This +* driver supports the following features: +* +* - Scatter-Gather DMA (SGDMA) +* - Simple DMA +* - Interrupts +* - Programmable interrupt coalescing for SGDMA +* - APIs to manage Buffer Descriptors (BD) movement to and from the SGDMA +* engine +* +* Simple DMA +* +* Simple DMA allows the application to define a single transaction between DMA +* and Device. It has two channels: one from the DMA to Device and the other +* from Device to DMA. Application has to set the buffer address and +* length fields to initiate the transfer in respective channel. +* +* Transactions +* +* The object used to describe a transaction is referred to as a Buffer +* Descriptor (BD). Buffer descriptors are allocated in the user application. +* The user application needs to set buffer address, transfer length, and +* control information for this transfer. The control information includes +* SOF and EOF. Definition of those masks are in xaxidma_hw.h +* +* Scatter-Gather DMA +* +* SGDMA allows the application to define a list of transactions in memory which +* the hardware will process without further application intervention. During +* this time, the application is free to continue adding more work to keep the +* Hardware busy. +* +* User can check for the completion of transactions through polling the +* hardware, or interrupts. +* +* SGDMA processes whole packets. A packet is defined as a series of +* data bytes that represent a message. SGDMA allows a packet of data to be +* broken up into one or more transactions. For example, take an Ethernet IP +* packet which consists of a 14 byte header followed by a 1 or more bytes of +* payload. With SGDMA, the application may point a BD to the header and another +* BD to the payload, then transfer them as a single message. This strategy can +* make a TCP/IP stack more efficient by allowing it to keep packet header and +* data in different memory regions instead of assembling packets into +* contiguous blocks of memory. +* +* BD Ring Management +* +* BD rings are shared by the software and the hardware. +* +* The hardware expects BDs to be setup as a linked list. The DMA hardware walks +* through the list by following the next pointer field of a completed BD. +* The hardware stops processing when the just completed BD is the same as the +* BD specified in the Tail Ptr register in the hardware. +* +* The last BD in the ring is linked to the first BD in the ring. +* +* All BD management are done inside the driver. The user application should not +* directly modify the BD fields. Modifications to the BD fields should always +* go through the specific API functions. +* +* Within the ring, the driver maintains four groups of BDs. Each group consists +* of 0 or more adjacent BDs: +* +* - Free: The BDs that can be allocated by the application with +* XAxiDma_BdRingAlloc(). +* +* - Pre-process: The BDs that have been allocated with +* XAxiDma_BdRingAlloc(). These BDs are under application control. The +* application modifies these BDs through driver API to prepare them +* for DMA transactions. +* +* - Hardware: The BDs that have been enqueued to hardware with +* XAxiDma_BdRingToHw(). These BDs are under hardware control and may be in a +* state of awaiting hardware processing, in process, or processed by +* hardware. It is considered an error for the application to change BDs +* while they are in this group. Doing so can cause data corruption and lead +* to system instability. +* +* - Post-process: The BDs that have been processed by hardware and have +* been extracted from the Hardware group with XAxiDma_BdRingFromHw(). +* These BDs are under application control. The application can check the +* transfer status of these BDs. The application use XAxiDma_BdRingFree() +* to put them into the Free group. +* +* BDs are expected to transition in the following way for continuous +* DMA transfers: +*
+*
+*         XAxiDma_BdRingAlloc()                   XAxiDma_BdRingToHw()
+*   Free ------------------------> Pre-process ----------------------> Hardware
+*                                                                      |
+*    /|\                                                               |
+*     |   XAxiDma_BdRingFree()                  XAxiDma_BdRingFromHw() |
+*     +--------------------------- Post-process <----------------------+
+*
+* 
+* +* When a DMA transfer is to be cancelled before enqueuing to hardware, +* application can return the requested BDs to the Free group using +* XAxiDma_BdRingUnAlloc(), as shown below: +*
+*
+*         XAxiDma_BdRingUnAlloc()
+*   Free <----------------------- Pre-process
+*
+* 
+* +* The API provides functions for BD list traversal: +* - XAxiDma_BdRingNext() +* - XAxiDma_BdRingPrev() +* +* These functions should be used with care as they do not understand where +* one group ends and another begins. +* +* SGDMA Descriptor Ring Creation +* +* BD ring is created using XAxiDma_BdRingCreate(). The memory for the BD ring +* is allocated by the application, and it has to be contiguous. Physical +* address is required to setup the BD ring. +* +* The applicaiton can use XAxiDma_BdRingMemCalc() to find out the amount of +* memory needed for a certain number of BDs. XAxiDma_BdRingCntCalc() can be +* used to find out how many BDs can be allocated for certain amount of memory. +* +* A helper function, XAxiDma_BdRingClone(), can speed up the BD ring setup if +* the BDs have same types of controls, for example, SOF and EOF. After +* using the XAxiDma_BdRingClone(), the application only needs to setup the +* buffer address and transfer length. Note that certain BDs in one packet, +* for example, the first BD and the last BD, may need to setup special +* control information. +* +* Descriptor Ring State Machine +* +* There are two states of the BD ring: +* +* - HALTED (H), where hardware is not running +* +* - NOT HALTED (NH), where hardware is running +* +* The following diagram shows the state transition for the DMA engine: +* +*
+*   _____ XAxiDma_StartBdRingHw(), or XAxiDma_BdRingStart(),   ______
+*   |   |               or XAxiDma_Resume()                    |    |
+*   | H |----------------------------------------------------->| NH |
+*   |   |<-----------------------------------------------------|    |
+*   -----   XAxiDma_Pause() or XAxiDma_Reset()                 ------
+* 
+* +* Interrupt Coalescing +* +* SGDMA provides control over the frequency of interrupts through interrupt +* coalescing. The DMA engine provides two ways to tune the interrupt +* coalescing: +* +* - The packet threshold counter. Interrupt will fire once the +* programmable number of packets have been processed by the engine. +* +* - The packet delay timer counter. Interrupt will fire once the +* programmable amount of time has passed after processing the last packet, +* and no new packets to process. Note that the interrupt will only fire if +* at least one packet has been processed. +* +* Interrupt +* +* Interrupts are handled by the user application. Each DMA channel has its own +* interrupt ID. The driver provides APIs to enable/disable interrupt, +* and tune the interrupt frequency regarding to packet processing frequency. +* +* Software Initialization +* +* +* To use the Simple mode DMA engine for transfers, the following setup is +* required: +* +* - DMA Initialization using XAxiDma_CfgInitialize() function. This step +* initializes a driver instance for the given DMA engine and resets the +* engine. +* +* - Enable interrupts if chosen to use interrupt mode. The application is +* responsible for setting up the interrupt system, which includes providing +* and connecting interrupt handlers and call back functions, before +* enabling the interrupts. +* +* - Set the buffer address and length field in respective channels to start +* the DMA transfer +* +* To use the SG mode DMA engine for transfers, the following setup are +* required: +* +* - DMA Initialization using XAxiDma_CfgInitialize() function. This step +* initializes a driver instance for the given DMA engine and resets the +* engine. +* +* - BD Ring creation. A BD ring is needed per DMA channel and can be built by +* calling XAxiDma_BdRingCreate(). +* +* - Enable interrupts if chose to use interrupt mode. The application is +* responsible for setting up the interrupt system, which includes providing +* and connecting interrupt handlers and call back functions, before +* enabling the interrupts. +* +* - Start a DMA transfer: Call XAxiDma_BdRingStart() to start a transfer for +* the first time or after a reset, and XAxiDma_BdRingToHw() if the channel +* is already started. Calling XAxiDma_BdRingToHw() when a DMA channel is not +* running will not put the BDs to the hardware, and the BDs will be processed +* later when the DMA channel is started through XAxiDma_BdRingStart(). +* +* How to start DMA transactions +* +* The user application uses XAxiDma_BdRingToHw() to submit BDs to the hardware +* to start DMA transfers. +* +* For both channels, if the DMA engine is currently stopped (using +* XAxiDma_Pause()), the newly added BDs will be accepted but not processed +* until the DMA engine is started, using XAxiDma_BdRingStart(), or resumed, +* using XAxiDma_Resume(). +* +* Software Post-Processing on completed DMA transactions +* +* If the interrupt system has been set up and the interrupts are enabled, +* a DMA channels notifies the software about the completion of a transfer +* through interrupts. Otherwise, the user application can poll for +* completions of the BDs, using XAxiDma_BdRingFromHw() or +* XAxiDma_BdHwCompleted(). +* +* - Once BDs are finished by a channel, the application first needs to fetch +* them from the channel using XAxiDma_BdRingFromHw(). +* +* - On the TX side, the application now could free the data buffers attached to +* those BDs as the data in the buffers has been transmitted. +* +* - On the RX side, the application now could use the received data in the +* buffers attached to those BDs. +* +* - For both channels, completed BDs need to be put back to the Free group +* using XAxiDma_BdRingFree(), so they can be used for future transactions. +* +* - On the RX side, it is the application's responsibility to have BDs ready +* to receive data at any time. Otherwise, the RX channel refuses to +* accept any data if it has no RX BDs. +* +* Examples +* +* We provide five examples to show how to use the driver API: +* - One for SG interrupt mode (xaxidma_example_sg_intr.c), multiple BD/packets transfer +* - One for SG polling mode (xaxidma_example_sg_poll.c), single BD transfer. +* - One for SG polling mode (xaxidma_poll_multi_pkts.c), multiple BD/packets transfer +* - One for simple polling mode (xaxidma_example_simple_poll.c) +* - One for simple Interrupt mode (xaxidma_example_simple_intr.c) +* +* Address Translation +* +* All buffer addresses and BD addresses for the hardware are physical +* addresses. The user application is responsible to provide physical buffer +* address for the BD upon BD ring creation. The user application accesses BD +* through its virtual addess. The driver maintains the address translation +* between the physical and virtual address for BDs. +* +* Cache Coherency +* +* This driver expects all application buffers attached to BDs to be in cache +* coherent memory. If cache is used in the system, buffers for transmit MUST +* be flushed from the cache before passing the associated BD to this driver. +* Buffers for receive MUST be invalidated before accessing the data. +* +* Alignment +* +* For BDs: +* +* Minimum alignment is defined by the constant XAXIDMA_BD_MINIMUM_ALIGNMENT. +* This is the smallest alignment allowed by both hardware and software for them +* to properly work. +* +* If the descriptor ring is to be placed in cached memory, alignment also MUST +* be at least the processor's cache-line size. Otherwise, system instability +* occurs. For alignment larger than the cache line size, multiple cache line +* size alignment is required. +* +* Aside from the initial creation of the descriptor ring (see +* XAxiDma_BdRingCreate()), there are no other run-time checks for proper +* alignment of BDs. +* +* For application data buffers: +* +* Application data buffers may reside on any alignment if DRE is built into the +* hardware. Otherwise, application data buffer must be word-aligned. The word +* is defined by XPAR_AXIDMA_0_M_AXIS_MM2S_TDATA_WIDTH for transmit and +* XPAR_AXIDMA_0_S_AXIS_S2MM_TDATA_WIDTH for receive. +* +* For scatter gather transfers that have more than one BDs in the chain of BDs, +* Each BD transfer length must be multiple of word too. Otherwise, internal +* error happens in the hardware. +* +* Error Handling +* +* The DMA engine will halt on all error conditions. It requires the software +* to do a reset before it can start process new transfer requests. +* +* Restart After Stopping +* +* After the DMA engine has been stopped (through reset or reset after an error) +* the software keeps track of the current BD pointer when reset happens, and +* processing of BDs can be resumed through XAxiDma_BdRingStart(). +* +* Limitations +* +* This driver does not have any mechanisms for mutual exclusion. It is up to +* the application to provide this protection. +* +* Hardware Defaults & Exclusive Use +* +* After the initialization or reset, the DMA engine is in the following +* default mode: +* - All interrupts are disabled. +* +* - Interrupt coalescing counter is 1. +* +* - The DMA engine is not running (halted). Each DMA channel is started +* separately, using XAxiDma_StartBdRingHw() if no BDs are setup for transfer +* yet, or XAxiDma_BdRingStart() otherwise. +* +* The driver has exclusive use of the registers and BDs. All accesses to the +* registers and BDs should go through the driver interface. +* +* Debug Print +* +* To see the debug print for the driver, please put "-DDEBUG" as the extra +* compiler flags in software platform settings. Also comment out the line in +* xdebug.h: "#undef DEBUG". +* +* Changes From v1.00a +* +* . We have changes return type for XAxiDma_BdSetBufAddr() from void to int +* . We added XAxiDma_LookupConfig() so that user does not need to look for the +* hardware settings anymore. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a jz   05/18/10 First release
+* 2.00a jz   08/10/10 Second release, added in xaxidma_g.c, xaxidma_sinit.c,
+*                     updated tcl file, added xaxidma_porting_guide.h
+* 3.00a jz   11/22/10 Support IP core parameters change
+* 4.00a rkv  02/22/11 Added support for simple DMA mode
+*		      New API added for simple DMA mode are
+*			- XAxiDma_Busy
+*			- XAxiDma_SimpleTransfer
+*		      New Macros added for simple DMA mode are
+* 			- XAxiDma_HasSg
+* 			- XAxiDma_IntrEnable
+* 			- XAxiDma_IntrGetEnabled
+* 			- XAxiDma_IntrDisable
+* 			- XAxiDma_IntrGetIrq
+* 			- XAxiDma_IntrAckIrq
+* 5.00a srt  08/25/11  Added support for memory barrier and modified
+*			Cache Macros to have a common API for Microblaze
+*			and Zynq.
+* 6.00a srt  01/24/12 Added support for Multi-Channel DMA mode.
+*		      - Changed APIs:
+*			* XAxiDma_GetRxRing(InstancePtr, RingIndex)
+*			* XAxiDma_Start(XAxiDma * InstancePtr, int RingIndex)
+*			* XAxiDma_Started(XAxiDma * InstancePtr, int RingIndex)
+*			* XAxiDma_Pause(XAxiDma * InstancePtr, int RingIndex)
+*			* XAxiDma_Resume(XAxiDma * InstancePtr, int RingIndex)
+*			* XAxiDma_SimpleTransfer(XAxiDma *InstancePtr,
+*        					u32 BuffAddr, u32 Length,
+*						int Direction, int RingIndex)
+*			* XAxiDma_StartBdRingHw(XAxiDma_BdRing * RingPtr,
+*					int RingIndex)
+*			* XAxiDma_BdRingStart(XAxiDma_BdRing * RingPtr,
+*						 int RingIndex)
+*			* XAxiDma_BdRingToHw(XAxiDma_BdRing * RingPtr,
+*        			int NumBd, XAxiDma_Bd * BdSetPtr, int RingIndex)
+*			* XAxiDma_BdRingDumpRegs(XAxiDma_BdRing * RingPtr,
+*						 int RingIndex)
+*			* XAxiDma_BdRingSnapShotCurrBd(XAxiDma_BdRing * RingPtr,
+*						 int RingIndex)
+*			* XAxiDma_BdSetLength(XAxiDma_Bd *BdPtr,
+*					u32 LenBytes, u32 LengthMask)
+*       		* XAxiDma_BdGetActualLength(BdPtr, LengthMask)
+*			* XAxiDma_BdGetLength(BdPtr, LengthMask)
+*		       - New APIs
+*			* XAxiDma_SelectKeyHole(XAxiDma *InstancePtr,
+*						int Direction, int Select)
+*			* XAxiDma_UpdateBdRingCDesc(XAxiDma_BdRing * RingPtr,
+*						int RingIndex)
+* 7.00a srt  06/18/12  All the APIs changed in v6_00_a are reverted back for
+*		       backward compatibility.
+*			- New API:
+*			  XAxiDma_GetRxIndexRing(InstancePtr, RingIndex)
+* 7.01a srt  10/26/12  - Fixed issue with driver as it fails with IP version
+*		         < 6.00a as the parameter C_NUM_*_CHANNELS is not
+*			 applicable.
+*		       - Changed the logic of MCDMA BD fields Set APIs, to
+*			 clear the field first and then set it.
+* 7.02a srt  01/23/13  Replaced *_TDATA_WIDTH parameters to *_DATA_WIDTH
+*		       (CR 691867)
+*		       Updated DDR base address for IPI designs (CR 703656).
+* 8.0   adk  19/12/13  Updated as per the New Tcl API's
+*	srt  01/29/14  Added support for Micro DMA Mode and cyclic mode of
+*		       operations.
+*		      - New APIs:
+*			* XAxiDma_SelectCyclicMode(XAxiDma *InstancePtr,
+*						int Direction, int Select)
+ *			* XAxiDma_BdSetBufAddrMicroMode(XAxiDma_Bd*, u32)
+*
+* 
+* +******************************************************************************/ + +#ifndef XAXIDMA_H_ /* prevent circular inclusions */ +#define XAXIDMA_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ +#include "xaxidma_bdring.h" +#ifdef __MICROBLAZE__ +#include "xenv.h" +#else +#include +#include "xil_cache.h" +#endif + +/************************** Constant Definitions *****************************/ + + +/**************************** Type Definitions *******************************/ + +/** + * The XAxiDma driver instance data. An instance must be allocated for each DMA + * engine in use. + */ +typedef struct XAxiDma { + u32 RegBase; /* Virtual base address of DMA engine */ + + int HasMm2S; /* Has transmit channel */ + int HasS2Mm; /* Has receive channel */ + int Initialized; /* Driver has been initialized */ + int HasSg; + + XAxiDma_BdRing TxBdRing; /* BD container management for TX channel */ + XAxiDma_BdRing RxBdRing[16]; /* BD container management for RX channel */ + int TxNumChannels; + int RxNumChannels; + int MicroDmaMode; +} XAxiDma; + +/** + * The configuration structure for AXI DMA engine + * + * This structure passes the hardware building information to the driver + */ +typedef struct { + u32 DeviceId; + u32 BaseAddr; + + int HasStsCntrlStrm; + int HasMm2S; + int HasMm2SDRE; + int Mm2SDataWidth; + int HasS2Mm; + int HasS2MmDRE; + int S2MmDataWidth; + int HasSg; + int Mm2sNumChannels; + int S2MmNumChannels; + int Mm2SBurstSize; + int S2MmBurstSize; + int MicroDmaMode; +} XAxiDma_Config; + + +/***************** Macros (Inline Functions) Definitions *********************/ +/*****************************************************************************/ +/** +* Get Transmit (Tx) Ring ptr +* +* Warning: This has a different API than the LLDMA driver. It now returns +* the pointer to the BD ring. +* +* @param InstancePtr is a pointer to the DMA engine instance to be +* worked on. +* +* @return Pointer to the Tx Ring +* +* @note C-style signature: +* XAxiDma_BdRing * XAxiDma_GetTxRing(XAxiDma * InstancePtr) +* This function is used only when system is configured as SG mode +* +*****************************************************************************/ +#define XAxiDma_GetTxRing(InstancePtr) \ + (&((InstancePtr)->TxBdRing)) + +/*****************************************************************************/ +/** +* Get Receive (Rx) Ring ptr +* +* Warning: This has a different API than the LLDMA driver. It now returns +* the pointer to the BD ring. +* +* @param InstancePtr is a pointer to the DMA engine instance to be +* worked on. +* +* @return Pointer to the Rx Ring +* +* @note +* C-style signature: +* XAxiDma_BdRing * XAxiDma_GetRxRing(XAxiDma * InstancePtr) +* This function is used only when system is configured as SG mode +* +*****************************************************************************/ +#define XAxiDma_GetRxRing(InstancePtr) \ + (&((InstancePtr)->RxBdRing[0])) + +/*****************************************************************************/ +/** +* Get Receive (Rx) Ring ptr of a Index +* +* Warning: This has a different API than the LLDMA driver. It now returns +* the pointer to the BD ring. +* +* @param InstancePtr is a pointer to the DMA engine instance to be +* worked on. +* @param RingIndex is the channel Index. +* +* @return Pointer to the Rx Ring +* +* @note +* C-style signature: +* XAxiDma_BdRing * XAxiDma_GetRxIndexRing(XAxiDma * InstancePtr, + int RingIndex) +* This function is used only when system is configured as SG mode +* +*****************************************************************************/ +#define XAxiDma_GetRxIndexRing(InstancePtr, RingIndex) \ + (&((InstancePtr)->RxBdRing[RingIndex])) + +/*****************************************************************************/ +/** +* This function checks whether system is configured as Simple or +* Scatter Gather mode +* +* @param InstancePtr is a pointer to the DMA engine instance to be +* worked on. +* +* @return +* - TRUE if configured as SG mode +* - FALSE if configured as simple mode +* +* @note None +* +*****************************************************************************/ +#define XAxiDma_HasSg(InstancePtr) ((InstancePtr)->HasSg) ? TRUE : FALSE + +/*****************************************************************************/ +/** + * This function enables interrupts specified by the Mask in specified + * direction, Interrupts that are not in the mask are not affected. + * + * @param InstancePtr is the driver instance we are working on + * @param Mask is the mask for the interrupts to be enabled + * @param Direction is DMA transfer direction, valid values are + * - XAXIDMA_DMA_TO_DEVICE. + * - XAXIDMA_DEVICE_TO_DMA. + * @return None + * + * @note None + * + *****************************************************************************/ +#define XAxiDma_IntrEnable(InstancePtr, Mask, Direction) \ + XAxiDma_WriteReg((InstancePtr)->RegBase + \ + (XAXIDMA_RX_OFFSET * Direction), XAXIDMA_CR_OFFSET, \ + (XAxiDma_ReadReg((InstancePtr)->RegBase + \ + (XAXIDMA_RX_OFFSET * Direction), XAXIDMA_CR_OFFSET)) \ + | (Mask & XAXIDMA_IRQ_ALL_MASK)) + + +/*****************************************************************************/ +/** + * This function gets the mask for the interrupts that are currently enabled + * + * @param InstancePtr is the driver instance we are working on + * @param Direction is DMA transfer direction, valid values are + * - XAXIDMA_DMA_TO_DEVICE. + * - XAXIDMA_DEVICE_TO_DMA. + * + * @return The bit mask for the interrupts that are currently enabled + * + * @note None + * + *****************************************************************************/ +#define XAxiDma_IntrGetEnabled(InstancePtr, Direction) \ + XAxiDma_ReadReg((InstancePtr)->RegBase + \ + (XAXIDMA_RX_OFFSET * Direction), XAXIDMA_CR_OFFSET) &\ + XAXIDMA_IRQ_ALL_MASK) + + + +/*****************************************************************************/ +/** + * This function disables interrupts specified by the Mask. Interrupts that + * are not in the mask are not affected. + * + * @param InstancePtr is the driver instance we are working on + * @param Mask is the mask for the interrupts to be disabled + * @param Direction is DMA transfer direction, valid values are + * - XAXIDMA_DMA_TO_DEVICE. + * - XAXIDMA_DEVICE_TO_DMA. + * @return None + * + * @note None + * + *****************************************************************************/ + #define XAxiDma_IntrDisable(InstancePtr, Mask, Direction) \ + XAxiDma_WriteReg((InstancePtr)->RegBase + \ + (XAXIDMA_RX_OFFSET * Direction), XAXIDMA_CR_OFFSET, \ + (XAxiDma_ReadReg((InstancePtr)->RegBase + \ + (XAXIDMA_RX_OFFSET * Direction), XAXIDMA_CR_OFFSET)) \ + & ~(Mask & XAXIDMA_IRQ_ALL_MASK)) + + +/*****************************************************************************/ +/** + * This function gets the interrupts that are asserted. + * + * @param InstancePtr is the driver instance we are working on + * @param Direction is DMA transfer direction, valid values are + * - XAXIDMA_DMA_TO_DEVICE. + * - XAXIDMA_DEVICE_TO_DMA. + * + * @return The bit mask for the interrupts asserted. + * + * @note None + * + *****************************************************************************/ +#define XAxiDma_IntrGetIrq(InstancePtr, Direction) \ + (XAxiDma_ReadReg((InstancePtr)->RegBase + \ + (XAXIDMA_RX_OFFSET * Direction), XAXIDMA_SR_OFFSET) &\ + XAXIDMA_IRQ_ALL_MASK) + +/*****************************************************************************/ +/** + * This function acknowledges the interrupts that are specified in Mask + * + * @param InstancePtr is the driver instance we are working on + * @param Mask is the mask for the interrupts to be acknowledge + * @param Direction is DMA transfer direction, valid values are + * - XAXIDMA_DMA_TO_DEVICE. + * - XAXIDMA_DEVICE_TO_DMA. + * + * @return None + * + * @note None. + * + *****************************************************************************/ +#define XAxiDma_IntrAckIrq(InstancePtr, Mask, Direction) \ + XAxiDma_WriteReg((InstancePtr)->RegBase + \ + (XAXIDMA_RX_OFFSET * Direction), XAXIDMA_SR_OFFSET, \ + (Mask) & XAXIDMA_IRQ_ALL_MASK) + + + +/************************** Function Prototypes ******************************/ + +/* + * Initialization and control functions in xaxidma.c + */ +XAxiDma_Config *XAxiDma_LookupConfig(u32 DeviceId); +int XAxiDma_CfgInitialize(XAxiDma * InstancePtr, XAxiDma_Config *Config); +void XAxiDma_Reset(XAxiDma * InstancePtr); +int XAxiDma_ResetIsDone(XAxiDma * InstancePtr); +int XAxiDma_Pause(XAxiDma * InstancePtr); +int XAxiDma_Resume(XAxiDma * InstancePtr); +u32 XAxiDma_Busy(XAxiDma *InstancePtr,int Direction); +int XAxiDma_SimpleTransfer(XAxiDma *InstancePtr, u32 BuffAddr, u32 Length, + int Direction); +int XAxiDma_SelectKeyHole(XAxiDma *InstancePtr, int Direction, int Select); +int XAxiDma_SelectCyclicMode(XAxiDma *InstancePtr, int Direction, int Select); +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_bd.c b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_bd.c new file mode 100644 index 00000000..a3d725f1 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_bd.c @@ -0,0 +1,339 @@ +/****************************************************************************** +* +* 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 xaxidma_bd.c + * + * Buffer descriptor (BD) management API implementation. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -------------------------------------------------------
+ * 1.00a jz   05/18/10 First release
+ * 2.00a jz   08/10/10 Second release, added in xaxidma_g.c, xaxidma_sinit.c,
+ *                     updated tcl file, added xaxidma_porting_guide.h
+ * 3.00a jz   11/22/10 Support IP core parameters change
+ * 6.00a srt  01/24/12 Added support for Multi-Channel DMA.
+ *		       - Changed APIs
+ *			* XAxiDma_BdSetLength(XAxiDma_Bd *BdPtr,
+ *					u32 LenBytes, u32 LengthMask)
+ *       		* XAxiDma_BdGetActualLength(BdPtr, LengthMask)
+ *			* XAxiDma_BdGetLength(BdPtr, LengthMask)
+ * 8.0   srt  01/29/14 Added support for Micro DMA Mode:
+ *		       - New API
+ *			 XAxiDma_BdSetBufAddrMicroMode(XAxiDma_Bd*, u32)
+ *
+ * 
+ * + *****************************************************************************/ + +#include "xaxidma_bd.h" + +/************************** Function Prototypes ******************************/ + +/*****************************************************************************/ +/** + * Set the length field for the given BD. + * + * Length has to be non-zero and less than LengthMask. + * + * For TX channels, the value passed in should be the number of bytes to + * transmit from the TX buffer associated with the given BD. + * + * For RX channels, the value passed in should be the size of the RX buffer + * associated with the given BD in bytes. This is to notify the RX channel + * the capability of the RX buffer to avoid buffer overflow. + * + * The actual receive length can be equal or smaller than the specified length. + * The actual transfer length will be updated by the hardware in the + * XAXIDMA_BD_STS_OFFSET word in the BD. + * + * @param BdPtr is the BD to operate on. + * @param LenBytes is the requested transfer length + * @param LengthMask is the maximum transfer length + * + * @returns + * - XST_SUCCESS for success + * - XST_INVALID_PARAM for invalid BD length + * + * @note This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +int XAxiDma_BdSetLength(XAxiDma_Bd *BdPtr, u32 LenBytes, u32 LengthMask) +{ + if (LenBytes <= 0 || (LenBytes > LengthMask)) { + + xdbg_printf(XDBG_DEBUG_ERROR, "invalid length %d\n", + (int)LenBytes); + + return XST_INVALID_PARAM; + } + + XAxiDma_BdWrite((BdPtr), XAXIDMA_BD_CTRL_LEN_OFFSET, + ((XAxiDma_BdRead((BdPtr), XAXIDMA_BD_CTRL_LEN_OFFSET) & \ + ~LengthMask)) | LenBytes); + + return XST_SUCCESS; +} +/*****************************************************************************/ +/** + * Set the BD's buffer address. + * + * @param BdPtr is the BD to operate on + * @param Addr is the address to set + * + * @return + * - XST_SUCCESS if buffer address set successfully + * - XST_INVALID_PARAM if hardware has no DRE and address is not + * aligned + * + * @note This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +int XAxiDma_BdSetBufAddr(XAxiDma_Bd* BdPtr, u32 Addr) +{ + u32 HasDRE; + u8 WordLen; + + HasDRE = XAxiDma_BdRead(BdPtr, XAXIDMA_BD_HAS_DRE_OFFSET); + WordLen = HasDRE & XAXIDMA_BD_WORDLEN_MASK; + + if (Addr & (WordLen - 1)) { + if ((HasDRE & XAXIDMA_BD_HAS_DRE_MASK) == 0) { + xil_printf("Error set buf addr %x with %x and %x," + " %x\r\n",Addr, HasDRE, (WordLen - 1), + Addr & (WordLen - 1)); + + return XST_INVALID_PARAM; + } + } + + XAxiDma_BdWrite(BdPtr, XAXIDMA_BD_BUFA_OFFSET, Addr); + + return XST_SUCCESS; + +} + +/*****************************************************************************/ +/** + * Set the BD's buffer address when configured for Micro Mode. The buffer + * address should be 4K aligned. + * + * @param BdPtr is the BD to operate on + * @param Addr is the address to set + * + * @return + * - XST_SUCCESS if buffer address set successfully + * - XST_INVALID_PARAM if hardware has no DRE and address is not + * aligned + * + * @note This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +int XAxiDma_BdSetBufAddrMicroMode(XAxiDma_Bd* BdPtr, u32 Addr) +{ + if (Addr & XAXIDMA_MICROMODE_MIN_BUF_ALIGN) { + xil_printf("Error set buf addr %x and %x," + " %x\r\n", Addr, XAXIDMA_MICROMODE_MIN_BUF_ALIGN, + Addr & XAXIDMA_MICROMODE_MIN_BUF_ALIGN); + + return XST_INVALID_PARAM; + } + + XAxiDma_BdWrite(BdPtr, XAXIDMA_BD_BUFA_OFFSET, Addr); + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** + * Set the APP word at the specified APP word offset for a BD. + * + * @param BdPtr is the BD to operate on. + * @param Offset is the offset inside the APP word, it is valid from + * 0 to 4 + * @param Word is the value to set + * + * @returns + * - XST_SUCCESS for success + * - XST_INVALID_PARAM under following error conditions: + * 1) StsCntrlStrm is not built in hardware + * 2) Offset is not in valid range + * + * @note + * If the hardware build has C_SG_USE_STSAPP_LENGTH set to 1, + * then the last APP word, XAXIDMA_LAST_APPWORD, must have + * non-zero value when AND with 0x7FFFFF. Not doing so will cause + * the hardware to stall. + * This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +int XAxiDma_BdSetAppWord(XAxiDma_Bd* BdPtr, int Offset, u32 Word) +{ + if (XAxiDma_BdRead(BdPtr, XAXIDMA_BD_HAS_STSCNTRL_OFFSET) == 0) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingSetAppWord: no sts cntrl" + "stream in hardware build, cannot set app word\r\n"); + + return XST_INVALID_PARAM; + } + + if ((Offset < 0) || (Offset > XAXIDMA_LAST_APPWORD)) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingSetAppWord: invalid" + "offset %d",Offset); + + return XST_INVALID_PARAM; + } + + XAxiDma_BdWrite(BdPtr, XAXIDMA_BD_USR0_OFFSET + Offset * 4, Word); + + return XST_SUCCESS; +} +/*****************************************************************************/ +/** + * Get the APP word at the specified APP word offset for a BD. + * + * @param BdPtr is the BD to operate on. + * @param Offset is the offset inside the APP word, it is valid from + * 0 to 4 + * @param Valid is to tell the caller whether parameters are valid + * + * @returns + * The APP word. Passed in parameter Valid holds 0 for failure, + * and 1 for success. + * + * @note This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +u32 XAxiDma_BdGetAppWord(XAxiDma_Bd* BdPtr, int Offset, int *Valid) +{ + *Valid = 0; + + if (XAxiDma_BdRead(BdPtr, XAXIDMA_BD_HAS_STSCNTRL_OFFSET) == 0) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingGetAppWord: no sts cntrl " + "stream in hardware build, no app word available\r\n"); + + return (u32)0; + } + + if((Offset < 0) || (Offset > XAXIDMA_LAST_APPWORD)) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingGetAppWord: invalid" + " offset %d", Offset); + + return (u32)0; + } + + *Valid = 1; + + return XAxiDma_BdRead(BdPtr, XAXIDMA_BD_USR0_OFFSET + Offset * 4); +} + +/*****************************************************************************/ +/** + * Set the control bits for a BD. + * + * @param BdPtr is the BD to operate on. + * @param Data is the bit value to set + * + * @return None + * + * @note This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +void XAxiDma_BdSetCtrl(XAxiDma_Bd* BdPtr, u32 Data) +{ + u32 RegValue = XAxiDma_BdRead(BdPtr, XAXIDMA_BD_CTRL_LEN_OFFSET); + + RegValue &= ~XAXIDMA_BD_CTRL_ALL_MASK; + + RegValue |= (Data & XAXIDMA_BD_CTRL_ALL_MASK); + + XAxiDma_BdWrite((BdPtr), XAXIDMA_BD_CTRL_LEN_OFFSET, RegValue); + + return; +} +/*****************************************************************************/ +/** + * Dump the fields of a BD. + * + * @param BdPtr is the BD to operate on. + * + * @return None + * + * @note This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +void XAxiDma_DumpBd(XAxiDma_Bd* BdPtr) +{ + + xil_printf("Dump BD %x:\r\n", (unsigned int)BdPtr); + xil_printf("\tNext Bd Ptr: %x\r\n", + (unsigned int)XAxiDma_BdRead(BdPtr, XAXIDMA_BD_NDESC_OFFSET)); + xil_printf("\tBuff addr: %x\r\n", + (unsigned int)XAxiDma_BdRead(BdPtr, XAXIDMA_BD_BUFA_OFFSET)); + xil_printf("\tMCDMA Fields: %x\r\n", + (unsigned int)XAxiDma_BdRead(BdPtr, XAXIDMA_BD_MCCTL_OFFSET)); + xil_printf("\tVSIZE_STRIDE: %x\r\n", + (unsigned int)XAxiDma_BdRead(BdPtr, + XAXIDMA_BD_STRIDE_VSIZE_OFFSET)); + xil_printf("\tContrl len: %x\r\n", + (unsigned int)XAxiDma_BdRead(BdPtr, XAXIDMA_BD_CTRL_LEN_OFFSET)); + xil_printf("\tStatus: %x\r\n", + (unsigned int)XAxiDma_BdRead(BdPtr, XAXIDMA_BD_STS_OFFSET)); + + xil_printf("\tAPP 0: %x\r\n", + (unsigned int)XAxiDma_BdRead(BdPtr, XAXIDMA_BD_USR0_OFFSET)); + xil_printf("\tAPP 1: %x\r\n", + (unsigned int)XAxiDma_BdRead(BdPtr, XAXIDMA_BD_USR1_OFFSET)); + xil_printf("\tAPP 2: %x\r\n", + (unsigned int)XAxiDma_BdRead(BdPtr, XAXIDMA_BD_USR2_OFFSET)); + xil_printf("\tAPP 3: %x\r\n", + (unsigned int)XAxiDma_BdRead(BdPtr, XAXIDMA_BD_USR3_OFFSET)); + xil_printf("\tAPP 4: %x\r\n", + (unsigned int)XAxiDma_BdRead(BdPtr, XAXIDMA_BD_USR4_OFFSET)); + + xil_printf("\tSW ID: %x\r\n", + (unsigned int)XAxiDma_BdRead(BdPtr, XAXIDMA_BD_ID_OFFSET)); + xil_printf("\tStsCtrl: %x\r\n", + (unsigned int)XAxiDma_BdRead(BdPtr, + XAXIDMA_BD_HAS_STSCNTRL_OFFSET)); + xil_printf("\tDRE: %x\r\n", + (unsigned int)XAxiDma_BdRead(BdPtr, XAXIDMA_BD_HAS_DRE_OFFSET)); + + xil_printf("\r\n"); +} diff --git a/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_bd.h b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_bd.h new file mode 100644 index 00000000..264c2aa5 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_bd.h @@ -0,0 +1,671 @@ +/****************************************************************************** +* +* 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 xaxidma_bd.h + * + * Buffer descriptor (BD) management API. + * + * Buffer Descriptors + * + * A BD defines a DMA transaction (see "Transaction" section in xaxidma.h). + * All accesses to a BD go through this set of API. + * + * The XAxiDma_Bd structure defines a BD. The first XAXIDMA_BD_HW_NUM_BYTES + * are shared between hardware and software. + * + * Actual Transfer Length + * + * The actual transfer length for receive could be smaller than the requested + * transfer length. The hardware sets the actual transfer length in the + * completed BD. The API to retrieve the actual transfer length is + * XAxiDma_GetActualLength(). + * + * User IP words + * + * There are 5 user IP words in each BD. + * + * If hardware does not have the StsCntrl stream built in, then these words + * are not usable. Retrieving these words get a NULL pointer and setting + * these words results an error. + * + * Performance + * + * BDs are typically in a non-cached memory space. Reducing the number of + * I/O operations to BDs can improve overall performance of the DMA channel. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- ------------------------------------------------------
+ * 1.00a jz   05/18/10 First release
+ * 2.00a jz   08/10/10 Second release, added in xaxidma_g.c, xaxidma_sinit.c,
+ *                     updated tcl file, added xaxidma_porting_guide.h
+ * 3.00a jz   11/22/10 Support IP core parameters change
+ * 5.00a srt  08/25/11 Changed Cache Macros to have a common API for Zynq
+ *		           and Microblaze.
+ * 6.00a srt  01/24/12 Added APIs to support Multi-Channel DMA:
+ *			XAxiDma_BdSetTId()
+ *			XAxiDma_BdGetTId()
+ *			XAxiDma_BdSetTDest()
+ *			XAxiDma_BdGetTDest()
+ *			XAxiDma_BdSetTUser()
+ *			XAxiDma_BdGetTUser()
+ *			XAxiDma_BdSetARCache()
+ *			XAxiDma_BdGetARCache()
+ *			XAxiDma_BdSetARUser()
+ *			XAxiDma_BdGetARUser()
+ *			XAxiDma_BdSetStride()
+ *			XAxiDma_BdGetStride()
+ *			XAxiDma_BdSetVSize()
+ *			XAxiDma_BdGetVSize()
+ *			- Changed APIs
+ *			XAxiDma_BdGetActualLength(BdPtr, LengthMask)
+ *			XAxiDma_BdGetLength(BdPtr, LengthMask)
+ *			XAxiDma_BdSetLength(XAxiDma_Bd* BdPtr,
+ *					u32 LenBytes, u32 LengthMask)
+ * 7.01a srt  10/26/12  Changed the logic of MCDMA BD fields Set APIs, to
+ *			clear the field first and set it.
+ * 8.0   srt  01/29/14 Added support for Micro DMA Mode.
+ *
+ * 
+ *****************************************************************************/ + +#ifndef XAXIDMA_BD_H_ /* To prevent circular inclusions */ +#define XAXIDMA_BD_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xaxidma_hw.h" +#include "xstatus.h" +#include "xdebug.h" +#include "xil_cache.h" + +#ifdef __MICROBLAZE__ +#include "xenv.h" +#else +#include +#endif + +/************************** Constant Definitions *****************************/ + +/**************************** Type Definitions *******************************/ + +/** + * The XAxiDma_Bd is the type for a buffer descriptor (BD). + */ + +typedef u32 XAxiDma_Bd[XAXIDMA_BD_NUM_WORDS]; + + +/***************** Macros (Inline Functions) Definitions *********************/ + +/****************************************************************************** + * Define methods to flush and invalidate cache for BDs should they be + * located in cached memory. + *****************************************************************************/ +#define XAXIDMA_CACHE_FLUSH(BdPtr) \ + Xil_DCacheFlushRange((unsigned int)(BdPtr), XAXIDMA_BD_HW_NUM_BYTES) + +#define XAXIDMA_CACHE_INVALIDATE(BdPtr) \ + Xil_DCacheInvalidateRange((unsigned int)(BdPtr), XAXIDMA_BD_HW_NUM_BYTES) + +/*****************************************************************************/ +/** +* +* 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 XAxiDma_BdRead(u32 BaseAddress, u32 Offset) +* +******************************************************************************/ +#define XAxiDma_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 XAxiDma_BdWrite(u32 BaseAddress, u32 RegOffset, u32 Data) +* +******************************************************************************/ +#define XAxiDma_BdWrite(BaseAddress, Offset, Data) \ + (*(u32*)((u32)(BaseAddress) + (u32)(Offset)) = (Data)) + +/*****************************************************************************/ +/** + * Zero out BD specific fields. BD fields that are for the BD ring or for the + * system hardware build information are not touched. + * + * @param BdPtr is the BD to operate on + * + * @return None + * + * @note + * C-style signature: + * void XAxiDma_BdClear(XAxiDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XAxiDma_BdClear(BdPtr) \ + memset((void *)(((u32)(BdPtr)) + XAXIDMA_BD_START_CLEAR), 0, \ + XAXIDMA_BD_BYTES_TO_CLEAR) + +/*****************************************************************************/ +/** + * Get the control bits for the BD + * + * @param BdPtr is the BD to operate on + * + * @return The bit mask for the control of the BD + * + * @note + * C-style signature: + * u32 XAxiDma_BdGetCtrl(XAxiDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XAxiDma_BdGetCtrl(BdPtr) \ + (XAxiDma_BdRead((BdPtr), XAXIDMA_BD_CTRL_LEN_OFFSET) \ + & XAXIDMA_BD_CTRL_ALL_MASK) +/*****************************************************************************/ +/** + * Retrieve the status of a BD + * + * @param BdPtr is the BD to operate on + * + * @return Word at offset XAXIDMA_BD_DMASR_OFFSET. Use XAXIDMA_BD_STS_*** + * values defined in xaxidma_hw.h to interpret the returned value + * + * @note + * C-style signature: + * u32 XAxiDma_BdGetSts(XAxiDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XAxiDma_BdGetSts(BdPtr) \ + (XAxiDma_BdRead((BdPtr), XAXIDMA_BD_STS_OFFSET) & \ + XAXIDMA_BD_STS_ALL_MASK) +/*****************************************************************************/ +/** + * Retrieve the length field value from the given BD. The returned value is + * the same as what was written with XAxiDma_BdSetLength(). Note that in the + * this value does not reflect the real length of received data. + * See the comments of XAxiDma_BdSetLength() for more details. To obtain the + * actual transfer length, use XAxiDma_BdGetActualLength(). + * + * @param BdPtr is the BD to operate on. + * @param LengthMask is the Maximum Transfer Length. + * + * @return The length value set in the BD. + * + * @note + * C-style signature: + * u32 XAxiDma_BdGetLength(XAxiDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XAxiDma_BdGetLength(BdPtr, LengthMask) \ + (XAxiDma_BdRead((BdPtr), XAXIDMA_BD_CTRL_LEN_OFFSET) & \ + LengthMask) + + +/*****************************************************************************/ +/** + * Set the ID field of the given BD. The ID is an arbitrary piece of data the + * application can associate with a specific BD. + * + * @param BdPtr is the BD to operate on + * @param Id is a 32 bit quantity to set in the BD + * + * @return None + * + * @note + * C-style signature: + * void XAxiDma_BdSetId(XAxiDma_Bd* BdPtr, void Id) + * + *****************************************************************************/ +#define XAxiDma_BdSetId(BdPtr, Id) \ + (XAxiDma_BdWrite((BdPtr), XAXIDMA_BD_ID_OFFSET, (u32)(Id))) + + +/*****************************************************************************/ +/** + * Retrieve the ID field of the given BD previously set with XAxiDma_BdSetId. + * + * @param BdPtr is the BD to operate on + * + * @return None + * + * @note + * C-style signature: + * u32 XAxiDma_BdGetId(XAxiDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XAxiDma_BdGetId(BdPtr) (XAxiDma_BdRead((BdPtr), XAXIDMA_BD_ID_OFFSET)) + +/*****************************************************************************/ +/** + * Get the BD's buffer address + * + * @param BdPtr is the BD to operate on + * + * @return None + * + * @note + * C-style signature: + * u32 XAxiDma_BdGetBufAddr(XAxiDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XAxiDma_BdGetBufAddr(BdPtr) \ + (XAxiDma_BdRead((BdPtr), XAXIDMA_BD_BUFA_OFFSET)) + +/*****************************************************************************/ +/** + * Check whether a BD has completed in hardware. This BD has been submitted + * to hardware. The application can use this function to poll for the + * completion of the BD. + * + * This function may not work if the BD is in cached memory. + * + * @param BdPtr is the BD to check on + * + * @return + * - 0 if not complete + * - XAXIDMA_BD_STS_COMPLETE_MASK if completed, may contain + * XAXIDMA_BD_STS_*_ERR_MASK bits. + * + * @note + * C-style signature: + * int XAxiDma_BdHwCompleted(XAxiDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XAxiDma_BdHwCompleted(BdPtr) \ + (XAxiDma_BdRead((BdPtr), XAXIDMA_BD_STS_OFFSET) & \ + XAXIDMA_BD_STS_COMPLETE_MASK) + +/*****************************************************************************/ +/** + * Get the actual transfer length of a BD. The BD has completed in hw. + * + * This function may not work if the BD is in cached memory. + * + * @param BdPtr is the BD to check on + * @param LengthMask is the Maximum Transfer Length. + * + * @return None + * + * @note + * C-style signature: + * int XAxiDma_BdGetActualLength(XAxiDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XAxiDma_BdGetActualLength(BdPtr, LengthMask) \ + (XAxiDma_BdRead((BdPtr), XAXIDMA_BD_STS_OFFSET) & \ + LengthMask) + +/*****************************************************************************/ +/** + * Set the TID field of the TX BD. + * Provides a stream identifier and can be used to differentiate between + * multiple streams of data that are being transferred across the same + * interface. + * + * @param BdPtr is the BD to operate on + * @param TId is a 8 bit quantity to set in the BD + * + * @return None + * + * @note + * C-style signature: + * void XAxiDma_BdSetTId(XAxiDma_Bd* BdPtr, void TId) + * + *****************************************************************************/ +#define XAxiDma_BdSetTId(BdPtr, TId) \ +{ \ + u32 val; \ + val = (XAxiDma_BdRead((BdPtr), XAXIDMA_BD_MCCTL_OFFSET) & \ + ~XAXIDMA_BD_TID_FIELD_MASK); \ + val |= ((u32)(TId) << XAXIDMA_BD_TID_FIELD_SHIFT); \ + XAxiDma_BdWrite((BdPtr), XAXIDMA_BD_MCCTL_OFFSET, val); \ +} + +/*****************************************************************************/ +/** + * Retrieve the TID field of the RX BD previously set with XAxiDma_BdSetTId. + * + * @param BdPtr is the BD to operate on + * + * @return None + * + * @note + * C-style signature: + * u32 XAxiDma_BdGetTId(XAxiDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XAxiDma_BdGetTId(BdPtr) \ + ((XAxiDma_BdRead((BdPtr), XAXIDMA_BD_STS_OFFSET)) & \ + XAXIDMA_BD_TID_FIELD_MASK) + +/*****************************************************************************/ +/** + * Set the TDEST field of the TX BD. + * Provides coarse routing information for the data stream. + * + * @param BdPtr is the BD to operate on + * @param TDest is a 8 bit quantity to set in the BD + * + * @return None + * + * @note + * C-style signature: + * void XAxiDma_BdSetTDest(XAxiDma_Bd* BdPtr, void TDest) + * + *****************************************************************************/ +#define XAxiDma_BdSetTDest(BdPtr, TDest) \ +{ \ + u32 val; \ + val = (XAxiDma_BdRead((BdPtr), XAXIDMA_BD_MCCTL_OFFSET) & \ + ~XAXIDMA_BD_TDEST_FIELD_MASK); \ + val |= ((u32)(TDest) << XAXIDMA_BD_TDEST_FIELD_SHIFT); \ + XAxiDma_BdWrite((BdPtr), XAXIDMA_BD_MCCTL_OFFSET, val); \ +} + +/*****************************************************************************/ +/** + * Retrieve the TDest field of the RX BD previously set with i + * XAxiDma_BdSetTDest. + * + * @param BdPtr is the BD to operate on + * + * @return None + * + * @note + * C-style signature: + * u32 XAxiDma_BdGetTDest(XAxiDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XAxiDma_BdGetTDest(BdPtr) \ + ((XAxiDma_BdRead((BdPtr), XAXIDMA_BD_STS_OFFSET)) & \ + XAXIDMA_BD_TDEST_FIELD_MASK) + +/*****************************************************************************/ +/** + * Set the TUSER field of the TX BD. + * User defined sideband signaling. + * + * @param BdPtr is the BD to operate on + * @param TUser is a 8 bit quantity to set in the BD + * + * @return None + * + * @note + * C-style signature: + * void XAxiDma_BdSetTUser(XAxiDma_Bd* BdPtr, void TUser) + * + *****************************************************************************/ +#define XAxiDma_BdSetTUser(BdPtr, TUser) \ +{ \ + u32 val; \ + val = (XAxiDma_BdRead((BdPtr), XAXIDMA_BD_MCCTL_OFFSET) & \ + ~XAXIDMA_BD_TUSER_FIELD_MASK); \ + val |= ((u32)(TUser) << XAXIDMA_BD_TUSER_FIELD_SHIFT); \ + XAxiDma_BdWrite((BdPtr), XAXIDMA_BD_MCCTL_OFFSET, val); \ +} + +/*****************************************************************************/ +/** + * Retrieve the TUSER field of the RX BD previously set with + * XAxiDma_BdSetTUser. + * + * @param BdPtr is the BD to operate on + * + * @return None + * + * @note + * C-style signature: + * u32 XAxiDma_BdGetTUser(XAxiDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XAxiDma_BdGetTUser(BdPtr) \ + ((XAxiDma_BdRead((BdPtr), XAXIDMA_BD_STS_OFFSET)) & \ + XAXIDMA_BD_TUSER_FIELD_MASK) + +/*****************************************************************************/ +/** + * Set the ARCACHE field of the given BD. + * This signal provides additional information about the cacheable + * characteristics of the transfer. + * + * @param BdPtr is the BD to operate on + * @param ARCache is a 8 bit quantity to set in the BD + * + * @return None + * + * @note + * C-style signature: + * void XAxiDma_BdSetARCache(XAxiDma_Bd* BdPtr, void ARCache) + * + *****************************************************************************/ +#define XAxiDma_BdSetARCache(BdPtr, ARCache) \ +{ \ + u32 val; \ + val = (XAxiDma_BdRead((BdPtr), XAXIDMA_BD_MCCTL_OFFSET) & \ + ~XAXIDMA_BD_ARCACHE_FIELD_MASK); \ + val |= ((u32)(ARCache) << XAXIDMA_BD_ARCACHE_FIELD_SHIFT); \ + XAxiDma_BdWrite((BdPtr), XAXIDMA_BD_MCCTL_OFFSET, val); \ +} + +/*****************************************************************************/ +/** + * Retrieve the ARCACHE field of the given BD previously set with + * XAxiDma_BdSetARCache. + * + * @param BdPtr is the BD to operate on + * + * @return None + * + * @note + * C-style signature: + * u32 XAxiDma_BdGetARCache(XAxiDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XAxiDma_BdGetARCache(BdPtr) \ + ((XAxiDma_BdRead((BdPtr), XAXIDMA_BD_MCCTL_OFFSET)) & \ + XAXIDMA_BD_ARCACHE_FIELD_MASK) + + +/*****************************************************************************/ +/** + * Set the ARUSER field of the given BD. + * Sideband signals used for user defined information. + * + * @param BdPtr is the BD to operate on + * @param ARUser is a 8 bit quantity to set in the BD + * + * @return None + * + * @note + * C-style signature: + * void XAxiDma_BdSetARUser(XAxiDma_Bd* BdPtr, void ARUser) + * + *****************************************************************************/ +#define XAxiDma_BdSetARUser(BdPtr, ARUser) \ +{ \ + u32 val; \ + val = (XAxiDma_BdRead((BdPtr), XAXIDMA_BD_MCCTL_OFFSET) & \ + ~XAXIDMA_BD_ARUSER_FIELD_MASK); \ + val |= ((u32)(ARUser) << XAXIDMA_BD_ARUSER_FIELD_SHIFT); \ + XAxiDma_BdWrite((BdPtr), XAXIDMA_BD_MCCTL_OFFSET, val); \ +} + + +/*****************************************************************************/ +/** + * Retrieve the ARUSER field of the given BD previously set with + * XAxiDma_BdSetARUser. + * + * @param BdPtr is the BD to operate on + * + * @return None + * + * @note + * C-style signature: + * u32 XAxiDma_BdGetARUser(XAxiDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XAxiDma_BdGetARUser(BdPtr) \ + ((XAxiDma_BdRead((BdPtr), XAXIDMA_BD_MCCTL_OFFSET)) & \ + XAXIDMA_BD_ARUSER_FIELD_MASK) + +/*****************************************************************************/ +/** + * Set the STRIDE field of the given BD. + * It is the address distance between the first address of successive + * horizontal reads. + * + * @param BdPtr is the BD to operate on + * @param Stride is a 32 bit quantity to set in the BD + * + * @return None + * + * @note + * C-style signature: + * void XAxiDma_BdSetStride(XAxiDma_Bd* BdPtr, void Stride) + * + *****************************************************************************/ +#define XAxiDma_BdSetStride(BdPtr, Stride) \ +{ \ + u32 val; \ + val = (XAxiDma_BdRead((BdPtr), XAXIDMA_BD_STRIDE_VSIZE_OFFSET) & \ + ~XAXIDMA_BD_STRIDE_FIELD_MASK); \ + val |= ((u32)(Stride) << XAXIDMA_BD_STRIDE_FIELD_SHIFT); \ + XAxiDma_BdWrite((BdPtr), XAXIDMA_BD_STRIDE_VSIZE_OFFSET, val); \ +} + +/*****************************************************************************/ +/** + * Retrieve the STRIDE field of the given BD previously set with + * XAxiDma_BdSetStride. + * + * @param BdPtr is the BD to operate on + * + * @return None + * + * @note + * C-style signature: + * u32 XAxiDma_BdGetStride(XAxiDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XAxiDma_BdGetStride(BdPtr) \ + ((XAxiDma_BdRead((BdPtr), XAXIDMA_BD_STRIDE_VSIZE_OFFSET)) & \ + XAXIDMA_BD_STRIDE_FIELD_MASK) + +/*****************************************************************************/ +/** + * Set the VSIZE field of the given BD. + * Number of horizontal lines for strided access. + * + * @param BdPtr is the BD to operate on + * @param VSize is a 32 bit quantity to set in the BD + * + * @return None + * + * @note + * C-style signature: + * void XAxiDma_BdSetVSize(XAxiDma_Bd* BdPtr, void VSize) + * + *****************************************************************************/ +#define XAxiDma_BdSetVSize(BdPtr, VSize) \ +{ \ + u32 val; \ + val = (XAxiDma_BdRead((BdPtr), XAXIDMA_BD_STRIDE_VSIZE_OFFSET) & \ + ~XAXIDMA_BD_VSIZE_FIELD_MASK); \ + val |= ((u32)(VSize) << XAXIDMA_BD_VSIZE_FIELD_SHIFT); \ + XAxiDma_BdWrite((BdPtr), XAXIDMA_BD_STRIDE_VSIZE_OFFSET, val); \ +} + +/*****************************************************************************/ +/** + * Retrieve the STRIDE field of the given BD previously set with + * XAxiDma_BdSetVSize. + * + * @param BdPtr is the BD to operate on + * + * @return None + * + * @note + * C-style signature: + * u32 XAxiDma_BdGetVSize(XAxiDma_Bd* BdPtr) + * + *****************************************************************************/ +#define XAxiDma_BdGetVSize(BdPtr) \ + ((XAxiDma_BdRead((BdPtr), XAXIDMA_BD_STRIDE_VSIZE_OFFSET)) & \ + XAXIDMA_BD_VSIZE_FIELD_MASK) + +/*****************************************************************************/ + +/************************** Function Prototypes ******************************/ + +int XAxiDma_BdSetLength(XAxiDma_Bd* BdPtr, u32 LenBytes, u32 LengthMask); +int XAxiDma_BdSetBufAddr(XAxiDma_Bd* BdPtr, u32 Addr); +int XAxiDma_BdSetBufAddrMicroMode(XAxiDma_Bd* BdPtr, u32 Addr); +int XAxiDma_BdSetAppWord(XAxiDma_Bd * BdPtr, int Offset, u32 Word); +u32 XAxiDma_BdGetAppWord(XAxiDma_Bd * BdPtr, int Offset, int *Valid); +void XAxiDma_BdSetCtrl(XAxiDma_Bd *BdPtr, u32 Data); + +/* Debug utility + */ +void XAxiDma_DumpBd(XAxiDma_Bd* BdPtr); + +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_bdring.c b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_bdring.c new file mode 100644 index 00000000..3799d85b --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_bdring.c @@ -0,0 +1,1533 @@ +/****************************************************************************** +* +* 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 xaxidma_bdring.c +* +* This file implements buffer descriptor ring related functions. For more +* information on how to manage the BD ring, please see xaxidma.h. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a jz   05/18/10 First release
+* 2.00a jz   08/10/10 Second release, added in xaxidma_g.c, xaxidma_sinit.c,
+*                     updated tcl file, added xaxidma_porting_guide.h
+* 3.00a jz   11/22/10 Support IP core parameters change
+* 5.00a srt  08/25/11 Added support for memory barrier.
+* 6.00a srt  01/24/12 Added support for Multi-Channel DMA.
+*		      - New API
+*			* XAxiDma_UpdateBdRingCDesc(XAxiDma_BdRing * RingPtr,
+*						int RingIndex)
+*		      - Changed APIs
+*			* XAxiDma_StartBdRingHw(XAxiDma_BdRing * RingPtr,
+*					int RingIndex)
+*			* XAxiDma_BdRingStart(XAxiDma_BdRing * RingPtr,
+*						 int RingIndex)
+*			* XAxiDma_BdRingToHw(XAxiDma_BdRing * RingPtr,
+*        			int NumBd, XAxiDma_Bd * BdSetPtr, int RingIndex)
+*			* XAxiDma_BdRingDumpRegs(XAxiDma_BdRing * RingPtr,
+*						 int RingIndex)
+*			* XAxiDma_BdRingSnapShotCurrBd(XAxiDma_BdRing * RingPtr,
+*						 int RingIndex)
+* 7.00a srt  06/18/12  All the APIs changed in v6_00_a are reverted back for
+*		       backward compatibility.
+*
+*
+* 
+******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xaxidma_bdring.h" + +/************************** Constant Definitions *****************************/ +/* Use 100 milliseconds for 100 MHz + * This interval is sufficient for hardware to finish 40MB transfer with + * 32-bit bus. + */ +#define XAXIDMA_STOP_TIMEOUT 500000 /* about 100 milliseconds on 100MHz */ + +/**************************** Type Definitions *******************************/ + + +/***************** Macros (Inline Functions) Definitions *********************/ +/* The following macros are helper functions inside this file. + */ + +/****************************************************************************** + * Compute the physical address of a descriptor from its virtual address + * + * @param BdPtr is the virtual address of the BD + * + * @returns Physical address of BdPtr + * + * @note Assume virtual and physical mapping is flat. + * RingPtr is an implicit parameter + * + *****************************************************************************/ +#define XAXIDMA_VIRT_TO_PHYS(BdPtr) \ + ((u32)(BdPtr) + (RingPtr->FirstBdPhysAddr - RingPtr->FirstBdAddr)) + +/****************************************************************************** + * Move the BdPtr argument ahead an arbitrary number of BDs wrapping around + * to the beginning of the ring if needed. + * + * We know if a wraparound should occur if the new BdPtr is greater than + * the high address in the ring OR if the new BdPtr crosses the 0xFFFFFFFF + * to 0 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 + * + * @returns None + * + * @note This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +#define XAXIDMA_RING_SEEKAHEAD(RingPtr, BdPtr, NumBd) \ + { \ + u32 Addr = (u32)(BdPtr); \ + \ + Addr += ((RingPtr)->Separation * (NumBd)); \ + if ((Addr > (RingPtr)->LastBdAddr) || ((u32)(BdPtr) > Addr)) \ + { \ + Addr -= (RingPtr)->Length; \ + } \ + \ + (BdPtr) = (XAxiDma_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 wraparound should occur if the new BdPtr is less than + * the base address in the ring OR if the new BdPtr crosses the 0xFFFFFFFF + * to 0 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 + * + * @returns None + * + * @note This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +#define XAXIDMA_RING_SEEKBACK(RingPtr, BdPtr, NumBd) \ + { \ + u32 Addr = (u32)(BdPtr); \ + \ + Addr -= ((RingPtr)->Separation * (NumBd)); \ + if ((Addr < (RingPtr)->FirstBdAddr) || ((u32)(BdPtr) < Addr)) \ + { \ + Addr += (RingPtr)->Length; \ + } \ + \ + (BdPtr) = (XAxiDma_Bd*)Addr; \ + } + +/************************** Function Prototypes ******************************/ + +/************************** Variable Definitions *****************************/ + + +/*****************************************************************************/ +/** + * Update Current Descriptor + * + * @param RingPtr is the Channel instance to be worked on + * + * @return + * - XST_SUCCESS upon success + * - XST_DMA_ERROR if no valid BD available to put into current + * BD register + * + * @note This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +int XAxiDma_UpdateBdRingCDesc(XAxiDma_BdRing* RingPtr) +{ + u32 RegBase; + XAxiDma_Bd *BdPtr; + int RingIndex = RingPtr->RingIndex; + + /* BD list has yet to be created for this channel */ + if (RingPtr->AllCnt == 0) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingStart: no bds\r\n"); + + return XST_DMA_SG_NO_LIST; + } + + /* Do nothing if already started */ + if (RingPtr->RunState == AXIDMA_CHANNEL_NOT_HALTED) { + /* Need to update tail pointer if needed (Engine is not + * transferring) + */ + return XST_SUCCESS; + } + + if (!XAxiDma_BdRingHwIsStarted(RingPtr)) { + /* If hardware is not running, then we need to put a valid current + * BD pointer to the current BD register before start the hardware + */ + RegBase = RingPtr->ChanBase; + + /* Put a valid BD pointer in the current BD pointer register + * So, the hardware is ready to go when tail BD pointer is updated + */ + BdPtr = (XAxiDma_Bd *)RingPtr->BdaRestart; + + if (!XAxiDma_BdHwCompleted(BdPtr)) { + if (RingPtr->IsRxChannel) { + if (!RingIndex) { + XAxiDma_WriteReg(RegBase, + XAXIDMA_CDESC_OFFSET, (u32)BdPtr); + } + else { + XAxiDma_WriteReg(RegBase, + (XAXIDMA_RX_CDESC0_OFFSET + + (RingIndex - 1) * XAXIDMA_RX_NDESC_OFFSET), + (u32)BdPtr); + } + } + else { + XAxiDma_WriteReg(RegBase, XAXIDMA_CDESC_OFFSET, + (u32)BdPtr); + } + } + else { + /* Look for an uncompleted BD + */ + while (XAxiDma_BdHwCompleted(BdPtr)) { + BdPtr = XAxiDma_BdRingNext(RingPtr, BdPtr); + + if ((u32)BdPtr == (u32) RingPtr->BdaRestart) { + xdbg_printf(XDBG_DEBUG_ERROR, + "StartBdRingHw: Cannot find valid cdesc\r\n"); + + return XST_DMA_ERROR; + } + + if (!XAxiDma_BdHwCompleted(BdPtr)) { + if (RingPtr->IsRxChannel) { + if (!RingIndex) { + XAxiDma_WriteReg(RegBase, + XAXIDMA_CDESC_OFFSET, (u32)BdPtr); + } + else { + XAxiDma_WriteReg(RegBase, + (XAXIDMA_RX_CDESC0_OFFSET + + (RingIndex - 1) * + XAXIDMA_RX_NDESC_OFFSET), + (u32)BdPtr); + } + } + else { + XAxiDma_WriteReg(RegBase, + XAXIDMA_CDESC_OFFSET, (u32)BdPtr); + } + break; + } + } + } + + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** + * Using a memory segment allocated by the caller, This fundtion creates and + * setup the BD ring. + * + * @param RingPtr is the BD ring instance to be worked on. + * @param PhysAddr is the physical base address of application memory + * region. + * @param VirtAddr is the virtual base address of the application 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 + * XAXIDMA_BD_MINIMUM_ALIGNMENT 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 application memory + * region. It is assumed the region is large enough to contain the + * BDs.Refer to the "SGDMA Ring Creation" section in xaxidma.h + * for more information. The minimum valid value for this + * parameter is 1. + * + * @return + * - XST_SUCCESS if initialization was successful + * - XST_NO_FEATURE if the provided instance is a non SGDMA type + * of DMA channel. + * - XST_INVALID_PARAM under any of the following conditions: + * 1) BdCount is not positive + * + * 2) PhysAddr and/or VirtAddr are not aligned to the given + * Alignment parameter; + * + * 3) Alignment parameter does not meet minimum requirements or + * is not a power of 2 value. + * + * - XST_DMA_SG_LIST_ERROR if the memory segment containing the + * list spans over address 0x00000000 in virtual address space. + * + * @note This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +int XAxiDma_BdRingCreate(XAxiDma_BdRing *RingPtr, u32 PhysAddr, + u32 VirtAddr, u32 Alignment, int BdCount) +{ + int i; + u32 BdVirtAddr; + u32 BdPhysAddr; + + if (BdCount <= 0) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCreate: non-positive BD" + " number %d\r\n", BdCount); + + return XST_INVALID_PARAM; + } + + /* In case there is a failure prior to creating list, make sure the + * following attributes are 0 to prevent calls to other SG 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 < XAXIDMA_BD_MINIMUM_ALIGNMENT) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCreate: alignment too " + "small %d, need to be at least %d\r\n", (int)Alignment, + XAXIDMA_BD_MINIMUM_ALIGNMENT); + + return XST_INVALID_PARAM; + } + + /* Make sure Alignment is a power of 2 */ + if ((Alignment - 1) & Alignment) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCreate: alignment not" + " valid %d\r\n", (int)Alignment); + + return XST_INVALID_PARAM; + } + + /* Make sure PhysAddr and VirtAddr are on same Alignment */ + if ((PhysAddr % Alignment) || (VirtAddr % Alignment)) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCreate: Physical address" + " %x and virtual address %x have different alignment\r\n", + (unsigned int)PhysAddr, (unsigned int)VirtAddr); + + return XST_INVALID_PARAM; + } + + /* Compute how many bytes will be between the start of adjacent BDs */ + RingPtr->Separation = + (sizeof(XAxiDma_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)) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCreate: BD space cross " + "0x0\r\n"); + + return XST_DMA_SG_LIST_ERROR; + } + + /* Initial ring setup: + * - Clear the entire space + * - Setup each BD's next pointer with the physical address of the + * next BD + * - Put hardware information in each BD + */ + memset((void *) VirtAddr, 0, (RingPtr->Separation * BdCount)); + + BdVirtAddr = VirtAddr; + BdPhysAddr = PhysAddr + RingPtr->Separation; + for (i = 1; i < BdCount; i++) { + XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_NDESC_OFFSET, + BdPhysAddr); + + /* Put hardware information in the BDs + */ + XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_HAS_STSCNTRL_OFFSET, + (u32)RingPtr->HasStsCntrlStrm); + + XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_HAS_DRE_OFFSET, + (((u32)(RingPtr->HasDRE)) << XAXIDMA_BD_HAS_DRE_SHIFT) | + RingPtr->DataWidth); + + XAXIDMA_CACHE_FLUSH(BdVirtAddr); + BdVirtAddr += RingPtr->Separation; + BdPhysAddr += RingPtr->Separation; + } + + /* At the end of the ring, link the last BD back to the top */ + XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_NDESC_OFFSET, PhysAddr); + + /* Setup the last BD's hardware information */ + XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_HAS_STSCNTRL_OFFSET, + (u32)RingPtr->HasStsCntrlStrm); + + XAxiDma_BdWrite(BdVirtAddr, XAXIDMA_BD_HAS_DRE_OFFSET, + (((u32)(RingPtr->HasDRE)) << XAXIDMA_BD_HAS_DRE_SHIFT) | + RingPtr->DataWidth); + + /* Setup and initialize pointers and counters */ + RingPtr->RunState = AXIDMA_CHANNEL_HALTED; + RingPtr->FirstBdAddr = VirtAddr; + RingPtr->FirstBdPhysAddr = PhysAddr; + RingPtr->LastBdAddr = BdVirtAddr; + RingPtr->Length = RingPtr->LastBdAddr - RingPtr->FirstBdAddr + + RingPtr->Separation; + RingPtr->AllCnt = BdCount; + RingPtr->FreeCnt = BdCount; + RingPtr->FreeHead = (XAxiDma_Bd *) VirtAddr; + RingPtr->PreHead = (XAxiDma_Bd *) VirtAddr; + RingPtr->HwHead = (XAxiDma_Bd *) VirtAddr; + RingPtr->HwTail = (XAxiDma_Bd *) VirtAddr; + RingPtr->PostHead = (XAxiDma_Bd *) VirtAddr; + RingPtr->BdaRestart = (XAxiDma_Bd *) PhysAddr; + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** + * Clone the given BD into every BD in the ring. Only the fields offset from + * XAXIDMA_BD_START_CLEAR are copied, for XAXIDMA_BD_BYTES_TO_CLEAR bytes. + * This covers: BufferAddr, Control/Buffer length, status, APP words 0 - 4, + * and software ID fields. + * + * This function can be called only when all BDs are in the free group such as + * immediately after creation of the ring. This prevents modification + * of BDs while they are in use by hardware or the application. + * + * @param RingPtr is the BD ring instance to be worked on. + * @param SrcBdPtr is the source BD template to be cloned into the list. + * + * @return + * - XST_SUCCESS if the list was modified. + * - XST_DMA_SG_NO_LIST if a list has not been created. + * - XST_DEVICE_IS_STARTED if the DMA channel has not been stopped. + * - XST_DMA_SG_LIST_ERROR if some of the BDs in this channel are + * under hardware or application control. + * + * @note This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +int XAxiDma_BdRingClone(XAxiDma_BdRing * RingPtr, XAxiDma_Bd * SrcBdPtr) +{ + int i; + u32 CurBd; + u32 Save; + XAxiDma_Bd TmpBd; + + /* Can't do this function if there isn't a ring */ + if (RingPtr->AllCnt == 0) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingClone: no bds\r\n"); + + return XST_DMA_SG_NO_LIST; + } + + /* Can't do this function with the channel running */ + if (RingPtr->RunState == AXIDMA_CHANNEL_NOT_HALTED) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingClone: bd ring started " + "already, cannot do\r\n"); + + return XST_DEVICE_IS_STARTED; + } + + /* Can't do this function with some of the BDs in use */ + if (RingPtr->FreeCnt != RingPtr->AllCnt) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingClone: some bds already " + "in use %d/%d\r\n",RingPtr->FreeCnt, RingPtr->AllCnt); + + return XST_DMA_SG_LIST_ERROR; + } + + /* Make a copy of the template then modify it by clearing + * the complete bit in status/control field + */ + memcpy(&TmpBd, SrcBdPtr, sizeof(XAxiDma_Bd)); + + Save = XAxiDma_BdRead(&TmpBd, XAXIDMA_BD_STS_OFFSET); + Save &= ~XAXIDMA_BD_STS_COMPLETE_MASK; + XAxiDma_BdWrite(&TmpBd, XAXIDMA_BD_STS_OFFSET, Save); + + for (i = 0, CurBd = RingPtr->FirstBdAddr; + i < RingPtr->AllCnt; i++, CurBd += RingPtr->Separation) { + + memcpy((void *)((u32)CurBd + XAXIDMA_BD_START_CLEAR), + (void *)((u32)(&TmpBd) + XAXIDMA_BD_START_CLEAR), + XAXIDMA_BD_BYTES_TO_CLEAR); + + XAXIDMA_CACHE_FLUSH(CurBd); + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** + * Start a DMA channel and + * Allow DMA transactions to commence on a given channel if descriptors are + * ready to be processed. + * + * After a DMA channel is started, it is not halted, and it is idle (no active + * DMA transfers). + * + * @param RingPtr is the Channel instance to be worked on + * + * @return + * - XST_SUCCESS upon success + * - XST_DMA_ERROR if no valid BD available to put into current + * BD register + * + * @note This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +int XAxiDma_StartBdRingHw(XAxiDma_BdRing * RingPtr) +{ + u32 RegBase; + int RingIndex = RingPtr->RingIndex; + + if (!XAxiDma_BdRingHwIsStarted(RingPtr)) { + /* Start the hardware + */ + RegBase = RingPtr->ChanBase; + XAxiDma_WriteReg(RegBase, XAXIDMA_CR_OFFSET, + XAxiDma_ReadReg(RegBase, XAXIDMA_CR_OFFSET) + | XAXIDMA_CR_RUNSTOP_MASK); + } + + if (XAxiDma_BdRingHwIsStarted(RingPtr)) { + /* Note as started */ + RingPtr->RunState = AXIDMA_CHANNEL_NOT_HALTED; + + /* If there are unprocessed BDs then we want the channel to begin + * processing right away + */ + if (RingPtr->HwCnt > 0) { + + XAXIDMA_CACHE_INVALIDATE(RingPtr->HwTail); + + if ((XAxiDma_BdRead(RingPtr->HwTail, + XAXIDMA_BD_STS_OFFSET) & + XAXIDMA_BD_STS_COMPLETE_MASK) == 0) { + if (RingPtr->IsRxChannel) { + if (!RingIndex) { + XAxiDma_WriteReg(RingPtr->ChanBase, + XAXIDMA_TDESC_OFFSET, + XAXIDMA_VIRT_TO_PHYS(RingPtr->HwTail)); + } + else { + XAxiDma_WriteReg(RingPtr->ChanBase, + (XAXIDMA_RX_TDESC0_OFFSET + + (RingIndex - 1) * XAXIDMA_RX_NDESC_OFFSET), + XAXIDMA_VIRT_TO_PHYS(RingPtr->HwTail)); + } + } + else { + XAxiDma_WriteReg(RingPtr->ChanBase, + XAXIDMA_TDESC_OFFSET, + XAXIDMA_VIRT_TO_PHYS(RingPtr->HwTail)); + } + } + } + + return XST_SUCCESS; + } + + return XST_DMA_ERROR; +} + +/*****************************************************************************/ +/** + * Start a DMA channel, updates current descriptors and + * Allow DMA transactions to commence on a given channel if descriptors are + * ready to be processed. + * + * After a DMA channel is started, it is not halted, and it is idle (no active + * DMA transfers). + * + * @param RingPtr is the Channel instance to be worked on + * + * @return + * - XST_SUCCESS upon success + * - XST_DMA_ERROR if no valid BD available to put into current + * BD register + * + * @note This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +int XAxiDma_BdRingStart(XAxiDma_BdRing * RingPtr) +{ + int Status; + + Status = XAxiDma_UpdateBdRingCDesc(RingPtr); + if (Status != XST_SUCCESS) { + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingStart: " + "Updating Current Descriptor Failed\n\r"); + return Status; + } + + Status = XAxiDma_StartBdRingHw(RingPtr); + if (Status != XST_SUCCESS) { + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingStart: " + "Starting Hardware Failed\n\r"); + return Status; + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** + * Set interrupt coalescing parameters for the given descriptor ring channel. + * + * @param RingPtr is a pointer to the descriptor ring instance to be + * worked on. + * @param Counter sets the packet counter on the channel. Valid range is + * - 1..255. + * - XAXIDMA_NO_CHANGE to leave this setting unchanged. + * @param Timer sets the waitbound timer on the channel. Valid range is + * - 0..255. + * - XAXIDMA_NO_CHANGE to leave this setting unchanged. + * Each unit depend on hardware building parameter + * C_DLYTMR_RESOLUTION,which is in the range from 0 to 100,000 + * clock cycles. A value of 0 disables the delay interrupt. + * + * @return + * - XST_SUCCESS if interrupt coalescing settings updated + * - XST_FAILURE if Counter or Timer parameters are out of range + * + * @note This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +int XAxiDma_BdRingSetCoalesce(XAxiDma_BdRing *RingPtr, u32 Counter, u32 Timer) +{ + u32 Cr; + + Cr = XAxiDma_ReadReg(RingPtr->ChanBase, XAXIDMA_CR_OFFSET); + + if (Counter != XAXIDMA_NO_CHANGE) { + if ((Counter == 0) || (Counter > 0xFF)) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingSetCoalesce: " + "invalid coalescing threshold %d", (int)Counter); + return XST_FAILURE; + } + + Cr = (Cr & ~XAXIDMA_COALESCE_MASK) | + (Counter << XAXIDMA_COALESCE_SHIFT); + } + + if (Timer != XAXIDMA_NO_CHANGE) { + if (Timer > 0xFF) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingSetCoalesce: " + "invalid delay counter %d", (int)Timer); + + return XST_FAILURE; + } + + Cr = (Cr & ~XAXIDMA_DELAY_MASK) | + (Timer << XAXIDMA_DELAY_SHIFT); + } + + XAxiDma_WriteReg(RingPtr->ChanBase, XAXIDMA_CR_OFFSET, Cr); + + return XST_SUCCESS; +} +/*****************************************************************************/ +/** + * Retrieve current interrupt coalescing parameters from the given descriptor + * ring channel. + * + * @param RingPtr is a pointer to the descriptor ring instance to be + * worked on. + * @param CounterPtr points to a memory location where the current packet + * counter will be written. + * @param TimerPtr points to a memory location where the current + * waitbound timer will be written. + * + * @return The passed in parameters, CounterPtr and TimerPtr, holds the + * references to the return values. + * + * @note This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +void XAxiDma_BdRingGetCoalesce(XAxiDma_BdRing * RingPtr, + u32 *CounterPtr, u32 *TimerPtr) +{ + u32 Cr; + + Cr = XAxiDma_ReadReg(RingPtr->ChanBase, XAXIDMA_CR_OFFSET); + + *CounterPtr = ((Cr & XAXIDMA_COALESCE_MASK) >> XAXIDMA_COALESCE_SHIFT); + *TimerPtr = ((Cr & XAXIDMA_DELAY_MASK) >> XAXIDMA_DELAY_SHIFT); +} + +/*****************************************************************************/ +/** + * Reserve locations in the BD ring. The set of returned BDs may be modified in + * preparation for future DMA transactions. Once the BDs are ready to be + * submitted to hardware, the application must call XAxiDma_BdRingToHw() in the + * same order which they were allocated here. Example: + * + *
+ *        NumBd = 2;
+ *        Status = XDsma_RingBdAlloc(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
+ *        XAxiDma_BdRingAlloc(MyRingPtr, NumBd1, &MySet1);
+ *        XAxiDma_BdRingToHw(MyRingPtr, NumBd1, MySet1);
+ *
+ *        // Legal
+ *        XAxiDma_BdRingAlloc(MyRingPtr, NumBd1, &MySet1);
+ *        XAxiDma_BdRingAlloc(MyRingPtr, NumBd2, &MySet2);
+ *        XAxiDma_BdRingToHw(MyRingPtr, NumBd1, MySet1);
+ *        XAxiDma_BdRingToHw(MyRingPtr, NumBd2, MySet2);
+ *
+ *        // Not legal
+ *        XAxiDma_BdRingAlloc(MyRingPtr, NumBd1, &MySet1);
+ *        XAxiDma_BdRingAlloc(MyRingPtr, NumBd2, &MySet2);
+ *        XAxiDma_BdRingToHw(MyRingPtr, NumBd2, MySet2);
+ *        XAxiDma_BdRingToHw(MyRingPtr, NumBd1, MySet1);
+ * 
+ * + * Use the API defined in xaxidmabd.h to modify individual BDs. Traversal of + * the BD set can be done using XAxiDma_BdRingNext() and XAxiDma_BdRingPrev(). + * + * @param RingPtr is a pointer to the descriptor 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 were returned in + * the BdSetPtr parameter. + * - XST_INVALID_PARAM if passed in NumBd is not positive + * - XST_FAILURE if there were not enough free BDs to satisfy + * the request. + * + * @note This function should not be preempted by another XAxiDma_BdRing + * function call that modifies the BD space. It is the caller's + * responsibility to provide a mutual exclusion mechanism. + * + * Do not modify more BDs than the number requested with the NumBd + * parameter. Doing so will lead to data corruption and system + * instability. + * + * This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +int XAxiDma_BdRingAlloc(XAxiDma_BdRing * RingPtr, int NumBd, + XAxiDma_Bd ** BdSetPtr) +{ + if (NumBd <= 0) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingAlloc: negative BD " + "number %d\r\n", NumBd); + + return XST_INVALID_PARAM; + } + + /* Enough free BDs available for the request? */ + if (RingPtr->FreeCnt < NumBd) { + xdbg_printf(XDBG_DEBUG_ERROR, + "Not enough BDs to alloc %d/%d\r\n", NumBd, RingPtr->FreeCnt); + + return XST_FAILURE; + } + + /* Set the return argument and move FreeHead forward */ + *BdSetPtr = RingPtr->FreeHead; + XAXIDMA_RING_SEEKAHEAD(RingPtr, RingPtr->FreeHead, NumBd); + RingPtr->FreeCnt -= NumBd; + RingPtr->PreCnt += NumBd; + + return XST_SUCCESS; +} +/*****************************************************************************/ +/** + * Fully or partially undo an XAxiDma_BdRingAlloc() operation. Use this + * function if all the BDs allocated by XAxiDma_BdRingAlloc() could not be + * transferred to hardware with XAxiDma_BdRingToHw(). + * + * This function releases the BDs after they have been allocated but before + * they have been given to hardware. + * + * This function is not the same as XAxiDma_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 = XAxiDma_BdRingAlloc(MyRingPtr, 10, &BdPtr);
+ *        ...
+ *        ...
+ *    if (Error)
+ *    {
+ *        Status = XAxiDma_BdRingUnAlloc(MyRingPtr, 10, &BdPtr);
+ *    }
+ * 
+ * + * A partial UnAlloc means some of the BDs Alloc'd will be returned: + * + *
+ *    Status = XAxiDma_BdRingAlloc(MyRingPtr, 10, &BdPtr);
+ *    BdsLeft = 10;
+ *    CurBdPtr = BdPtr;
+ *
+ *    while (BdsLeft)
+ *    {
+ *       if (Error)
+ *       {
+ *          Status = XAxiDma_BdRingUnAlloc(MyRingPtr, BdsLeft, CurBdPtr);
+ *       }
+ *
+ *       CurBdPtr = XAxiDma_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 descriptor ring instance to be + * worked on. + * @param NumBd is the number of BDs to unallocate + * @param BdSetPtr points to the first of the BDs to be returned. + * + * @return + * - XST_SUCCESS if the BDs were unallocated. + * - XST_INVALID_PARAM if passed in NumBd is negative + * - 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 XAxiDma ring + * function call that modifies the BD space. It is the caller's + * responsibility to provide a mutual exclusion mechanism. + * + * This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +int XAxiDma_BdRingUnAlloc(XAxiDma_BdRing * RingPtr, int NumBd, + XAxiDma_Bd * BdSetPtr) +{ + XAxiDma_Bd *TmpBd; + + if (NumBd <= 0) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingUnAlloc: negative BD" + " number %d\r\n", NumBd); + + return XST_INVALID_PARAM; + } + + /* Enough BDs in the preprocessing state for the request? */ + if (RingPtr->PreCnt < NumBd) { + xdbg_printf(XDBG_DEBUG_ERROR, + "Pre-allocated BDs less than requested %d/%d\r\n", + RingPtr->PreCnt, NumBd); + + return XST_FAILURE; + } + + /* The last BD in the BD set must has the FreeHead as its next BD. + * Otherwise, this is not a valid operation. + */ + TmpBd = BdSetPtr; + XAXIDMA_RING_SEEKAHEAD(RingPtr, TmpBd, NumBd); + + if (TmpBd != RingPtr->FreeHead) { + xdbg_printf(XDBG_DEBUG_ERROR, + "Unalloc does not go back to free head\r\n"); + + return XST_FAILURE; + } + + /* Set the return argument and move FreeHead backward */ + XAXIDMA_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 + * XAxiDma_BdRingAlloc(). Once this function returns, the argument BD set goes + * under hardware control. Changes to these BDs should be held until they are + * finished by hardware to avoid data corruption and system instability. + * + * For transmit, the set will be rejected if the last BD of the set does not + * mark the end of a packet or the first BD does not mark the start of a packet. + * + * @param RingPtr is a pointer to the descriptor ring 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_INVALID_PARAM if passed in NumBd is negative + * - XST_FAILURE if the set of BDs was rejected because the first + * BD does not have its start-of-packet bit set, or the last BD + * does not have its end-of-packet bit set, or any one of the BDs + * has 0 length. + * - XST_DMA_SG_LIST_ERROR if this function was called out of + * sequence with XAxiDma_BdRingAlloc() + * + * @note This function should not be preempted by another XAxiDma ring + * function call that modifies the BD space. It is the caller's + * responsibility to provide a mutual exclusion mechanism. + * + * This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +int XAxiDma_BdRingToHw(XAxiDma_BdRing * RingPtr, int NumBd, + XAxiDma_Bd * BdSetPtr) +{ + XAxiDma_Bd *CurBdPtr; + int i; + u32 BdCr; + u32 BdSts; + int RingIndex = RingPtr->RingIndex; + + if (NumBd < 0) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingToHw: negative BD number " + "%d\r\n", NumBd); + + return XST_INVALID_PARAM; + } + + /* If the commit set is empty, do nothing */ + if (NumBd == 0) { + return XST_SUCCESS; + } + + /* Make sure we are in sync with XAxiDma_BdRingAlloc() */ + if ((RingPtr->PreCnt < NumBd) || (RingPtr->PreHead != BdSetPtr)) { + + xdbg_printf(XDBG_DEBUG_ERROR, "Bd ring has problems\r\n"); + return XST_DMA_SG_LIST_ERROR; + } + + CurBdPtr = BdSetPtr; + BdCr = XAxiDma_BdGetCtrl(CurBdPtr); + BdSts = XAxiDma_BdGetSts(CurBdPtr); + + /* In case of Tx channel, the first BD should have been marked + * as start-of-frame + */ + if (!(RingPtr->IsRxChannel) && !(BdCr & XAXIDMA_BD_CTRL_TXSOF_MASK)) { + + xdbg_printf(XDBG_DEBUG_ERROR, "Tx first BD does not have " + "SOF\r\n"); + + return XST_FAILURE; + } + + /* Clear the completed status bit + */ + for (i = 0; i < NumBd - 1; i++) { + + /* Make sure the length value in the BD is non-zero. */ + if (XAxiDma_BdGetLength(CurBdPtr, + RingPtr->MaxTransferLen) == 0) { + + xdbg_printf(XDBG_DEBUG_ERROR, "0 length bd\r\n"); + + return XST_FAILURE; + } + + BdSts &= ~XAXIDMA_BD_STS_COMPLETE_MASK; + XAxiDma_BdWrite(CurBdPtr, XAXIDMA_BD_STS_OFFSET, BdSts); + + /* Flush the current BD so DMA core could see the updates */ + XAXIDMA_CACHE_FLUSH(CurBdPtr); + + CurBdPtr = XAxiDma_BdRingNext(RingPtr, CurBdPtr); + BdCr = XAxiDma_BdRead(CurBdPtr, XAXIDMA_BD_CTRL_LEN_OFFSET); + BdSts = XAxiDma_BdRead(CurBdPtr, XAXIDMA_BD_STS_OFFSET); + } + + /* In case of Tx channel, the last BD should have EOF bit set */ + if (!(RingPtr->IsRxChannel) && !(BdCr & XAXIDMA_BD_CTRL_TXEOF_MASK)) { + + xdbg_printf(XDBG_DEBUG_ERROR, "Tx last BD does not have " + "EOF\r\n"); + + return XST_FAILURE; + } + + /* Make sure the length value in the last BD is non-zero. */ + if (XAxiDma_BdGetLength(CurBdPtr, + RingPtr->MaxTransferLen) == 0) { + + xdbg_printf(XDBG_DEBUG_ERROR, "0 length bd\r\n"); + + return XST_FAILURE; + } + + /* The last BD should also have the completed status bit cleared + */ + BdSts &= ~XAXIDMA_BD_STS_COMPLETE_MASK; + XAxiDma_BdWrite(CurBdPtr, XAXIDMA_BD_STS_OFFSET, BdSts); + + /* Flush the last BD so DMA core could see the updates */ + XAXIDMA_CACHE_FLUSH(CurBdPtr); + DATA_SYNC; + + /* This set has completed pre-processing, adjust ring pointers and + * counters + */ + XAXIDMA_RING_SEEKAHEAD(RingPtr, RingPtr->PreHead, NumBd); + RingPtr->PreCnt -= NumBd; + RingPtr->HwTail = CurBdPtr; + RingPtr->HwCnt += NumBd; + + /* If it is running, signal the engine to begin processing */ + if (RingPtr->RunState == AXIDMA_CHANNEL_NOT_HALTED) { + if (RingPtr->IsRxChannel) { + if (!RingIndex) { + XAxiDma_WriteReg(RingPtr->ChanBase, + XAXIDMA_TDESC_OFFSET, + XAXIDMA_VIRT_TO_PHYS(RingPtr->HwTail)); + } + else { + XAxiDma_WriteReg(RingPtr->ChanBase, + (XAXIDMA_RX_TDESC0_OFFSET + + (RingIndex - 1) * + XAXIDMA_RX_NDESC_OFFSET), + XAXIDMA_VIRT_TO_PHYS(RingPtr->HwTail)); + } + } + else { + XAxiDma_WriteReg(RingPtr->ChanBase, + XAXIDMA_TDESC_OFFSET, + XAXIDMA_VIRT_TO_PHYS(RingPtr->HwTail)); + } + } + + return XST_SUCCESS; +} + +/*****************************************************************************/ +/** + * Returns a set of BD(s) that have been processed by hardware. The returned + * BDs may be examined by the application to determine the outcome of the DMA + * transactions. Once the BDs have been examined, the application must call + * XAxiDma_BdRingFree() in the same order which they were retrieved here. + * + * Example: + * + *
+ *        NumBd = XAxiDma_BdRingFromHw(MyRingPtr, XAXIDMA_ALL_BDS, &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
+ *        XAxiDma_BdRingFromHw(MyRingPtr, NumBd1, &MySet1);
+ *        XAxiDma_BdRingFree(MyRingPtr, NumBd1, MySet1);
+ *
+ *        // Legal
+ *        XAxiDma_BdRingFromHw(MyRingPtr, NumBd1, &MySet1);
+ *        XAxiDma_BdRingFromHw(MyRingPtr, NumBd2, &MySet2);
+ *        XAxiDma_BdRingFree(MyRingPtr, NumBd1, MySet1);
+ *        XAxiDma_BdRingFree(MyRingPtr, NumBd2, MySet2);
+ *
+ *        // Not legal
+ *        XAxiDma_BdRingFromHw(MyRingPtr, NumBd1, &MySet1);
+ *        XAxiDma_BdRingFromHw(MyRingPtr, NumBd2, &MySet2);
+ *        XAxiDma_BdRingFree(MyRingPtr, NumBd2, MySet2);
+ *        XAxiDma_BdRingFree(MyRingPtr, NumBd1, MySet1);
+ * 
+ * + * If hardware has 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 descriptor ring instance to be + * worked on. + * @param BdLimit is the maximum number of BDs to return in the set. Use + * XAXIDMA_ALL_BDS to return all BDs that have been processed. + * @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. + * + * This function should not be preempted by another XAxiDma ring + * function call that modifies the BD space. It is the caller's + * responsibility to provide a mutual exclusion mechanism. + * + * This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +int XAxiDma_BdRingFromHw(XAxiDma_BdRing * RingPtr, int BdLimit, + XAxiDma_Bd ** BdSetPtr) +{ + XAxiDma_Bd *CurBdPtr; + int BdCount; + int BdPartialCount; + u32 BdSts; + u32 BdCr; + + CurBdPtr = RingPtr->HwHead; + BdCount = 0; + BdPartialCount = 0; + BdSts = 0; + BdCr = 0; + + /* If no BDs in work group, then there's nothing to search */ + if (RingPtr->HwCnt == 0) { + *BdSetPtr = (XAxiDma_Bd *)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 completed bit clear in the status + * word which means hardware has not completed processing of that + * BD. + * - RingPtr->HwTail is reached + * - The number of requested BDs has been processed + */ + + while (BdCount < BdLimit) { + /* Read the status */ + XAXIDMA_CACHE_INVALIDATE(CurBdPtr); + BdSts = XAxiDma_BdRead(CurBdPtr, XAXIDMA_BD_STS_OFFSET); + BdCr = XAxiDma_BdRead(CurBdPtr, XAXIDMA_BD_CTRL_LEN_OFFSET); + + /* If the hardware still hasn't processed this BD then we are + * done + */ + if (!(BdSts & XAXIDMA_BD_STS_COMPLETE_MASK)) { + 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. + * + * For tx BDs, EOF bit is in the control word + * For rx BDs, EOF bit is in the status word + */ + if (((!(RingPtr->IsRxChannel) && + (BdCr & XAXIDMA_BD_CTRL_TXEOF_MASK)) || + ((RingPtr->IsRxChannel) && (BdSts & + XAXIDMA_BD_STS_RXEOF_MASK)))) { + + BdPartialCount = 0; + } + else { + BdPartialCount++; + } + + /* Reached the end of the work group */ + if (CurBdPtr == RingPtr->HwTail) { + break; + } + + /* Move on to the next BD in work group */ + CurBdPtr = XAxiDma_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) { + *BdSetPtr = RingPtr->HwHead; + RingPtr->HwCnt -= BdCount; + RingPtr->PostCnt += BdCount; + XAXIDMA_RING_SEEKAHEAD(RingPtr, RingPtr->HwHead, BdCount); + + return BdCount; + } + else { + *BdSetPtr = (XAxiDma_Bd *)NULL; + + return 0; + } +} +/*****************************************************************************/ +/** + * Frees a set of BDs that had been previously retrieved with + * XAxiDma_BdRingFromHw(). + * + * @param RingPtr is a pointer to the descriptor ring 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 + * XAxiDma_BdRingFromHw(). + * + * @return + * - XST_SUCCESS if the set of BDs was freed. + * - XST_INVALID_PARAM if NumBd is negative + * - XST_DMA_SG_LIST_ERROR if this function was called out of + * sequence with XAxiDma_BdRingFromHw(). + * + * @note This function should not be preempted by another XAxiDma + * function call that modifies the BD space. It is the caller's + * responsibility to ensure mutual exclusion. + * + * This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +int XAxiDma_BdRingFree(XAxiDma_BdRing * RingPtr, int NumBd, + XAxiDma_Bd * BdSetPtr) +{ + if (NumBd < 0) { + + xdbg_printf(XDBG_DEBUG_ERROR, + "BdRingFree: negative BDs %d\r\n", NumBd); + + return XST_INVALID_PARAM; + } + + /* If the BD Set to free is empty, do nothing + */ + if (NumBd == 0) { + return XST_SUCCESS; + } + + /* Make sure we are in sync with XAxiDma_BdRingFromHw() */ + if ((RingPtr->PostCnt < NumBd) || (RingPtr->PostHead != BdSetPtr)) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingFree: Error free BDs: " + "post count %d to free %d, PostHead %x to free ptr %x\r\n", + RingPtr->PostCnt, NumBd, + (unsigned int)RingPtr->PostHead, + (unsigned int)BdSetPtr); + + return XST_DMA_SG_LIST_ERROR; + } + + /* Update pointers and counters */ + RingPtr->FreeCnt += NumBd; + RingPtr->PostCnt -= NumBd; + XAXIDMA_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: + * + * - The BD ring is linked correctly in physical address space. + * - The internal pointers point to BDs in the ring. + * - The internal counters add up. + * + * The channel should be stopped (through XAxiDma_Pause() or XAxiDma_Reset()) + * prior to calling this function. + * + * @param RingPtr is a pointer to the descriptor ring to be worked on. + * + * @return + * - XST_SUCCESS if no errors were found. + * - XST_DMA_SG_NO_LIST if the ring 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,and the BD ring should be recreated through + * XAxiDma_BdRingCreate() to avoid data corruption or system + * instability. + * + * @note This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +int XAxiDma_BdRingCheck(XAxiDma_BdRing * RingPtr) +{ + u32 AddrV; + u32 AddrP; + int i; + + /* Is the list created */ + if (RingPtr->AllCnt == 0) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCheck: no BDs\r\n"); + + return XST_DMA_SG_NO_LIST; + } + + /* Can't check if channel is running */ + if (RingPtr->RunState == AXIDMA_CHANNEL_NOT_HALTED) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCheck: Bd ring is " + "running, cannot check it\r\n"); + + return XST_IS_STARTED; + } + + /* RunState doesn't make sense */ + else if (RingPtr->RunState != AXIDMA_CHANNEL_HALTED) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCheck: unknown BD ring " + "state %d ", RingPtr->RunState); + + return XST_DMA_SG_LIST_ERROR; + } + + /* Verify internal pointers point to correct memory space */ + AddrV = (u32) RingPtr->FreeHead; + if ((AddrV < RingPtr->FirstBdAddr) || (AddrV > RingPtr->LastBdAddr)) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCheck: FreeHead wrong " + "%x, should be in range of %x/%x\r\n", + (unsigned int)AddrV, + (unsigned int)RingPtr->FirstBdAddr, + (unsigned int)RingPtr->LastBdAddr); + + return XST_DMA_SG_LIST_ERROR; + } + + AddrV = (u32) RingPtr->PreHead; + if ((AddrV < RingPtr->FirstBdAddr) || (AddrV > RingPtr->LastBdAddr)) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCheck: PreHead wrong %x, " + "should be in range of %x/%x\r\n", + (unsigned int)AddrV, + (unsigned int)RingPtr->FirstBdAddr, + (unsigned int)RingPtr->LastBdAddr); + + return XST_DMA_SG_LIST_ERROR; + } + + AddrV = (u32) RingPtr->HwHead; + if ((AddrV < RingPtr->FirstBdAddr) || (AddrV > RingPtr->LastBdAddr)) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCheck: HwHead wrong %x, " + "should be in range of %x/%x\r\n", + (unsigned int)AddrV, + (unsigned int)RingPtr->FirstBdAddr, + (unsigned int)RingPtr->LastBdAddr); + + return XST_DMA_SG_LIST_ERROR; + } + + AddrV = (u32) RingPtr->HwTail; + if ((AddrV < RingPtr->FirstBdAddr) || (AddrV > RingPtr->LastBdAddr)) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCheck: HwTail wrong %x, " + "should be in range of %x/%x\r\n", + (unsigned int)AddrV, + (unsigned int)RingPtr->FirstBdAddr, + (unsigned int)RingPtr->LastBdAddr); + + return XST_DMA_SG_LIST_ERROR; + } + + AddrV = (u32) RingPtr->PostHead; + if ((AddrV < RingPtr->FirstBdAddr) || (AddrV > RingPtr->LastBdAddr)) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCheck: PostHead wrong " + "%x, should be in range of %x/%x\r\n", + (unsigned int)AddrV, + (unsigned int)RingPtr->FirstBdAddr, + (unsigned int)RingPtr->LastBdAddr); + + return XST_DMA_SG_LIST_ERROR; + } + + /* Verify internal counters add up */ + if ((RingPtr->HwCnt + RingPtr->PreCnt + RingPtr->FreeCnt + + RingPtr->PostCnt) != RingPtr->AllCnt) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCheck: internal counter " + "error\r\n"); + + return XST_DMA_SG_LIST_ERROR; + } + + /* Verify BDs are linked correctly */ + AddrV = RingPtr->FirstBdAddr; + AddrP = RingPtr->FirstBdPhysAddr + RingPtr->Separation; + for (i = 1; i < RingPtr->AllCnt; i++) { + XAXIDMA_CACHE_INVALIDATE(AddrV); + /* Check next pointer for this BD. It should equal to the + * physical address of next BD + */ + if (XAxiDma_BdRead(AddrV, XAXIDMA_BD_NDESC_OFFSET) != AddrP) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCheck: Next Bd " + "ptr %x wrong, expect %x\r\n", + (unsigned int)XAxiDma_BdRead(AddrV, + XAXIDMA_BD_NDESC_OFFSET), + (unsigned int)AddrP); + + return XST_DMA_SG_LIST_ERROR; + } + + /* Move on to next BD */ + AddrV += RingPtr->Separation; + AddrP += RingPtr->Separation; + } + + XAXIDMA_CACHE_INVALIDATE(AddrV); + /* Last BD should point back to the beginning of ring */ + if (XAxiDma_BdRead(AddrV, XAXIDMA_BD_NDESC_OFFSET) != + RingPtr->FirstBdPhysAddr) { + + xdbg_printf(XDBG_DEBUG_ERROR, "BdRingCheck: last Bd Next BD " + "ptr %x wrong, expect %x\r\n", + (unsigned int)XAxiDma_BdRead(AddrV, + XAXIDMA_BD_NDESC_OFFSET), + (unsigned int)RingPtr->FirstBdPhysAddr); + + return XST_DMA_SG_LIST_ERROR; + } + + /* No problems found */ + return XST_SUCCESS; +} +/*****************************************************************************/ +/** + * Dump the registers for a channel. + * + * @param RingPtr is a pointer to the descriptor ring to be worked on. + * + * @return None + * + * @note This function can be used only when DMA is in SG mode + * + *****************************************************************************/ +void XAxiDma_BdRingDumpRegs(XAxiDma_BdRing *RingPtr) { + u32 RegBase = RingPtr->ChanBase; + int RingIndex = RingPtr->RingIndex; + + xil_printf("Dump registers %x:\r\n", (unsigned int)RegBase); + xil_printf("Control REG: %08x\r\n", + (unsigned int)XAxiDma_ReadReg(RegBase, XAXIDMA_CR_OFFSET)); + xil_printf("Status REG: %08x\r\n", + (unsigned int)XAxiDma_ReadReg(RegBase, XAXIDMA_SR_OFFSET)); + + if (RingIndex) { + xil_printf("Cur BD REG: %08x\r\n", + (unsigned int)XAxiDma_ReadReg(RegBase, + XAXIDMA_RX_CDESC0_OFFSET + ((RingIndex - 1) * + XAXIDMA_RX_NDESC_OFFSET))); + xil_printf("Tail BD REG: %08x\r\n", + (unsigned int)XAxiDma_ReadReg(RegBase, + XAXIDMA_RX_TDESC0_OFFSET + ((RingIndex - 1) * + XAXIDMA_RX_NDESC_OFFSET))); + } + else { + xil_printf("Cur BD REG: %08x\r\n", + (unsigned int)XAxiDma_ReadReg(RegBase, XAXIDMA_CDESC_OFFSET)); + xil_printf("Tail BD REG: %08x\r\n", + (unsigned int)XAxiDma_ReadReg(RegBase, XAXIDMA_TDESC_OFFSET)); + } + + xil_printf("\r\n"); +} diff --git a/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_bdring.h b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_bdring.h new file mode 100644 index 00000000..c50558ef --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_bdring.h @@ -0,0 +1,522 @@ +/****************************************************************************** +* +* 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 xaxidma_bdring.h +* +* This file contains DMA channel related structure and constant definition +* as well as function prototypes. Each DMA channel is managed by a Buffer +* Descriptor ring, and XAxiDma_BdRing is chosen as the symbol prefix used in +* this file. See xaxidma.h for more information on how a BD ring is managed. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a jz   05/18/10 First release
+* 2.00a jz   08/10/10 Second release, added in xaxidma_g.c, xaxidma_sinit.c,
+*                     updated tcl file, added xaxidma_porting_guide.h
+* 3.00a jz   11/22/10 Support IP core parameters change
+* 6.00a srt  01/24/12 Added support for Multi-Channel DMA.
+*		      - New API
+*			* XAxiDma_UpdateBdRingCDesc(XAxiDma_BdRing * RingPtr,
+*						int RingIndex)
+*		      - Changed APIs
+*			* XAxiDma_StartBdRingHw(XAxiDma_BdRing * RingPtr,
+*					int RingIndex)
+*			* XAxiDma_BdRingStart(XAxiDma_BdRing * RingPtr,
+*						 int RingIndex)
+*			* XAxiDma_BdRingToHw(XAxiDma_BdRing * RingPtr,
+*        			int NumBd, XAxiDma_Bd * BdSetPtr, int RingIndex)
+*			* XAxiDma_BdRingDumpRegs(XAxiDma_BdRing * RingPtr,
+*						 int RingIndex)
+*			* XAxiDma_BdRingSnapShotCurrBd(XAxiDma_BdRing * RingPtr,
+*						 int RingIndex)
+* 7.00a srt  06/18/12  All the APIs changed in v6_00_a are reverted back for
+*		       backward compatibility.
+*
+*
+* 
+* +******************************************************************************/ + +#ifndef XAXIDMA_BDRING_H_ /* prevent circular inclusions */ +#define XAXIDMA_BDRING_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************** Include Files *********************************/ + +#include "xstatus.h" +#include "xaxidma_bd.h" + + + +/************************** Constant Definitions *****************************/ +/* State of a DMA channel + */ +#define AXIDMA_CHANNEL_NOT_HALTED 1 +#define AXIDMA_CHANNEL_HALTED 2 + +/* Argument constant to simplify argument setting + */ +#define XAXIDMA_NO_CHANGE 0xFFFFFFFF +#define XAXIDMA_ALL_BDS 0x0FFFFFFF /* 268 Million */ + +/**************************** Type Definitions *******************************/ + +/** Container structure for descriptor storage control. If address translation + * is enabled, then all addresses and pointers excluding FirstBdPhysAddr are + * expressed in terms of the virtual address. + */ +typedef struct { + u32 ChanBase; /**< physical base address*/ + + int IsRxChannel; /**< Is this a receive channel */ + volatile int RunState; /**< Whether channel is running */ + int HasStsCntrlStrm; /**< Whether has stscntrl stream */ + int HasDRE; + int DataWidth; + u32 MaxTransferLen; + + u32 FirstBdPhysAddr; /**< Physical address of 1st BD in list */ + u32 FirstBdAddr; /**< Virtual address of 1st BD in list */ + u32 LastBdAddr; /**< Virtual address of last BD in the list */ + u32 Length; /**< Total size of ring in bytes */ + u32 Separation; /**< Number of bytes between the starting + address of adjacent BDs */ + XAxiDma_Bd *FreeHead; /**< First BD in the free group */ + XAxiDma_Bd *PreHead; /**< First BD in the pre-work group */ + XAxiDma_Bd *HwHead; /**< First BD in the work group */ + XAxiDma_Bd *HwTail; /**< Last BD in the work group */ + XAxiDma_Bd *PostHead; /**< First BD in the post-work group */ + XAxiDma_Bd *BdaRestart; /**< BD to load when channel is started */ + int FreeCnt; /**< Number of allocatable BDs in free group */ + int PreCnt; /**< Number of BDs in pre-work group */ + int HwCnt; /**< Number of BDs in work group */ + int PostCnt; /**< Number of BDs in post-work group */ + int AllCnt; /**< Total Number of BDs for channel */ + int RingIndex; /**< Ring Index */ +} XAxiDma_BdRing; + +/***************** Macros (Inline Functions) Definitions *********************/ + +/*****************************************************************************/ +/** +* Use this macro at initialization time to determine how many BDs will fit +* within the given memory constraints. +* +* The results of this macro can be provided to XAxiDma_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, 126,...) +* @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: +* int XAxiDma_BdRingCntCalc(u32 Alignment, u32 Bytes) +* This function is used only when system is configured as SG mode +* +******************************************************************************/ +#define XAxiDma_BdRingCntCalc(Alignment, Bytes) \ + (int)((Bytes)/((sizeof(XAxiDma_Bd)+((Alignment)-1))&~((Alignment)-1))) + +/*****************************************************************************/ +/** +* Use this macro at initialization time to determine how many bytes of memory +* are 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 +* +* @return The number of bytes of memory required to create a BD list +* with the given memory constraints. +* +* @note +* C-style signature: +* int XAxiDma_BdRingMemCalc(u32 Alignment, u32 NumBd) +* This function is used only when system is configured as SG mode +* +******************************************************************************/ +#define XAxiDma_BdRingMemCalc(Alignment, NumBd) \ + (int)((sizeof(XAxiDma_Bd)+((Alignment)-1)) & ~((Alignment)-1))*(NumBd) + +/****************************************************************************/ +/** +* Return the total number of BDs allocated by this channel with +* XAxiDma_BdRingCreate(). +* +* @param RingPtr is the BD ring to operate on. +* +* @return The total number of BDs allocated for this channel. +* +* @note +* C-style signature: +* int XAxiDma_BdRingGetCnt(XAxiDma_BdRing* RingPtr) +* This function is used only when system is configured as SG mode +* +*****************************************************************************/ +#define XAxiDma_BdRingGetCnt(RingPtr) ((RingPtr)->AllCnt) + +/****************************************************************************/ +/** +* Return the number of BDs allocatable with XAxiDma_BdRingAlloc() for pre- +* processing. +* +* @param RingPtr is the BD ring to operate on. +* +* @return The number of BDs currently allocatable. +* +* @note +* C-style signature: +* int XAxiDma_BdRingGetFreeCnt(XAxiDma_BdRing* RingPtr) +* This function is used only when system is configured as SG mode +* +*****************************************************************************/ +#define XAxiDma_BdRingGetFreeCnt(RingPtr) ((RingPtr)->FreeCnt) + + +/****************************************************************************/ +/** +* Snap shot the latest BD a BD ring is processing. +* +* @param RingPtr is the BD ring to operate on. +* +* @return None +* +* @note +* C-style signature: +* void XAxiDma_BdRingSnapShotCurrBd(XAxiDma_BdRing* RingPtr) +* This function is used only when system is configured as SG mode +* +*****************************************************************************/ +#define XAxiDma_BdRingSnapShotCurrBd(RingPtr) \ + { \ + if (!RingPtr->IsRxChannel) { \ + (RingPtr)->BdaRestart = \ + (XAxiDma_Bd *)XAxiDma_ReadReg((RingPtr)->ChanBase, \ + XAXIDMA_CDESC_OFFSET); \ + } else { \ + if (!RingPtr->RingIndex) { \ + (RingPtr)->BdaRestart = \ + (XAxiDma_Bd *)XAxiDma_ReadReg( \ + (RingPtr)->ChanBase, \ + XAXIDMA_CDESC_OFFSET); \ + } else { \ + (RingPtr)->BdaRestart = \ + (XAxiDma_Bd *)XAxiDma_ReadReg( \ + (RingPtr)->ChanBase, \ + (XAXIDMA_RX_CDESC0_OFFSET + \ + (RingPtr->RingIndex - 1) * \ + XAXIDMA_RX_NDESC_OFFSET)); \ + } \ + } \ + } + +/****************************************************************************/ +/** +* Get the BD a BD ring is processing. +* +* @param RingPtr is the BD ring to operate on. +* +* @return The current BD that the BD ring is working on +* +* @note +* C-style signature: +* XAxiDma_Bd * XAxiDma_BdRingGetCurrBd(XAxiDma_BdRing* RingPtr) +* This function is used only when system is configured as SG mode +* +*****************************************************************************/ +#define XAxiDma_BdRingGetCurrBd(RingPtr) \ + (XAxiDma_Bd *)XAxiDma_ReadReg((RingPtr)->ChanBase, \ + XAXIDMA_CDESC_OFFSET) \ + +/****************************************************************************/ +/** +* Return the next BD in the ring. +* +* @param RingPtr is the BD ring to operate on. +* @param BdPtr is the current BD. +* +* @return The next BD in the ring relative to the BdPtr parameter. +* +* @note +* C-style signature: +* XAxiDma_Bd *XAxiDma_BdRingNext(XAxiDma_BdRing* RingPtr, +* XAxiDma_Bd *BdPtr) +* This function is used only when system is configured as SG mode +* +*****************************************************************************/ +#define XAxiDma_BdRingNext(RingPtr, BdPtr) \ + (((u32)(BdPtr) >= (RingPtr)->LastBdAddr) ? \ + (XAxiDma_Bd*)(RingPtr)->FirstBdAddr : \ + (XAxiDma_Bd*)((u32)(BdPtr) + (RingPtr)->Separation)) + +/****************************************************************************/ +/** +* Return the previous BD in the ring. +* +* @param RingPtr is the DMA channel to operate on. +* @param BdPtr is the current BD. +* +* @return The previous BD in the ring relative to the BdPtr parameter. +* +* @note +* C-style signature: +* XAxiDma_Bd *XAxiDma_BdRingPrev(XAxiDma_BdRing* RingPtr, +* XAxiDma_Bd *BdPtr) +* This function is used only when system is configured as SG mode +* +*****************************************************************************/ +#define XAxiDma_BdRingPrev(RingPtr, BdPtr) \ + (((u32)(BdPtr) <= (RingPtr)->FirstBdAddr) ? \ + (XAxiDma_Bd*)(RingPtr)->LastBdAddr : \ + (XAxiDma_Bd*)((u32)(BdPtr) - (RingPtr)->Separation)) + +/****************************************************************************/ +/** +* Retrieve the contents of the channel status register +* +* @param RingPtr is the channel instance to operate on. +* +* @return Current contents of status register +* +* @note +* C-style signature: +* u32 XAxiDma_BdRingGetSr(XAxiDma_BdRing* RingPtr) +* This function is used only when system is configured as SG mode +* +*****************************************************************************/ +#define XAxiDma_BdRingGetSr(RingPtr) \ + XAxiDma_ReadReg((RingPtr)->ChanBase, XAXIDMA_SR_OFFSET) + +/****************************************************************************/ +/** +* Get error bits of a DMA channel +* +* @param RingPtr is the channel instance to operate on. +* +* @return Rrror bits in the status register, they should be interpreted +* with XAXIDMA_ERR_*_MASK defined in xaxidma_hw.h +* +* @note +* C-style signature: +* u32 XAxiDma_BdRingGetError(XAxiDma_BdRing* RingPtr) +* This function is used only when system is configured as SG mode +* +*****************************************************************************/ +#define XAxiDma_BdRingGetError(RingPtr) \ + (XAxiDma_ReadReg((RingPtr)->ChanBase, XAXIDMA_SR_OFFSET) \ + & XAXIDMA_ERR_ALL_MASK) + +/****************************************************************************/ +/** +* Check whether a DMA channel is started, meaning the channel is not halted. +* +* @param RingPtr is the channel instance to operate on. +* +* @return +* - 1 if channel is started +* - 0 otherwise +* +* @note +* C-style signature: +* int XAxiDma_BdRingHwIsStarted(XAxiDma_BdRing* RingPtr) +* +*****************************************************************************/ +#define XAxiDma_BdRingHwIsStarted(RingPtr) \ + ((XAxiDma_ReadReg((RingPtr)->ChanBase, XAXIDMA_SR_OFFSET) \ + & XAXIDMA_HALTED_MASK) ? FALSE : TRUE) + +/****************************************************************************/ +/** +* Check if the current DMA channel is busy with a DMA operation. +* +* @param RingPtr is the channel instance to operate on. +* +* @return +* - 1 if the DMA is busy. +* - 0 otherwise +* +* @note +* C-style signature: +* int XAxiDma_BdRingBusy(XAxiDma_BdRing* RingPtr) +* This function is used only when system is configured as SG mode +* +*****************************************************************************/ +#define XAxiDma_BdRingBusy(RingPtr) \ + (XAxiDma_BdRingHwIsStarted(RingPtr) && \ + ((XAxiDma_ReadReg((RingPtr)->ChanBase, XAXIDMA_SR_OFFSET) \ + & XAXIDMA_IDLE_MASK) ? FALSE : TRUE)) + +/****************************************************************************/ +/** +* Set interrupt enable bits for a channel. This operation will modify the +* XAXIDMA_CR_OFFSET register. +* +* @param RingPtr is the channel instance to operate on. +* @param Mask consists of the interrupt signals to enable.Bits not +* specified in the mask are not affected. +* +* @note +* C-style signature: +* void XAxiDma_BdRingIntEnable(XAxiDma_BdRing* RingPtr, u32 Mask) +* This function is used only when system is configured as SG mode +* +*****************************************************************************/ +#define XAxiDma_BdRingIntEnable(RingPtr, Mask) \ + (XAxiDma_WriteReg((RingPtr)->ChanBase, XAXIDMA_CR_OFFSET, \ + XAxiDma_ReadReg((RingPtr)->ChanBase, XAXIDMA_CR_OFFSET) \ + | ((Mask) & XAXIDMA_IRQ_ALL_MASK))) + +/****************************************************************************/ +/** +* Get enabled interrupts of a channel. It is in XAXIDMA_CR_OFFSET register. +* +* @param RingPtr is the channel instance to operate on. +* @return Enabled interrupts of a channel. Use XAXIDMA_IRQ_* defined in +* xaxidma_hw.h to interpret this returned value. +* +* @note +* C-style signature: +* u32 XAxiDma_BdRingIntGetEnabled(XAxiDma_BdRing* RingPtr) +* This function is used only when system is configured as SG mode +* +*****************************************************************************/ +#define XAxiDma_BdRingIntGetEnabled(RingPtr) \ + (XAxiDma_ReadReg((RingPtr)->ChanBase, XAXIDMA_CR_OFFSET) \ + & XAXIDMA_IRQ_ALL_MASK) + +/****************************************************************************/ +/** +* Clear interrupt enable bits for a channel. It modifies the +* XAXIDMA_CR_OFFSET register. +* +* @param RingPtr is the channel instance to operate on. +* @param Mask consists of the interrupt signals to disable.Bits not +* specified in the Mask are not affected. +* +* @note +* C-style signature: +* void XAxiDma_BdRingIntDisable(XAxiDma_BdRing* RingPtr, +* u32 Mask) +* This function is used only when system is configured as SG mode +* +*****************************************************************************/ +#define XAxiDma_BdRingIntDisable(RingPtr, Mask) \ + (XAxiDma_WriteReg((RingPtr)->ChanBase, XAXIDMA_CR_OFFSET, \ + XAxiDma_ReadReg((RingPtr)->ChanBase, XAXIDMA_CR_OFFSET) & \ + ~((Mask) & XAXIDMA_IRQ_ALL_MASK))) + +/****************************************************************************/ +/** +* Retrieve the contents of the channel's IRQ register XAXIDMA_SR_OFFSET. This +* operation can be used to see which interrupts are pending. +* +* @param RingPtr is the channel instance to operate on. +* +* @return Current contents of the IRQ_OFFSET register. Use +* XAXIDMA_IRQ_*** values defined in xaxidma_hw.h to interpret +* the returned value. +* +* @note +* C-style signature: +* u32 XAxiDma_BdRingGetIrq(XAxiDma_BdRing* RingPtr) +* This function is used only when system is configured as SG mode +* +*****************************************************************************/ +#define XAxiDma_BdRingGetIrq(RingPtr) \ + (XAxiDma_ReadReg((RingPtr)->ChanBase, XAXIDMA_SR_OFFSET) \ + & XAXIDMA_IRQ_ALL_MASK) + +/****************************************************************************/ +/** +* Acknowledge asserted interrupts. It modifies XAXIDMA_SR_OFFSET register. +* A mask bit set for an unasserted interrupt has no effect. +* +* @param RingPtr is the channel instance to operate on. +* @param Mask are the interrupt signals to acknowledge +* +* @note +* C-style signature: +* void XAxiDma_BdRingAckIrq(XAxiDma_BdRing* RingPtr) +* This function is used only when system is configured as SG mode +* +*****************************************************************************/ +#define XAxiDma_BdRingAckIrq(RingPtr, Mask) \ + XAxiDma_WriteReg((RingPtr)->ChanBase, XAXIDMA_SR_OFFSET,\ + (Mask) & XAXIDMA_IRQ_ALL_MASK) + +/************************* Function Prototypes ******************************/ + +/* + * Descriptor ring functions xaxidma_bdring.c + */ +int XAxiDma_StartBdRingHw(XAxiDma_BdRing* RingPtr); +int XAxiDma_UpdateBdRingCDesc(XAxiDma_BdRing* RingPtr); +int XAxiDma_BdRingCreate(XAxiDma_BdRing * RingPtr, u32 PhysAddr, + u32 VirtAddr, u32 Alignment, int BdCount); +int XAxiDma_BdRingClone(XAxiDma_BdRing * RingPtr, XAxiDma_Bd * SrcBdPtr); +int XAxiDma_BdRingAlloc(XAxiDma_BdRing * RingPtr, int NumBd, + XAxiDma_Bd ** BdSetPtr); +int XAxiDma_BdRingUnAlloc(XAxiDma_BdRing * RingPtr, int NumBd, + XAxiDma_Bd * BdSetPtr); +int XAxiDma_BdRingToHw(XAxiDma_BdRing * RingPtr, int NumBd, + XAxiDma_Bd * BdSetPtr); +int XAxiDma_BdRingFromHw(XAxiDma_BdRing * RingPtr, int BdLimit, + XAxiDma_Bd ** BdSetPtr); +int XAxiDma_BdRingFree(XAxiDma_BdRing * RingPtr, int NumBd, + XAxiDma_Bd * BdSetPtr); +int XAxiDma_BdRingStart(XAxiDma_BdRing * RingPtr); +int XAxiDma_BdRingSetCoalesce(XAxiDma_BdRing * RingPtr, u32 Counter, u32 Timer); +void XAxiDma_BdRingGetCoalesce(XAxiDma_BdRing * RingPtr, + u32 *CounterPtr, u32 *TimerPtr); + +/* The following functions are for debug only + */ +int XAxiDma_BdRingCheck(XAxiDma_BdRing * RingPtr); +void XAxiDma_BdRingDumpRegs(XAxiDma_BdRing *RingPtr); +#ifdef __cplusplus +} +#endif + +#endif /* end of protection macro */ diff --git a/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_g.c b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_g.c new file mode 100644 index 00000000..202bcf84 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_g.c @@ -0,0 +1,83 @@ +/****************************************************************************** +* +* 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 xaxidma_g.c +* +* Provide a template for user to define their own hardware settings. +* +* If using XPS, then XPS will automatically generate this file. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a jz   08/16/10 First release
+* 2.00a jz   08/10/10 Second release, added in xaxidma_g.c, xaxidma_sinit.c,
+*                     updated tcl file, added xaxidma_porting_guide.h
+* 3.00a jz   11/22/10 Support IP core parameters change
+* 4.00a rkv  02/22/11 Added support for simple DMA mode
+* 6.00a srt  01/24/12 Added support for Multi-Channel DMA mode
+* 7.02a srt  01/23/13 Replaced *_TDATA_WIDTH parameters to *_DATA_WIDTH
+*		      (CR 691867)
+*
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xaxidma.h" + +/************************** Constant Definitions *****************************/ +#define XPAR_AXIDMA_0_INCLUDE_SG 0 + +XAxiDma_Config XAxiDma_ConfigTable[] = +{ + { + XPAR_AXIDMA_0_DEVICE_ID, + XPAR_AXIDMA_0_BASEADDR, + XPAR_AXIDMA_0_SG_INCLUDE_STSCNTRL_STRM, + XPAR_AXIDMA_0_INCLUDE_MM2S, + XPAR_AXIDMA_0_INCLUDE_MM2S_DRE, + XPAR_AXIDMA_0_M_AXI_MM2S_DATA_WIDTH, + XPAR_AXIDMA_0_INCLUDE_S2MM, + XPAR_AXIDMA_0_INCLUDE_S2MM_DRE, + XPAR_AXIDMA_0_M_AXI_S2MM_DATA_WIDTH, + XPAR_AXIDMA_0_INCLUDE_SG, + XPAR_AXIDMA_0_NUM_MM2S_CHANNELS, + XPAR_AXIDMA_0_NUM_S2MM_CHANNELS + } +}; diff --git a/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_hw.h b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_hw.h new file mode 100644 index 00000000..8386f3b3 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_hw.h @@ -0,0 +1,331 @@ +/****************************************************************************** +* +* 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 xaxidma_hw.h + * + * Hardware definition file. It defines the register interface and Buffer + * Descriptor (BD) definitions. + * + *
+ * MODIFICATION HISTORY:
+ *
+ * Ver   Who  Date     Changes
+ * ----- ---- -------- -------------------------------------------------------
+ * 1.00a jz   05/18/10 First release
+ * 2.00a jz   08/10/10 Second release, added in xaxidma_g.c, xaxidma_sinit.c,
+ *                     updated tcl file, added xaxidma_porting_guide.h
+ * 3.00a jz   11/22/10 Support IP core parameters change
+ * 4.00a rkv  02/22/11 Added support for simple DMA mode
+ * 6.00a srt  01/24/12 Added support for Multi-Channel DMA mode
+ * 8.0   srt  01/29/14 Added support for Micro DMA Mode and Cyclic mode of
+ *		       operations.
+ *
+ * 
+ * + *****************************************************************************/ + +#ifndef XAXIDMA_HW_H_ /* prevent circular inclusions */ +#define XAXIDMA_HW_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "xil_types.h" +#include "xil_io.h" + +/************************** Constant Definitions *****************************/ + +/** @name DMA Transfer Direction + * @{ + */ +#define XAXIDMA_DMA_TO_DEVICE 0x00 +#define XAXIDMA_DEVICE_TO_DMA 0x01 + + +/** @name Buffer Descriptor Alignment + * @{ + */ +#define XAXIDMA_BD_MINIMUM_ALIGNMENT 0x40 /**< Minimum byte alignment + requirement for descriptors to + satisfy both hardware/software + needs */ +/*@}*/ + +/** @name Micro DMA Buffer Address Alignment + * @{ + */ +#define XAXIDMA_MICROMODE_MIN_BUF_ALIGN 0xFFF /**< Minimum byte alignment + requirement for buffer address + in Micro DMA mode */ +/*@}*/ + +/** @name Maximum transfer length + * This is determined by hardware + * @{ + */ +#define XAXIDMA_MAX_TRANSFER_LEN 0x7FFFFF /* Max length hw supports */ +#define XAXIDMA_MCHAN_MAX_TRANSFER_LEN 0x00FFFF /* Max length MCDMA + hw supports */ +/*@}*/ + +/* Register offset definitions. Register accesses are 32-bit. + */ +/** @name Device registers + * Register sets on TX and RX channels are identical + * @{ + */ +#define XAXIDMA_TX_OFFSET 0x00000000 /**< TX channel registers base + * offset */ +#define XAXIDMA_RX_OFFSET 0x00000030 /**< RX channel registers base + * offset */ + +/* This set of registers are applicable for both channels. Add + * XAXIDMA_TX_OFFSET to get to TX channel, and XAXIDMA_RX_OFFSET to get to RX + * channel + */ +#define XAXIDMA_CR_OFFSET 0x00000000 /**< Channel control */ +#define XAXIDMA_SR_OFFSET 0x00000004 /**< Status */ +#define XAXIDMA_CDESC_OFFSET 0x00000008 /**< Current descriptor pointer */ +#define XAXIDMA_TDESC_OFFSET 0x00000010 /**< Tail descriptor pointer */ +#define XAXIDMA_SRCADDR_OFFSET 0x00000018 /**< Simple mode source address + pointer */ +#define XAXIDMA_DESTADDR_OFFSET 0x00000018 /**< Simple mode destination address pointer */ +#define XAXIDMA_BUFFLEN_OFFSET 0x00000028 /**< Tail descriptor pointer */ +#define XAXIDMA_SGCTL_OFFSET 0x0000002c /**< SG Control Register */ + +/** Multi-Channel DMA Descriptor Offsets **/ +#define XAXIDMA_RX_CDESC0_OFFSET 0x00000040 /**< Rx Current Descriptor 0 */ +#define XAXIDMA_RX_TDESC0_OFFSET 0x00000048 /**< Rx Tail Descriptor 0 */ +#define XAXIDMA_RX_NDESC_OFFSET 0x00000020 /**< Rx Next Descriptor Offset */ +/*@}*/ + +/** @name Bitmasks of XAXIDMA_CR_OFFSET register + * @{ + */ +#define XAXIDMA_CR_RUNSTOP_MASK 0x00000001 /**< Start/stop DMA channel */ +#define XAXIDMA_CR_RESET_MASK 0x00000004 /**< Reset DMA engine */ +#define XAXIDMA_CR_KEYHOLE_MASK 0x00000008 /**< Keyhole feature */ +#define XAXIDMA_CR_CYCLIC_MASK 0x00000010 /**< Cyclic Mode */ +/*@}*/ + +/** @name Bitmasks of XAXIDMA_SR_OFFSET register + * + * This register reports status of a DMA channel, including + * run/stop/idle state, errors, and interrupts (note that interrupt + * masks are shared with XAXIDMA_CR_OFFSET register, and are defined + * in the _IRQ_ section. + * + * The interrupt coalescing threshold value and delay counter value are + * also shared with XAXIDMA_CR_OFFSET register, and are defined in a + * later section. + * @{ + */ +#define XAXIDMA_HALTED_MASK 0x00000001 /**< DMA channel halted */ +#define XAXIDMA_IDLE_MASK 0x00000002 /**< DMA channel idle */ +#define XAXIDMA_ERR_INTERNAL_MASK 0x00000010 /**< Datamover internal + * err */ +#define XAXIDMA_ERR_SLAVE_MASK 0x00000020 /**< Datamover slave err */ +#define XAXIDMA_ERR_DECODE_MASK 0x00000040 /**< Datamover decode + * err */ +#define XAXIDMA_ERR_SG_INT_MASK 0x00000100 /**< SG internal err */ +#define XAXIDMA_ERR_SG_SLV_MASK 0x00000200 /**< SG slave err */ +#define XAXIDMA_ERR_SG_DEC_MASK 0x00000400 /**< SG decode err */ +#define XAXIDMA_ERR_ALL_MASK 0x00000770 /**< All errors */ + +/** @name Bitmask for interrupts + * These masks are shared by XAXIDMA_CR_OFFSET register and + * XAXIDMA_SR_OFFSET register + * @{ + */ +#define XAXIDMA_IRQ_IOC_MASK 0x00001000 /**< Completion intr */ +#define XAXIDMA_IRQ_DELAY_MASK 0x00002000 /**< Delay interrupt */ +#define XAXIDMA_IRQ_ERROR_MASK 0x00004000 /**< Error interrupt */ +#define XAXIDMA_IRQ_ALL_MASK 0x00007000 /**< All interrupts */ +/*@}*/ + +/** @name Bitmask and shift for delay and coalesce + * These masks are shared by XAXIDMA_CR_OFFSET register and + * XAXIDMA_SR_OFFSET register + * @{ + */ +#define XAXIDMA_DELAY_MASK 0xFF000000 /**< Delay timeout + * counter */ +#define XAXIDMA_COALESCE_MASK 0x00FF0000 /**< Coalesce counter */ + +#define XAXIDMA_DELAY_SHIFT 24 +#define XAXIDMA_COALESCE_SHIFT 16 +/*@}*/ + + +/* Buffer Descriptor (BD) definitions + */ + +/** @name Buffer Descriptor offsets + * USR* fields are defined by higher level IP. + * setup for EMAC type devices. The first 13 words are used by hardware. + * All words after the 13rd word are for software use only. + * @{ + */ +#define XAXIDMA_BD_NDESC_OFFSET 0x00 /**< Next descriptor pointer */ +#define XAXIDMA_BD_BUFA_OFFSET 0x08 /**< Buffer address */ +#define XAXIDMA_BD_MCCTL_OFFSET 0x10 /**< Multichannel Control Fields */ +#define XAXIDMA_BD_STRIDE_VSIZE_OFFSET 0x14 /**< 2D Transfer Sizes */ +#define XAXIDMA_BD_CTRL_LEN_OFFSET 0x18 /**< Control/buffer length */ +#define XAXIDMA_BD_STS_OFFSET 0x1C /**< Status */ + +#define XAXIDMA_BD_USR0_OFFSET 0x20 /**< User IP specific word0 */ +#define XAXIDMA_BD_USR1_OFFSET 0x24 /**< User IP specific word1 */ +#define XAXIDMA_BD_USR2_OFFSET 0x28 /**< User IP specific word2 */ +#define XAXIDMA_BD_USR3_OFFSET 0x2C /**< User IP specific word3 */ +#define XAXIDMA_BD_USR4_OFFSET 0x30 /**< User IP specific word4 */ + +#define XAXIDMA_BD_ID_OFFSET 0x34 /**< Sw ID */ +#define XAXIDMA_BD_HAS_STSCNTRL_OFFSET 0x38 /**< Whether has stscntrl strm */ +#define XAXIDMA_BD_HAS_DRE_OFFSET 0x3C /**< Whether has DRE */ + +#define XAXIDMA_BD_HAS_DRE_MASK 0xF00 /**< Whether has DRE mask */ +#define XAXIDMA_BD_WORDLEN_MASK 0xFF /**< Whether has DRE mask */ + +#define XAXIDMA_BD_HAS_DRE_SHIFT 8 /**< Whether has DRE shift */ +#define XAXIDMA_BD_WORDLEN_SHIFT 0 /**< Whether has DRE shift */ + +#define XAXIDMA_BD_START_CLEAR 8 /**< Offset to start clear */ +#define XAXIDMA_BD_BYTES_TO_CLEAR 48 /**< BD specific bytes to be + * cleared */ + +#define XAXIDMA_BD_NUM_WORDS 16 /**< Total number of words for + * one BD*/ +#define XAXIDMA_BD_HW_NUM_BYTES 52 /**< Number of bytes hw used */ + +/* The offset of the last app word. + */ +#define XAXIDMA_LAST_APPWORD 4 + +/*@}*/ + + +/** @name Bitmasks of XAXIDMA_BD_CTRL_OFFSET register + * @{ + */ +#define XAXIDMA_BD_CTRL_TXSOF_MASK 0x08000000 /**< First tx packet */ +#define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000 /**< Last tx packet */ +#define XAXIDMA_BD_CTRL_ALL_MASK 0x0C000000 /**< All control bits */ +/*@}*/ + +/** @name Bitmasks of XAXIDMA_BD_STS_OFFSET register + * @{ + */ +#define XAXIDMA_BD_STS_COMPLETE_MASK 0x80000000 /**< Completed */ +#define XAXIDMA_BD_STS_DEC_ERR_MASK 0x40000000 /**< Decode error */ +#define XAXIDMA_BD_STS_SLV_ERR_MASK 0x20000000 /**< Slave error */ +#define XAXIDMA_BD_STS_INT_ERR_MASK 0x10000000 /**< Internal err */ +#define XAXIDMA_BD_STS_ALL_ERR_MASK 0x70000000 /**< All errors */ +#define XAXIDMA_BD_STS_RXSOF_MASK 0x08000000 /**< First rx pkt */ +#define XAXIDMA_BD_STS_RXEOF_MASK 0x04000000 /**< Last rx pkt */ +#define XAXIDMA_BD_STS_ALL_MASK 0xFC000000 /**< All status bits */ +/*@}*/ + +/** @name Bitmasks and shift values for XAXIDMA_BD_MCCTL_OFFSET register + * @{ + */ +#define XAXIDMA_BD_TDEST_FIELD_MASK 0x0000000F +#define XAXIDMA_BD_TID_FIELD_MASK 0x00000F00 +#define XAXIDMA_BD_TUSER_FIELD_MASK 0x000F0000 +#define XAXIDMA_BD_ARCACHE_FIELD_MASK 0x0F000000 +#define XAXIDMA_BD_ARUSER_FIELD_MASK 0xF0000000 + +#define XAXIDMA_BD_TDEST_FIELD_SHIFT 0 +#define XAXIDMA_BD_TID_FIELD_SHIFT 8 +#define XAXIDMA_BD_TUSER_FIELD_SHIFT 16 +#define XAXIDMA_BD_ARCACHE_FIELD_SHIFT 24 +#define XAXIDMA_BD_ARUSER_FIELD_SHIFT 28 + +/** @name Bitmasks and shift values for XAXIDMA_BD_STRIDE_VSIZE_OFFSET register + * @{ + */ +#define XAXIDMA_BD_STRIDE_FIELD_MASK 0x0000FFFF +#define XAXIDMA_BD_VSIZE_FIELD_MASK 0xFFF80000 + +#define XAXIDMA_BD_STRIDE_FIELD_SHIFT 0 +#define XAXIDMA_BD_VSIZE_FIELD_SHIFT 19 + +/**************************** Type Definitions *******************************/ + +/***************** Macros (Inline Functions) Definitions *********************/ + +#define XAxiDma_In32 Xil_In32 +#define XAxiDma_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 XAxiDma_ReadReg(u32 BaseAddress, u32 RegOffset) +* +******************************************************************************/ +#define XAxiDma_ReadReg(BaseAddress, RegOffset) \ + XAxiDma_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 XAxiDma_WriteReg(u32 BaseAddress, u32 RegOffset, u32 Data) +* +******************************************************************************/ +#define XAxiDma_WriteReg(BaseAddress, RegOffset, Data) \ + XAxiDma_Out32((BaseAddress) + (RegOffset), (Data)) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_porting_guide.h b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_porting_guide.h new file mode 100644 index 00000000..ff764a32 --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_porting_guide.h @@ -0,0 +1,251 @@ +/****************************************************************************** +* +* 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 xaxidma_porting_guide.h +* +* This is a guide on how to move from using the xlldma driver to use xaxidma +* driver. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a jz   05/18/10 First release
+* 2.00a jz   08/10/10 Second release, added in xaxidma_g.c, xaxidma_sinit.c,
+*                     updated tcl file, added xaxidma_porting_guide.h
+* 4.00a rkv  02/22/11 Added support for simple DMA mode
+* 6.00a srt  03/27/12 Added support for MCDMA mode
+* 7.00a srt  06/18/12 API calls are reverted back for backward compatibility.
+*
+* 
+* +* Overview +* +* The API for xaxidma driver is similar to xlldma driver. The prefix for the +* API functions and structures is XAxiDma_ for the xaxidma driver. +* +* Due to hardware feature changes, signatures of some API functions are a +* little bit different from the xlldma API functions. +* +* We present API functions: +* - That only have prefix changes +* - That have different return type +* - That are new API functions +* - That have been removed +* +* Note that data structures have different prefix of XAxiDma_. Those API +* functions, that have data structures with prefix change, are considered as +* prefix change. +* +* API Functions That Only Have Prefix Changes +* +*
+*         xlldma driver              |         xaxidma driver (upto v5_00_a)
+* -----------------------------------------------------------------------
+*    XLlDma_Reset(...)               |  XAxiDma_Reset(...)
+*    XLlDma_BdRingSnapShotCurrBd(...)|  XAxiDma_BdRingSnapShotCurrBd(...)
+*    XLlDma_BdRingNext(...)          |  XAxiDma_BdRingNext(...)
+*    XLlDma_BdRingPrev(...)          |  XAxiDma_BdRingPrev(...)
+*    XLlDma_BdRingGetSr(...)         |  XAxiDma_BdRingGetSr(...)
+*    XLlDma_BdRingBusy(...)          |  XAxiDma_BdRingBusy(...)
+*    XLlDma_BdRingIntEnable(...)     |  XAxiDma_BdRingIntEnable(...)
+*    XLlDma_BdRingIntDisable(...)    |  XAxiDma_BdRingIntDisable(...)
+*    XLlDma_BdRingIntGetEnabled(...) |  XAxiDma_BdRingIntGetEnabled(...)
+*    XLlDma_BdRingGetIrq(...)        |  XAxiDma_BdRingGetIrq(...)
+*    XLlDma_BdRingAckIrq(...)        |  XAxiDma_BdRingAckIrq(...)
+*    XLlDma_BdRingCreate(...)        |  XAxiDma_BdRingCreate(...)
+*    XLlDma_BdRingClone(...)         |  XAxiDma_BdRingClone(...)
+*    XLlDma_BdRingAlloc(...)         |  XAxiDma_BdRingAlloc(...)
+*    XLlDma_BdRingUnAlloc(...)       |  XAxiDma_BdRingUnAlloc(...)
+*    XLlDma_BdRingToHw(...)          |  XAxiDma_BdRingToHw(...)
+*    XLlDma_BdRingFromHw(...)        |  XAxiDma_BdRingFromHw(...)
+*    XLlDma_BdRingFree(...)          |  XAxiDma_BdRingFree(...)
+*    XLlDma_BdRingStart(...)         |  XAxiDma_BdRingStart(...)
+*    XLlDma_BdRingCheck(...)         |  XAxiDma_BdRingCheck(...)
+*    XLlDma_BdRingSetCoalesce(...)   |  XAxiDma_BdRingSetCoalesce(...)
+*    XLlDma_BdRingGetCoalesce(...)   |  XAxiDma_BdRingGetCoalesce(...)
+*    XLlDma_BdRead(...)              |  XAxiDma_BdRead(...)
+*    XLlDma_BdWrite(...)             |  XAxiDma_BdWrite(...)
+*    XLlDma_BdClear(...)             |  XAxiDma_BdClear(...)
+*    XLlDma_BdSetId(...)             |  XAxiDma_BdSetId(...)
+*    XLlDma_BdGetId(...)             |  XAxiDma_BdGetId(...)
+*    XLlDma_BdGetLength(...)         |  XAxiDma_BdGetLength(...)
+*    XLlDma_BdGetBufAddr(...)        |  XAxiDma_BdGetBufAddr(...)
+*
+*
+* +* API Functions That Have Different Return Type +* +* Due to possible hardware failures, The caller should check the return value +* of the following functions. +* +*
+*         xlldma driver              |         xaxidma driver
+* -----------------------------------------------------------------------
+* void XLlDma_Pause(...)             | int XAxiDma_Pause(...)
+* void XLlDma_Resume(...)            | int XAxiDma_Resume(...)
+* 
+* +* The following functions have return type changed: +* +*
+*         xlldma driver              |         xaxidma driver
+* -----------------------------------------------------------------------
+* XLlDma_BdRing XLlDma_GetRxRing(...)| XAxiDma_BdRing * XAxiDma_GetRxRing(...)
+* XLlDma_BdRing XLlDma_GetTxRing(...)| XAxiDma_BdRing * XAxiDma_GetTxRing(...)
+* u32 XLlDma_BdRingMemCalc(...)      | int XAxiDma_BdRingMemCalc(...)
+* u32 XLlDma_BdRingCntCalc(...)      | int XAxiDma_BdRingCntCalc(...)
+* u32 XLlDma_BdRingGetCnt(...)       | int XAxiDma_BdRingGetCnt(...)
+* u32 XLlDma_BdRingGetFreeCnt(...)   | int XAxiDma_BdRingGetFreeCnt(...)
+* void XLlDma_BdSetLength(...)       | int XAxiDma_BdSetLength(...)
+* void XLlDma_BdSetBufAddr(...)      | int XAxiDma_BdSetBufAddr(...)
+*
+* +* API Functions That Are New API Functions +* +* Now that the AXI DMA core is a standalone core, some new API are intrduced. +* Some other functions are added due to hardware interface change, so to +* replace old API functions. +* +* - XAxiDma_Config *XAxiDma_LookupConfig(u32 DeviceId); +* - int XAxiDma_CfgInitialize(XAxiDma * InstancePtr, XAxiDma_Config *Config); +* - int XAxiDma_ResetIsDone(XAxiDma * InstancePtr); +* - XAxiDma_Bd * XAxiDma_BdRingGetCurrBd(XAxiDma_BdRing* RingPtr); +* - int XAxiDma_BdRingHwIsStarted(XAxiDma_BdRing* RingPtr); +* - void XAxiDma_BdRingDumpRegs(XAxiDma_BdRing *RingPtr); +* - int XAxiDma_StartBdRingHw(XAxiDma_BdRing* RingPtr); +* - void XAxiDma_BdSetCtrl(XAxiDma_Bd *BdPtr, u32 Data); +* - u32 XAxiDma_BdGetCtrl(XAxiDma_Bd* BdPtr); +* - u32 XAxiDma_BdGetSts(XAxiDma_Bd* BdPtr); +* - int XAxiDma_BdHwCompleted(XAxiDma_Bd* BdPtr); +* - int XAxiDma_BdGetActualLength(XAxiDma_Bd* BdPtr); +* - int XAxiDma_BdSetAppWord(XAxiDma_Bd * BdPtr, int Offset, u32 Word); +* - u32 XAxiDma_BdGetAppWord(XAxiDma_Bd * BdPtr, int Offset, int *Valid); +* +* API Functions That Have Been Removed +* +* Please see individual function comments for how to replace the removed API +* function with new API functions. +* +* - void XLlDma_Initialize(XLlDma * InstancePtr, u32 BaseAddress). +* This function is replaced by XAxiDma_LookupConfig()/XAxiDma_CfgInitialize() +* +* - u32 XLlDma_BdRingGetCr(XLlDma_BdRing* RingPtr). +* This is replaced by XAxiDma_BdRingGetError(XAxiDma_BdRing* RingPtr) +* +* - u32 XLlDma_BdRingSetCr(XLlDma_BdRing* RingPtr, u32 Data). +* This function is covered by other API functions: +* - void XAxiDma_BdRingIntEnable(XAxiDma_BdRing* RingPtr, u32 Mask) +* - void XAxiDma_BdRingIntDisable(XAxiDma_BdRing* RingPtr, u32 Mask) +* - int XAxiDma_BdRingSetCoalesce(XAxiDma_BdRing * RingPtr, u32 Counter, +* u32 Timer) +* +* - u32 XLlDma_BdSetStsCtrl(XLlDma_Bd* BdPtr, u32 Data). +* Replaced by XAxiDma_BdSetCtrl(XAxiDma_Bd *BdPtr, u32 Data); +* +* - u32 XLlDma_BdGetStsCtrl(XLlDma_Bd* BdPtr). +* Replaced by XAxiDma_BdGetCtrl(XAxiDma_Bd* BdPtr) and +* XAxiDma_BdGetSts(XAxiDma_Bd* BdPtr). +* +* API Functions That Have Been Added to support simple DMA mode +* +* - u32 XAxiDma_Busy(XAxiDma *InstancePtr,int Direction); +* - int XAxiDma_SimpleTransfer(XAxiDma *InstancePtr, u32 BuffAddr, int Length, +* int Direction); +* - XAxiDma_HasSg(InstancePtr); +* - XAxiDma_IntrEnable(InstancePtr,Mask,Direction); +* - XAxiDma_IntrGetEnabled(InstancePtr, Direction); +* - XAxiDma_IntrDisable(InstancePtr, Mask, Direction); +* - XAxiDma_IntrGetIrq(InstancePtr, Direction); +* - XAxiDma_IntrAckIrq(InstancePtr, Mask, Direction); +* +* For xaxidma driver v6_00_a Multiple Channel Support +* --------------------------------------------------- +* This driver supports Multi-channel mode and accordingly some APIs are +* changed to index multiple channels. Few new APIs are added. +* - Changed APIs +* * XAxiDma_GetRxRing(InstancePtr, RingIndex) +* * XAxiDma_Start(XAxiDma * InstancePtr, int RingIndex) +* * XAxiDma_Started(XAxiDma * InstancePtr, int RingIndex) +* * XAxiDma_Pause(XAxiDma * InstancePtr, int RingIndex) +* * XAxiDma_Resume(XAxiDma * InstancePtr, int RingIndex) +* * XAxiDma_SimpleTransfer(XAxiDma *InstancePtr, +* u32 BuffAddr, u32 Length, +* int Direction, int RingIndex) +* * XAxiDma_StartBdRingHw(XAxiDma_BdRing * RingPtr, +* int RingIndex) +* * XAxiDma_BdRingStart(XAxiDma_BdRing * RingPtr, +* int RingIndex) +* * XAxiDma_BdRingToHw(XAxiDma_BdRing * RingPtr, +* int NumBd, XAxiDma_Bd * BdSetPtr, int RingIndex) +* * XAxiDma_BdRingDumpRegs(XAxiDma_BdRing * RingPtr, +* int RingIndex) +* * XAxiDma_BdRingSnapShotCurrBd(XAxiDma_BdRing * RingPtr, +* int RingIndex) +* * XAxiDma_BdSetLength(XAxiDma_Bd *BdPtr, +* u32 LenBytes, u32 LengthMask) +* * XAxiDma_BdGetActualLength(BdPtr, LengthMask) +* * XAxiDma_BdGetLength(BdPtr, LengthMask) +* +* - New APIs +* * XAxiDma_SelectKeyHole(XAxiDma *InstancePtr, +* int Direction, int Select) +* * XAxiDma_UpdateBdRingCDesc(XAxiDma_BdRing * RingPtr, +* int RingIndex) +* * XAxiDma_BdSetTId() +* * XAxiDma_BdGetTId() +* * XAxiDma_BdSetTDest() +* * XAxiDma_BdGetTDest() +* * XAxiDma_BdSetTUser() +* * XAxiDma_BdGetTUser() +* * XAxiDma_BdSetARCache() +* * XAxiDma_BdGetARCache() +* * XAxiDma_BdSetARUser() +* * XAxiDma_BdGetARUser() +* * XAxiDma_BdSetStride() +* * XAxiDma_BdGetStride() +* * XAxiDma_BdSetVSize() +* * XAxiDma_BdGetVSize() +* For xaxidma driver v7_00_a +* --------------------------------------------------- +* - New API +* * XAxiDma_GetRxIndexRing(InstancePtr, RingIndex) +* +* - Changed APIs +* All the APIs changed in v6_00_a are reverted back for backward +* compatibility. +*
+* +******************************************************************************/ diff --git a/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_sinit.c b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_sinit.c new file mode 100644 index 00000000..aa5f451f --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/src/xaxidma_sinit.c @@ -0,0 +1,92 @@ +/****************************************************************************** +* +* 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 xaxidma_sinit.c +* +* Look up the hardware settings using device ID. The hardware setting is inside +* the configuration table in xaxidma_g.c, generated automatically by XPS or +* manually by the user. +* +*
+* MODIFICATION HISTORY:
+*
+* Ver   Who  Date     Changes
+* ----- ---- -------- -------------------------------------------------------
+* 1.00a jz   08/16/10 First release
+* 2.00a jz   08/10/10 Second release, added in xaxidma_g.c, xaxidma_sinit.c,
+*                     updated tcl file, added xaxidma_porting_guide.h
+* 3.00a jz   11/22/10 Support IP core parameters change
+* 5.00a srt  08/29/11 Removed a compiler warning
+*
+* 
+* +******************************************************************************/ + +/***************************** Include Files *********************************/ + +#include "xparameters.h" +#include "xaxidma.h" + + +/*****************************************************************************/ +/** + * Look up the hardware configuration for a device instance + * + * @param DeviceId is the unique device ID of the device to lookup for + * + * @return + * The configuration structure for the device. If the device ID is + * not found,a NULL pointer is returned. + * + * @note None + * + ******************************************************************************/ +XAxiDma_Config *XAxiDma_LookupConfig(u32 DeviceId) +{ + extern XAxiDma_Config XAxiDma_ConfigTable[]; + XAxiDma_Config *CfgPtr; + u32 Index; + + CfgPtr = NULL; + + for (Index = 0; Index < XPAR_XAXIDMA_NUM_INSTANCES; Index++) { + if (XAxiDma_ConfigTable[Index].DeviceId == DeviceId) { + + CfgPtr = &XAxiDma_ConfigTable[Index]; + break; + } + } + + return CfgPtr; +} diff --git a/XilinxProcessorIPLib/drivers/axidma/src/xdebug.h b/XilinxProcessorIPLib/drivers/axidma/src/xdebug.h new file mode 100644 index 00000000..4f26468c --- /dev/null +++ b/XilinxProcessorIPLib/drivers/axidma/src/xdebug.h @@ -0,0 +1,93 @@ +/****************************************************************************** +* +* 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. +* +******************************************************************************/ +#ifndef _XDEBUG_H +#define _XDEBUG_H + +#if defined(DEBUG) && !defined(NDEBUG) + +#include + +#ifndef XDEBUG_WARNING +#define XDEBUG_WARNING +#warning DEBUG is enabled +#endif + +#define XDBG_DEBUG_ERROR 0x00000001 /* error condition messages */ +#define XDBG_DEBUG_GENERAL 0x00000002 /* general debug messages */ +#define XDBG_DEBUG_ALL 0xFFFFFFFF /* all debugging data */ + +#define XDBG_DEBUG_FIFO_REG 0x00000100 /* display register reads/writes */ +#define XDBG_DEBUG_FIFO_RX 0x00000101 /* receive debug messages */ +#define XDBG_DEBUG_FIFO_TX 0x00000102 /* transmit debug messages */ +#define XDBG_DEBUG_FIFO_ALL 0x0000010F /* all fifo debug messages */ + +#define XDBG_DEBUG_TEMAC_REG 0x00000400 /* display register reads/writes */ +#define XDBG_DEBUG_TEMAC_RX 0x00000401 /* receive debug messages */ +#define XDBG_DEBUG_TEMAC_TX 0x00000402 /* transmit debug messages */ +#define XDBG_DEBUG_TEMAC_ALL 0x0000040F /* all temac debug messages */ + +#define XDBG_DEBUG_TEMAC_ADPT_RX 0x00000800 /* receive debug messages */ +#define XDBG_DEBUG_TEMAC_ADPT_TX 0x00000801 /* transmit debug messages */ +#define XDBG_DEBUG_TEMAC_ADPT_IOCTL 0x00000802 /* ioctl debug messages */ +#define XDBG_DEBUG_TEMAC_ADPT_MISC 0x00000803 /* debug msg for other routines */ +#define XDBG_DEBUG_TEMAC_ADPT_ALL 0x0000080F /* all temac adapter debug messages */ + +#define xdbg_current_types (XDBG_DEBUG_ERROR) + +#define xdbg_stmnt(x) x + +/* In VxWorks, if _WRS_GNU_VAR_MACROS is defined, special syntax is needed for + * macros that accept variable number of arguments + */ +#if defined(XENV_VXWORKS) && defined(_WRS_GNU_VAR_MACROS) +#define xdbg_printf(type, args...) (((type) & xdbg_current_types) ? printf (## args) : 0) + +#else /* ANSI Syntax */ + +#define xdbg_printf(type, ...) (((type) & xdbg_current_types) ? printf (__VA_ARGS__) : 0) + +#endif + +#else /* defined(DEBUG) && !defined(NDEBUG) */ + +#define xdbg_stmnt(x) + +/* See VxWorks comments above */ +#if defined(XENV_VXWORKS) && defined(_WRS_GNU_VAR_MACROS) +#define xdbg_printf(type, args...) +#else /* ANSI Syntax */ +#define xdbg_printf(...) +#endif + +#endif /* defined(DEBUG) && !defined(NDEBUG) */ + +#endif /* _XDEBUG_H */