#include <stdio.h>
#include "upp_common.h"

#define UPP_ISR_TEST

/* Transfer size */
#define xferSize	8320 //(2048)	// max: 8192
#define lineCnt		(1)		// note: xferSize should be evenly divisible by lineCnt.
#define dataWidth	(16)		// 8, 16

/* Buffers placed in L2 memory */
#pragma DATA_SECTION(xmtBuffer,".L2_buffers");
#pragma DATA_ALIGN(xmtBuffer,8);
char xmtBuffer[xferSize];

#pragma DATA_SECTION(rcvBuffer,".L2_buffers");
#pragma DATA_ALIGN(rcvBuffer,8);
char rcvBuffer[xferSize];

/* Function definitions */
static void LOCAL_delay(int cnt);

/*
 *  upp_dlb_test : simple uPP digital loopback test.
 *  Note : PSC is assumed to be turned on, by default_setup in the C6657 gel file.
 */
int upp_dlb_test(){

	int i         = 0;
	int status    = 0;
	int intStatus = 0;
	int nCnt      = 5; /* loop count of DMA xfer */

	uppDevParams uPP;

	upp_fill_buffer(xmtBuffer, dataWidth, UPP_DP_RJUST_0FILL, xferSize);	// fill transmit buffer with test pattern
	upp_fill_buffer(rcvBuffer, 0, UPP_DP_RJUST_0FILL, xferSize);			// clear receive buffer

	upp_key_config();	// program the KICK0 and 1 registers.
    upp_pinmux_enable(); // Though internal loopback, enable uPP in PIN_CONTROL_1

	// read PID
	int pid = CSL_FEXT(uppRegs->UPPID, UPP_UPPID_REVID);
	if(pid != CSL_UPP_UPPID_RESETVAL){
			printf("\n Error : Incorrect UPP ID read.");
			goto upp_test_exit;
	}

    // toggle SW reset in PCR
	CSL_FINST(uppRegs->UPPCR, UPP_UPPCR_SWRST, RESET);
	LOCAL_delay(200);
	CSL_FINST(uppRegs->UPPCR, UPP_UPPCR_SWRST, RUNNING);


	// init regs: CTL, ICR, IVR, TCR
	uPP = uppDevParams_DEFAULT;
	uPP.A.direction = UPP_DIR_XMT;
	uPP.A.dataRate = UPP_DR_SDR;
	uPP.A.dataWidthVal = dataWidth;
	uPP.A.idleValueVal = 0xAAAA;
	uPP.A.clkDivVal = 0x1;			// use clock div between 0 and 0xF
	uPP.A.txThresh = UPP_TT_64B;

	uPP.B.direction = UPP_DIR_RCV;
	uPP.B.dataRate = UPP_DR_SDR;
	uPP.B.dataWidthVal = dataWidth;
	uPP.B.idleValueVal = 0xBBBB;
	uPP.B.clkDivVal = 0x1;
	uPP.B.rcvThresh = UPP_TT_64B;

	uPP.loopback = UPP_LB_INTERNAL;
	uPP.numChannelsVal = 2;

	status = upp_config(&uPP);
	  if (status < 0)
		  goto upp_test_exit;

	// init interrupt regs
#if 1
	memset((void *)&intCnt, 0, sizeof(upp_int_cnt));
	upp_intc_setup(upp_isr);	// setup intc (removed: use polled operation)

	upp_int_enable(	//upp_int_EOLI |
					upp_int_EOWI |
					upp_int_ERRI | upp_int_UORI | upp_int_DPEI |
					//upp_int_EOLQ |
					upp_int_EOWQ |
					upp_int_ERRQ | upp_int_UORQ | upp_int_DPEQ |
					0 );
#endif


#ifdef UPP_ISR_TEST
	/* trigger the first DMA Tx/Rx */
	// Ensure uPP not enabled yet.
	CSL_FINST(uppRegs->UPPCR, UPP_UPPCR_EN, DISABLE);

	// init DMA channels
	while(CSL_FEXT(uppRegs->UPQS2, UPP_UPQS2_PEND) == 0) //UPP_UPQS2_ACT
		upp_dma_prog(UPP_DMA_CHAN_Q, (void *)rcvBuffer, lineCnt, xferSize / lineCnt, xferSize / lineCnt);

	while(CSL_FEXT(uppRegs->UPIS2, UPP_UPIS2_PEND) == 0)
		upp_dma_prog(UPP_DMA_CHAN_I, (void *)xmtBuffer, lineCnt, xferSize / lineCnt, xferSize / lineCnt);


	// Enable uPP here. PCR.EN bit
	 CSL_FINST(uppRegs->UPPCR, UPP_UPPCR_EN, ENABLE);
#else
	for(i=0; i<nCnt ; i++)
	{
		// Ensure uPP not enabled yet.
		 CSL_FINST(uppRegs->UPPCR, UPP_UPPCR_EN, DISABLE);

		// init DMA channels
        while(CSL_FEXT(uppRegs->UPQS2, UPP_UPQS2_PEND) == 0) //UPP_UPQS2_ACT
        	upp_dma_prog(UPP_DMA_CHAN_Q, (void *)rcvBuffer, lineCnt, xferSize / lineCnt, xferSize / lineCnt);

        while(CSL_FEXT(uppRegs->UPIS2, UPP_UPIS2_PEND) == 0)
        	upp_dma_prog(UPP_DMA_CHAN_I, (void *)xmtBuffer, lineCnt, xferSize / lineCnt, xferSize / lineCnt);


		// Enable uPP here. PCR.EN bit
		 CSL_FINST(uppRegs->UPPCR, UPP_UPPCR_EN, ENABLE);

		// Poll for EOW/EOL bits, I and Q channel
		do{
		  intStatus = uppRegs->UPISR;
		 }while (!((intStatus & upp_int_EOWI)&& (intStatus & upp_int_EOWQ)));

        // Ensure no error condition
		if(((intStatus & (upp_int_ERRI |upp_int_UORI | upp_int_DPEI)) || (intStatus & (upp_int_ERRQ |upp_int_UORQ | upp_int_DPEQ))))
		{
			status = -1;
			goto upp_test_exit;
		}

		// Verify the buffer
		if(upp_check_buffer(xmtBuffer, rcvBuffer, xferSize) != 0)
		{
			status = -1;
			printf ("uPP DLB failed for the %d test\n", i);
			goto upp_test_exit;
		}
		else
		{
			printf ("uPP DLB passed for the %d test\n", i);
		}
	}
#endif
	status = 0;

    upp_test_exit:
	  return status;
}

static void LOCAL_delay(int cnt)
{
	int i;

	for (i = 0; i < cnt; i++)
		asm(" nop");
}
volatile int gtestTxFlag = 0;
volatile int gtestRxFlag = 0;
int gtestTxCnt = 1;
int gtestRxCnt = 1;
int main(void) {
	int status;
	status =upp_dlb_test();
	while(1)
	{
		if(gtestTxFlag == 1)
		{
		    while(CSL_FEXT(uppRegs->UPIS2, UPP_UPIS2_PEND) == 0)
		    {
		    	gtestTxCnt++;
		    	upp_dma_prog(UPP_DMA_CHAN_I, (void *)xmtBuffer, 1, 8320, 0);
		    }
		    gtestTxFlag = 0;
		}

		if(gtestRxFlag == 1)
		{
		    while(CSL_FEXT(uppRegs->UPQS2, UPP_UPQS2_PEND) == 0) //UPP_UPQS2_ACT
		    {
			    gtestRxCnt++;
			    upp_dma_prog(UPP_DMA_CHAN_Q, (void *)rcvBuffer, 1, 8320, 0);
		    }
		    gtestRxFlag = 0;
		}
	}
	return status;
}
