#include "jesd_csu.h"
#include "jesd204.h"
#include "ape_csu.h"
#include "ucp_csu.h"
#include "ucp_utility.h"
#include "ucp_drv_common.h"

stJesdCsuPara gJesdCsuPara;


int32_t jesd_csu_init(uint8_t antNum, uint8_t margin)
{
	if ((0 == antNum) || (8 < antNum))
	{
		return -1;
	}
	if (7 < margin)
	{
		return -1;
	}

	
	volatile uint32_t  *reg_addr = NULL;

    reg_addr = &JS_CSU_DMAADDRL0;  
    for(int index = 0; index < 16 * 8; index++)
    {
        do_write((reg_addr+index), 0); 
	}

	memset(&gJesdCsuPara, 0, sizeof(stJesdCsuPara));
	gJesdCsuPara.antNum = antNum;
	gJesdCsuPara.m = antNum*2;
	gJesdCsuPara.n = JS_204B_CONVERTER_BITS;
	gJesdCsuPara.cs = JS_204B_CS_BITS;
	gJesdCsuPara.cf = JS_204B_CF_VAL;
	if (0 == gJesdCsuPara.cf)
	{
		gJesdCsuPara.nTotal = JS_204B_CONVERTER_BITS + JS_204B_CS_BITS;
	}
	else
	{
		gJesdCsuPara.nTotal = JS_204B_CONVERTER_BITS;
	}
	if (0 != (gJesdCsuPara.nTotal%4))
	{
		gJesdCsuPara.nTotal = ((gJesdCsuPara.nTotal>>2)+1) << 2;
	}
	gJesdCsuPara.seq = antNum;
	gJesdCsuPara.margin = margin;
	
	//	[ 1: 0] -> CS
	//	[ 6: 4] -> Margin
	//	[15: 8] -> Num, (16+2*Num)=2*N
	//	[23:16] -> N*M
	//	[25:24] -> SeqNum
	//	[27:26] -> M/2-1
	if (4 < antNum)
	{
		gJesdCsuPara.m = gJesdCsuPara.m >> 1;
		gJesdCsuPara.seq = gJesdCsuPara.seq >> 1;
	}
	uint32_t val = (((gJesdCsuPara.m>>1)-1)<<26)+((gJesdCsuPara.seq-1)<<24)+(((gJesdCsuPara.nTotal*gJesdCsuPara.m)/gJesdCsuPara.seq)<<16)+((gJesdCsuPara.n-8)<<8)+(margin<<4)+gJesdCsuPara.cs;
	debug_write((DBG_DDR_IDX_DRV_BASE+216), val); // 0x360
	do_write((&JS_CSU_JESDRX0SET), val);
	do_write((&JS_CSU_JESDTX0SET), val);
	do_write((&JS_CSU_FINDDMATAG), 0x60);						// st wait wr resp
	do_write((&JS_CSU_ALMOSTFULLSENDTHRED), 0x00040010); 		// [30:16]sendthred,<4, stop write; [14:0]almostfull, >=0x400,start write, 256bit as unit
	do_write((&JS_CSU_EM_BS_SMSEL_PREDATANUM), ((0x1<<14) | (0x5<<5) | 0x8));
	if (4 < antNum)
	{
		do_write((&JS_CSU_JESDRX1SET), val);
		do_write((&JS_CSU_JESDTX1SET), val);
		do_write((&JS_CSU_ALMOSTFULLSENDTHRED), 0x80048010); 	// [30:16]sendthred,<4, stop write; [14:0]almostfull, >=0x400,start write
		do_write((&JS_CSU_EM_BS_SMSEL_PREDATANUM), ((0x3<<14) | (0x5<<5) | 0x8));
	}

	return 0;
}

int32_t jesd_csu_rx_inlatch_thres_cfg(uint8_t ch, uint32_t send_threshold, uint32_t almostfull_threshold)
{
	uint32_t val = (ch << 31) | (send_threshold << 16) | (ch << 15) | almostfull_threshold;
	do_write((&JS_CSU_ALMOSTFULLSENDTHRED), val); 

	return 0;
}

