/**
 *   @file  edma_test.c
 *
 *   @brief
 *      This is the Example test code for the EDMA CSL Functional layer.
 *
 *  \par
 *  NOTE:
 *      (C) Copyright 2009 Texas Instruments, Inc.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *    Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 *    Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the
 *    distribution.
 *
 *    Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
*/

#include <stdio.h>
#include <ti/csl/csl_edma3.h>
#include <ti/csl/csl_edma3Aux.h>
#include <ti/csl/csl_cacheAux.h>

/**********************************************************************
 ************************** Global Variables **************************
 **********************************************************************/

/* Global Variables which are used to dump the TPCC register overlay in the
 * debugger... */

CSL_TpccRegs*  gEDMACC2Regs  = (CSL_TpccRegs*)CSL_EDMA2CC_REGS;


/* Global Buffers (Source and Destination) for PING-PONG */
float srcBuff1[512];
float dstBuff1[512];

CSL_Edma3Handle                 hModule;
CSL_Edma3Obj                    edmaObj;
CSL_Edma3ParamHandle            hParamPing;
CSL_Edma3ChannelObj             chObj;
CSL_Edma3CmdIntr                regionIntr;
CSL_Edma3ChannelHandle          hChannel;
CSL_Edma3ParamSetup             myParamSetup;
CSL_Edma3Context                context;
CSL_Edma3ChannelAttr            chAttr;
CSL_Status                      status;
Uint32                          loopIndex;

/**********************************************************************
 ************************ EDMA TEST FUNCTIONS *************************
 **********************************************************************/

/**
 *  @b Description
 *  @n
 *      This is utility function used by the EDMA example to verify the
 *      Data transfer.
 *
 *  @retval
 *      Success -   TRUE
 *  @retval
 *      Error -   FALSE
 */
static Bool Verify_Transfer
(
    Uint16      aCnt,
    Uint16      bCnt,
    Uint16      cCnt,
    Uint16      srcBIdx,
    Uint16      dstBIdx,
    Uint16      srcCIdx,
    Uint16      dstCIdx,
    float      *srcBuff,
    float      *dstBuff,
    Bool        abSync
)
{
    Uint32      loopIndex1;
    Uint32      loopIndex2;
    Uint32      loopIndex3;
    float*      srcArrayPtr = (float*)srcBuff;
    float*      dstArrayPtr = (float*)dstBuff;
    float*      srcFramePtr = (float*)srcBuff;
    float*      dstFramePtr = (float*)dstBuff;
    Uint16      key;


    /* Invalidate the cache before verification */
    /* Disable Interrupts */
    key = _disable_interrupts();
    CACHE_invL1d ((void *)srcBuff, 512*sizeof(float), CACHE_WAIT);
    CACHE_invL2 ((void *)srcBuff, 512*sizeof(float), CACHE_WAIT);
    CACHE_invL1d ((void *)dstBuff, 512*sizeof(float), CACHE_WAIT);
    CACHE_invL2 ((void *)dstBuff, 512*sizeof(float), CACHE_WAIT);
    _mfence();
    /* Re-enable Interrupts. */
    _restore_interrupts(key);


    for (loopIndex1 = 0; loopIndex1 < cCnt; loopIndex1++) {
        for (loopIndex2 = 0; loopIndex2 < bCnt; loopIndex2++) {
            for (loopIndex3 = 0; loopIndex3 < aCnt; loopIndex3++)
                if (srcArrayPtr[loopIndex3] != dstArrayPtr[loopIndex3])
                {
                	printf("Not Working at %d\n",loopIndex3);
                    return FALSE;
                }
            srcArrayPtr = srcArrayPtr + srcBIdx;
            dstArrayPtr = dstArrayPtr + dstBIdx;
        }

        if (abSync) {
            srcFramePtr = srcFramePtr + srcCIdx;
            srcArrayPtr = srcFramePtr;
            dstFramePtr = dstFramePtr + dstCIdx;
            dstArrayPtr = dstFramePtr;
        }
        else {
            srcFramePtr = srcArrayPtr + srcCIdx - srcBIdx;
            srcArrayPtr = srcFramePtr;
            dstFramePtr = dstArrayPtr + dstCIdx - dstBIdx;
            dstArrayPtr = dstFramePtr;
        }
    }

    return TRUE;
}

