#include "tpb_system.h"
#include "environment.h"    
#include "timer.h"
#include "DMAScheduler.h"
#include "image_control.h"
#include "srio_master.h"
#include "csl_intcAux.h"
#include "tpb_system.h"

#define BOARD_TIMEOUT						120000

TCPBHWInfo CPBHWInfo[TPB_CPB_MAX_COUNT];

#pragma DATA_ALIGN (CPBStatus, 8)
TCPBStatus CPBStatus[TPB_CPB_MAX_COUNT];
unsigned int CPB_StatusList[TPB_CPB_MAX_COUNT];	// read from cpb

int CPBFirstCheck[TPB_CPB_MAX_COUNT];
unsigned int CPBFirstCheckTime[TPB_CPB_MAX_COUNT];

#pragma DATA_ALIGN (Invalidate_Image_Command_Data, 8)
unsigned int Invalidate_Image_Command_Data;

#pragma DATA_ALIGN (CPBCompatibility, 8)
TCPBCompatibility CPBCompatibility;

#define RUN_STEP_INIT							0
#define RUN_STEP_CPB_RESET_LOW_1				1
#define RUN_STEP_CPB_RESET_LOW_1_WAIT		2
#define RUN_STEP_CPB_RESET_HIGH_1				3
#define RUN_STEP_CPB_RESET_HIGH_1_WAIT		4
#define RUN_STEP_CPB_RESET_LOW_2				5
#define RUN_STEP_CPB_RESET_LOW_2_WAIT		6
#define RUN_STEP_CPB_RESET_HIGH_2				7
#define RUN_STEP_CPB_RESET_HIGH_2_WAIT		8
#define RUN_STEP_CPB_SET_PLL					9
#define RUN_STEP_CPB_CLEAR						10
#define RUN_STEP_CPB_CLEAR_WAIT				11
#define RUN_STEP_CPB_RUN						12
#define RUN_STEP_SETUP							13
#define RUN_STEP_COMPLETE						14

#define RUN_SUB_STEP_INIT					0
#define RUN_SUB_STEP_LOAD_PROGRAM		1
#define RUN_SUB_STEP_CPB_DOWNLOAD		2
#define RUN_SUB_STEP_COM_WAIT			3
#define RUN_SUB_STEP_CPB_BOOT				4
#define RUN_SUB_STEP_COMPLETE				5


#define CPB_RESET_LOW_WAITING_TIME		1000
#define CPB_RESET_HIGH_WAITING_TIME		1000

#define _PLL1CTL_ADDR				0x020E0100u
#define _PLL1M_ADDR					0x020E0110u
TRunInfo RunInfo;
TSrioRunInfo SrioRunInfo;

typedef struct 
{
	unsigned int BoardID;
	unsigned char CPUKind;
	unsigned char dummy[3];
} TCPBBootInfo;

#pragma DATA_SECTION(ProgramBuffer, ".sdram");
#pragma DATA_ALIGN(ProgramBuffer, 1024);
unsigned char ProgramBuffer[DOWNLOAD_MAX_SIZE];
#pragma DATA_SECTION(ProgramBinBuffer, ".sdram");
#pragma DATA_ALIGN(ProgramBinBuffer, 1024);
unsigned char ProgramBinBuffer[CPB_MAX_CODE_SIZE];

#pragma DATA_SECTION(SrioProgramBinBuffer, ".sdram");
#pragma DATA_ALIGN(SrioProgramBinBuffer, 1024);
unsigned char SrioProgramBinBuffer[SYSTEM_MAX_SPB_CLIENT_BOARD_COUNT][CPB_MAX_CODE_SIZE];

#define PROGRAM_COPY_PAGE_SIZE			512

#pragma DATA_ALIGN(SrioTempBufferW, 4);
#pragma DATA_ALIGN(SrioTempBufferR, 4);
unsigned int SrioTempBufferW[PROGRAM_COPY_PAGE_SIZE];
unsigned int SrioTempBufferR[PROGRAM_COPY_PAGE_SIZE];

int CPBBootEnable;
unsigned int CPBBootStartTime;
unsigned int CPBClearVal;

TSPBSubSystem SPBSubSystem;
unsigned int Current50usTime;
unsigned int Current50usCounter;
#define MAX_50US_COUNT				10000000u
volatile int System_Reset_SW = 0;
unsigned int System_Reset_Trigger_Time;
TSRIOTransferStatus CommandTransferStatus[SYSTEM_CPB_COUNT];

