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

//CSL_UppRegs UPPRegs;
// breakpoint macro
//#define INSERT_BREAKPOINT_HERE	(asm(" nop"))

// config
#define xferSize	(512)	// max: 8192
#define lineCnt		(1)		// note: xferSize should be evenly divisible by lineCnt.
#define dataWidth	(8)		// 8, 16


#pragma DATA_SECTION(xmtBuffer,".L2_buffers");
#pragma DATA_ALIGN(xmtBuffer,64);
char xmtBuffer[xferSize];	//

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



static void LOCAL_delay(int cnt);


int main(void) {

//	UPPRegs->UPCTL = 0xDEADBEEF;

    uppDevParams uPP;
	int status = 0;

	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_ch0_pinmuxEn();	// setup pinmux // Varada : Pin mux functions disabled. Because test runs on EVM, in internal loopback mode.
//	upp_ch1_pinmuxEn(); // Varada : Also cannot find CSL_BOOTCFG_0_REGS .....

	upp_psc_enable();	// setup power, Varada : Consider turning ON everything thru gel

	// 1. toggle SW reset in PCR
	CSL_FINST(uppRegs->UPPCR, UPP_UPPCR_SWRST, RESET);
	LOCAL_delay(200);
	CSL_FINST(uppRegs->UPPCR, UPP_UPPCR_SWRST, RUNNING);// Varada : RUNNING instead of RUN

	// 2. read PID (skip)
	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;
	}


	// 3. 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_128B;

	uPP.A.useTristate = 0x1;        // Varada: added this since RX DMA completes before TX DMA programmed

	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_128B;

	uPP.B.useEnable   = 0;
	uPP.B.useStart    = 0;
	uPP.B.useWait     = 0;
	uPP.B.useTristate = 0x1;		// Varada: added this since RX DMA completes before TX DMA programmed

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

	status = upp_config(&uPP);

	if (status < 0) return status;

	// 4. init interrupt regs

	//upp_intc_setup(upp_isr);	// setup intc (removed: use polled operation)

#if 0 // Varada : Comment this as using polled mode.
	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

	// 5. init PCR enable

	// CSL_FINST(uppRegs->UPPCR, UPP_UPPCR_EN, ENABLE); // Varada : enable later

	// 6. init DMA channels

	//upp_dma_prog(UPP_DMA_CHAN_Q, (void *)rcvBuffer, lineCnt, xferSize / lineCnt, xferSize / lineCnt);
	//upp_dma_prog(UPP_DMA_CHAN_I, (void *)xmtBuffer, lineCnt, xferSize / lineCnt, xferSize / lineCnt);
	upp_dma_prog(UPP_DMA_CHAN_Q, (void *)rcvBuffer, lineCnt, xferSize / lineCnt, 0);
	upp_dma_prog(UPP_DMA_CHAN_I, (void *)xmtBuffer, lineCnt, xferSize / lineCnt, 0);

	// 7. observe transfers, interrupts : Varada : Todo : Make this polling : EOW/EOL bits for I and Q channel

#if 0
	while (1) {
		// count EOL events
		status = upp_int_status();
		if (status & upp_int_EOLI)
		{
			intCnt.EOLI++;
			upp_int_clear(upp_int_EOLI);
		}
		if (status & upp_int_EOLQ)
		{
			intCnt.EOLQ++;
			upp_int_clear(upp_int_EOLQ);
		}

		// break loop if EOW events occur
		if ((status & (upp_int_EOWI | upp_int_EOWQ)) == (upp_int_EOWI | upp_int_EOWQ))
			break;
	}

	// check for any last-second EOL interrupts (prevent race condition)
	status = upp_int_status();
	intCnt.EOLI += (status & upp_int_EOLI) ? 1 : 0;
	intCnt.EOLQ += (status & upp_int_EOLQ) ? 1 : 0;

	// check received buffer
	status = upp_check_buffer(rcvBuffer, xmtBuffer, xferSize);

	// check EOL interrupts
	status |= (intCnt.EOLI == lineCnt) ? 0 : -1;
	status |= (intCnt.EOLQ == lineCnt) ? 0 : -1;
#endif
	status = 0;
	return status;

	upp_test_exit:

}

static void LOCAL_delay(int cnt)
{
	int i;

	for (i = 0; i < cnt; i++)
		asm(" nop");
}
