#include "HPI_Controller.h"
#include "common.h"
#include "DMAScheduler.h"
#include "timer.h"
#include "spb_system.h"
#include <csl_edma2.h>
#include <csl_edma3.h>
#include <csl_edma3Aux.h>
#include <csl_intc.h>
#include <csl_intcAux.h>
#include <csl_tmr.h>
#include <csl_tmrAux.h>
#define HPI_TRANSFER_QUEUE_COUNT			128
#define HPI_TRANSFER_QUEUE_MASK				127

#define HPI_STATUS_IDLE						0
#define HPI_STATUS_BUSY						1


#define HPI_TRANSFER_COMMAND_WRITE			0
#define HPI_TRANSFER_COMMAND_READ			1
#define HPI_TRANSFER_COMMAND_CLEAR			2

typedef struct
{
	unsigned char TargetCPB;
	unsigned char Command;
	unsigned int BufferAddress;
	unsigned int CPBAddress;
	unsigned int CountWord;
	THPITransferStatus *TransferStatus;
}
THPITransferUnit;

unsigned char HPITransferQueueStart;
unsigned char HPITransferQueueEnd;
THPITransferUnit HPITransferQueue[HPI_TRANSFER_QUEUE_COUNT];

#define HPI_CONTROL_INTERRUPT				0
#define HPI_CONTROL_READ_CTRL				1

typedef struct
{
	unsigned char TargetCPB;
	unsigned char Control;
	THPIControlStatus *ControlStatus;
} THPIControlUnit;
unsigned char HPIControlQueueStart;
unsigned char HPIControlQueueEnd;
THPIControlUnit HPIControlQueue[HPI_TRANSFER_QUEUE_COUNT];

//TDMATableUnit HPI_Transfer_DMA_Table;

unsigned char HPIStatus;
CSL_Edma3ParamSetup HPI_Write_EDMA_Config, HPI_Read_EDMA_Config, HPI_Clear_EDMA_Config;
CSL_Edma3ParamHandle        hHPI_EDMAParam;
CSL_Edma3ChannelHandle      hHPI_EDMAChannel;
CSL_Edma3CmdIntr            HPI_RegionIntr;
CSL_Edma3ChannelAttr        HPIChaSet;
CSL_Edma3ChannelObj         HPIChObj;
extern CSL_Edma3Handle 				hNFAEdma;
CSL_Edma3CmdDrae            hpiregionSetup;

unsigned int HPI_EDMATCCNumber; 
int hpi_read_cnt,hpi_write_cnt,hpi_clr_cnt;
extern CSL_TmrHandle TimerHandle1;
#pragma DATA_ALIGN(HPI_Clear_Zero, 8)
unsigned int HPI_Clear_Zero = 0;
void HPI_EDMA_TriggerNextUnit(void);
void HPI_Transfer_Complete(void);
int hpi_transfer_ing=0;

int hpi_int_count =0;
int hpi_complete_count =0;
  
