#include "data_transfer.h"
#include "DMAScheduler.h"
#include "image_control.h"
#include "data_indicator.h"
#include "environment.h"
#include "com.h"
#include "timer.h"
#include <csl_intc.h>
#include <csl_intcAux.h>
#include <csl_edma2.h>
#define SDRAM1_ADDR							(unsigned char *)0x80000000
#define CPB_IMAGE_BUFFER_ADDRESS			0xE00E8080



// for dma copy
#define COPY_BLOCK_SIZE								1024
#pragma DATA_ALIGN(copy_temp_buffer1, 8);
#pragma DATA_ALIGN(copy_temp_buffer2, 8);
unsigned char copy_temp_buffer1[COPY_BLOCK_SIZE];
unsigned char copy_temp_buffer2[COPY_BLOCK_SIZE];

extern CSL_Edma3Handle 				hNFAEdma;
#define HPI_BUFFER_STATE_LOAD				0

#pragma DATA_ALIGN(clear_value, 8);
unsigned int clear_value[MAX_SDRAM_COPY_SIZE / 4];


#pragma DATA_ALIGN(HPIStat, 8)

#define MAX_DMA_JOB_COUNT		16
#define DMA_TABLE_SIZE			16

#define IMG_CHECK_COUNT	8
#define SMALL_SIZE_HPI_COM_TIMEOUT	200		//200ms
#define LARGE_SIZE_HPI_COM_TIMEOUT	3000	//3000ms
#define DMA_ACTIVE_TIME_OUT	5

#define min(x, y) ((x) < (y) ? (x) : (y))


CSL_Edma3CmdDrae            QdmaregionSetup;
CSL_Edma3ChannelAttr        QdmaChaSet;
CSL_Edma3ChannelObj         QdmaChObj;
CSL_Edma3ParamHandle        hQDMAParam;
CSL_Edma3ChannelHandle      hQDMAChannel;

unsigned int PartialCheckSum(unsigned char* src, unsigned int len, unsigned int size);

void Request_DMA_Linear_Copy_Direct(void *dst_address, void *src_address, int size, unsigned int esize)
{
	unsigned char *src_addr, *dst_addr;
	int remain_word_cnt = (size >> DMA_SHIFT(esize));
	int max_transfer_word_cnt = (MAX_SDRAM_COPY_SIZE >> DMA_SHIFT(esize));
	int copy_cnt;
	TQDMARequestUnit qdmaRequestUnit;
	volatile unsigned int qdmaFin;
	volatile unsigned int checkStartTime;

	src_addr = (unsigned char *) src_address;
	dst_addr = (unsigned char *) dst_address;
	while(remain_word_cnt)
	{
		if (remain_word_cnt < max_transfer_word_cnt)
		{
			copy_cnt = remain_word_cnt;
		}
		else
		{
			copy_cnt = max_transfer_word_cnt;
		}
		qdmaFin = 0;
		qdmaRequestUnit.Opt = MakeDMAOpt(esize, EDMA_CFG_NO_INC_NO_INC);
		qdmaRequestUnit.Src = (Uint32)src_addr;
		qdmaRequestUnit.Cnt = copy_cnt;
		qdmaRequestUnit.Dst = (Uint32)dst_addr;
		qdmaRequestUnit.Idx = 0;
		qdmaRequestUnit.Fin = &qdmaFin;
		QDMA_Request(&qdmaRequestUnit);
		
		while (!qdmaFin);

		src_addr += (copy_cnt << DMA_SHIFT(esize));
		dst_addr += (copy_cnt << DMA_SHIFT(esize));
		remain_word_cnt -= copy_cnt;
	}	
}

