/*-----------------------------------------------------------------------*/
/*  NAME : algo_dma_auto_incr.c                                          */
/*                                                                       */
/*  DESCRIPTION:                                                         */
/*                                                                       */
/*  This file demonstrates double buffering of data from external ->     */
/*  internal memory, and internal -> external memory on an image frame.  */
/*  Data from the image frame is transferred to internal memory on a     */
/*  block by block basis.                                                */
/*                                                                       */
/*  2D -> 1D transfers are used for incoming data and 1D -> 2D transfers */
/*  are used for outgoing data. Two parameter registers are used, 1 for  */
/*  the incoming ping/pong buffers and 1 for the outgoing ping/pong      */
/*  buffers.                                                             */
/*                                                                       */
/*  Autoincrementing at each DMA block transfer completion is used to    */
/*  to reduce the number of times entries in the parameter ram need to   */
/*  be updated. At the end of each block-row, the src and dst pointers   */
/*  are updated in the parameter ram to reflect the starting addresses   */
/*  of the next row of blocks.                                           */
/*=======================================================================*/
/*  Texas Instruments incorporated 2012.                                 */
/*-----------------------------------------------------------------------*/


/*-----------------------------------------------------------------------*/
/*  Standard header includes for c environment.                          */
/*-----------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

/*-----------------------------------------------------------------------*/
/*  These are the include files that are needed for edma/qdma.           */
/*-----------------------------------------------------------------------*/


#include <vcop/vcop.h>
#include "../inc/csl_edma.h"
#include "../inc/cslr_edmacc.h"
#include "../inc/eve.h"
#include "../inc/tistdtypes.h"
#include "../inc/eve_dma_macros.h"
#include "../inc/eve_dma_funcs.h"
#include "../inc/algo_dma_auto_incr.h"
#include "../inc/image_dims.h"
#include "../inc/vcop_sobelxy_kernel.h"

extern unsigned short  * __pblock_vcop_sobelX_3x3_uchar_char; //[32];
extern unsigned short  * __pblock_vcop_sobelY_3x3_uchar_char; //[32];
extern unsigned short  * __pblock_vcop_sobel_magnitude; //[16];

