/*
 *  Copyright (C) 2021 Texas Instruments Incorporated
 *
 *  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 <kernel/dpl/DebugP.h>
#include <kernel/dpl/CacheP.h>
#include <kernel/dpl/CycleCounterP.h>
#include <drivers/soc.h>
#include "ti-arm-clang\generated\ti_drivers_open_close.h"
#include "ti-arm-clang\generated\ti_board_open_close.h"
#include <string.h>

#define APP_OSPI_FLASH_DMA_REPEAT_CNT             (10U)
#define APP_OSPI_FLASH_DMA_TEST_SIZE_BYTES        (256*1024)
#define APP_OSPI_FLASH_DMA_BUF_SIZE               (APP_OSPI_FLASH_DMA_TEST_SIZE_BYTES)
#define APP_OSPI_FLASH_DMA_TRPD_SIZE              (UDMA_GET_TRPD_TR15_SIZE(1U))
#define APP_OSPI_FLASH_DMA_TR_INFINITE_RELOAD_CNT (0x1FFU)

#define APP_OSPI_FLASH_DMA_OFFSET (0x800000) /* 2MB offset in flash so that bootloader and any app flashed is not overwritten */


#define APP_OSPI_FLASH_DMA_OFFSET_DIRECT (0x800000) 

/* App Object */
typedef struct
{
    /* TR Event parameters */
    Udma_EventObject trEventObj_channel0;
    Udma_EventHandle trEventHandle_channel0;
    Udma_EventPrms trEventParams_channel0;

    Udma_EventObject trEventObj_channel1;
    Udma_EventHandle trEventHandle_channel1;
    Udma_EventPrms trEventParams_channel1;

    /* Profiling parameters */
    uint64_t ticksDelay;
    uint64_t txTotalTicks;
    uint64_t rxTotalTicks[APP_OSPI_FLASH_DMA_REPEAT_CNT];

    /* Driver handles */
    Flash_Handle   flashHandle;
    OSPI_Handle    ospiHandle;
    Udma_DrvHandle udmaDrvHandle;
    Udma_ChHandle  udmaChHandle_channel0;
    Udma_ChHandle  udmaChHandle_channel1;

} App_OspiFlashDmaObj;

App_OspiFlashDmaObj gAppObj;

/* TRPD memory */
uint8_t udgOspiFlashDmaTrpdMemChannel0[APP_OSPI_FLASH_DMA_TRPD_SIZE] __attribute__((aligned(UDMA_CACHELINE_ALIGNMENT)));
uint8_t udgOspiFlashDmaTrpdMemChannel1[APP_OSPI_FLASH_DMA_TRPD_SIZE] __attribute__((aligned(UDMA_CACHELINE_ALIGNMENT)));


/* App test buffers */
uint8_t gOspiFlashDmaTxBuf[APP_OSPI_FLASH_DMA_BUF_SIZE] __attribute__((aligned(128U)));
uint8_t gOspiFlashDmaRxBuf[APP_OSPI_FLASH_DMA_BUF_SIZE] __attribute__((aligned(128U)));

extern Flash_Config gFlashConfig[CONFIG_FLASH_NUM_INSTANCES]; 


int32_t App_OspiFlashDmaInit(App_OspiFlashDmaObj *appObj);
int32_t App_OspiFlashDmaDeinit(App_OspiFlashDmaObj *appObj);
static inline uint64_t App_OspiFlashDmaGetTicksDiff(uint32_t stop, uint32_t start, uint32_t delay);
int32_t App_OspiFlashDmaTrEventRegister(App_OspiFlashDmaObj *appObj);
int32_t App_OspiFlashDmaTrEventUnregister(App_OspiFlashDmaObj *appObj);
void App_OspiFlashDmaTrpdInit(Udma_ChHandle chHandle, uint8_t chIdx, uint8_t* trpdMem, void *src, void *dst, uint32_t length);
void App_OspiFlashDmaFillBuffers(uint32_t lenBytes);
int32_t App_OspiFlashDmaCompareBuffers(uint32_t lenBytes);
void App_printPerformanceResults(App_OspiFlashDmaObj *appObj, uint32_t numBytes);