void Request_DMA_Linear_Copy_Indirect(void *dst_address, void *src_address, int size, unsigned int esize)
{
	unsigned char *src_addr, *dst_addr;
	int remain_word_cnt = (size >> DMA_SHIFT(esize));
	int max_transfer_word_cnt = (COPY_BLOCK_SIZE >> DMA_SHIFT(esize));
	int copy_cnt;
	TQDMARequestUnit qdmaRequestUnit;
	volatile unsigned int qdmaFin;
	volatile unsigned int checkStartTime;

	src_addr = (unsigned char *) src_address;
	dst_addr = (unsigned char *) dst_address;

 	while (remain_word_cnt)
 	{
		if (remain_word_cnt < max_transfer_word_cnt)
		{
			copy_cnt = remain_word_cnt;
		}
		else
		{
			copy_cnt = max_transfer_word_cnt;
		}

		qdmaFin = 0;
		qdmaRequestUnit.Opt = MakeDMAOpt(esize, EDMA_CFG_NO_INC_NO_INC);
		qdmaRequestUnit.Src = (Uint32)src_addr;
		qdmaRequestUnit.Cnt = copy_cnt;
		qdmaRequestUnit.Dst = (Uint32)copy_temp_buffer1;
		qdmaRequestUnit.Idx = 0;
		qdmaRequestUnit.Fin = &qdmaFin;
		QDMA_Request(&qdmaRequestUnit);
		
		while (!qdmaFin);
		qdmaFin = 0;
		qdmaRequestUnit.Opt = MakeDMAOpt(esize, EDMA_CFG_NO_INC_NO_INC);
		qdmaRequestUnit.Src = (Uint32)copy_temp_buffer1;
		qdmaRequestUnit.Cnt = copy_cnt;
		qdmaRequestUnit.Dst = (Uint32)dst_addr;
		qdmaRequestUnit.Idx = 0;
		qdmaRequestUnit.Fin = &qdmaFin;
		QDMA_Request(&qdmaRequestUnit);		
		while (!qdmaFin);
		src_addr += (copy_cnt << DMA_SHIFT(esize));
		dst_addr += (copy_cnt << DMA_SHIFT(esize));
		remain_word_cnt -= copy_cnt;
 	} 	
}

void Request_CopyData(void *dst_address, void *src_address, int size)
{
	unsigned int srcESize;
	unsigned int dstESize;
	unsigned int countESize;
	unsigned int transferESize;
	unsigned int CopySDR2SDR = FALSE;
	// data_address ¢¯¥ì¢¯¨£ A¢Ò¡íc
	if ((unsigned int)src_address >= (unsigned int)SDRAM1_ADDR)	// SDRAM ¢¯¥ì¢¯¨£AI¢¬e
	{
		if ((unsigned int)dst_address >= (unsigned int)SDRAM1_ADDR)  // SDR -> SDR
		{
			CopySDR2SDR = TRUE;
		}
	}

	// analyze element size(alignment of address and size)
	if (((unsigned int)src_address & 0x03) == 0) // src is 4-byte aligned
	{
		srcESize = DMA_ESIZE_32BIT;
	}
	else if (((unsigned int)src_address & 0x01) == 0) // src is 2-byte aligned
	{
		srcESize = DMA_ESIZE_16BIT;
	}
	else
	{
		srcESize = DMA_ESIZE_8BIT;
	}

	if (((unsigned int)dst_address & 0x03) == 0) // dst is 4-byte aligned
	{
		dstESize = DMA_ESIZE_32BIT;
	}
	else if (((unsigned int)dst_address & 0x01) == 0) // dst is 2-byte aligned
	{
		dstESize = DMA_ESIZE_16BIT;
	}
	else
	{
		dstESize = DMA_ESIZE_8BIT;
	}

	if (((unsigned int)size & 0x03) == 0) // size is 4-byte aligned
	{
		countESize = DMA_ESIZE_32BIT;
	}
	else if (((unsigned int)size & 0x01) == 0) // size is 2-byte aligned
	{
		countESize = DMA_ESIZE_16BIT;
	}
	else
	{
		countESize = DMA_ESIZE_8BIT;
	}

	transferESize = min(min(srcESize, dstESize), countESize);

	if (CopySDR2SDR)
	{
		Request_DMA_Linear_Copy_Indirect(dst_address, src_address, size, transferESize);
	}
	else
	{
		Request_DMA_Linear_Copy_Direct(dst_address, src_address, size, transferESize);
	}
}