void algo_dma_auto_incr
(
    CSL_EdmaccRegsOvly  edma_cc,
    DMA_State_Struct    *dma_state_struct, 
    unsigned char       *src, 
    unsigned char       *dst, 
    unsigned char       *src_proc, 
    unsigned char       *dst_proc, 
    char                *dstX_proc, 
    char                *dstY_proc, 
    signed short        *intermed, 
    unsigned int        chan_in,
    unsigned int        chan_out,
    Bool                *trf_pend,
    unsigned int         inPitch[]
)
{
    volatile unsigned int   *tparam;

    /* ----------------------------------------------------- */
    /* Loop Variables                                        */
    /* Where y_offset is the vertical offset to the next     */
    /* image block.                                          */
    /* ----------------------------------------------------- */
    int                     x, y, y_offset;

    /* ----------------------------------------------------- */
    /* Pointers to buffers in external memory                */
    /* ----------------------------------------------------- */

    unsigned char           *src_ext;
    unsigned char           *dst_ext;

    /* ----------------------------------------------------- */
    /* Transfer complete codes for input and output          */
    /* ping/pong channels                                    */
    /* ----------------------------------------------------- */

    unsigned int            tcc_in;
    unsigned int            tcc_out;

    /* ----------------------------------------------------- */
    /* ESR values for each event                             */
    /* ----------------------------------------------------- */

    unsigned int            evt_no_set_in;
    unsigned int            evt_no_set_out;


    /* ----------------------------------------------------- */
    /* Words used to set register values for DMA submission  */
    /* and completion. These will be passed as arguments to  */
    /* the DMA_SUBMIT() and DMA_WAIT macros to trigger       */
    /* transfers and wait for completion.                    */
    /* ----------------------------------------------------- */

    unsigned int            wait_word;
    unsigned int            submit_word;
    unsigned int            wait_word_in_out;
    unsigned int            submit_word_in_out;
    unsigned int            submit_out;
    unsigned int            wait_out;
    unsigned int            submit_in;
    unsigned int            wait_in;


    /* ----------------------------------------------------- */
    /* Input image dimensions                                */
    /* ----------------------------------------------------- */

    unsigned int imgw       = IMG_WIDTH;
    unsigned int imgh       = IMG_HEIGHT;


    /* ----------------------------------------------------- */
    /* Block dimensions                                      */
    /* ----------------------------------------------------- */

    unsigned int blkw           = BLK_WIDTH;
    unsigned int blkh           = BLK_HEIGHT;
    unsigned int src_line_pitch = inPitch[0];
    unsigned int dst_line_pitch = IMG_WIDTH;
    unsigned int pad            = BLK_PAD;


    /* ----------------------------------------------------- */
    /* Pointer to VCOP IBUFL/H buffers for processing        */
    /* ----------------------------------------------------- */

    unsigned char           *src_vcop_proc;
    char                    *OUTX_buf;
    char                    *OUTY_buf;
    unsigned char           *dst_vcop_proc;

    /* -------------------------------------------------------------------- */
    /* Used to check if we are processing the first or last block in the    */
    /* row.                                                                 */
    /* -------------------------------------------------------------------- */

    unsigned int first_hrz_block  = 0;
    unsigned int last_hrz_block   = (IMG_WIDTH/BLK_WIDTH) - 1;

//    unsigned int num_wpreg_params;

    unsigned int auto_incr_cnt;

    unsigned int  flag;

    /* -------------------------------------------------------------------- */
    /* Assign pointers to IBUFL/H buffers                                   */
    /* -------------------------------------------------------------------- */

    src_vcop_proc = src_proc;
    OUTX_buf = dstX_proc;
    OUTY_buf = dstY_proc;
    dst_vcop_proc = dst_proc;

    /* -------------------------------------------------------------------- */
    /* Assign pointers to DDR buffers                                       */
    /* -------------------------------------------------------------------- */

    src_ext = src;
    dst_ext = dst;

    /* -------------------------------------------------------------------- */
    /* Precompute the transfer complete codes and event set register values */
    /* that will be passed into the DMA_WAIT and DMA_SUBMIT macros. These   */
    /* macros are used to start transfers and check for completion.         */
    /* -------------------------------------------------------------------- */

    tcc_in          =    0x1 << dma_state_struct->tcc_val[chan_in];
    tcc_out         =    0x1 << dma_state_struct->tcc_val[chan_out];

    evt_no_set_in   =    (CSL_EDMACC_ESR_E0_SET << dma_state_struct->physical_chan[chan_in]);
    evt_no_set_out  =    (CSL_EDMACC_ESR_E0_SET << dma_state_struct->physical_chan[chan_out]);

    wait_word_in_out     =    tcc_in | tcc_out;
    submit_word_in_out   =    evt_no_set_in | evt_no_set_out;

    submit_out      =    evt_no_set_out;
    wait_out        =    tcc_out;

    submit_in       =    evt_no_set_in;
    wait_in         =    tcc_in;

    auto_incr_cnt = 2*(imgw/blkw);

    /* -------------------------------------------------------------------- */
    /* Initialize parameter regs for the VCOP copy function.                */
    /* -------------------------------------------------------------------- */

    VCOP_BUF_SWITCH_SET (WBUF_SYST, IBUFHB_SYST, IBUFLB_SYST, IBUFHA_SYST, IBUFLA_SYST);

//    num_wpreg_params =
    vcop_sobelX_3x3_uchar_char_init
    (

         src_vcop_proc,  // IBUFLA
         intermed,       // WBUF
         OUTX_buf,       // IBUFLA
         blkw + pad, // input width
         blkh + pad, // input height
         blkw,       // output width
         blkh,       // output height
         blkw,       // compute width
         blkh + pad, // compute height
         0, // input type - uchar
         2, // intermediate array type - short
         2, // output type - char
         3, // round_shift value
        __pblock_vcop_sobelX_3x3_uchar_char      
     );

//    num_wpreg_params =
    vcop_sobelY_3x3_uchar_char_init
    (

         src_vcop_proc,  // IBUFLA
         intermed,       // WBUF
         OUTY_buf,       // IBUFLA
         blkw + pad, // input width
         blkh + pad, // input height
         blkw,       // output width
         blkh,       // output height
         blkw,       // compute width
         blkh + pad, // compute height
         0, // input type - uchar
         2, // intermediate array type - short
         2, // output type - char
         3, // round_shift value
        __pblock_vcop_sobelY_3x3_uchar_char      
     );
 
//     num_wpreg_params =
     vcop_sobel_magnitude_init
     (
         OUTX_buf,       //IBUFLA
         OUTY_buf,       //IBUFLA
         dst_vcop_proc,  // IBUFHA
         blkw,
         blkh,
         blkw/2,
         __pblock_vcop_sobel_magnitude
     );  
    
    /* ----------------------------------------------------------------- */
    /* Processing loop begins here                                       */
    /* ----------------------------------------------------------------- */

    flag  = BUF_PING;

    for(y = 0; y < imgh/blkh; y++)
    {
        /* ------------------------------------------------------------- */
        /* Prologue:                                                     */
        /* Transfer the first block in row, reset image pointers and     */
        /* block count for autoincrementing                              */    
        /* ------------------------------------------------------------- */

        y_offset = y*blkh;

        /* ------------------------------------------------------------- */
        /* Set pointers for current block row.                           */
        /* ------------------------------------------------------------- */

        src_ext = src + (y_offset * src_line_pitch);
        dst_ext = dst + (y_offset/2 * dst_line_pitch/2);

        /* ------------------------------------------------------------- */
        /* Assign pointer values to their associated PARAM ram entries   */
        /* ------------------------------------------------------------- */

        tparam     =    dma_state_struct->trig_param[chan_in];
        tparam[1]  =    (unsigned int) src_ext;
        tparam[7]  =    auto_incr_cnt;

        tparam     =    dma_state_struct->trig_param[chan_out];    
        tparam[3]  =    (unsigned int) dst_ext;
        tparam[7]  =    auto_incr_cnt; 

        /* -------------------------------------------------------------- */
        /* Assign ping/pong buffer to first block transfer in row         */
        /* -------------------------------------------------------------- */
 
        submit_word    =    submit_in;
        wait_word      =    wait_in;

        /*---------------------------------------------------------------*/
        /*  Set transfer pending status flag, to indicate that transfer  */
        /*  is in progress.                                              */
        /*---------------------------------------------------------------*/

        *trf_pend  =  TRUE;

        VCOP_BUF_SWITCH_SET (WBUF_VCOP, IBUFHB_VCOP, IBUFLB_VCOP, IBUFHA_SYST, IBUFLA_SYST);   

        /* ------------------------------------------------------------- */
        /* Kick off first block transfer                                 */
        /* ------------------------------------------------------------- */

        DMA_SUBMIT(submit_word);

        /* ------------------------------------------------------------- */
        /*  Check for completion of first horizontal block before        */
        /*  before entering inner loop.                                  */
        /* ------------------------------------------------------------- */

        DMA_WAIT(wait_word);

        /*---------------------------------------------------------------*/
        /*  Clear trf_pend status, as we have finished waiting on trans. */
        /*---------------------------------------------------------------*/

        *trf_pend   = FALSE;
        
        /* --------------------------------------------------------------*/
        /* Inner loop, used to process a horizontal row of image blocks  */
        /* ------------------------------------------------------------- */

        flag = BUF_PING;

        for(x = 0; x < (imgw/blkw); x++)
        {

            /* --------------------------------------------------------- */
            /* Case A: Ping                                              */
            /*                                                           */
            /* We will transfer a new ping buffer to internal memory and */
            /* transfer the previously processed ping buffer to external */
            /* mem. While this transfer is occuring, we will process     */
            /* data in the pong buffer.                                  */
            /*                                                           */
            /* Case B: Pong                                              */
            /*                                                           */
            /* We will transfer a new pong buffer to internal memory and */
            /* transfer the previously processed pong buffer to external */
            /* mem. While this transfer is occuring, we will process     */
            /* data in the ping buffer.                                  */
            /* --------------------------------------------------------- */

            flag = VCOP_BUF_SWITCH_TOGGLE (flag);

            submit_word = submit_word_in_out;
            wait_word = wait_word_in_out;

            /* -------------------------------------------------------- */
            /* If we are at first or last iteration in inner loop, set  */
            /* the enable words to be single direction "in" or "out"    */
            /* channels.                                                */
            /* -------------------------------------------------------- */
    
            if(x == last_hrz_block)
            {
                submit_word = submit_out;
                wait_word   = wait_out;
            }

            if(x == first_hrz_block)
            {
                submit_word = submit_in;
                wait_word   = wait_in;
            }

            *trf_pend  =  TRUE;


            /* ------------------------------------------------------------- */
            /* Kick off transfers of next block to process before processing */
            /* the current block.                                            */
            /* ------------------------------------------------------------- */

            DMA_SUBMIT(submit_word);

            /* ------------------------------------------------------------- */
            /* Use VCOP to copy data from IBUFL to IBUFH while DMA transfers */
            /* are occuring.                                                 */
            /* ------------------------------------------------------------- */

            vcop_sobelX_3x3_uchar_char_vloops(__pblock_vcop_sobelX_3x3_uchar_char);
            vcop_sobelY_3x3_uchar_char_vloops(__pblock_vcop_sobelY_3x3_uchar_char);
            vcop_sobel_magnitude_vloops(__pblock_vcop_sobel_magnitude);

            /* ------------------------ */
            /* Wait for VCOP to be done */
            /* ------------------------ */

            _vcop_vloop_done();

            /* ------------------------------------------------------------- */
            /* Check for transfer completion after processing data           */
            /* ------------------------------------------------------------- */

            DMA_WAIT(wait_word);

            *trf_pend   = FALSE;
        }

        /* ----------------------------------------------------------------- */
        /*  Epilogue:                                                        */
        /*  Transfer the last processed block in the row                     */
        /* ----------------------------------------------------------------- */

        flag = VCOP_BUF_SWITCH_TOGGLE (flag); 

        wait_word        =  wait_out;
        submit_word      =  submit_out;

        *trf_pend  =  TRUE;

        DMA_SUBMIT(submit_word);
        DMA_WAIT(wait_word);
 
        *trf_pend   = FALSE;

   }
}

/*-----------------------------------------------------------------------*/
/*  End of file algo_dma_auto_incr.c                                     */
/*=======================================================================*/
/*  Texas Instruments incorporated 2012.                                 */
/*-----------------------------------------------------------------------*/