void ospi_flash_dma_main(void *args)
{
    int32_t status = SystemP_SUCCESS;
    App_OspiFlashDmaObj *pAppObj = &gAppObj;
    uint32_t tCnt, triggerMask;
    volatile uint32_t * pSwTriggerRegChannel0;
    volatile uint64_t *intrStatusRegChannel0;
    volatile uint64_t *intrClearRegChannel0;
    volatile uint64_t intrStatusChannel0;
    volatile uint64_t intrMaskChannel0;


    volatile uint32_t * pSwTriggerRegChannel1;
    volatile uint64_t *intrStatusRegChannel1;
    volatile uint64_t *intrClearRegChannel1;
    volatile uint64_t intrStatusChannel1;
    volatile uint64_t intrMaskChannel1;

    //void* rxBuf = &gOspiFlashDmaRxBuf[0];

    /* Open OSPI and UDMA Drivers, among others */
    Drivers_open();

    /* Open Flash driver with OSPI instance as input */
    status = Board_driversOpen();
    DebugP_assert(status==SystemP_SUCCESS);

    DebugP_log("[OSPI] DMA low latency example without cache started...\r\n");

    /* Initialize app object */
    App_OspiFlashDmaInit(pAppObj);
    triggerMask = ((uint32_t)1U << (CSL_UDMAP_TR_FLAGS_TRIGGER_GLOBAL0 - 1U));
    
    
    
    
    pSwTriggerRegChannel1 = (volatile uint32_t *) Udma_chGetSwTriggerRegister(pAppObj->udmaChHandle_channel1);
    intrMaskChannel1 = pAppObj->trEventParams_channel1.intrMask;
    intrClearRegChannel1 = pAppObj->trEventParams_channel1.intrClearReg;
    intrStatusRegChannel1 = pAppObj->trEventParams_channel1.intrStatusReg;


    CSL_REG32_WR(pSwTriggerRegChannel1, triggerMask);

        while(1U)
        {
            intrStatusChannel1 = CSL_REG64_RD(intrStatusRegChannel1);

            if(intrStatusChannel1 & intrMaskChannel1)
            {
                CSL_REG64_WR(intrClearRegChannel1, intrMaskChannel1);
                break;
            }
        }



    /* Processing loop */
    pSwTriggerRegChannel0 = (volatile uint32_t *) Udma_chGetSwTriggerRegister(pAppObj->udmaChHandle_channel0);
    intrMaskChannel0 = pAppObj->trEventParams_channel0.intrMask;
    intrClearRegChannel0 = pAppObj->trEventParams_channel0.intrClearReg;
    intrStatusRegChannel0 = pAppObj->trEventParams_channel0.intrStatusReg;

    for(tCnt = 0; tCnt < APP_OSPI_FLASH_DMA_REPEAT_CNT; tCnt++)
    {
        uint32_t rxStartTicks, rxStopTicks;
        CycleCounterP_reset();
        rxStartTicks = CycleCounterP_getCount32();

        /* Set channel trigger and wait for completion */
        CSL_REG32_WR(pSwTriggerRegChannel0, triggerMask);

        while(1U)
        {
            intrStatusChannel0 = CSL_REG64_RD(intrStatusRegChannel0);
            /* Check whether the interrupt status Reg is set - which indicates the
            * transfer completion of appTestObj->numBytes */
            if(intrStatusChannel0 & intrMaskChannel0)
            {
                /* Clear interrupt */
                CSL_REG64_WR(intrClearRegChannel0, intrMaskChannel0);
                break;
            }
        }
   
        rxStopTicks = CycleCounterP_getCount32();

        pAppObj->rxTotalTicks[tCnt] = App_OspiFlashDmaGetTicksDiff(rxStopTicks, rxStartTicks, pAppObj->ticksDelay);

        /* Compare buffers */
        status = App_OspiFlashDmaCompareBuffers(APP_OSPI_FLASH_DMA_TEST_SIZE_BYTES);

        if(status != SystemP_SUCCESS)
        {
            break;
        }
    }

    /* Print performance stats */
    App_printPerformanceResults(pAppObj, APP_OSPI_FLASH_DMA_TEST_SIZE_BYTES);

    status += App_OspiFlashDmaDeinit(pAppObj);

    if(status == SystemP_SUCCESS)
    {
        DebugP_log("All tests have passed !!!\r\n");
    }
    else
    {
        DebugP_log("Some tests have failed !!!\r\n");
    }

    Board_driversClose();
    Drivers_close();
}