/**
 *  @b Description
 *  @n
 *      This is the example routine which perform EDMA ping pong buffer transfer
 *      where channel is open in the global region.
 *      It implements following steps
 *          - Intializes and Opens the EDMA Module .
 *          - Sets up the interrupt for the EDMA global region.
 *          - Sets up the EDMA module using the API csl_edma3Hwsetup ()
 *          - Enables the EDMA global region
 *          - Opens the channel 'channelNum' get the param handle for PARAM 1, 2
 *          - PING is mapped to PARAM Entry 1
 *          - PONG is mapped to PARAM Entry 2
 *          - PING is Linked with PONG...
 *          - Enables the EDMA interrupt using CSL_EDMA3_CMD_INTR_ENABLE.
 *          - Enables Interrupt (Bit 0-2) for the global region interrupts
 *          - Manually triggers the DMA channel 'channelNum'(This should be PING)
 *          - Polls on IPR bit 0 (Since TCC for PING is 0)
 *          - Clear the pending bit
 *          - Manually triggers the channel 'channelNum' (This should be PONG)
 *          - Polls on IPR bit 1 (Since TCC for PONG is 1)
 *          - Clears the pending bit
 *          - Compares the data in the destination buffer is proper or not.
 *          - Closes the EDMA module and channel.
 *
 *  @param[in]  instNum
 *      EDMA Instance Number on which the test is executed.
 *  @param[in]  channelNum
 *      EDMA Channel Number on which the test is executed
 *
 *  @retval
 *      Success -   0
 *  @retval
 *      Failure -   <0
 */
static Int32 edma_ping_pong_xfer_gbl_region_init (Int32 instNum, Uint8 channelNum)
{


    /* Start the EDMA PING-PONG test over the Global Region. */
    printf ("Debug: Testing EDMA(%d) Ping-Pong Test (Global) Region for Channel %d...\n", instNum, channelNum);

    /* Initialize data  */
    for (loopIndex = 0; loopIndex < 512; loopIndex++)
    {
        srcBuff1[loopIndex] =(int) loopIndex;
        dstBuff1[loopIndex] = 0;
    }

    /* Module initialization */
    if (CSL_edma3Init(&context) != CSL_SOK)
    {
        printf ("Error: EDMA module initialization failed\n");
        return -1;
    }

    /* Open the EDMA Module using the provided instance number */
    hModule = CSL_edma3Open(&edmaObj, instNum, NULL, &status);
    if ( (hModule == NULL) || (status != CSL_SOK))
    {
        printf ("Error: EDMA module open failed\n");
        return -1;
    }

    /* Channel open */
    chAttr.regionNum = CSL_EDMA3_REGION_GLOBAL;
    chAttr.chaNum    = channelNum;
    hChannel = CSL_edma3ChannelOpen(&chObj, instNum, &chAttr, &status);
    if ((hChannel == NULL) || (status != CSL_SOK))
    {
        printf ("Error: Unable to open EDMA Channel:%d\n", channelNum);
        return -1;
    }

    if(!instNum)
    {
        /* For first EDMA instance there are only 2 TCs and 2 event queues
         * Modify the channel default queue setup from 0 to 1
         */
         if (CSL_edma3HwChannelSetupQue(hChannel,CSL_EDMA3_QUE_1) != CSL_SOK)
        {
            printf ("Error: EDMA channel setup queue failed\n");
            return -1;
        }
    }
    else
    {
        /* For EDMA instance 1 and 2 maximum of 4 TCs and 4 event queues are supported
         * Change Channel Default queue setup from 0 to 3
         */
        if (CSL_edma3HwChannelSetupQue(hChannel,CSL_EDMA3_QUE_3) != CSL_SOK)
        {
            printf ("Error: EDMA channel setup queue failed\n");
            return -1;
        }
    }


    hParamPing = CSL_edma3GetParamHandle(hChannel, 2, &status);
    if (hParamPing == NULL)
    {
        printf ("Error: EDMA Get Parameter Entry failed for 2.\n");
        return -1;
    }

    /* Setup the parameter entry parameters (Ping buffer) */
    myParamSetup.option = CSL_EDMA3_OPT_MAKE(CSL_EDMA3_ITCCH_DIS, \
                                             CSL_EDMA3_TCCH_DIS, \
                                             CSL_EDMA3_ITCINT_DIS, \
                                             CSL_EDMA3_TCINT_EN, \
                                             0, CSL_EDMA3_TCC_NORMAL,\
                                             CSL_EDMA3_FIFOWIDTH_NONE, \
                                             CSL_EDMA3_STATIC_DIS, \
                                             CSL_EDMA3_SYNC_A, \
                                             CSL_EDMA3_ADDRMODE_INCR, \
                                             CSL_EDMA3_ADDRMODE_INCR );
    myParamSetup.srcAddr    = (Uint32)srcBuff1;
    myParamSetup.aCntbCnt   = CSL_EDMA3_CNT_MAKE(512*sizeof(float),1);
    myParamSetup.dstAddr    = (Uint32)dstBuff1;
    myParamSetup.srcDstBidx = CSL_EDMA3_BIDX_MAKE(1,1);
    myParamSetup.linkBcntrld= CSL_EDMA3_LINKBCNTRLD_MAKE(CSL_EDMA3_LINK_NULL,0);
    myParamSetup.srcDstCidx = CSL_EDMA3_CIDX_MAKE(0,1);
    myParamSetup.cCnt = 1;

    /* Interrupt enable (Bits 0-1)  for the global region interrupts */
    regionIntr.region = CSL_EDMA3_REGION_GLOBAL;
    regionIntr.intr   = 0x3;
    regionIntr.intrh  = 0x0000;
    CSL_edma3HwControl(hModule,CSL_EDMA3_CMD_INTR_ENABLE,&regionIntr);

    regionIntr.region = CSL_EDMA3_REGION_GLOBAL;
    regionIntr.intr   = 0;
    regionIntr.intrh  = 0;

    /* Map the DMA Channel to PARAM Block 2. */
    CSL_edma3MapDMAChannelToParamBlock (hModule, channelNum, 2);

return 0;
}


