EdmaMgr : Added support for transfers with large pitch. 3.30.01.07_eng
authorJacob Stiffler <j-stiffler@ti.com>
Wed, 30 Jul 2014 14:21:38 +0000 (10:21 -0400)
committerChris Ring <cring@ti.com>
Wed, 30 Jul 2014 18:08:20 +0000 (11:08 -0700)
Because of HW limitations, transfers with a pitch exceeding 16-bit
representation cannot be accomplished in a single TCC. However, this may be
accomplished through chaining. This patch adds "Large" APIs to allocate the
necessary resources and perform 1D2D and 2D1D transfers when the pitch exceeds
the HW limitation.

packages/ti/sdo/fc/edmamgr/edmamgr.c
packages/ti/sdo/fc/edmamgr/edmamgr.h
packages/ti/sdo/fc/edmamgr/edmamgr_xfer.h

index d3d401e4620498e598097ae1fcaaf1aa1463fa5a..321ac28d4ef6a69c51f79cddf774b9c0a6c5b748 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, Texas Instruments Incorporated
+ * Copyright (c) 2013-2014, Texas Instruments Incorporated
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -29,7 +29,6 @@
  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-
 #include <xdc/std.h>
 #include <ti/xdais/ires.h>
 
 #include "edmamgr.h"
 #include "edmamgr_heap.h"
 
+#ifndef ECPY_INLINE_ALL
+#include <xdc/runtime/Diags.h>
+#include <xdc/runtime/Log.h>
+#include <ti/sdo/fc/ecpy/ecpy_util.h>
+#endif
+
 static IRES_ProtocolRevision _iresEDMA3ChanRevision =
         IRES_EDMA3CHAN_PROTOCOLREVISION_2_0_0;
 
@@ -205,6 +210,94 @@ EdmaMgr_Handle EdmaMgr_alloc(int32_t max_linked_transfers)
     return ((EdmaMgr_Handle)&EdmaMgr_channels[i]);
 }
 