void HPI_Controller_Init(void)
{
	CSL_Edma3CmdDrae            regionSetup;

	CSL_Edma3Context            context;
	CSL_Status                  status;
	hpi_read_cnt=hpi_write_cnt=hpi_clr_cnt=0;
	HPITransferQueueStart = HPITransferQueueEnd = 0;
	HPIControlQueueStart = HPIControlQueueEnd = 0;
	HPIStatus = HPI_STATUS_IDLE;
	
//	HPI_EDMATCCNumber = AllocEDMAInterruptHandler(HPI_Transfer_Complete);
	HPI_EDMATCCNumber = CSL_EDMA3_CHA_DSPINT;

	if(HPI_EDMATCCNumber < 32)
	{
		hpiregionSetup.region = CSL_EDMA3_REGION_0;
		hpiregionSetup.drae =  (0x1 << HPI_EDMATCCNumber) ;
		hpiregionSetup.draeh =  0x0;
	}
	else
	{
		hpiregionSetup.region = CSL_EDMA3_REGION_0;
		hpiregionSetup.drae =  0x0;
		hpiregionSetup.draeh =  (0x1 << HPI_EDMATCCNumber - 32);
	}
	
	CSL_edma3HwControl(hNFAEdma,CSL_EDMA3_CMD_DMAREGION_ENABLE,&hpiregionSetup);


	HPIChaSet.regionNum =CSL_EDMA3_REGION_0;// CSL_EDMA3_REGION_GLOBAL; //CSL_EDMA3_REGION_0;
	HPIChaSet.chaNum = CSL_EDMA3_CHA_DSPINT;
	hHPI_EDMAChannel = CSL_edma3ChannelOpen(&HPIChObj, CSL_EDMA3, &HPIChaSet, &status);	
	CSL_edma3HwChannelControl(hHPI_EDMAChannel,CSL_EDMA3_CMD_CHANNEL_ENABLE, NULL);

	HPI_Write_EDMA_Config.option = CSL_EDMA3_OPT_MAKE( CSL_EDMA3_ITCCH_DIS, CSL_EDMA3_TCCH_DIS, CSL_EDMA3_ITCINT_DIS, CSL_EDMA3_TCINT_EN,\
	                                  				HPI_EDMATCCNumber, CSL_EDMA3_TCC_NORMAL, CSL_EDMA3_FIFOWIDTH_32BIT, CSL_EDMA3_STATIC_DIS, CSL_EDMA3_SYNC_A, CSL_EDMA3_ADDRMODE_INCR, CSL_EDMA3_ADDRMODE_INCR); 
	HPI_Write_EDMA_Config.srcDstBidx = CSL_EDMA3_BIDX_MAKE(4,0);     
	HPI_Write_EDMA_Config.linkBcntrld = CSL_EDMA3_LINKBCNTRLD_MAKE(CSL_EDMA3_LINK_NULL,0);     
	HPI_Write_EDMA_Config.srcDstCidx = CSL_EDMA3_CIDX_MAKE(0,0);     
	HPI_Write_EDMA_Config.cCnt = 1;

	HPI_Read_EDMA_Config.option = CSL_EDMA3_OPT_MAKE( CSL_EDMA3_ITCCH_DIS, CSL_EDMA3_TCCH_DIS, CSL_EDMA3_ITCINT_DIS, CSL_EDMA3_TCINT_EN,\
	                                  				HPI_EDMATCCNumber, CSL_EDMA3_TCC_NORMAL, CSL_EDMA3_FIFOWIDTH_32BIT, CSL_EDMA3_STATIC_DIS, CSL_EDMA3_SYNC_A, CSL_EDMA3_ADDRMODE_INCR, CSL_EDMA3_ADDRMODE_INCR); 

	HPI_Read_EDMA_Config.srcDstBidx = CSL_EDMA3_BIDX_MAKE(0,4);     
	HPI_Read_EDMA_Config.linkBcntrld = CSL_EDMA3_LINKBCNTRLD_MAKE(CSL_EDMA3_LINK_NULL,0);     
	HPI_Read_EDMA_Config.srcDstCidx = CSL_EDMA3_CIDX_MAKE(0,0);     
	HPI_Read_EDMA_Config.cCnt = 1;

	HPI_Clear_EDMA_Config.option = CSL_EDMA3_OPT_MAKE( CSL_EDMA3_ITCCH_DIS, CSL_EDMA3_TCCH_DIS, CSL_EDMA3_ITCINT_DIS, CSL_EDMA3_TCINT_EN,\
	                                  				HPI_EDMATCCNumber, CSL_EDMA3_TCC_NORMAL, CSL_EDMA3_FIFOWIDTH_32BIT, CSL_EDMA3_STATIC_DIS, CSL_EDMA3_SYNC_A, CSL_EDMA3_ADDRMODE_INCR, CSL_EDMA3_ADDRMODE_INCR); 
						
	HPI_Clear_EDMA_Config.srcDstBidx = CSL_EDMA3_BIDX_MAKE(4,4);     
	HPI_Clear_EDMA_Config.linkBcntrld = CSL_EDMA3_LINKBCNTRLD_MAKE(CSL_EDMA3_LINK_NULL,0);     
	HPI_Clear_EDMA_Config.srcDstCidx = CSL_EDMA3_CIDX_MAKE(0,0);     
	HPI_Clear_EDMA_Config.cCnt = 1;

	


	if(HPI_EDMATCCNumber < 32)
	{
		HPI_RegionIntr.region = CSL_EDMA3_REGION_0;
		HPI_RegionIntr.intr = (0x1<<HPI_EDMATCCNumber);
		HPI_RegionIntr.intrh = 0x0;
	}
	else
	{
		HPI_RegionIntr.region = CSL_EDMA3_REGION_0;
		HPI_RegionIntr.intr = 0x0;
		HPI_RegionIntr.intrh =  (0x1<<(HPI_EDMATCCNumber - 32));
	}
	CSL_edma3HwControl(hNFAEdma,CSL_EDMA3_CMD_INTR_ENABLE,&HPI_RegionIntr); 
	CSL_edma3HwControl(hNFAEdma,CSL_EDMA3_CMD_INTRPEND_CLEAR, &HPI_RegionIntr);
	hHPI_EDMAParam = CSL_edma3GetParamHandle(hHPI_EDMAChannel, CSL_EDMA3_CHA_DSPINT, &status); 

//	CSL_intcInterruptEnable(CSL_INTC_VECTID_6);
}