int32_t jesd_csu_rx_list_init(uint32_t listAddr, uint32_t nodeNum, stJesdCsuNodePara* pListNode)
{
	if ((NULL == pListNode) || (0 == listAddr) || (0 == nodeNum))
	{
		return -1;
	}
	uint8_t mrg = gJesdCsuPara.margin;
	// 设置链表节点cmd
	uint32_t rxListCmdL = 0;
	uint32_t rxListCmdH = 0;
	// bit4=1，多维DMA
	// bit5=0，普通模式
	// bit[7:6]=3，该DMA可跟随上一个DMA，下一个DMA可跟随本DMA
	rxListCmdL = (1<<4)+(0<<5)+(3<<6); 

	stCsuLinkDesc1L3D* pLinkDesc = NULL;
	stCsuLinkDesc1L3D stLinkDesc;
	
	// rx: jesd -> ddr
	// 前7个下行时隙+特殊时隙的前6个符号
	int32_t i = 0;
	for(i = 0; i < nodeNum; i++)
	{
		if (0 == i)
		{
			rxListCmdL = (1<<4)+(0<<5)+(3<<6)+(1<<23); 
		}
		else
		{
			rxListCmdL = (1<<4)+(0<<5)+(3<<6);
		}
		// src
		pLinkDesc = (stCsuLinkDesc1L3D*)listAddr + 2*i;
		memset(&stLinkDesc, 0, sizeof(stCsuLinkDesc1L3D));
		stLinkDesc.cmdFifoL = rxListCmdL;
		stLinkDesc.cmdFifoH = rxListCmdH & 0x3FFF;
		stLinkDesc.dmaAddrL = 0;
		stLinkDesc.dmaXNum = 0x20;
		stLinkDesc.dmaYStep = 0x20;
		stLinkDesc.dmaYNum = 1;
		stLinkDesc.dmaZStep = 0x20;
		stLinkDesc.dmaAllNum = pListNode[i].allNum;
		stLinkDesc.dmaCGran = 1;
		stLinkDesc.dmaGran = 0;
		stLinkDesc.nAddrMode = 0;	// list addr is contiguous
		memcpy_ext(pLinkDesc, &stLinkDesc, sizeof(stCsuLinkDesc1L3D));
		// dst
		pLinkDesc = (stCsuLinkDesc1L3D*)listAddr + 2*i + 1;
		memset(&stLinkDesc, 0, sizeof(stCsuLinkDesc1L3D));
		stLinkDesc.cmdFifoL = rxListCmdL;
		stLinkDesc.cmdFifoH = rxListCmdH & 0x3FFF;
		stLinkDesc.dmaAddrL = pListNode[i].dataAddr;
		stLinkDesc.dmaXNum = 0x20 * (1<<mrg);	// 32*(2^margin)
		stLinkDesc.dmaYStep = pListNode[i].yStep;
		stLinkDesc.dmaYNum = gJesdCsuPara.seq;
		stLinkDesc.dmaZStep = 0x20 * (1<<mrg);	// 32*(2^margin)
		stLinkDesc.dmaAllNum = pListNode[i].allNum;
		stLinkDesc.dmaSize = 0xF;		// write global
		stLinkDesc.nAddrMode = 0;	// list addr is contiguous
		memcpy_ext(pLinkDesc, &stLinkDesc, sizeof(stCsuLinkDesc1L3D));
	}
	
	return 0;
}

int32_t jesd_csu_tx_list_init(uint32_t listAddr, uint32_t nodeNum, stJesdCsuNodePara* pListNode)
{
	if ((NULL == pListNode) || (0 == listAddr) || (0 == nodeNum))
	{
		return -1;
	}
	uint8_t mrg = gJesdCsuPara.margin;
	// 设置链表节点CMD
	uint32_t txListCmdL = 0;
	uint32_t txListCmdH = 0;
	// bit4=1，多维DMA
	// bit5=0，普通模式
	// bit[7:6]=3，该DMA可跟随上一个DMA，下一个DMA可跟随本DMA
	txListCmdL = (1<<4)+(0<<5)+(3<<6);

	stCsuLinkDesc1L3D* pLinkDesc = NULL;
	stCsuLinkDesc1L3D stLinkDesc;
	
	// tx: ddr -> cpri
	// 特殊时隙的后4个符号+后2个上行时隙
	int32_t i = 0;
	for(i = 0; i < nodeNum; i++)
	{
		// src
		pLinkDesc = (stCsuLinkDesc1L3D*)listAddr + 2*i;
		memset(&stLinkDesc, 0, sizeof(stCsuLinkDesc1L3D));
		stLinkDesc.cmdFifoL = txListCmdL;
		stLinkDesc.cmdFifoH = txListCmdH & 0x3FFF;
		stLinkDesc.dmaAddrL = pListNode[i].dataAddr;
		stLinkDesc.dmaXNum = 0x20*(1<<mrg);	// 32*(2^margin)
		stLinkDesc.dmaYStep = pListNode[i].yStep;
		stLinkDesc.dmaYNum = gJesdCsuPara.seq;
		stLinkDesc.dmaZStep = 0x20*(1<<mrg);	// 32*(2^margin)
		stLinkDesc.dmaAllNum = pListNode[i].allNum;
		stLinkDesc.dmaSize = 0xF;
		stLinkDesc.nAddrMode = 0;	// list addr is contiguous
		memcpy_ext(pLinkDesc, &stLinkDesc, sizeof(stCsuLinkDesc1L3D));
		// dst
		pLinkDesc = (stCsuLinkDesc1L3D*)listAddr + 2*i + 1;
		memset(&stLinkDesc, 0, sizeof(stCsuLinkDesc1L3D));
		stLinkDesc.cmdFifoL = txListCmdL;
		stLinkDesc.cmdFifoH = txListCmdH & 0x3FFF;
		stLinkDesc.dmaAddrL = 0;
		stLinkDesc.dmaXNum = 0x20;
		stLinkDesc.dmaYStep = 0x20;
		stLinkDesc.dmaYNum = 1;
		stLinkDesc.dmaZStep = 0x20;
		stLinkDesc.dmaAllNum = pListNode[i].allNum;
		stLinkDesc.dmaSize = 0;	// 0x8;// 
		stLinkDesc.dmaCGran = 1;
		stLinkDesc.dmaGran = 0;
		stLinkDesc.nAddrMode = 0;		// list addr is contiguous
		memcpy_ext(pLinkDesc, &stLinkDesc, sizeof(stCsuLinkDesc1L3D));
	}
	
	return 0;
}