//---------------------------------------------------------------------------
void ClearCPBStatus(void)
{
	int cpbIndex;
	for (cpbIndex = 0; cpbIndex < TPB_CPB_MAX_COUNT; cpbIndex++)
	{
		CPB_StatusList[cpbIndex] = 0;
		CPBFirstCheck[cpbIndex] = 0;
		CPBFirstCheckTime[cpbIndex] = 0;
	}

	for (cpbIndex = 0; cpbIndex < TPB_CPB_MAX_COUNT; cpbIndex++)
	{
		SPBSubSystem.CPBInfo[cpbIndex].ProcessingState = CPB_PROCESSING_READY;
	}
}
//---------------------------------------------------------------------------
void InitTPBSystem(void)
{
	int cpbIndex, camIndex;
	for (cpbIndex = 0; cpbIndex < TPB_CPB_MAX_COUNT; cpbIndex++)
	{
		CPB_StatusList[cpbIndex] = 0;
		CPBFirstCheck[cpbIndex] = 0;
		CPBFirstCheckTime[cpbIndex] = 0;
	}
	for (cpbIndex = 0; cpbIndex < TPB_CPB_MAX_COUNT; cpbIndex++)
	{
		CPBStatus[cpbIndex].Status = CPB_STATUS_DISABLED;
		SPBSubSystem.CPBInfo[cpbIndex].ProcessingState = CPB_PROCESSING_READY;
	}

	RunInfo.RunSW = 0;
	RunInfo.RunMode = 0;
	RunInfo.RunCPB_FFID = 0;
	SrioRunInfo.RunSW = 0;
	SrioRunInfo.RunMode = 0;
	SrioRunInfo.RunCPB_FFID = 0;

	CPBBootEnable = 0;

	System_Reset_SW = FALSE;
}
//---------------------------------------------------------------------------
int IsAvailableCPB(int cpbIndex)
{
	if (!CPBStatus[cpbIndex].IsDown)
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

void CPB_Run_Ready(unsigned int runMode, unsigned int runMaskL, unsigned int runMaskH,
	TFFID runCPB_FFID)
{
	if (RunInfo.RunSW == 0)
	{
		RunInfo.RunMode = runMode;
		RunInfo.RunMask[0] = runMaskL;
		RunInfo.RunMask[1] = runMaskH;
		RunInfo.RunCPB_FFID = PID_CPB_TABLET_5;
		RunInfo.RunStep = RUN_STEP_INIT;
		RunInfo.RunSW = 1;		
	}
}

void CPB_Auto_Boot(void)
{	
	if (SrioRunInfo.RunSW == 0)
	{
		SrioRunInfo.RunMode = 0;
		SrioRunInfo.RunCPB_FFID = PID_CPB_TABLET_5;
		SrioRunInfo.RunStep = CPB_BOOT_PROCESS_READY;
		SrioRunInfo.RunSW = 1;		
	}
}
//---------------------------------------------------------------------------

void  CPBProcessingCheckStart(int cpbIndex)
{
	SPBSubSystem.CPBInfo[cpbIndex].ProcessingState = CPB_PROCESSING_RUNNING;
	CPB_StatusList[cpbIndex] = CPB_PROCESSING_RUNNING;	
}

void Cpb_Boot_Process()
{
	
	int hexSize;
	int cpbIndex;
	int srioportIndex=0;
	TCPBBootInfo cpbBootInfo;
	TSRIOTransferStatus SrioTransferStatus;
	int program_read_complete=0;
	int bError = 0;
	TErrorCode cpb_boot_result;
	int port_boot_complete_flag = 0;
	int boot_complet[4];
	int boot_inttrupt[4] = {1,1,1,1};
	int boot_start_cmd = 0xc8c8;
	while(SrioRunInfo.RunSW)
	{
		switch(SrioRunInfo.RunStep)
		{
			case CPB_BOOT_PROCESS_READY:
				{
					for (cpbIndex = 0; cpbIndex < TPB_CPB_MAX_COUNT; cpbIndex++)
					{
						SrioRunInfo.Error[cpbIndex] = 0;
						SrioRunInfo.RunSuccess[cpbIndex] = 0;
						CPBStatus[cpbIndex].Enabled = TRUE;
						CPBStatus[cpbIndex].IsDown = FALSE;							
						CPBStatus[cpbIndex].Status = CPB_STATUS_BOOT_READY;
					}
					
					SrioRunInfo.CurrentCPBIndex = 0;
					SrioRunInfo.RunStep = CPB_BOOT_PROCESS_LOAD_PROGRAM;
				}
				break;			
			case CPB_BOOT_PROCESS_LOAD_PROGRAM:
				{
					SrioRunInfo.TargetCPURev = CPU_KIND_6678;

					if(program_read_complete == 0 )
					{
						cpb_boot_result = ReadFromFlash(SrioRunInfo.RunCPB_FFID, ProgramBuffer, DOWNLOAD_MAX_SIZE, &hexSize);
						if(cpb_boot_result)
						{
						 	bError = 1;
						}
						else
						{
							program_read_complete = 1;
						}
					}

					if(bError==0)
					{
						for (cpbIndex = 0; cpbIndex < SYSTEM_MAX_SPB_CLIENT_BOARD_COUNT; cpbIndex++)
						{
							SrioRunInfo.CPBProgram[cpbIndex] = (unsigned char *)&SrioProgramBinBuffer[cpbIndex];
							SrioRunInfo.CPBProgramSize[cpbIndex] = ConvertProgram(ProgramBuffer+(CPB_MAX_CODE_SIZE*cpbIndex), SrioRunInfo.CPBProgram[cpbIndex], CPB_MAX_CODE_SIZE, CPB_HEX_FORMAT_L2SEG+0x100*cpbIndex);	
						}
					}
					else
					{
						SrioRunInfo.RunStep = CPB_BOOT_PROCESS_IDLE;
						SrioRunInfo.RunSW = 0;
						break;
					}
			
					SrioRunInfo.RunStep = CPB_BOOT_PROCESS_DOWNLOAD;
				}
				break;

			case CPB_BOOT_PROCESS_DOWNLOAD:
				{	
					int tryCount = 0;
					int remainDataLength = 0;
					int programAddr = 0;
					int copyLength = 0;
					int i;
					
					cpbIndex = SrioRunInfo.CurrentCPBIndex;
					CPBStatus[cpbIndex].Status = CPB_STATUS_BOOTING;
					if (CPBStatus[cpbIndex].Enabled)
					{
						cpb_boot_result = ERROR_CODE_NONE;
						cpbBootInfo.BoardID = BoardID + cpbIndex + 1;
						cpbBootInfo.CPUKind = CPU_KIND_6678;
						Request_CopyData(SrioRunInfo.CPBProgram[cpbIndex%8], &cpbBootInfo, sizeof(TCPBBootInfo));

						for (tryCount = 0; tryCount < CPB_BOOT_RETRY_COUNT; tryCount++)
						{
							remainDataLength = (SrioRunInfo.CPBProgramSize[cpbIndex%8] + 3) / 4 * 4;
							programAddr = 0;
							
							while(remainDataLength > 0)
							{
								if (remainDataLength > CPB_PROGRAM_TRANSFER_SIZE)
								{
									copyLength = CPB_PROGRAM_TRANSFER_SIZE;
								}
								else
								{
									copyLength = remainDataLength;
								}

								Request_CopyData(SrioTempBufferW, (SrioRunInfo.CPBProgram[cpbIndex%8] + programAddr), copyLength);
								Sleep(2);
								Request_SRIO_WriteData(cpbIndex,SrioTempBufferW,CPBHWInfo[cpbIndex].BaseL2Addr+programAddr,copyLength/4,&SrioTransferStatus);
								Sleep(2);
								Request_SRIO_ReadData(cpbIndex,SrioTempBufferR,CPBHWInfo[cpbIndex].BaseL2Addr+programAddr,copyLength/4,&SrioTransferStatus);	

								for (i = 0; i < copyLength / 4; i ++)
								{
									if (*(SrioTempBufferW + i) != *(SrioTempBufferR + i))
									{
										ErrorUnit_Put(BoardID + cpbIndex + 1, ERROR_TYPE_MESSAGE, ERROR_CODE_NOTMATCH, *HPI_CTRL(cpbIndex), *(SrioTempBufferW + i), *(SrioTempBufferR + i));
										bError = 1;
										break;
									}
								}
								if (bError) 
								{
									break;
								}
								else
								{
									programAddr += copyLength;
									remainDataLength -= copyLength;
								}
							}
							if (!bError) break;
						}
													
						if (tryCount > CPB_BOOT_RETRY_COUNT)
						{	
							cpb_boot_result = ERROR_CODE_NOTMATCH;
						}
												
						if (!bError)	// success
						{
							SrioRunInfo.RunSuccess[cpbIndex] = 1;
							CPBStatus[cpbIndex].Status = CPB_STATUS_IDLE;
//							ErrorUnit_Put(BoardID + cpbIndex + 1, ERROR_TYPE_WARNING, cpb_boot_result, __LINE__, hexSize, SrioRunInfo.CPBProgramSize);
						}
						else	// CPB download failure
						{

							ErrorUnit_Put(BoardID + cpbIndex + 1, ERROR_TYPE_WARNING, cpb_boot_result, __LINE__, hexSize, SrioRunInfo.CPBProgramSize);
							CPBStatus[cpbIndex].Enabled = FALSE;
							CPBStatus[cpbIndex].IsDown = TRUE;
							CPBStatus[cpbIndex].Status = CPB_STATUS_DISABLED;
						}
					}
					SrioRunInfo.CurrentCPBIndex++;					
					if(SrioRunInfo.CurrentCPBIndex == TPB_CPB_MAX_COUNT)
					{
						SrioRunInfo.RunStep = CPB_BOOT_PROCESS_RUN;
					}
						
				}
				break;
			case CPB_BOOT_PROCESS_RUN:
				{
					srioportIndex = 0;
					Request_SRIO_WriteData(srioportIndex*8,&boot_start_cmd, 0x85000000,1,&SrioTransferStatus);
					CPBBootStartTime = Board1MSTmr;
					SrioRunInfo.RunStep = CPB_BOOT_PROCESS_COMPLETE;
				}
				break;
			case CPB_BOOT_PROCESS_COMPLETE:
				{
					if(!CPBStatus[srioportIndex*8+1].Enabled)
					{
						for(cpbIndex = srioportIndex*8 ; cpbIndex < srioportIndex*8+8 ;  cpbIndex++)
						{
							CPBStatus[cpbIndex].Enabled = FALSE;
							CPBStatus[cpbIndex].IsDown = TRUE;
							CPBStatus[cpbIndex].Status = CPB_STATUS_DISABLED;
						}
						port_boot_complete_flag |= 0x1<<srioportIndex;
					}
					else
					{
						Request_SRIO_ReadData(srioportIndex*8,&boot_complet[srioportIndex],CPBHWInfo[srioportIndex*8].SrioBootCompleteAddr,1,&SrioTransferStatus);
						Sleep(1);
						if(boot_complet[srioportIndex] == 0xFF)
						{
							for(cpbIndex = srioportIndex*8 ; cpbIndex < srioportIndex*8+8 ;  cpbIndex++)
							{						
								CPBStatus[cpbIndex].Status = CPB_STATUS_IDLE;
							}
							port_boot_complete_flag |= 0x1<<srioportIndex;
						}
						else
						{
							Request_SRIO_WriteData(srioportIndex*8,&boot_start_cmd, 0x85000000,1,&SrioTransferStatus);
							if(CPBBootStartTime + SRIO_BOOT_WAIT_TIME < Board1MSTmr)
							{
								for (cpbIndex = srioportIndex*8; cpbIndex < srioportIndex*8+8; cpbIndex++)
								{
									if(boot_complet[srioportIndex]&(0x1<<(cpbIndex-srioportIndex*8)))
									{
										CPBStatus[cpbIndex].Status = CPB_STATUS_IDLE;
									}
									else
									{
										CPBStatus[cpbIndex].Enabled = FALSE;
										CPBStatus[cpbIndex].IsDown = TRUE;
										CPBStatus[cpbIndex].Status = CPB_STATUS_DISABLED;							
									}
								}
								port_boot_complete_flag |= 0x1<<srioportIndex;	
							}
						}
					
					}

					if(port_boot_complete_flag==0x1)
					{
						for (cpbIndex = 0; cpbIndex < TPB_CPB_MAX_COUNT; cpbIndex++)
						{

							if (CPBStatus[cpbIndex].IsDown)
							{
								CPBStatus[cpbIndex].Enabled = FALSE;
								CPBStatus[cpbIndex].IsDown = TRUE;
								CPBStatus[cpbIndex].Status = CPB_STATUS_DISABLED;

							}
							else
							{
								CPBStatus[cpbIndex].Enabled = TRUE;
								CPBStatus[cpbIndex].IsDown = FALSE;							
								CPBStatus[cpbIndex].Status = CPB_STATUS_IDLE;
							}
						}
						SrioRunInfo.RunStep = CPB_BOOT_PROCESS_IDLE;
						SrioRunInfo.RunSW = 0;				
					}
				}
				break;				
		}
	}
}

int Check_CPBProcess(int cpbIndex)
{
	Request_SRIO_ReadData(cpbIndex, (Uint32) &(CPB_StatusList[cpbIndex]), (Uint32) CPBHWInfo[cpbIndex].CPBStatusAddr, 1, &CommandTransferStatus[cpbIndex]);
	return CPB_StatusList[cpbIndex];
}