+/*********************************************************************************
+ * FUNCTION PURPOSE: Allocate EdmaMgr handle for Large strides
+ *********************************************************************************
+  DESCRIPTION:      This function allocates an EDMA channel for large transfers
+                    where the pitch is larger than the HW limit of 16 bits.
+
+                    Since these transfers excede the HW limits of a single PaRAM,
+                    two channels must be chained, and "src" or "dst" addresses
+                    will be stored in a look-up table.
+
+                    The first EdmaMgr channel will read these addresses from the
+                    table, and transfer them to the PaRAM of the second channel.
+                    Once this transfer is complete, chaining will trigger the
+                    transfer of the actual data in the second channel. Once the
+                    second channel completes the transfer, chaining will trigger
+                    the first channel to read the next address in the table.
+                    This will continue until the entire data is transfered.
+
+  Parameters :      Inputs: max_num_lines  : maximum number of lines in large
+                                             1D2D or 2D1D transfers required for
+                                             the channel.
+
+                    Output: Valid EdmaMgr handle on success;
+                            NULL handle if there is an error.
+ *********************************************************************************/
+EdmaMgr_Handle EdmaMgr_allocLarge(int32_t max_num_lines)
+{
+    EdmaMgr_Handle   h1, h2;
+    EdmaMgr_Channel  *chan1, *chan2;
+    uint32_t         tcc1, tcc2;
+
+    /*
+     *  Allocate a basic EdmaMgr channel.
+     *
+     *  This channel will be responsible for transferring addresses from the
+     *  lookup table to the PaRAM of the second channel.
+     */
+    if ( (h1 = EdmaMgr_alloc(1)) == NULL )
+        return ((EdmaMgr_Handle)NULL);
+
+    /*
+     *  Allocate a basic EdmaMgr channel.
+     *
+     *  This channel will be responsible for transferring the data of interest,
+     *  line by line.
+     */
+    if ( (h2 = EdmaMgr_alloc(1)) == NULL ) {
+        EdmaMgr_free(h1);
+        return ((EdmaMgr_Handle)NULL);
+    }
+
+    chan1 = (EdmaMgr_Channel *)h1;
+    chan2 = (EdmaMgr_Channel *)h2;
+
+    /* Allocate memory for the address lookup table. */
+    chan1->addrTable.size      = max_num_lines*sizeof(uint32_t);
+    chan1->addrTable.alignment = sizeof(uint32_t);
+
+    if( !EdmaMgr_heap_alloc( &chan1->addrTable, 1) ) {
+        EdmaMgr_free(chan1);
+        EdmaMgr_free(chan2);
+        return ((EdmaMgr_Handle)NULL);
+    }
+
+    /* Obtain each channel's TCC so that chaining can be configured, */
+    tcc1 = chan1->edmaHandle->assignedTccIndices[0];
+    tcc2 = chan2->edmaHandle->assignedTccIndices[0];
+
+    /* PaRAM OPT settings for first in chain. */
+    /* This TCC will load the second in the chain with the SRC address from a table in memory */
+    chan1->optChained = ECPY_PARAMOPTS_TCCBITS(tcc2) |   /* Chain to the second channel's TCC */
+                        ECPY_PARAMOPTS_ITCCHEN       |   /* Chain on intermediate transfers (after each address is loaded to the second channel). */
+                        ECPY_PARAMOPTS_TCCHEN        |   /* Chain on final transfer (after last address is loaded). */
+                        ECPY_PARAMOPTS_TCC_INTEN     |   /* Enable interrupt on final transfer (Sets IPR bit after final transfer). */
+                        ECPY_PARAMOPTS_ABSYNC;           /* Sync transfer chaining on A and B CNTs. */
+
+    /* PaRAM OPT settings for second in chain. */
+    /* This TCC will transfer the actual data of interest. */
+    chan2->optChained = ECPY_PARAMOPTS_TCCBITS(tcc1) |   /* Chain to the first channel. */
+                        ECPY_PARAMOPTS_ITCCHEN       |   /* Chain in intermediate transfers (to obtain next address from table). */
+                        ECPY_PARAMOPTS_TCC_INTEN     |   /* Enable interrupt on final transfer (Sets IPR bit after final transfer). */
+                        ECPY_PARAMOPTS_ABSYNC;           /* Sync transfer chaining on A and B CNTs. */
+
+    chan1->chainedChannel = chan2;
+
+    return ((EdmaMgr_Handle)chan1);
+}
+
 /*********************************************************************************
  * FUNCTION PURPOSE: Free EdmaMgr handle
  *********************************************************************************
@@ -223,37 +316,51 @@ int32_t EdmaMgr_free(EdmaMgr_Handle h)
     int32_t scratchId = -1;
     int32_t i, ret_val = EdmaMgr_SUCCESS;
 
-    /* Verify that this is a valid handle? */
-    for (i = 0; i < EDMA_MGR_MAX_NUM_CHANNELS; i++)
-        if (chan == &EdmaMgr_channels[i])
-            break;
-
-    if (i >= EDMA_MGR_MAX_NUM_CHANNELS)
-        return EdmaMgr_ERROR_INVHANDLE;
-
     /* Make sure all transfers have completed */
     EdmaMgr_wait(h);
 