void Request_HPI_WriteData(unsigned char targetCPB, unsigned int bufferAddress, unsigned int cpbAddress, unsigned int countWord, THPITransferStatus *transferStatus)
{
	//unsigned int gie;
	unsigned char isFirstUnit = FALSE;
	int currentTime;
//	while(hpi_lock);
	CSL_IntcGlobalEnableState 	state;
	CSL_intcGlobalDisable(&state);
  	 CSL_edma3HwControl (hNFAEdma,CSL_EDMA3_CMD_INTR_DISABLE, &HPI_RegionIntr);
//	if (HPITransferQueueStart == HPITransferQueueEnd)
//	{
//		isFirstUnit = TRUE;
//	}

	HPITransferQueue[HPITransferQueueEnd].TargetCPB = targetCPB;
	HPITransferQueue[HPITransferQueueEnd].Command = HPI_TRANSFER_COMMAND_WRITE;
	HPITransferQueue[HPITransferQueueEnd].BufferAddress = bufferAddress;
	HPITransferQueue[HPITransferQueueEnd].CPBAddress = cpbAddress;
	HPITransferQueue[HPITransferQueueEnd].CountWord = countWord;
	HPITransferQueue[HPITransferQueueEnd].TransferStatus = transferStatus;
	HPITransferQueue[HPITransferQueueEnd].TransferStatus->Status = HPI_TRANSEFR_STATUS_PENDING;
	HPITransferQueueEnd = (HPITransferQueueEnd + 1) & HPI_TRANSFER_QUEUE_MASK;
	if (HPIStatus == HPI_STATUS_IDLE)//&& isFirstUnit)
	{
//		HPIStatus = HPI_STATUS_BUSY;
		HPI_EDMA_TriggerNextUnit();	
	}
	CSL_edma3HwControl (hNFAEdma,CSL_EDMA3_CMD_INTR_ENABLE, &HPI_RegionIntr);
	CSL_intcGlobalEnable(&state);
}