extern int32_t ospi_flash_eraseBlk(uint32_t blkNum);
extern int32_t ospi_flash_norOspi_data_Write(uint32_t offset, uint8_t *buf, uint32_t len);

extern int32_t ospi_flash_norOspi_data_read(uint32_t offset, uint32_t *buf, uint32_t len);


extern int32_t MY_readIndirect(uint32_t offset, uint32_t *buf, uint32_t len);

uint8_t buffer_read[APP_OSPI_FLASH_DMA_TEST_SIZE_BYTES] __attribute__((aligned(128U)));

int32_t App_OspiFlashDmaInit(App_OspiFlashDmaObj *appObj)
{
    int32_t status = SystemP_SUCCESS;
    int32_t udmaStatus = UDMA_SOK;
    uint32_t ticksDelay;
    uint64_t trpdMemPhy;
    uint32_t flashSrcAddr;

    appObj->flashHandle         = gFlashHandle[CONFIG_FLASH0];
    appObj->ospiHandle          = OSPI_getHandle(CONFIG_OSPI0);
    appObj->udmaDrvHandle       = &gUdmaDrvObj[CONFIG_UDMA0];
    appObj->udmaChHandle_channel0        = gConfigUdma0BlkCopyChHandle[CONFIG_UDMA0];

    appObj->udmaChHandle_channel1        = gConfigUdma0BlkCopyChHandle[1];



    appObj->txTotalTicks        = 0U;
    memset(&appObj->rxTotalTicks, 0, APP_OSPI_FLASH_DMA_REPEAT_CNT * sizeof(uint32_t));

    /* Get ticks delay */
    CycleCounterP_reset();
    ticksDelay = CycleCounterP_getCount32();
    ticksDelay = CycleCounterP_getCount32() - ticksDelay;
    appObj->ticksDelay = ticksDelay;

    /* Register the TR Event */
    status = App_OspiFlashDmaTrEventRegister(appObj);
    DebugP_assert(status == SystemP_SUCCESS);
    memset(gOspiFlashDmaRxBuf, 0, APP_OSPI_FLASH_DMA_BUF_SIZE);
    ospi_flash_ReadDirect(APP_OSPI_FLASH_DMA_OFFSET, gOspiFlashDmaRxBuf, APP_OSPI_FLASH_DMA_BUF_SIZE);

    memset(gOspiFlashDmaRxBuf, 0, APP_OSPI_FLASH_DMA_BUF_SIZE);
    status = ospi_flash_eraseBlk(32);

    status = ospi_flash_eraseBlk(0);

    /* UDMA Channel enable */
    udmaStatus = Udma_chEnable(appObj->udmaChHandle_channel0);
    DebugP_assert(UDMA_SOK == udmaStatus);


    udmaStatus = Udma_chEnable(appObj->udmaChHandle_channel1);
    DebugP_assert(UDMA_SOK == udmaStatus);


    /* Fill buffers with known data */
    App_OspiFlashDmaFillBuffers(APP_OSPI_FLASH_DMA_TEST_SIZE_BYTES);

    //status = OSPI_enableDacMode(appObj->ospiHandle);

    //ospi_flash_WriteDirect(0, gOspiFlashDmaTxBuf, APP_OSPI_FLASH_DMA_BUF_SIZE);




    /* Enable the DAC mode so that the DMA can read directly from the flash */
    status = OSPI_enableDacMode(appObj->ospiHandle);

    /* Enable PHY */
    if((OSPI_isPhyEnable(appObj->ospiHandle) == TRUE) && (OSPI_getPhyEnableSuccess(appObj->ospiHandle) == TRUE))
    {
        //OSPI_enablePhy(appObj->ospiHandle);
        /* We are using DMA separately, so no need to check if OSPI DMA mode is enabled */
        //OSPI_enablePhyPipeline(appObj->ospiHandle);
    }

    /* Submit TRPD to channel */
    //
    
    trpdMemPhy = (uint64_t) Udma_defaultVirtToPhyFxn(udgOspiFlashDmaTrpdMemChannel0, 0U, NULL);
    flashSrcAddr = OSPI_getFlashDataBaseAddr(appObj->ospiHandle) + APP_OSPI_FLASH_DMA_OFFSET+0x400000;
    App_OspiFlashDmaTrpdInit(appObj->udmaChHandle_channel0,
                             0,
                             &udgOspiFlashDmaTrpdMemChannel0[0],
                             (void *)flashSrcAddr,
                             &gOspiFlashDmaRxBuf[0],
                             APP_OSPI_FLASH_DMA_TEST_SIZE_BYTES);

    udmaStatus = Udma_ringQueueRaw(Udma_chGetFqRingHandle(appObj->udmaChHandle_channel0), trpdMemPhy);

    DebugP_assert(udmaStatus==UDMA_SOK);




    uint64_t trpdMemPhy1;
    uint32_t flashDstAddr1;



    trpdMemPhy1 = (uint64_t) Udma_defaultVirtToPhyFxn(udgOspiFlashDmaTrpdMemChannel1, 0U, NULL);
    flashDstAddr1 = OSPI_getFlashDataBaseAddr(appObj->ospiHandle) + APP_OSPI_FLASH_DMA_OFFSET;
    App_OspiFlashDmaTrpdInit(appObj->udmaChHandle_channel1,
                             1,
                             &udgOspiFlashDmaTrpdMemChannel1[0],
                             &gOspiFlashDmaTxBuf[0],
                             (void *)flashDstAddr1,
                             APP_OSPI_FLASH_DMA_TEST_SIZE_BYTES);

    udmaStatus = Udma_ringQueueRaw(Udma_chGetFqRingHandle(appObj->udmaChHandle_channel1), trpdMemPhy1);
    

    


    DebugP_assert(udmaStatus==UDMA_SOK);

    if(udmaStatus == UDMA_SOK)
    {
        status = SystemP_SUCCESS;
    }
    else
    {
        status = SystemP_FAILURE;
    }

    return status;
}