-    /* Prepare IRES resource descriptor */
-    resDesc.resourceName = IRES_EDMA3CHAN_PROTOCOLNAME;
-    resDesc.revision = &_iresEDMA3ChanRevision;
-    resDesc.protocolArgs = (IRES_ProtocolArgs *)&(chan->edmaArgs);
-    resDesc.handle = (IRES_Handle)chan->edmaHandle;
+    /* While loop for freeing chained channels. */
+    while ( chan != NULL ) {
+      EdmaMgr_Channel *chainedChan = chan->chainedChannel;
 
-    ECPY_deleteHandle(chan->ecpyHandle);
+      /* Verify that this is a valid handle? */
+      for (i = 0; i < EDMA_MGR_MAX_NUM_CHANNELS; i++)
+          if (chan == &EdmaMgr_channels[i])
+              break;
 
-    ires_status =
-            RMAN_freeAllocatedResources((Int)EdmaMgr_channels, &resDesc, 1,
-            scratchId);
-    if (ires_status != IRES_OK) {
-        ret_val = EdmaMgr_ERROR_FREE;
-    }
+      if (i >= EDMA_MGR_MAX_NUM_CHANNELS)
+          return EdmaMgr_ERROR_INVHANDLE;
+
+      /* Prepare IRES resource descriptor */
+      resDesc.resourceName = IRES_EDMA3CHAN_PROTOCOLNAME;
+      resDesc.revision = &_iresEDMA3ChanRevision;
+      resDesc.protocolArgs = (IRES_ProtocolArgs *)&(chan->edmaArgs);
+      resDesc.handle = (IRES_Handle)chan->edmaHandle;
 
-    chan->ecpyHandle = NULL;
-    chan->edmaHandle = NULL;
-    chan->xferPending = FALSE;
+      ECPY_deleteHandle(chan->ecpyHandle);
 
-    chan->edmaArgs.numPaRams = 0;
+      ires_status =
+              RMAN_freeAllocatedResources((Int)EdmaMgr_channels, &resDesc, 1,
+              scratchId);
+      if (ires_status != IRES_OK) {
+          ret_val = EdmaMgr_ERROR_FREE;
+      }
+
+      chan->ecpyHandle = NULL;
+      chan->edmaHandle = NULL;
+      chan->xferPending = FALSE;
+
+      chan->edmaArgs.numPaRams = 0;
+      chan->chainedChannel = NULL;
+
+      if ( chan->addrTable.base ) {
+          EdmaMgr_heap_free(&chan->addrTable, 1);
+          chan->addrTable.base = NULL;
+          chan->addrTable.size = 0;
+      }
+
+      chan = chainedChan;
+    }
 
     return ret_val;
 }
index 38cc60daa0ee9c4b827aec6662e259f6c8aa0282..b6e3fe31a68858e528667144e51a5921aabcc6ad 100644 (file)
@@ -72,7 +72,7 @@ typedef void *EdmaMgr_Handle;
 
 
 /** @cond INTERNAL */