int32_t jesd_csu_rx_dmaReg_Cfg(uint8_t ch, uint32_t listAddr, uint32_t nodeNum)
{
	uint32_t offset_w = (ch<<3);
	// set dma buffer
	do_write(((uint32_t*)(&JS_CSU_DMAADDRL0)+offset_w), listAddr); 			// DDR or SM
	do_write(((uint32_t*)(&JS_CSU_DMAADDRH0)+offset_w), 0); 				// DDR or SM
	do_write(((uint32_t*)(&JS_CSU_DMASIZEGRANALLNUM0)+offset_w), nodeNum);	// allnum is id num

	return 0;
}

int32_t jesd_csu_tx_dmaReg_Cfg(uint8_t ch, uint32_t listAddr, uint32_t nodeNum)
{
	uint32_t offset_w = (ch<<3);
	// set dma buffer
	do_write(((uint32_t*)(&JS_CSU_DMAADDRL2)+offset_w), listAddr); 			// DDR or SM
	do_write(((uint32_t*)(&JS_CSU_DMAADDRH2)+offset_w), 0); 				// DDR or SM
	do_write(((uint32_t*)(&JS_CSU_DMASIZEGRANALLNUM2)+offset_w), nodeNum);	// allnum is id num

	return 0;
}

int32_t jesd_csu_rx_start_ch(uint8_t ch)
{
	stCsuDmaCmdL cpriCmdL;
	*(uint32_t*)(&cpriCmdL) = 0;

	// rx cmd
	// 1 link
	// 读一级链表，写一级链表，多维DMA，非cache模式，src buf=0，tag=0
	cpriCmdL.rCmd = 1;
	cpriCmdL.wCmd = 1;
	cpriCmdL.dmaType = 1;
	cpriCmdL.continueLast = 0;
	cpriCmdL.continueNext = 0;
	cpriCmdL.idSrc = JESD_CSU_RX0_TAG+ch;
	cpriCmdL.dmaTag = JESD_CSU_RX0_TAG+ch;
	//cpriCmdL.flush = 1;
	
	do_write(&(JS_CSU_CMDHIGHDATA), 0);
	do_write(((uint32_t*)&(JS_CSU_CMDFIFO0)+(ch<<1)), *(uint32_t*)(&cpriCmdL));
	
	return 0;
}

int32_t jesd_csu_tx_start_ch(uint8_t ch)
{
	stCsuDmaCmdL cpriCmdL;
	*(uint32_t*)(&cpriCmdL) = 0;

	// tx cmd
	// 1 link
	// 读一级链表，写一级链表，多维DMA，非cache模式，src buf=1，tag=1
	cpriCmdL.rCmd = 1;
	cpriCmdL.wCmd = 1;
	cpriCmdL.dmaType = 1;
	cpriCmdL.continueLast = 1;
	cpriCmdL.continueNext = 1;
	cpriCmdL.idSrc = JESD_CSU_TX0_TAG+ch;
	cpriCmdL.dmaTag = JESD_CSU_TX0_TAG+ch;
	//cpriCmdL.flush = 1;
	
	do_write(&(JS_CSU_CMDHIGHDATA), 0);
	do_write(((uint32_t*)&(JS_CSU_CMDFIFO1)+(ch<<1)), (*(uint32_t*)(&cpriCmdL)));
	
	return 0;
}

int32_t jesd_csu_start()
{
	jesd_csu_tx_start_ch(0);
	if (4 < gJesdCsuPara.antNum)
	{
		jesd_csu_tx_start_ch(1);
	}

	return 0;
}

int32_t jesd_csu_rx_start()
{
	jesd_csu_rx_start_ch(0);
	if (4 < gJesdCsuPara.antNum)
	{
		jesd_csu_rx_start_ch(1);
	}

	return 0;
}

int32_t jesd_csu_stat_lookup(uint8_t tag)
{
	if (31 < tag)
	{
		return -1;
	}
	return ((do_read_volatile(&JS_CSU_DMASTATUS)>>tag)&0x1);
}