int32_t App_OspiFlashDmaDeinit(App_OspiFlashDmaObj *appObj)
{
    int32_t status = SystemP_SUCCESS;
    int32_t udmaStatus = UDMA_SOK;

    /* Disable PHY */
    if((OSPI_isPhyEnable(appObj->ospiHandle) == TRUE) && (OSPI_getPhyEnableSuccess(appObj->ospiHandle) == TRUE))
    {
        OSPI_disablePhy(appObj->ospiHandle);
        OSPI_disablePhyPipeline(appObj->ospiHandle);
    }

    /* Since TR Reload Count Set for perpetual loop, TRPD never completes and comes back to CQ.
     * To exit, teardown the channel using Udma_chDisable */
    udmaStatus = Udma_chDisable(appObj->udmaChHandle_channel0, UDMA_DEFAULT_CH_DISABLE_TIMEOUT);
    DebugP_assert(udmaStatus == UDMA_SOK);

    /* During channel forced teardown to break from the TR Reload Perpetual loop,
     * DMA will complete the already reloaded TR. This results in setting the
     * interrupt status register after this transfer completion.
     * Hence clear the interrupt */
    CSL_REG64_WR(appObj->trEventParams_channel0.intrClearReg, appObj->trEventParams_channel0.intrMask);

    /* Unregister the event */
    status = App_OspiFlashDmaTrEventUnregister(appObj);
    DebugP_assert(status == SystemP_SUCCESS);

    return status;
}

static inline uint64_t App_OspiFlashDmaGetTicksDiff(uint32_t stop, uint32_t start, uint32_t delay)
{
    uint32_t ticksDiff;

    if(stop > start)
    {
        ticksDiff = (uint64_t)(stop - start - delay);
    }
    else
    {
        /* Counter overflow, assume only one overflow has happened */
        ticksDiff = (uint64_t)((0xFFFFFFFFU - start) + stop - delay);
    }

    return ticksDiff;
}