-typedef struct {
+typedef struct _EdmaMgr_Channel {
   IRES_EDMA3CHAN_Handle        edmaHandle;
   ECPY_Handle                  ecpyHandle;
   IRES_EDMA3CHAN_ProtocolArgs  edmaArgs;
@@ -81,6 +81,9 @@ typedef struct {
   IRES_YieldFxn                yieldFxn;
   IRES_YieldArgs               yieldArgs;
   IRES_YieldContext            yieldContext;
+  uint32_t                     optChained;
+  IALG_MemRec                  addrTable;
+  struct _EdmaMgr_Channel     *chainedChannel;
 } EdmaMgr_Channel;
 /** @endcond */
 
@@ -137,6 +140,24 @@ EdmaMgr_Handle EdmaMgr_alloc
 );
 
 
+/**
+ *  @brief      Allocate an EdmaMgr channel for "Large" 1D2D or 2D1D transfers
+ *              which have a pitch outside the range [-32768,32768].
+ *
+ *  @param[in]  max_num_lines    Maximum number of lines to be transfered.
+ *
+ *  @retval     NULL        Failure to allocate the channel
+ *  @retval     non-NULL    Success
+ *
+ *  @pre        EdmaMgr_init() must have first been called.
+ *
+ */
+EdmaMgr_Handle EdmaMgr_allocLarge
+(
+  int32_t max_num_lines
+);
+
+
 /**
  *  @brief      Frees an EdmaMgr channel.
  *
@@ -448,6 +469,73 @@ int32_t EdmaMgr_copy2D2DSepLinked
   int32_t           num_transfers
 );
 
+/**
+ *  @brief      Perform a 1D->2D large transfer
+ *
+ *  @param[in]  h           Handle returned from EdmaMgr_alloc().
+ *  @param[in]  src         Source address
+ *  @param[in]  dst         Destination address
+ *  @param[in]  num_bytes   Number of bytes to transfer
+ *  @param[in]  num_lines   Number of lines
+ *  @param[in]  pitch       Pitch
+ *
+ *  @pre        @c h must be a handle successfully returned from
+ *              EdmaMgr_allocLarge().
+ *
+ *  @remarks    Perform a 1D->2D transfer of @c num_bytes bytes.  The source
+ *              is one dimensional, and the destination is two dimensional.
+ *
+ *  @remarks    After every line of @c num_bytes is transferred, the @c src
+ *              address is incremented by @c num_bytes and the @c dst address
+ *              is incremented by @c pitch bytes.
+ *
+ *  @remarks    This should be used when the pitch is outside the range of
+ *              [-32768,32767].
+ */
+int32_t EdmaMgr_copy1D2DLarge
+(
+  EdmaMgr_Handle    h,
+  void *restrict    src,
+  void *restrict    dst,
+  int32_t           num_bytes,
+  int32_t           num_lines,
+  int32_t           pitch
+);
+
+/**
+ *  @brief      Perform a 2D->1D large transfer
+ *
+ *  @param[in]  h           Handle returned from EdmaMgr_alloc().
+ *  @param[in]  src         Source address
+ *  @param[in]  dst         Destination address
+ *  @param[in]  num_bytes   Number of bytes to transfer
+ *  @param[in]  num_lines   Number of lines
+ *  @param[in]  pitch       Pitch
+ *
+ *  @pre        @c h must be a handle successfully returned from
+ *              EdmaMgr_allocLarge().
+ *
+ *  @remarks    Perform a 2D->1D transfer of @c num_bytes bytes.  The source
+ *              is two dimensional, and the destination is one dimensional.
+ *
+ *  @remarks    After every line of @c num_bytes is transferred, the @c src
+ *              address is incremented by @c pitch and the @c dst address
+ *              is incremented by @c num_bytes bytes.
+ *
+ *  @remarks    This should be used when the pitch is outside the range of
+ *              [-32768,32767].
+ */
+int32_t EdmaMgr_copy2D1DLarge
+(
+  EdmaMgr_Handle    h,
+  void *restrict    src,
+  void *restrict    dst,
+  int32_t           num_bytes,
+  int32_t           num_lines,
+  int32_t           pitch
+);
+
+
 /**
  *  @brief      Perform a fast copy. This API inherits the transfer configuration
  *              of a previous transfer and only modifies the @c src and @c dst
index 5e5539743fa7fc85fac56c8007e8dca8bad3d634..c57459fe0cd27c1892dfe9f3b8637df567e7e7bd 100644 (file)
@@ -35,7 +35,6 @@
 #ifndef ti_sdo_fc_edmamgr_EdmaMgr_XFER_
 #define ti_sdo_fc_edmamgr_EdmaMgr_XFER_
 
-
 /*---------------------------------------------------------------*/
 /* This function convert single local address to global addresse */
 /*---------------------------------------------------------------*/
@@ -67,6 +66,10 @@ void EdmaMgr_wait(EdmaMgr_Handle h)
 
   if (edmamgrChan->xferPending) {
     ECPY_directWait(edmamgrChan->ecpyHandle);
+
+    if ( edmamgrChan->chainedChannel )
+      ECPY_directWait(edmamgrChan->chainedChannel->ecpyHandle);
+
     edmamgrChan->xferPending = FALSE;
   }
   return;
@@ -701,6 +704,370 @@ int32_t EdmaMgr_copyLinkedFast
   return (0);
 }
 