void Request_HPI_ReadData(unsigned char targetCPB, unsigned int bufferAddress, unsigned int cpbAddress, unsigned int countWord, THPITransferStatus *transferStatus)
{
	//unsigned int gie;
//	unsigned char isFirstUnit = FALSE;
//	int currentTime;
	CSL_IntcGlobalEnableState 	state;
	CSL_intcGlobalDisable(&state);
//	while(hpi_lock);
  	CSL_edma3HwControl (hNFAEdma,CSL_EDMA3_CMD_INTR_DISABLE, &HPI_RegionIntr);
//	if (HPITransferQueueStart == HPITransferQueueEnd)
//	{ 
//		isFirstUnit = TRUE;
//	}

	HPITransferQueue[HPITransferQueueEnd].TargetCPB = targetCPB;
	HPITransferQueue[HPITransferQueueEnd].Command = HPI_TRANSFER_COMMAND_READ;
	HPITransferQueue[HPITransferQueueEnd].BufferAddress = bufferAddress;
	HPITransferQueue[HPITransferQueueEnd].CPBAddress = cpbAddress;
	HPITransferQueue[HPITransferQueueEnd].CountWord = countWord;
	HPITransferQueue[HPITransferQueueEnd].TransferStatus = transferStatus;
	HPITransferQueue[HPITransferQueueEnd].TransferStatus->Status = HPI_TRANSEFR_STATUS_PENDING;
	HPITransferQueueEnd = (HPITransferQueueEnd + 1) & HPI_TRANSFER_QUEUE_MASK;
	if (HPIStatus == HPI_STATUS_IDLE)// && isFirstUnit)
	{
//		HPIStatus = HPI_STATUS_BUSY;
		HPI_EDMA_TriggerNextUnit();
	}
	CSL_edma3HwControl (hNFAEdma,CSL_EDMA3_CMD_INTR_ENABLE, &HPI_RegionIntr);
	CSL_intcGlobalEnable(&state);
}

void Request_HPI_ClearData(unsigned char targetCPB, unsigned int cpbAddress, unsigned int countWord, THPITransferStatus *transferStatus)
{
	unsigned char isFirstUnit = FALSE;
	CSL_IntcGlobalEnableState 	state;
	CSL_intcGlobalDisable(&state);
    CSL_edma3HwControl (hNFAEdma,CSL_EDMA3_CMD_INTR_DISABLE, &HPI_RegionIntr);
	if (HPITransferQueueStart == HPITransferQueueEnd)
	{
		isFirstUnit = TRUE;
	}

	HPITransferQueue[HPITransferQueueEnd].TargetCPB = targetCPB;
	HPITransferQueue[HPITransferQueueEnd].Command = HPI_TRANSFER_COMMAND_CLEAR;
	HPITransferQueue[HPITransferQueueEnd].CPBAddress = cpbAddress;
	HPITransferQueue[HPITransferQueueEnd].CountWord = countWord;
	HPITransferQueue[HPITransferQueueEnd].TransferStatus = transferStatus;
	HPITransferQueue[HPITransferQueueEnd].TransferStatus->Status = HPI_TRANSEFR_STATUS_PENDING;
	HPITransferQueueEnd = (HPITransferQueueEnd + 1) & HPI_TRANSFER_QUEUE_MASK;
	if (HPIStatus == HPI_STATUS_IDLE)// && isFirstUnit)
	{
//		HPIStatus = HPI_STATUS_BUSY;
		HPI_EDMA_TriggerNextUnit();		
	}
	CSL_edma3HwControl (hNFAEdma,CSL_EDMA3_CMD_INTR_ENABLE, &HPI_RegionIntr);
	CSL_intcGlobalEnable(&state);
}