int32_t App_OspiFlashDmaTrEventRegister(App_OspiFlashDmaObj *appObj)
{
    int32_t status = SystemP_SUCCESS;
    int32_t udmaStatus = UDMA_SOK;

    if(NULL != appObj)
    {
        Udma_EventHandle eventHandleChannel0 = &appObj->trEventObj_channel0;
        UdmaEventPrms_init(&appObj->trEventParams_channel0);
        appObj->trEventParams_channel0.eventType = UDMA_EVENT_TYPE_TR;
        appObj->trEventParams_channel0.eventMode = UDMA_EVENT_MODE_SHARED;
        appObj->trEventParams_channel0.chHandle  = appObj->udmaChHandle_channel0;
        /* For polling mode we can't use the existing controller event as that is meant only for interrupt event -
         *  we can't mix interrupt and poll mode in same controller handle. Set the parameter to NULL
         *  so that the driver creates a new controller event. */
        appObj->trEventParams_channel0.controllerEventHandle = NULL;
        appObj->trEventParams_channel0.eventCb           = NULL;
        appObj->trEventParams_channel0.appData           = NULL; /* No callback */
        udmaStatus = Udma_eventRegister(appObj->udmaDrvHandle, eventHandleChannel0, &appObj->trEventParams_channel0);
        DebugP_assert(udmaStatus == UDMA_SOK);
        appObj->trEventHandle_channel0 = eventHandleChannel0;


        Udma_EventHandle eventHandleChannel1 = &appObj->trEventObj_channel1;
        UdmaEventPrms_init(&appObj->trEventParams_channel1);
        appObj->trEventParams_channel1.eventType = UDMA_EVENT_TYPE_TR;
        appObj->trEventParams_channel1.eventMode = UDMA_EVENT_MODE_SHARED;
        appObj->trEventParams_channel1.chHandle  = appObj->udmaChHandle_channel1;

        appObj->trEventParams_channel1.controllerEventHandle = eventHandleChannel0;
        appObj->trEventParams_channel1.eventCb           = NULL;
        appObj->trEventParams_channel1.appData           = NULL; /* No callback */
        udmaStatus = Udma_eventRegister(appObj->udmaDrvHandle, eventHandleChannel1, &appObj->trEventParams_channel1);
        DebugP_assert(udmaStatus == UDMA_SOK);
        appObj->trEventHandle_channel1 = eventHandleChannel1;
        
    }
    else
    {
        status = SystemP_FAILURE;
    }

    return status;
}

int32_t App_OspiFlashDmaTrEventUnregister(App_OspiFlashDmaObj *appObj)
{
    int32_t status = SystemP_SUCCESS;

    if(NULL != appObj)
    {
        int32_t udmaStatus = Udma_eventUnRegister(appObj->trEventHandle_channel0);
        DebugP_assert(udmaStatus == UDMA_SOK);
        udmaStatus = Udma_eventUnRegister(appObj->trEventHandle_channel1);
        DebugP_assert(udmaStatus == UDMA_SOK);
        appObj->trEventHandle_channel0 = NULL;
        appObj->trEventHandle_channel1 = NULL;
    }
    else
    {
        status = SystemP_FAILURE;
    }

    return status;
}