+
+/*----------------------------------------------------------*/
+/*  The following function performs a 1D->2D transfer       */
+/*  where the source is 1D one dimensional and destination  */
+/*  is 2D two dimensional. This function uses channel       */
+/*  number "chan_num" to transfer "num_lines" lines         */
+/*  each of "num_bytes" bytes. In this case after every     */
+/*  line of "num_bytes" is transferred, "src" source is     */
+/*  incremeneted by "num_bytes" and "dst" destination is    */
+/*  incremenetd by "pitch" bytes.                           */
+/*----------------------------------------------------------*/
+#if defined (EDMAMGR_INLINE_ALL)
+static __inline
+#endif
+int32_t EdmaMgr_copy1D2DLarge
+(
+  EdmaMgr_Handle    h,
+  void *restrict    src,
+  void *restrict    dst,
+  int32_t           num_bytes,
+  int32_t           num_lines,
+  int32_t           pitch
+)
+{
+  EdmaMgr_Channel *edmamgrChan = (EdmaMgr_Channel *)h;
+  ECPY_Params p;
+
+  /* Setting up the parameters for the transfer */
+  memset(&p, 0, sizeof(ECPY_Params));
+
+  if ( (pitch & (~0xFFFF)) == 0 ) {
+    /* If pitch fits in HW reg, fall back on basic 1D2D transfer */
+    p.transferType = ECPY_1D2D;
+    p.numFrames    = 1;
+    p.elementSize = num_bytes;
+    p.numElements  = num_lines;
+    p.srcElementIndex = num_bytes;
+    p.dstElementIndex = pitch;
+    p.srcAddr = (void *)EDMA_MGR_ADDR_LOC_TO_GLOB(src);
+    p.dstAddr = (void *)EDMA_MGR_ADDR_LOC_TO_GLOB(dst);
+
+    ECPY_directConfigure(edmamgrChan->ecpyHandle, &p, 1);
+
+    ECPY_directSetFinal(edmamgrChan->ecpyHandle, 1);
+
+  } else {
+    int32_t i;
+    uint32_t  *addrTable = (uint32_t *)edmamgrChan->addrTable.base;
+    IRES_EDMA3CHAN_PaRamStruct *paRam;
+    ECPY_Params p_0;
+    memset (&p_0, 0, sizeof(ECPY_Params));
+
+    /* Set address lookup table based on "dst" and "pitch" */
+    for ( i = 0; i < num_lines; i++) {
+        addrTable[i] = (uint32_t)dst + i*pitch;
+    }
+
+    /*
+     *  PaRAM for channel 1
+     *
+     *  This PaRAM set is responsible for populating the "dst" field of the
+     *  PaRAM set for the second channel.
+     */
+
+    /*
+     *  1D2D so that destination address (channel 2's PaRAM "dst" field) is
+     *  constant.
+     */
+    p_0.transferType  = ECPY_1D2D;
+
+    /*
+     *  elementSize is the size of "dst" address.
+     */
+    p_0.elementSize = sizeof(uint32_t);
+
+    /*
+     *  Transfer 1 address per synchronization event.
+     */
+    p_0.numElements = 1;
+
+    /*
+     *  "num_lines" is the total number of addresses to transfer as well as the
+     *  number of synchronization events.
+     */
+    p_0.numFrames   = num_lines;
+
+    /*
+     *  After an address is transferred, point to the next one.
+     */
+    p_0.srcElementIndex = sizeof(uint32_t);
+    p_0.srcFrameIndex = sizeof(uint32_t);
+
+    /*
+     *  Do not increment the destination address since the destination for the
+     *  addresses is the second channel's PaRAM which remains constant.
+     */
+    p_0.dstElementIndex = 0;
+    p_0.dstFrameIndex = 0;
+
+    /*
+     *  src of this channel is the lookup table
+     */
+    p_0.srcAddr = (void *)EDMA_MGR_ADDR_LOC_TO_GLOB(addrTable);
+
+    /*
+     *  Obtain the address to the second channel's PaRam 'dst' field, and use
+     *  that for the first channels destination.
+     */
+    paRam = (IRES_EDMA3CHAN_PaRamStruct *)edmamgrChan->chainedChannel->edmaHandle->assignedPaRamAddresses[0];
+    p_0.dstAddr = (void *)&paRam->dst; /*PaRAM for chan2 dstAddr field*/
+
+
+
+    /*
+     *  PaRAM for channel 2
+     *
+     *  This PaRAM set is responsible for transfer the actual data of interest.
+     *  The 'dst' field of this set will be modified by the first channel.
+     */
+
+    /*
+     *  2D2D transfer
+     */
+    p.transferType = ECPY_2D2D;
+
+    /*
+     *  Number of bytes to transfer to each dst address in lookup table.
+     */
+    p.elementSize  = num_bytes;
+    p.numElements  = 1;
+
+    /*
+     *  Set C CNT to num_lines since using AB-sychronization.
+     */
+    p.numFrames    = num_lines;
+
+    /*
+     * SRC is linearized as a 1-D vector, so increment src by num_bytes.
+     */
+    p.srcElementIndex = num_bytes;
+    p.srcFrameIndex   = num_bytes;
+
+    /*
+     * DST will be updated by channel 1, so automatic incrementing is not needed.
+     */
+    p.dstElementIndex = 0;
+    p.dstFrameIndex   = 0;
+
+    /*
+     *  Set SRC to 1-D vector.
+     */
+    p.srcAddr = (void *)EDMA_MGR_ADDR_LOC_TO_GLOB(src);
+
+    /*
+     *  Don't Care as DST will be updated by channel 1.
+     */
+    p.dstAddr = (void *)NULL;  /* This will be updated by p_0 */
+
+    /* Write Channel 1 PaRAM to HW. */
+    ECPY_directConfigure(edmamgrChan->ecpyHandle, &p_0, 1);
+    ECPY_directSetFinal(edmamgrChan->ecpyHandle, 1);
+
+    /* Write Channel 2 PaRAM to HW. */
+    ECPY_directConfigure(edmamgrChan->chainedChannel->ecpyHandle, &p, 1);
+    ECPY_directSetFinal(edmamgrChan->chainedChannel->ecpyHandle, 1);
+
+    /* Override OPT for chaining */
+    paRam = (IRES_EDMA3CHAN_PaRamStruct *)edmamgrChan->edmaHandle->assignedPaRamAddresses[0];
+    paRam->opt = edmamgrChan->optChained;
+
+    paRam = (IRES_EDMA3CHAN_PaRamStruct *)edmamgrChan->chainedChannel->edmaHandle->assignedPaRamAddresses[0];
+    paRam->opt = edmamgrChan->chainedChannel->optChained;
+
+  }
+
+  /* Initiate transfer */
+  ECPY_directStartEdma(edmamgrChan->ecpyHandle);
+
+  edmamgrChan->xferPending = TRUE;
+
+  return(0);
+}
+
+/*----------------------------------------------------------*/
+/* This function performs a 2D->1D transfer by usinng the   */
+/* channel number "chan_num" by performing a transfer from  */
+/* source "src" to destination "dst", "num_lines" lines     */
+/* each of "num_bytes" bytes. At the end of transferring    */
+/* "num_bytes" bytes per line, the source is incremented    */
+/* by "pitch" bytes and the destination is incremented by   */
+/* "num_bytes" bytes as "src" is 2D and "dst" is 1D.        */
+/*----------------------------------------------------------*/
+#if defined (EDMAMGR_INLINE_ALL)
+static __inline
+#endif
+int32_t EdmaMgr_copy2D1DLarge
+(
+  EdmaMgr_Handle    h,
+  void *restrict    src,
+  void *restrict    dst,
+  int32_t           num_bytes,
+  int32_t           num_lines,
+  int32_t           pitch
+)
+{
+  EdmaMgr_Channel *edmamgrChan = (EdmaMgr_Channel *)h;
+  ECPY_Params p;
+
+  /* Setting up the parameters for the first transfer (data grp 1) */
+  memset(&p, 0, sizeof(ECPY_Params));
+
+  if ( (pitch & (~0xFFFF)) == 0 ) {
+    /* If pitch fits in HW reg, fall back on basic 1D2D transfer */
+    p.transferType = ECPY_2D1D;
+    p.numFrames    = 1;
+    p.elementSize = num_bytes;
+    p.numElements  = num_lines;
+    p.srcElementIndex = pitch;
+    p.dstElementIndex = num_bytes;
+    p.srcAddr = (void *)EDMA_MGR_ADDR_LOC_TO_GLOB(src);
+    p.dstAddr = (void *)EDMA_MGR_ADDR_LOC_TO_GLOB(dst);
+
+    ECPY_directConfigure(edmamgrChan->ecpyHandle, &p, 1);
+
+    ECPY_directSetFinal(edmamgrChan->ecpyHandle, 1);
+  } else {
+    int32_t i;
+    uint32_t  *addrTable = (uint32_t *)edmamgrChan->addrTable.base;
+    IRES_EDMA3CHAN_PaRamStruct *paRam;
+    ECPY_Params p_0;
+    memset (&p_0, 0, sizeof(ECPY_Params));
+
+    /* Set address lookup table based on "src" and "pitch" */
+    for ( i = 0; i < num_lines; i++) {
+        addrTable[i] = (uint32_t)src + i*pitch;
+    }
+
+    /*
+     *  PaRAM for channel 1
+     *
+     *  This PaRAM set is responsible for populating the "src" field of the
+     *  PaRAM set for the second channel.
+     */
+
+    /*
+     *  1D2D so that destination address (channel 2's PaRAM "src" field) is
+     *  constant.
+     */
+    p_0.transferType  = ECPY_1D2D;
+
+    /*
+     *  elementSize is the size of "src" address.
+     */
+    p_0.elementSize = sizeof(uint32_t);
+
+    /*
+     *  Transfer 1 address per synchronization event.
+     */
+    p_0.numElements = 1;
+
+    /*
+     *  "num_lines" is the total number of addresses to transfer as well as the
+     *  number of synchronization events.
+     */
+    p_0.numFrames   = num_lines;
+
+    /*
+     *  After an address is transferred, point to the next one.
+     */
+    p_0.srcElementIndex = sizeof(uint32_t);
+    p_0.srcFrameIndex = sizeof(uint32_t);
+
+    /*
+     *  Do not increment the destination address since the destination for the
+     *  addresses is the second channel's PaRAM which remains constant.
+     */
+    p_0.dstElementIndex = 0;
+    p_0.dstFrameIndex = 0;
+
+    /*
+     *  src of this channel is the lookup table
+     */
+    p_0.srcAddr = (void *)EDMA_MGR_ADDR_LOC_TO_GLOB(addrTable);
+
+    /*
+     *  Obtain the address to the second channel's PaRam 'src' field, and use
+     *  that for the first channels destination.
+     */
+    paRam = (IRES_EDMA3CHAN_PaRamStruct *)edmamgrChan->chainedChannel->edmaHandle->assignedPaRamAddresses[0];
+    p_0.dstAddr = (void *)&paRam->src; /*PaRAM for chan2 srcAddr field*/
+
+
+
+    /*
+     *  PaRAM for channel 2
+     *
+     *  This PaRAM set is responsible for transfer the actual data of interest.
+     *  The 'src' field of this set will be modified by the first channel.
+     */
+
+    /*
+     *  2D2D transfer
+     */
+    p.transferType = ECPY_2D2D;
+
+    /*
+     *  Number of bytes to transfer from each src address in lookup table.
+     */
+    p.elementSize  = num_bytes;
+    p.numElements  = 1;
+
+    /*
+     *  Set C CNT to num_lines since using AB-sychronization.
+     */
+    p.numFrames    = num_lines;
+
+    /*
+     * SRC will be updated by channel 1, so automatic incrementing is not needed.
+     */
+    p.srcElementIndex = 0;
+    p.srcFrameIndex   = 0;
+
+    /*
+     * DST is linearized as a 1-D vector, so increment DST by num_bytes.
+     */
+    p.dstElementIndex = num_bytes;
+    p.dstFrameIndex   = num_bytes;
+
+    /*
+     *  Don't Care as SRC will be updated by channel 1.
+     */
+    p.srcAddr = (void *)NULL;  /* This will be updated by p_0 */
+
+    /*
+     *  Set DST to 1-D vector.
+     */
+    p.dstAddr = (void *)EDMA_MGR_ADDR_LOC_TO_GLOB(dst);
+
+    /* Write Channel 1 PaRAM to HW. */
+    ECPY_directConfigure(edmamgrChan->ecpyHandle, &p_0, 1);
+    ECPY_directSetFinal(edmamgrChan->ecpyHandle, 1);
+
+    /* Write Channel 2 PaRAM to HW. */
+    ECPY_directConfigure(edmamgrChan->chainedChannel->ecpyHandle, &p, 1);
+    ECPY_directSetFinal(edmamgrChan->chainedChannel->ecpyHandle, 1);
+
+    /* Override OPT for chaining */
+    paRam = (IRES_EDMA3CHAN_PaRamStruct *)edmamgrChan->edmaHandle->assignedPaRamAddresses[0];
+    paRam->opt = edmamgrChan->optChained;
+
+    paRam = (IRES_EDMA3CHAN_PaRamStruct *)edmamgrChan->chainedChannel->edmaHandle->assignedPaRamAddresses[0];
+    paRam->opt = edmamgrChan->chainedChannel->optChained;
+
+  }
+
+  /* Initiate transfer */
+  ECPY_directStartEdma(edmamgrChan->ecpyHandle);
+
+  edmamgrChan->xferPending = TRUE;
+
+  return(0);
+}
+
+
 #endif /* ti_sdo_fc_edmamgr_EdmaMgr_XFER_ */
 
 #else