void Request_ClearData_Aligned(void *dst_address, unsigned int fill_value, int size)
{
	int clear_size_int;
	int m;
	unsigned int *dst_addr;
	volatile unsigned int qdmaFin;
	unsigned int checkStartTime;

	int remain_size_int = size / 4;	
	TQDMARequestUnit qdmaRequestUnit;

	dst_addr = (unsigned int *) dst_address;
	
	for(m = 0; m < MAX_SDRAM_COPY_SIZE / 4; m++)
	{
		clear_value[m] = fill_value;
	}

	while(remain_size_int)
	{
		if (remain_size_int < MAX_SDRAM_COPY_SIZE / 4)
		{
			clear_size_int = remain_size_int;
		}
		else
		{
			clear_size_int = MAX_SDRAM_COPY_SIZE / 4;
		}

		qdmaFin = 0;
		qdmaRequestUnit.Opt = MakeDMAOpt(DMA_ESIZE_32BIT, EDMA_CFG_NO_NONE_NO_INC);
		qdmaRequestUnit.Src = (Uint32)clear_value;
		qdmaRequestUnit.Cnt = clear_size_int;
		qdmaRequestUnit.Dst = (Uint32)dst_addr;
		qdmaRequestUnit.Idx = 0;
		qdmaRequestUnit.Fin = &qdmaFin;
		QDMA_Request(&qdmaRequestUnit);		
		
		checkStartTime = Board50usTimer;
		while (!qdmaFin)
		{
			if(Board50usTimer - checkStartTime > 10)
			{
				ErrorUnit_Put(BoardID, ERROR_TYPE_CRITICAL, ERROR_CODE_OVERFLOW, __LINE__, clear_size_int, 0);
				break;
			}
		}

		dst_addr += clear_size_int;
		remain_size_int -= clear_size_int;
	}
}

//---------------------------------------------------------------------------
void Request_BayerImageScaleConversion(void *src_address, void *dst_address, int srcWidth, int dstWidth, int size, int reduction, int byteSize)
{
	int m;
	unsigned char *dst_addr;
	unsigned char *src_addr;
	volatile unsigned int qdmaFin;
	unsigned int checkStartTime;
	int yPositionCount;

	TQDMARequestUnit qdmaRequestUnit;
	int remain_size_int = size;

	dst_addr = (unsigned char *) dst_address;
	src_addr = (unsigned char *) src_address;
	
	yPositionCount = 0;

	while(remain_size_int >= 0)
	{
		if(yPositionCount % reduction == 0)
		{
			qdmaFin = 0;
			qdmaRequestUnit.Opt = 0;
			qdmaRequestUnit.Src = (Uint32)src_addr;
			qdmaRequestUnit.Cnt = srcWidth * 2;
			qdmaRequestUnit.Dst = (Uint32)dst_addr;
			qdmaRequestUnit.Idx = 0;
			qdmaRequestUnit.Fin = &qdmaFin;
			QDMA_Request_ScaleConversion(&qdmaRequestUnit, reduction, byteSize);		
			
			checkStartTime = Board50usTimer;
			while (!qdmaFin)
			{
				if(Board50usTimer - checkStartTime > 2)
				{
					ErrorUnit_Put(BoardID, ERROR_TYPE_CRITICAL, ERROR_CODE_OVERFLOW, __LINE__, 0, 0);
					break;
				}
			}

			dst_addr += dstWidth * 2;
		}

		src_addr += srcWidth*2;
		remain_size_int -= srcWidth * 2;
		yPositionCount++;
	}
}
//---------------------------------------------------------------------------
unsigned int PartialCheckSum(unsigned char* src, unsigned int len, unsigned int size)
{
	unsigned int sum = 0;
	int i;

	for(i = len - 1; i >= 0; i -= size)
	{
		sum += *(src + i);
	}

	return sum;
}