void App_OspiFlashDmaTrpdInit(Udma_ChHandle chHandle, uint8_t chIdx, uint8_t* trpdMem, void *src, void *dst, uint32_t length)
{
    CSL_UdmapCppi5TRPD *pTrpd = (CSL_UdmapCppi5TRPD *)trpdMem;
    CSL_UdmapTR15 *pTr;
    uint32_t cqRingNum = Udma_chGetCqRingNum(chHandle);

    /* Make TRPD */
    UdmaUtils_makeTrpdTr15(trpdMem, 1U, cqRingNum);
    CSL_udmapCppi5TrSetReload((CSL_UdmapCppi5TRPD*)pTrpd, APP_OSPI_FLASH_DMA_TR_INFINITE_RELOAD_CNT, 0U);

    /* Setup TR */
    pTr = UdmaUtils_getTrpdTr15Pointer(trpdMem, 0U);
    pTr->flags  = CSL_FMK(UDMAP_TR_FLAGS_TYPE, CSL_UDMAP_TR_FLAGS_TYPE_4D_BLOCK_MOVE_REPACKING_INDIRECTION);
    pTr->flags |= CSL_FMK(UDMAP_TR_FLAGS_STATIC, 0U);
    pTr->flags |= CSL_FMK(UDMAP_TR_FLAGS_EOL, CSL_UDMAP_TR_FLAGS_EOL_ICNT0_ICNT1_ICNT2_ICNT3);
    pTr->flags |= CSL_FMK(UDMAP_TR_FLAGS_EVENT_SIZE, CSL_UDMAP_TR_FLAGS_EVENT_SIZE_COMPLETION);
    pTr->flags |= CSL_FMK(UDMAP_TR_FLAGS_TRIGGER0, CSL_UDMAP_TR_FLAGS_TRIGGER_GLOBAL0);
    pTr->flags |= CSL_FMK(UDMAP_TR_FLAGS_TRIGGER1, CSL_UDMAP_TR_FLAGS_TRIGGER_NONE);
    pTr->flags |= CSL_FMK(UDMAP_TR_FLAGS_TRIGGER0_TYPE, CSL_UDMAP_TR_FLAGS_TRIGGER_TYPE_ALL);
    pTr->flags |= CSL_FMK(UDMAP_TR_FLAGS_TRIGGER1_TYPE, CSL_UDMAP_TR_FLAGS_TRIGGER_TYPE_ALL);
    pTr->flags |= CSL_FMK(UDMAP_TR_FLAGS_CMD_ID, 0x25U);
    pTr->flags |= CSL_FMK(UDMAP_TR_FLAGS_SA_INDIRECT, 0U);
    pTr->flags |= CSL_FMK(UDMAP_TR_FLAGS_DA_INDIRECT, 0U);
    pTr->flags |= CSL_FMK(UDMAP_TR_FLAGS_EOP, 1U);

    pTr->icnt0    = length;
    pTr->icnt1    = 1;
    pTr->icnt2    = 1;
    pTr->icnt3    = 1;
    pTr->addr     = (uint64_t) Udma_defaultVirtToPhyFxn(src, 0U, NULL);
    pTr->fmtflags = 0x00000000U;        /* Linear addressing, 1 byte per elem. */

    pTr->dicnt0   = length;
    pTr->dicnt1   = 1;
    pTr->dicnt2   = 1;
    pTr->dicnt3   = 1;
    pTr->daddr    = (uint64_t) Udma_defaultVirtToPhyFxn(dst, 0U, NULL);

    pTr->dim1     = pTr->icnt0;
    pTr->dim2     = (pTr->icnt0 * pTr->icnt1);
    pTr->dim3     = (pTr->icnt0 * pTr->icnt1 * pTr->icnt2);
    pTr->ddim1    = pTr->dicnt0;
    pTr->ddim2    = (pTr->dicnt0 * pTr->dicnt1);
    pTr->ddim3    = (pTr->dicnt0 * pTr->dicnt1 * pTr->dicnt2);

}

void App_OspiFlashDmaFillBuffers(uint32_t lenBytes)
{
    uint32_t i;
    uint32_t wordLength = lenBytes;

    for(i = 0U; i < wordLength; i++)
    {
        gOspiFlashDmaTxBuf[i] = (i*5)%256;
        gOspiFlashDmaRxBuf[i] = 0U;
    }
}

int32_t App_OspiFlashDmaCompareBuffers(uint32_t lenBytes)
{
    int32_t status = SystemP_SUCCESS;
    uint32_t i;
    uint32_t wordLength = lenBytes/sizeof(uint32_t);

    if(lenBytes % sizeof(uint32_t) != 0)
    {
        wordLength += 1;
    }

    for(i = 0U; i < wordLength; i++)
    {
        if(gOspiFlashDmaTxBuf[i] != gOspiFlashDmaRxBuf[i])
        {
            status = SystemP_FAILURE;
            DebugP_logError("OSPI read data mismatch at index %d !!!\r\n", i);
            break;
        }
    }

    return status;
}

void App_printPerformanceResults(App_OspiFlashDmaObj *appObj, uint32_t numBytes)
{
    uint64_t cpuClockRate = 0U;
    uint32_t clkRateMHz = 0U;
    uint32_t txTicks, rxTicks, rxAvgTicks;

    cpuClockRate = SOC_getSelfCpuClk();
    clkRateMHz = cpuClockRate/1000000;

    txTicks = appObj->txTotalTicks;
    DebugP_log("OSPI Write %d bytes in %u ns\r\n", numBytes, txTicks*1000U/clkRateMHz);

    uint32_t i;
    rxAvgTicks = 0U;

    for(i = 0; i < APP_OSPI_FLASH_DMA_REPEAT_CNT; i++)
    {
        rxTicks = appObj->rxTotalTicks[i];
        DebugP_log("OSPI Read %d bytes in %u ns\r\n", numBytes, rxTicks*1000U/clkRateMHz);
        rxAvgTicks += rxTicks;
    }

    rxAvgTicks /= APP_OSPI_FLASH_DMA_REPEAT_CNT;

    DebugP_log("Average time for OSPI Read %d bytes in %u ns\r\n", numBytes, rxAvgTicks*1000U/clkRateMHz);
}