void Request_HPI_RaiseInterrupt(unsigned char targetCPB, THPIControlStatus *controlStatus)
{
    CSL_edma3HwControl (hNFAEdma,CSL_EDMA3_CMD_INTR_DISABLE, &HPI_RegionIntr);
	if (HPIStatus == HPI_STATUS_IDLE)
	{	
		*HPI_CTRL(targetCPB) = 0x00020202;
		controlStatus->Status = HPI_CONTROL_STATUS_COMPLETE;
		
	}
	else
	{
		HPIControlQueue[HPIControlQueueEnd].TargetCPB = targetCPB;
		HPIControlQueue[HPIControlQueueEnd].Control = HPI_CONTROL_INTERRUPT;
		HPIControlQueue[HPIControlQueueEnd].ControlStatus = controlStatus;
		HPIControlQueue[HPIControlQueueEnd].ControlStatus->Status = HPI_CONTROL_STATUS_PENDING;
		HPIControlQueueEnd = (HPIControlQueueEnd + 1) & HPI_TRANSFER_QUEUE_MASK;
	}
	CSL_edma3HwControl (hNFAEdma,CSL_EDMA3_CMD_INTR_ENABLE, &HPI_RegionIntr);
}

void Request_HPI_PollingInterrupt(unsigned char targetCPB, THPIControlStatus *controlStatus)
{
    CSL_edma3HwControl (hNFAEdma,CSL_EDMA3_CMD_INTR_DISABLE, &HPI_RegionIntr);
	if (HPIStatus == HPI_STATUS_IDLE)
	{
		controlStatus->ControlResult = *HPI_CTRL(targetCPB);
		controlStatus->Status = HPI_CONTROL_STATUS_COMPLETE;
	}
	else
	{
		HPIControlQueue[HPIControlQueueEnd].TargetCPB = targetCPB;
		HPIControlQueue[HPIControlQueueEnd].Control = HPI_CONTROL_READ_CTRL;
		HPIControlQueue[HPIControlQueueEnd].ControlStatus = controlStatus;
		HPIControlQueue[HPIControlQueueEnd].ControlStatus->Status = HPI_CONTROL_STATUS_PENDING;
		HPIControlQueueEnd = (HPIControlQueueEnd + 1) & HPI_TRANSFER_QUEUE_MASK;
	}
	CSL_edma3HwControl (hNFAEdma,CSL_EDMA3_CMD_INTR_ENABLE, &HPI_RegionIntr);
}