static Int32 edma_ping_pong_xfer_gbl_region (Int32 instNum, Uint8 channelNum)
{
    /* Ping setup */
    if (CSL_edma3ParamSetup(hParamPing,&myParamSetup) != CSL_SOK)
    {
        printf ("Error: EDMA Parameter Entry Setup failed\n");
        return -1;
    }

    /* Trigger channel */
    CSL_edma3HwChannelControl(hChannel,CSL_EDMA3_CMD_CHANNEL_SET,NULL);


    /* Poll on IPR bit 0 */
    do {
        CSL_edma3GetHwStatus(hModule,CSL_EDMA3_QUERY_INTRPEND,&regionIntr);
    } while (!(regionIntr.intr & 0x1));

    /* Clear the pending bit */
    CSL_edma3HwControl(hModule,CSL_EDMA3_CMD_INTRPEND_CLEAR,&regionIntr);
    /* The test passed. */
    return 0;
}

int verify_transfer_pingpong(){
    /* Check transfer by comparing the source and destination buffers */
    if(Verify_Transfer( 512, 1, 1, 0, 0, 0, 0, srcBuff1, dstBuff1, TRUE) == FALSE)
    {
        printf ("Error: Verification (Source1/Destination1) Failed\n");
        return -1;
    }
    return 0;
}

close_EDMA(){
/* Close channel */
if (CSL_edma3ChannelClose(hChannel) != CSL_SOK)
{
    printf("Error: EDMA Channel Close failed\n");
}

/* Close EDMA module */
if (CSL_edma3Close(hModule) != CSL_SOK)
{
    printf("Error: EDMA Module Close failed\n");
}
}

void main (void)
{
    Uint8  channelNum=0;
    Uint8  instNum = 0;
    int i;

        if (edma_ping_pong_xfer_gbl_region_init(instNum, channelNum) < 0)
        {
            printf ("Error: Init EDMA(%d) Channel %d FAILED\n", instNum, channelNum);
            return;
        }
        printf ("Debug: Init EDMA(%d) Ping-Pong Test (Global) Region for Channel %d Passed\n", instNum, channelNum);


    for(i=0;i<10;i++)
    {
    	if (edma_ping_pong_xfer_gbl_region(instNum, channelNum) < 0)
    	{
    		printf ("Error: EDMA(%d) Channel %d FAILED\n", instNum, channelNum); return;
    	}
		if (verify_transfer_pingpong() == 0)
		{
			printf ("Debug: Testing EDMA(%d) Ping-Pong Test (Global) Region for Channel %d Passed\n", instNum, channelNum);
		}
    }

    close_EDMA();
    return;
}