void HPI_EDMA_TriggerNextUnit(void)
{
	CSL_Status                  status;	
	CSL_edma3HwControl (hNFAEdma,CSL_EDMA3_CMD_INTR_DISABLE, &HPI_RegionIntr);
	if (HPITransferQueue[HPITransferQueueStart].Command == HPI_TRANSFER_COMMAND_WRITE)
	{
		*HPI_CTRL(HPITransferQueue[HPITransferQueueStart].TargetCPB) = 0x00000200;
		*((volatile unsigned int *) CPBHWInfo[HPITransferQueue[HPITransferQueueStart].TargetCPB].HPIAddr_Addr) = (HPITransferQueue[HPITransferQueueStart].CPBAddress >> 2);

		HPI_Write_EDMA_Config.srcAddr = HPITransferQueue[HPITransferQueueStart].BufferAddress;
		HPI_Write_EDMA_Config.dstAddr = (unsigned int) CPBHWInfo[HPITransferQueue[HPITransferQueueStart].TargetCPB].HPIData_Inc_Addr;

		HPI_Write_EDMA_Config.aCntbCnt = CSL_EDMA3_CNT_MAKE((HPITransferQueue[HPITransferQueueStart].CountWord*4),1); 
		CSL_edma3ParamSetup(hHPI_EDMAParam, &HPI_Write_EDMA_Config);
	}
	else if (HPITransferQueue[HPITransferQueueStart].Command == HPI_TRANSFER_COMMAND_READ)
	{
		*HPI_CTRL(HPITransferQueue[HPITransferQueueStart].TargetCPB) = 0x00000A00;
		*((volatile unsigned int *) CPBHWInfo[HPITransferQueue[HPITransferQueueStart].TargetCPB].HPIAddr_Addr) = (HPITransferQueue[HPITransferQueueStart].CPBAddress >> 2);
		*HPI_CTRL(HPITransferQueue[HPITransferQueueStart].TargetCPB) = 0x00000A10;
		TEMP = 0x0;
		TEMP = 0x0;
		TEMP = 0x0;	
		TEMP = 0x0;
		TEMP = 0x0;	
		HPI_Read_EDMA_Config.srcAddr = (unsigned int) CPBHWInfo[HPITransferQueue[HPITransferQueueStart].TargetCPB].HPIData_Inc_Addr;
		HPI_Read_EDMA_Config.dstAddr = HPITransferQueue[HPITransferQueueStart].BufferAddress;

		HPI_Read_EDMA_Config.aCntbCnt = CSL_EDMA3_CNT_MAKE((HPITransferQueue[HPITransferQueueStart].CountWord*4),1); 
		CSL_edma3ParamSetup(hHPI_EDMAParam, &HPI_Read_EDMA_Config);		
	}
	else if (HPITransferQueue[HPITransferQueueStart].Command == HPI_TRANSFER_COMMAND_CLEAR)
	{
		HPI_Clear_EDMA_Config.srcAddr = HPI_Clear_Zero;
		HPI_Clear_EDMA_Config.dstAddr = (unsigned int) CPBHWInfo[HPITransferQueue[HPITransferQueueStart].TargetCPB].HPIData_Inc_Addr;

		HPI_Clear_EDMA_Config.aCntbCnt = CSL_EDMA3_CNT_MAKE((HPITransferQueue[HPITransferQueueStart].CountWord*4),1); 
		CSL_edma3ParamSetup(hHPI_EDMAParam, &HPI_Clear_EDMA_Config);
	}


	HPIStatus = HPI_STATUS_BUSY;
	hpi_int_count++;
	status = CSL_edma3HwChannelControl(hHPI_EDMAChannel,CSL_EDMA3_CMD_CHANNEL_SET,NULL);
	CSL_edma3HwControl (hNFAEdma,CSL_EDMA3_CMD_INTR_ENABLE, &HPI_RegionIntr);
	
}

void HPI_Transfer_Complete(void)
{

	CSL_edma3HwControl (hNFAEdma,CSL_EDMA3_CMD_INTRPEND_CLEAR, &HPI_RegionIntr);
		
	while (HPIControlQueueStart != HPIControlQueueEnd)
	{
		if (HPIControlQueue[HPIControlQueueStart].Control == HPI_CONTROL_INTERRUPT)
		{
			*HPI_CTRL(HPIControlQueue[HPIControlQueueStart].TargetCPB) = 0x00020002;
			HPIControlQueue[HPIControlQueueStart].ControlStatus->Status = HPI_CONTROL_STATUS_COMPLETE;
		}
		else if (HPIControlQueue[HPIControlQueueStart].Control == HPI_CONTROL_READ_CTRL)
		{
			HPIControlQueue[HPIControlQueueStart].ControlStatus->ControlResult = *HPI_CTRL(HPIControlQueue[HPIControlQueueStart].TargetCPB);
			HPIControlQueue[HPIControlQueueStart].ControlStatus->Status = HPI_CONTROL_STATUS_COMPLETE;
		}
		HPIControlQueueStart = (HPIControlQueueStart + 1) & HPI_TRANSFER_QUEUE_MASK;
	}

	HPITransferQueue[HPITransferQueueStart].TransferStatus->Status = HPI_TRANSEFR_STATUS_COMPLETE;
	HPITransferQueueStart = (HPITransferQueueStart + 1) & HPI_TRANSFER_QUEUE_MASK;
	hpi_complete_count++;

	if (HPITransferQueueStart != HPITransferQueueEnd)
	{
		
		HPI_EDMA_TriggerNextUnit();	
//		HPIStatus = HPI_STATUS_BUSY;
	}
 	else{
		HPIStatus = HPI_STATUS_IDLE;
	}

}


void HPI_Controller_Process(void)
{

}

