//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//

#include <windows.h>
#include <bsp.h>
#include <dbgserial.h>
#include <oal_i2cEmul.h>
#include <MAX8698.h>
#include <fmd.h>
#include <clkinfo.h>
#include "loader.h"
#include "usb.h"
#include "menu.h"

#include "SVEDriverAPI.h"
#include "ldi.h"
#include "display_con.h"
#include "mipidsi_reg.h"
#include "SVE_API.h"
#include "celogo.H"
#include "backlight_pdd.h"

//extern PSectorInfo g_pSectorInfoBuf;
//extern BOOL ReadBlock(DWORD dwBlock, LPBYTE pbBlock, PSectorInfo pSectorInfoTable);



//volatile static GPIO_REG		*pGPIOReg = NULL;
//volatile static PWM_REG			*pPMUPMReg = NULL;
//volatile static CMU_CLK_REG		*pCMUCLKReg = NULL;

    volatile GPIO_REG *pGPIOReg = NULL;
    volatile DISPLAY_REG *pDispReg = NULL;
    volatile PMU_PM_REG *pPMUPMReg = NULL;
    volatile CMU_CLK_REG *pCMUCLKReg = NULL;
    volatile CMU_MISC_REG *pCMUMISCReg =NULL;
    volatile BSP_ARGS *pBSPArgs      =NULL;

 volatile PWM_REG *v_pPWMregs = NULL;

DWORD g_dwD0Brightness = 100;

//added by terry 2012.06.15
//#define SD_CHANNEL0 // it could be SD_CHANNEL2
	DWORD g_oSD_CHANNEL0 ;




#define 	LCD_XSIZE_TFT LCD_HEIGHT;
#define		LCD_YSIZE_TFT LCD_WIDTH;



#ifdef SDMMC_BOOT
#include <HSMMCDRV.h>
#endif
//-------------------------------
// Global variables.
//


//#define BEEPER // 使用峰鸣器时，打开此宏
//added by terry for LOGO.BIN
BOOL    bIsLogoBin = FALSE;

DWORD           g_ImageType = IMAGE_TYPE_NK;
PDownloadManifest	g_pDownloadManifest;
MultiBINInfo    g_BINRegionInfo;

PBOOT_CFG       g_pBootCfg;
#ifdef SDMMC_BOOT
UCHAR			g_TOC[TOC_SECTOR_SIZE];
#else
UCHAR           g_TOC[NAND_SECTOR_SIZE];
#endif
const PTOC      g_pTOC = (PTOC)&g_TOC;
DWORD           g_dwTocEntry = TOC_ENTRY_NK;
BOOL            g_bBootMediaExist = FALSE;
BOOL            g_bDownloadImage  = FALSE;
BOOLEAN         g_bUSBDownload = TRUE;
BOOLEAN         g_bT32Download = FALSE;
DWORD			wNUM_BLOCKS;

#ifndef SDMMC_BOOT
FlashInfo		g_FlashInfo;

DWORD			_NUM_OF_BLOCKS;
DWORD			_BYTES_PER_BLOCK;
WORD			_SECTORS_PER_BLOCK;
WORD			_BYTES_PER_SECTOR;

extern int DWORDToBytes(UCHAR *szData, const DWORD dwData);
extern UINT32 USBWriteString(UINT8 * pbData, UINT32 cbData);

#else
ADDRESSINFOSECTOR g_AddressInfoSector;
#endif
//-------------------------------
// External variables.
//
extern SYSTEM_CLOCK g_SysClockTable[SYS_CLK_DEF_MAX];

//-------------------------------
// Function prototypes.
//
// System Function
void SetCPUClock(void);
// Display Function
static void InitializeDisplay(void);
// For USB Download function.
extern void InitializeInterrupt();
extern BOOL CheckUSBDownload();
extern void OTGDEV_SetSoftDisconnect();
extern BOOL UbootReadData(DWORD cbData, LPBYTE pbData);
//Argument Initialize
extern void OALArgsInit(BSP_ARGS* pArgs);

void EBOOT_BL_InitPWM();
void EBOOT_BL_SetBrightness(DWORD dwValue);

#ifdef PWMTIMEOUT0  // for time0 time1

#define BKL_TCNTB	(v_pPWMregs->TCNTB0)
#define BKL_TCMPB	(v_pPWMregs->TCMPB0)
#define BKL_TCON	(v_pPWMregs->TCON)

#define BKL_TCON_OFFSETBIT			(0)

#else // time2

#define BKL_TCNTB	(v_pPWMregs->TCNTB2)
#define BKL_TCMPB	(v_pPWMregs->TCMPB2)
#define BKL_TCON	(v_pPWMregs->TCON)

#define BKL_TCON_OFFSETBIT			(0xc)

#endif

#define BKL_TCON_Start              (0x1 << BKL_TCON_OFFSETBIT)
#define BKL_TCON_Update             (0x2 << BKL_TCON_OFFSETBIT)
#define BKL_TCON_AutoReload         (0x8 << BKL_TCON_OFFSETBIT)



#if(LCD_MODULE == LCD_MODULE_LTV350)


#if 0
//added by terry for qimei 4.3 inch  backlight GPD00 pwn
	#define	BACKLIGHT_ON(gpioreg)    {  Set_PinData(gpioreg, GPH24_Output, 1);    \
								Set_PinFunction(gpioreg, GPH24_Output); 	\
								EBOOT_BL_InitPWM();} //GPD00
#else
//added by terry for qimei 4.3 inch  backlight GPD00		
// GPH3_5--->DISPLAY--1

	#define	BACKLIGHT_ON(gpioreg)    {  Set_PinData(gpioreg, GPH24_Output, 1);    \
								Set_PinFunction(gpioreg, GPH24_Output); 	\
								Set_PinData(gpioreg, GPF35_Output, 1);    \
								Set_PinFunction(gpioreg, GPF35_Output); 	\
								Set_PinData(gpioreg, GPD00_Output, 1);    \
								Set_PinFunction(gpioreg, GPD00_Output); }
#endif

#else
//added by terry 20110922
#define BACKLIGHT_ON(gpioreg)  {  Set_PinData(gpioreg, GPH24_Output, 1);    \
								Set_PinFunction(gpioreg, GPH24_Output); 	\
								Set_PinData(gpioreg, GPF35_Output, 1);    \
								Set_PinFunction(gpioreg, GPF35_Output); 	\
								Set_PinData(gpioreg, GPD00_Output, 0);    \
								Set_PinFunction(gpioreg, GPD00_Output); }

#define BACKLIGHT_OFF(gpioreg)  {  Set_PinData(gpioreg, GPD03_Output, 0);      \
                                   Set_PinFunction(gpioreg, GPD03_Output); }


#endif

#define beeper1(gpioreg) {  Set_PinData(gpioreg, GPD02_Output, 1); Set_PinFunction(gpioreg, GPD02_Output);}

#define beeper2(gpioreg) {  EBOOT_BL_InitPWM();} //GPD00

#define beeper_off(gpioreg) {   Set_PinFunction(gpioreg, GPD02_Output);Set_PinData(gpioreg, GPD02_Output, 0);}

#ifdef SDMMC_BOOT
static void SpinForever(void)
{
    EdbgOutputDebugString("SpinForever...\r\n");
    while(1)
    {
        ;
    }
}
#endif

/*
    @func   void | main | Samsung bootloader C routine entry point.
    @rdesc  N/A.
    @comm
    @xref
*/
void main(void)
{
    BootloaderMain();

    // Should never get here.
    //
    SPIN_FOREVER;
}

/*
    @func   BOOL | OEMDebugInit | Initializes the serial port for debug output message.
    @rdesc  TRUE == Success and FALSE == Failure.
    @comm
    @xref
*/
BOOL OEMDebugInit(void)
{

    // Set up function callbacks used by blcommon.
    //
    g_pOEMVerifyMemory   = OEMVerifyMemory;      // Verify RAM.
    g_pOEMMultiBINNotify = OEMMultiBINNotify;

    // Call serial initialization routine (shared with the OAL).
    //
    OEMInitDebugSerial();

    return(TRUE);
}

#define POWERLOCK_ON(gpioreg)  {  Set_PinData(gpioreg, GPH00_Output, 1);      \
                                  Set_PinFunction(gpioreg, GPH00_Output); }

/*
    @func   BOOL | OEMPlatformInit | Initialize the Samsung SMD2440 platform hardware.
    @rdesc  TRUE = Success, FALSE = Failure.
    @comm
    @xref
*/
BOOL OEMPlatformInit(void)
{
    ULONG BootDelay;
    UINT8 KeySelect;
    UINT32 dwStartTime, dwPrevTime, dwCurrTime;
	volatile GPIO_REG *pGPIOReg = (GPIO_REG *)OALPAtoVA(BASE_REG_PA_GPIO, FALSE);
  	
    EdbgOutputDebugString("Microsoft Windows CE Bootloader for the Samsung SMDKV210 Version %d.%d Built %s\r\n\r\n",
                          EBOOT_VERSION_MAJOR, EBOOT_VERSION_MINOR, __DATE__);

    // Initialize BSPArgs and load OAL Log mask
    OALArgsInit((BSP_ARGS *) IMAGE_SHARE_ARGS_UA_START);

	POWERLOCK_ON(pGPIOReg);

    // Initialize Interrupt (VIC)
    InitializeInterrupt();

#ifdef SDMMC_BOOT

    if ( !SDHC_INIT())
    {
        OALMSG(TRUE, (TEXT("ERROR: HSMMC_Init Failed.\r\n")));
        SpinForever();
    }
    else
    {
         OALMSG(TRUE, (TEXT("HSMMC_Init Success!!!\r\n")));
#if 1    
		SDHC_READ(AISSTARTSECTOR,SECTOROFAIS, (UINT32)(&g_AddressInfoSector));

		if (g_AddressInfoSector.dwSignature != 0x53c5d5d)
		{	
			g_AddressInfoSector.dwSignature = 0x53c5d5d;
			g_AddressInfoSector.dwBootimageStartSector = 0;
			g_AddressInfoSector.dwBootImageTotalSector = 0;
			g_AddressInfoSector.dwFlashImageStartSector = 0;
			g_AddressInfoSector.dwFlashImageTotalSector = 0;
	        OALMSG(TRUE, (TEXT("##### Address Info Sector is not fused!!\r\n")));			
		}
#endif
    }
#endif
    // Initialize FLASH
    if (!BP_Init((LPBYTE)BINFS_RAM_START, BINFS_RAM_LENGTH, NULL, NULL, NULL) )
    {
        OALMSG(OAL_WARN, (TEXT("WARNING: OEMPlatformInit failed to initialize Boot Media.\r\n")));
        g_bBootMediaExist = FALSE;
    }
    else
    {
        g_bBootMediaExist = TRUE;
#ifndef SDMMC_BOOT
		// Get flash info
		if (!FMD_GetInfo(&g_FlashInfo)) 
		{
			OALMSG(1, (TEXT("FMD_GetInfo was failed.\r\n")));
			SPIN_FOREVER;
		}

		// EBOOT global variables related to the NAND flash memory spec
	    _NUM_OF_BLOCKS = g_FlashInfo.dwNumBlocks;
		_BYTES_PER_BLOCK = g_FlashInfo.dwBytesPerBlock;
		_SECTORS_PER_BLOCK = g_FlashInfo.wSectorsPerBlock;
		_BYTES_PER_SECTOR = g_FlashInfo.wDataBytesPerSector;	    
#endif        
    }

    
    // Try to retrieve TOC (and Boot config) from boot media
    //
    if (TOC_Read() == FALSE)
    {
        // use default settings
        TOC_Init();
        TOC_Write();
    }

    OALLogSetZones(g_pBSPArgs->dwOALLogMask);
    
    SetCPUClock();

//	MenuHandlerCLKChange((void *)(0));


    // Initialize the display.
    InitializeDisplay();
#ifdef BEEPER

    //beeper  蜂鸣器 	
    if (1) // GPIO方式
    {   
        beeper1(pGPIOReg);
    }
    else  // PWM方式
    {
        beeper2(pGPIOReg); // 蜂鸣器 PWM TIME2
		EdbgOutputDebugString ( "PWM beep.\r\n");
    }
#endif 
    //BL_SetBrightness(100);

    // Display boot message - user can halt the autoboot by pressing any key on the serial terminal emulator.
    //
    BootDelay = g_pBootCfg->BootDelay;

    if(g_pBootCfg->ConfigFlags & CONFIG_FLAGS_KITL)
        g_pBSPArgs->kitl.flags = OAL_KITL_FLAGS_ENABLED | OAL_KITL_FLAGS_VMINI;
    OALMSG(OAL_INFO, (TEXT("\n\nFlags= %x, kitl.flags= %x \r\n"),g_pBootCfg->ConfigFlags,g_pBSPArgs->kitl.flags));

    if (g_pBootCfg->ConfigFlags & BOOT_TYPE_DIRECT)
    {
        OALMSG(TRUE, (TEXT("Press [ENTER] to launch image stored in Flash or [SPACE] to cancel.\r\n")));
        OALMSG(TRUE, (TEXT("\r\nInitiating image launch in %d seconds. "),BootDelay--));
    }
    else
    {
        OALMSG(TRUE, (TEXT("Press [ENTER] to download now or [SPACE] to cancel.\r\n")));
        OALMSG(TRUE, (TEXT("\r\nInitiating image download in %d seconds. "),BootDelay--));
    }

    dwStartTime = OEMEthGetSecs();
    dwPrevTime  = dwStartTime;
    dwCurrTime  = dwStartTime;
    KeySelect   = 0;


	BACKLIGHT_ON(pGPIOReg);


    // Allow the user to break into the bootloader menu.
    //
    while((dwCurrTime - dwStartTime) < g_pBootCfg->BootDelay)
    {
        KeySelect = OEMReadDebugByte();
        if ((KeySelect == 0x20) || (KeySelect == 0x0d))
    	{
		
		//BACKLIGHT_ON(pGPIOReg);
		break;
    	}
        dwCurrTime = OEMEthGetSecs();

	if(dwCurrTime - dwStartTime >=1)
	{	
		//BACKLIGHT_ON(pGPIOReg);				
	}

        if (dwCurrTime > dwPrevTime)
        {
            int i = 0, j = 0;

            // 1 Second has elapsed - update the countdown timer.
            dwPrevTime = dwCurrTime;
            if (BootDelay < 9)
                i = 11;
            else if (BootDelay < 99)
                i = 12;
            else if (BootDelay < 999)
                i = 13;

            for(j = 0; j < i; j++)
                OEMWriteDebugByte((BYTE)0x08); // print back space
            EdbgOutputDebugString ( "%d seconds. ", BootDelay--);
        }
    }
	OALMSG(OAL_INFO, (TEXT("\r\n")));

#ifdef BEEPER
    beeper_off(pGPIOReg);
#endif    
    // Boot or enter bootloader menu.
    //
    switch(KeySelect)
    {
    case 0x20: // Boot menu.
        //g_bDownloadImage = MainMenu(g_pBootCfg);
        EbootMainMenu();
        break;
    case 0x00: // Fall through if no keys were pressed -or-
    case 0x0d: // the user cancelled the countdown.
    default:
        break;
    }

    CheckUSBDownload();

    OALMSG(OAL_FUNC, (TEXT("_OEMPlatformInit.\r\n")));
   
    return(TRUE);
}


/*
    @func   DWORD | OEMPreDownload | Complete pre-download tasks - get IP address, initialize TFTP, etc.
    @rdesc  BL_DOWNLOAD = Platform Builder is asking us to download an image, BL_JUMP = Platform Builder is requesting we jump to an existing image, BL_ERROR = Failure.
    @comm
    @xref
*/
DWORD OEMPreDownload(void)
{
    DWORD dwDHCPLeaseTime = 0;
    PDWORD pdwDHCPLeaseTime = &dwDHCPLeaseTime;
    DWORD dwBootFlags = 0;

    OALMSG(OAL_FUNC, (TEXT("+OEMPreDownload.\r\n")));

    // Create device name based on Ethernet address (this is how Platform Builder identifies this device).
    //
    OALKitlCreateName(BSP_DEVICE_PREFIX, g_pBSPArgs->kitl.mac, g_pBSPArgs->deviceID);
    OALMSG(OAL_INFO, (L"INFO: *** Device Name '%hs' ***\r\n", g_pBSPArgs->deviceID));

        if ( !g_bDownloadImage)
        {
            return(BL_JUMP);
        }

    else if (g_bUSBDownload == TRUE)
    {
        // clear ram being downloading to 0xff because of initializing dummy data or downloaded data through usb
        OALMSG(TRUE, (TEXT("Please send the Image through USB.\r\n")));
    }

     OALMSG(OAL_FUNC, (TEXT("-OEMPreDownload.\r\n")));

    return(BL_DOWNLOAD);
}


/*
    @func   BOOL | OEMReadData | Generically read download data (abstracts actual transport read call).
    @rdesc  TRUE = Success, FALSE = Failure.
    @comm
    @xref
*/
BOOL OEMReadData(DWORD dwData, PUCHAR pData)
{
    BOOL ret = FALSE;

	//RETAILMSG(1, (TEXT("OEMReadData+++++\r\n")));	

    if ( g_bUSBDownload == TRUE )
    {
        ret = UbootReadData(dwData, pData);
    }

	// RETAILMSG(1, (TEXT("OEMReadData-----\r\n")));	

    return(ret);
}

void OEMReadDebugString(CHAR * szString)
{
    USHORT cwNumChars = 0;
    USHORT InChar = 0;

    while(!((InChar == 0x0d) || (InChar == 0x0a)))
    {
        InChar = OEMReadDebugByte();
        if (InChar != OEM_DEBUG_COM_ERROR && InChar != OEM_DEBUG_READ_NODATA)
        {
            if ((InChar >= 'a' && InChar <='z') || (InChar >= 'A' && InChar <= 'Z') || (InChar >= '0' && InChar <= '9'))
            {
                if (cwNumChars < 16)
                {
                    szString[cwNumChars++] = (char)InChar;
                    OEMWriteDebugByte((BYTE)InChar);
                }
            }
            // If it's a backspace, back up.
            //
            else if (InChar == 8)
            {
                if (cwNumChars > 0)
                {
                    cwNumChars--;
                    OEMWriteDebugByte((BYTE)InChar);
                }
            }
        }
    }

    // If it's a carriage return with an empty string, don't change anything.
    //
    if (cwNumChars)
    {
        szString[cwNumChars] = '\0';
        EdbgOutputDebugString("\r\n");
    }
}


/*
    @func   void | OEMShowProgress | Displays download progress for the user.
    @rdesc  N/A.
    @comm
    @xref
*/
void OEMShowProgress(DWORD dwPacketNum)
{
    OALMSG(OAL_FUNC, (TEXT("+%s\r\n"), _T(__FUNCTION__)));
    
    OALMSG(OAL_FUNC, (TEXT("-%s\r\n"), _T(__FUNCTION__)));
}


/*
    @func   void | OEMLaunch | Executes the stored/downloaded image.
    @rdesc  N/A.
    @comm
    @xref
*/

void OEMLaunch( DWORD dwImageStart, DWORD dwImageLength, DWORD dwLaunchAddr, const ROMHDR *pRomHdr )
{
    //INT32 nErr;
    DWORD dwPhysLaunchAddr;
    
    OALMSG(OAL_FUNC, (TEXT("+OEMLaunch.\r\n")));

    
    OALMSG(TRUE, (TEXT("+OEMLaunch.  dwLaunchAddr = 0x%x\r\n"),dwLaunchAddr));


    
    // If the user requested that a disk image (stored in RAM now) be written to the SmartMedia card, so it now.
    //
    if (g_bDownloadImage)
    {
        // Since this platform only supports RAM images, the image cache address is the same as the image RAM address.
        //

        switch (g_ImageType)
        {

// added by terry for logo.bin 2012.06.18
			case IMAGE_TYPE_LOGO:
                if (!WriteRawImageToBootMedia(dwImageStart, dwImageLength, dwLaunchAddr))
                {
                    OALMSG(OAL_ERROR, (TEXT("ERROR: OEMLaunch: Failed to store logo.bin image to Smart Media.\r\n")));
                    goto CleanUp;
                }
                OALMSG(TRUE, (TEXT("INFO: logo.bin image stored to Smart Media.  Please Reboot.  Halting...\r\n")));
                while(1)
                {
                    // Wait...
                }
                break;


		
            case IMAGE_TYPE_STEPLDR:
        	case IMAGE_TYPE_IPL:
        	case IMAGE_TYPE_BOOTIMAGE:
                if (!WriteRawImageToBootMedia(dwImageStart, dwImageLength, dwLaunchAddr))
                {
                    OALMSG(OAL_ERROR, (TEXT("ERROR: OEMLaunch: Failed to store image to Smart Media.\r\n")));
                    goto CleanUp;
                }
                OALMSG(TRUE, (TEXT("INFO: Step loader image stored to Smart Media.  Please Reboot.  Halting...\r\n")));
                while(1)
                {
                    // Wait...
                }
                break;

            case IMAGE_TYPE_EBOOT:
                g_pTOC->id[TOC_ENTRY_EBOOT].dwLoadAddress = dwImageStart;
                g_pTOC->id[TOC_ENTRY_EBOOT].dwTtlSectors = FILE_TO_SECTOR_SIZE(dwImageLength);
                if (!WriteRawImageToBootMedia(dwImageStart, dwImageLength, dwLaunchAddr))
                {
                    OALMSG(OAL_ERROR, (TEXT("ERROR: OEMLaunch: Failed to store image to Smart Media.\r\n")));
                    goto CleanUp;
                }
                if (dwLaunchAddr && (g_pTOC->id[TOC_ENTRY_EBOOT].dwJumpAddress != dwLaunchAddr))
                {
                    g_pTOC->id[0].dwJumpAddress = dwLaunchAddr;
                    if ( !TOC_Write() ) {
                        EdbgOutputDebugString("*** OEMLaunch ERROR: TOC_Write failed! Next boot may not load from disk *** \r\n");
                    }
                    TOC_Print();
                }
                OALMSG(TRUE, (TEXT("INFO: Eboot image stored to Smart Media.  Please Reboot.  Halting...\r\n")));
                while(1)
                {
                    // Wait...
                }

                break;

            case IMAGE_TYPE_NK:

				WriteFlashNK(dwImageStart, dwImageLength); //lqm added.

				if (dwLaunchAddr && (g_pTOC->id[g_dwTocEntry].dwJumpAddress != dwLaunchAddr))
				{
					g_pTOC->id[g_dwTocEntry].dwJumpAddress = dwLaunchAddr;
					if ( !TOC_Write() ) {
						EdbgOutputDebugString("*** OEMLaunch ERROR: TOC_Write failed! Next boot may not load from disk *** \r\n");
					}
					TOC_Print();
				}				
				OALMSG(1, (TEXT("A XIP region was written to the flash memory successfully.\r\n")));

				break;

			
            default:
                break;
        }
    }
    else {
        EdbgOutputDebugString("INFO: g_ImageType: 0x%x\r\n", g_ImageType);
        switch(g_ImageType)
        {
    		case IMAGE_TYPE_NK:
    			OALMSG(TRUE, (TEXT("OEMLaunch: IMAGE_TYPE_NK\r\n")));

				if(g_pTOC->id[TOC_ENTRY_NK].dwSignature == IMAGE_MXIP_SIG ||
					g_pTOC->id[TOC_ENTRY_NK].dwSignature == IMAGE_SXIP_SIG)
				{
					OALMSG(1, (TEXT("Launch the NK...\r\n")));
				
					if(LoadNK() != TRUE)
					{
						OALMSG(1, (TEXT("<ERROR> Failed to load the NK.\r\n")));
						while(1);
					}
					else
					{
						Launch(OALVAtoPA((DWORD *)g_pTOC->id[TOC_ENTRY_NK].dwJumpAddress));
					}
					
				}
				else
				{
					OALMSG(1, (TEXT("<ERROR> There is no NK in the NAND flash memory\r\n")));
				}
			
    			break;
            default:
                return /*FALSE*/;
        }
      }

    // If a launch address was provided, we must have downloaded the image, save the address in case we
    // want to jump to this image next time.  If no launch address was provided, retrieve the last one.
    //
    if (dwLaunchAddr && (g_pTOC->id[g_dwTocEntry].dwJumpAddress != dwLaunchAddr))
    {
        g_pTOC->id[g_dwTocEntry].dwJumpAddress = dwLaunchAddr;
    }
    else
    {
        dwLaunchAddr= g_pTOC->id[g_dwTocEntry].dwJumpAddress;
        OALMSG(OAL_INFO, (TEXT("INFO: using TOC[%d] dwJumpAddress: 0x%x\r\n"), g_dwTocEntry, dwLaunchAddr));
    }

    // Disable all of the interrupt enable before the launch to prevent an interrupt occurrence while the MMU is disabled.
    //
    System_DisableIRQ();

    // Jump to downloaded image (use the physical address since we'll be turning the MMU off)...
    //
    dwPhysLaunchAddr = (DWORD)OALVAtoPA((void *)dwLaunchAddr);
    EdbgOutputDebugString("INFO: OEMLaunch: Jumping to Physical Address 0x%Xh (Virtual Address 0x%Xh)...\r\n\r\n\r\n", dwPhysLaunchAddr, dwLaunchAddr);

    // Jump...
    //
    Launch(dwPhysLaunchAddr);

            
CleanUp:

    OALMSG(TRUE, (TEXT("ERROR: OEMLaunch: Halting...\r\n")));
    SPIN_FOREVER;

	return /*FALSE*/;
   
}


//------------------------------------------------------------------------------
//
//  Function Name:  OEMVerifyMemory( DWORD dwStartAddr, DWORD dwLength )
//  Description..:  This function verifies the passed address range lies
//                  within a valid region of memory. Additionally this function
//                  sets the g_ImageType if the image is a boot loader.
//  Inputs.......:  DWORD           Memory start address
//                  DWORD           Memory length
//  Outputs......:  BOOL - true if verified, false otherwise
//
//------------------------------------------------------------------------------

BOOL OEMVerifyMemory( DWORD dwStartAddr, DWORD dwLength )
{
    OALMSG(OAL_FUNC, (TEXT("+OEMVerifyMemory.\r\n")));
    OALMSG(TRUE, (TEXT("dwStartAddr = 0x%x \r\n"), dwStartAddr));
    OALMSG(TRUE, (TEXT("dwLength = 0x%x \r\n"), dwLength));

    // Is the image being downloaded the stepldr?
    //if ((dwStartAddr >= STEPLDR_RAM_IMAGE_BASE) &&
    if (   ((dwStartAddr + dwLength - 1) < (STEPLDR_RAM_IMAGE_BASE + STEPLDR_RAM_IMAGE_SIZE)))
    {
        OALMSG(TRUE, (TEXT("Stepldr image\r\n")));
        g_ImageType = IMAGE_TYPE_STEPLDR;     // Stepldr image.
        return TRUE;
    }
    // Is the image being downloaded the block0 image?
    //if ((dwStartAddr >= BLOCK0_RAM_IMAGE_BASE) &&
    if(   ((dwStartAddr + dwLength - 1) < (BLOCK0_RAM_IMAGE_BASE + BLOCK0_RAM_IMAGE_SIZE)))
    {
        OALMSG(TRUE, (TEXT("Block0 image\r\n")));
        g_ImageType = IMAGE_TYPE_STEPLDR;     // block0 image.
        return TRUE;
    }
    // Is the image being downloaded the IPL?
    else if ((dwStartAddr >= IPL_RAM_IMAGE_BASE) &&
            ((dwStartAddr + dwLength - 1) < (IPL_RAM_IMAGE_BASE + IPL_RAM_IMAGE_SIZE)))
    {
        OALMSG(TRUE, (TEXT("Ipl image\r\n")));
        g_ImageType = IMAGE_TYPE_IPL;     // Ipl image.
        return TRUE;
    }
    // Is the image being downloaded the bootimage?
    //if ((dwStartAddr >= BOOTIMAGE_RAM_IMAGE_BASE) &&
    if (   ((dwStartAddr + dwLength - 1) < (BOOTIMAGE_RAM_IMAGE_BASE + BOOTIMAGE_RAM_IMAGE_SIZE)))
    {
        OALMSG(TRUE, (TEXT("bootimage\r\n")));
        g_ImageType = IMAGE_TYPE_BOOTIMAGE;     // Stepldr image.
        return TRUE;
    }
    // Is the image being downloaded the bootloader?
    else if ((dwStartAddr >= EBOOT_STORE_ADDRESS) &&
            ((dwStartAddr + dwLength - 1) < (EBOOT_STORE_ADDRESS + EBOOT_STORE_MAX_LENGTH)))
    {
        OALMSG(TRUE, (TEXT("Eboot image\r\n")));
        g_ImageType = IMAGE_TYPE_EBOOT;     // Eboot image.
        return TRUE;
    }
    // Is the image being downloaded the dio.nb0?
//	else if (dwStartAddr == 0)
//    {
//        OALMSG(TRUE, (TEXT("dio.nb0 image\r\n")));
//        g_ImageType = IMAGE_TYPE_DIONB0;     // dio.nb0 image.
//        return TRUE;
//    }
    // Is it a dio image?
//    else if ((dwStartAddr >= NAND_ROM_IMAGE_BASE) &&
//        ((dwStartAddr + dwLength - 1) < (NAND_ROM_IMAGE_BASE + NAND_ROM_IMAGE_SIZE)))
//    {
//        OALMSG(OAL_INFO, (TEXT("DIO image\r\n")));
//        g_ImageType = IMAGE_TYPE_DIO;     // dio image.
//        return TRUE;
//    }
    // Is it a ram image?
//    else if ((dwStartAddr >= ROM_RAMIMAGE_START) &&
//        ((dwStartAddr + dwLength - 1) < (ROM_RAMIMAGE_START + ROM_RAMIMAGE_SIZE)))
//    {
//        OALMSG(OAL_INFO, (TEXT("RAM image\r\n")));
//        g_ImageType = IMAGE_TYPE_NK;
//        return TRUE;
//    }
    else if (!dwStartAddr && !dwLength)
    {
        OALMSG(TRUE, (TEXT("Don't support raw image\r\n")));
        g_ImageType = IMAGE_TYPE_UNKNOWN;
        return FALSE;
	
    }
    else if((dwStartAddr >= NK_RAM_IMAGE_BASE) &&
    		(dwStartAddr < (NK_RAM_IMAGE_BASE + NK_RAM_IMAGE_SIZE)))
    {
    	OALMSG(TRUE, (TEXT("NK image\r\n")));
    	g_ImageType = IMAGE_TYPE_NK;
    	return TRUE;
    }
	else if((dwStartAddr >= LOGBMP_RAM_IMAGE_BASE) &&
    		(dwStartAddr < (LOGBMP_RAM_IMAGE_BASE + LOGBMP_RAM_IMAGE_SIZE)))
	{
		OALMSG(TRUE, (TEXT("LOGO bin image\r\n")));
		g_ImageType = IMAGE_TYPE_LOGO;
		return TRUE;
	}	
    else
    {
        OALMSG(TRUE, (TEXT("Flash bin image\r\n")));
        g_ImageType = IMAGE_TYPE_DIOBIN;
        return TRUE;
    }

    // HACKHACK: get around MXIP images with funky addresses
    OALMSG(TRUE, (TEXT("BIN image type unknow\r\n")));

    OALMSG(OAL_FUNC, (TEXT("_OEMVerifyMemory.\r\n")));

    return FALSE;
}

/*
    @func   void | OEMMultiBINNotify | Called by blcommon to nofity the OEM code of the number, size, and location of one or more BIN regions,
                                       this routine collects the information and uses it when temporarily caching a flash image in RAM prior to final storage.
    @rdesc  N/A.
    @comm
    @xref
*/
void OEMMultiBINNotify(const PMultiBINInfo pInfo)
{

    BYTE nCount;
    DWORD g_dwMinImageStart;

	//UCHAR sizedata[4];

	//added by terry for LOGO.bin 2012.06.18
	if(g_ImageType == IMAGE_TYPE_LOGO)
		return;


	OALMSG(OAL_FUNC, (TEXT("+OEMMultiBINNotify.\r\n")));

	// save the download manifest information
	g_pDownloadManifest = pInfo;
	
    OALMSG(OAL_FUNC, (TEXT("-OEMMultiBINNotify.\r\n")));
    

    OALMSG(OAL_FUNC, (TEXT("+OEMMultiBINNotify.\r\n")));

    if (!pInfo || !pInfo->dwNumRegions)
    {
        OALMSG(OAL_WARN, (TEXT("WARNING: OEMMultiBINNotify: Invalid BIN region descriptor(s).\r\n")));
        return;
    }

    if (!pInfo->Region[0].dwRegionStart && !pInfo->Region[0].dwRegionLength)
    {
        return;
    }

    g_dwMinImageStart = pInfo->Region[0].dwRegionStart;

    OALMSG(TRUE, (TEXT("\r\nDownload BIN file information:\r\n")));
    OALMSG(TRUE, (TEXT("-----------------------------------------------------\r\n")));
    for (nCount = 0 ; nCount < pInfo->dwNumRegions ; nCount++)
    {
        OALMSG(TRUE, (TEXT("[%d]: Base Address=0x%x  Length=0x%x\r\n"),
            nCount, pInfo->Region[nCount].dwRegionStart, pInfo->Region[nCount].dwRegionLength));
        if (pInfo->Region[nCount].dwRegionStart < g_dwMinImageStart)
        {
            g_dwMinImageStart = pInfo->Region[nCount].dwRegionStart;
            if (g_dwMinImageStart == 0)
            {
                OALMSG(OAL_WARN, (TEXT("WARNING: OEMMultiBINNotify: Bad start address for region (%d).\r\n"), nCount));
                return;
            }
        }
    }

    OALMSG(TRUE, (TEXT("-----------------------------------------------------\r\n")));
#if 0  //lqm masked.
	if(pInfo->dwNumRegions)
	{
		DWORDToBytes(sizedata, pInfo->dwNumRegions);
		USBWriteString(sizedata, 4);
	}
#endif
		
    OALMSG(OAL_FUNC, (TEXT("_OEMMultiBINNotify.\r\n")));
}


/*
    @func   PVOID | GetKernelExtPointer | Locates the kernel region's extension area pointer.
    @rdesc  Pointer to the kernel's extension area.
    @comm
    @xref
*/
PVOID GetKernelExtPointer(DWORD dwRegionStart, DWORD dwRegionLength)
{
    DWORD dwCacheAddress = 0;
    ROMHDR *pROMHeader;
    DWORD dwNumModules = 0;
    TOCentry *pTOC;

    if (dwRegionStart == 0 || dwRegionLength == 0)
        return(NULL);

    if (*(LPDWORD) OEMMapMemAddr (dwRegionStart, dwRegionStart + ROM_SIGNATURE_OFFSET) != ROM_SIGNATURE)
        return NULL;

    // A pointer to the ROMHDR structure lives just past the ROM_SIGNATURE (which is a longword value).  Note that
    // this pointer is remapped since it might be a flash address (image destined for flash), but is actually cached
    // in RAM.
    //
    dwCacheAddress = *(LPDWORD) OEMMapMemAddr (dwRegionStart, dwRegionStart + ROM_SIGNATURE_OFFSET + sizeof(ULONG));
    pROMHeader     = (ROMHDR *) OEMMapMemAddr (dwRegionStart, dwCacheAddress);

    // Make sure sure are some modules in the table of contents.
    //
    if ((dwNumModules = pROMHeader->nummods) == 0)
        return NULL;

	RETAILMSG(1,(TEXT("[main.c] pROMHeader = 0x%x  dwCacheAddress =0x%x\r\n"),(DWORD)pROMHeader,dwCacheAddress));
	RETAILMSG(1,(TEXT("[main.c] dwNumModules = 0x%x\r\n"),dwNumModules));

	
    // Locate the table of contents and search for the kernel executable and the TOC immediately follows the ROMHDR.
    //
    pTOC = (TOCentry *)(pROMHeader + 1);

    while(dwNumModules--) {
        LPBYTE pFileName = OEMMapMemAddr(dwRegionStart, (DWORD)pTOC->lpszFileName);
        if (!strcmp((const char *)pFileName, "nk.exe")) {
			//RETAILMSG(1,(TEXT("[main.c] pTOC = 0x%x\r\n"),(DWORD)pTOC));			
            return ((PVOID)(pROMHeader->pExtensions));
        }
        ++pTOC;
    }
    return NULL;
}


void SetCPUClock(void)
{
 //   #ifdef InitialClockChangeWithTOC
    static volatile CMU_CLK_REG *pCMUCLKReg;
    static volatile DRAMCON_REG *pDMC0Reg;
    static volatile DRAMCON_REG *pDMC1Reg;

    pCMUCLKReg = (volatile CMU_CLK_REG*)OALPAtoVA(BASE_REG_PA_CMU_CLK, FALSE);
    pDMC0Reg = (volatile DRAMCON_REG*)OALPAtoVA(BASE_REG_PA_DMC0, FALSE);
    pDMC1Reg = (volatile DRAMCON_REG*)OALPAtoVA(BASE_REG_PA_DMC1, FALSE);
//    #endif

    #ifdef InitialClockChangeWithTOC
    if((g_pBootCfg->Clock_Info.SYS_CLK_DEF <0)||(g_pBootCfg->Clock_Info.SYS_CLK_DEF>(SYS_CLK_DEF_MAX-1)||(g_pBootCfg->Clock_Info.ARM_CLK == 0)))
    {
        OALMSG(OAL_ARGS&&OAL_OEM_FUNC, (L"EbootCFG: Clock definition is invalid\r\n"));
        memcpy(&g_pBootCfg->Clock_Info, &g_SysClockTable[SYS_CLK_DEF1], sizeof(g_pBootCfg->Clock_Info));
    }
    memcpy(&g_pBSPArgs->SystemClocks, &g_pBootCfg->Clock_Info, sizeof(g_pBSPArgs->SystemClocks));
    ClockChange((void *)pCMUCLKReg, (void *)pDMC0Reg, (void *)pDMC1Reg, &g_pBootCfg->Clock_Info);
    #else

#define	ARMCLOCK1GHZ

#ifndef ARMCLOCK1GHZ
	// Clock Changing is possible in only EBoot Menu
    memcpy(&g_pBSPArgs->SystemClocks, &g_SysClockTable[SYS_CLK_DEF1], sizeof(g_pBSPArgs->SystemClocks));
#else
	//added by terry for ARM_CLOCK support 1Ghz
	memcpy(&g_pBSPArgs->SystemClocks, &g_SysClockTable[SYS_CLK_DEF0], sizeof(g_pBSPArgs->SystemClocks));
    ClockChange((void *)pCMUCLKReg, (void *)pDMC0Reg, (void *)pDMC1Reg, &g_pBSPArgs->SystemClocks);
#endif
	//RETAILMSG(TRUE, (TEXT("<eboot>  SetCPUClock ........ \r\n")));

	
    #endif

    g_pBSPArgs->bDVFSDisable = g_pBootCfg->bDVFSDisable;
    EdbgOutputDebugString("[Eboot] g_pBSPArgs->bDVFSDisable: %d\r\n", g_pBSPArgs->bDVFSDisable);    

}

static void InitializeMIPIDPHY()
{
    volatile PMU_MISC_REG *g_pPMUMISCRegs = (PMU_MISC_REG *)OALPAtoVA(BASE_REG_PA_PMU_MISC, FALSE);

    g_pPMUMISCRegs->IP_CON_REG.MIPI_DPHY_CONTROL= (g_pPMUMISCRegs->IP_CON_REG.MIPI_DPHY_CONTROL & ~(BW_ENABLE_MIPI_DSI_DPHY<<BP_ENABLE_MIPI_DSI_DPHY))|
                (MIPI_DSI_DPHY_ENABLE<<BP_ENABLE_MIPI_DSI_DPHY);

    g_pPMUMISCRegs->IP_CON_REG.MIPI_DPHY_CONTROL= g_pPMUMISCRegs->IP_CON_REG.MIPI_DPHY_CONTROL |
                (MIPI_DPHY_ENABLE<<BP_ENABLE_MIPI_WHOLE_DPHY);			
}

#ifdef SDMMC_BOOT


#else

BOOL ReadBlock_LOGO(DWORD dwBlock, LPBYTE pbBlock, PSectorInfo pSectorInfoTable)
{
	int iSector = 0;
    for (iSector = 0; iSector < g_FlashInfo.wSectorsPerBlock; iSector++) {
        if (!FMD_ReadSector(dwBlock * g_FlashInfo.wSectorsPerBlock + iSector, pbBlock, pSectorInfoTable, 1))
            return FALSE;
        if (pbBlock)
            pbBlock += g_FlashInfo.wDataBytesPerSector;
        if (pSectorInfoTable)
            pSectorInfoTable++;
    }
    return TRUE;
}
#endif


#define EBOOT_FRAMEBUFFER_UA_START IMAGE_EBOOT_FRAMEBUFFER_UA_START

//WORD g_LcdXSize=800;
//WORD g_LcdYSize=480;

static void ShowLogo_sub(PVOID pLogoBipMap)
{

	// show logo on the center
	DWORD index, xpos, ypos;
	
	DWORD dwLeft, dwTop;
	DWORD dwBitMapWidth, dwBitMapHeight;
	
	volatile PUSHORT ptr = (PUSHORT)EBOOT_FRAMEBUFFER_UA_START;

	unsigned short *pBitMap = (unsigned short *)pLogoBipMap;
	// cal the display pos.
	dwBitMapWidth = (LCD_WIDTH <= pBitMap[0]) ? LCD_WIDTH : pBitMap[0];
	dwBitMapHeight = (LCD_HEIGHT <= pBitMap[1]) ? LCD_HEIGHT : pBitMap[1];

	dwLeft = (LCD_WIDTH-dwBitMapWidth) / 2;
	dwTop = (LCD_HEIGHT - dwBitMapHeight) / 2;

	memset((WORD *)EBOOT_FRAMEBUFFER_UA_START, 0x00, (LCD_WIDTH*LCD_HEIGHT*2));	//black
	// Display bitmap.
	ptr += (LCD_WIDTH*dwTop)+dwLeft;
	index = 2;

	RETAILMSG(TRUE, (TEXT("<eboot>dwLeft=%d, dwTop=%d; width=%d, height=%d\r\n"),dwLeft, dwTop, dwBitMapWidth, dwBitMapHeight));

	for(ypos =0; ypos<dwBitMapHeight; ypos++)
	{
		volatile  unsigned short * disp_ptr = ptr;

		for (xpos = 0; xpos < dwBitMapWidth; xpos++)
		{
			// display bitmap.
			*(disp_ptr++) = pBitMap[index];
			index++;	
		}
		ptr += LCD_WIDTH;
	}
}




//WORD g_LcdXSize=800;
//WORD g_LcdYSize=480;

#define __MAKEWORD(low, high)	((WORD)( ((BYTE)(low))|(((BYTE)(high))<<8) ))

void ShowLogoFromSD(void)
{
#ifdef SDMMC_BOOT
		// show logo on the center
		DWORD index, xpos, ypos;
		
		DWORD dwLeft, dwTop;
		DWORD dwBitMapWidth, dwBitMapHeight;
	
		SectorInfo si;
	
		DWORD i;
	
		DWORD dwBlock=0x6;
		DWORD IsFlashLogo = 0;
	
		DWORD logoFileSize = 0;
		DWORD nRector = 0;
		
		volatile PUSHORT ptr = (PUSHORT)EBOOT_FRAMEBUFFER_UA_START;
	
		unsigned char *_BitMap_ = IMAGE_2D_FRAMEBUFFER_UA_START;   
	
		bool bRet =false;
	
		DWORD StartSector = LOGOSTARTSECTOR;
	
		//	read 1 sector 
		if(!SDHC_READ(StartSector, 1, (UINT32) _BitMap_))
		{
			StartSector++;
			if(!SDHC_READ(StartSector, 1, (UINT32) _BitMap_))	
			{
				RETAILMSG(1,(TEXT("\r\n[showlogo] ReadBlock!..fail......")));
				goto Error_LOGO1;	
			}
	
		}
	
	
	// check logo data valid.
		if((0xAAAA== (__MAKEWORD(_BitMap_[0], _BitMap_[1]))) && (0x0000== (__MAKEWORD(_BitMap_[2], _BitMap_[3]))))
		{
			index = 4;
		}
		else
		{
			RETAILMSG(TRUE, (TEXT("<logo>Logo is not valid bitmap format!\r\n")));
			goto Error_LOGO1;		
		}
	
	
		//modified by zhoupeng 2008.12.10		
		// cal the display pos.
		dwBitMapWidth = __MAKEWORD(_BitMap_[5], _BitMap_[4]);
		dwBitMapHeight = __MAKEWORD(_BitMap_[7], _BitMap_[6]);	
	
	
		if(LCD_WIDTH < dwBitMapWidth) 
		{
			dwBitMapWidth = LCD_WIDTH;
		}
	
		if(LCD_HEIGHT < dwBitMapHeight)
		{
			dwBitMapHeight = LCD_HEIGHT;
		}
	
		index = 8;	// 去掉前8个字节的数据才是真正的图像数据
	
		dwLeft = (LCD_WIDTH-dwBitMapWidth) / 2;
		dwTop = (LCD_HEIGHT - dwBitMapHeight) / 2;
	
		logoFileSize = dwBitMapWidth * dwBitMapHeight *2 ;//   800*480*2
	
		nRector = logoFileSize/SDMMC_SECTOR_SIZE + ((logoFileSize%SDMMC_SECTOR_SIZE)?1:0);
		nRector--;
	
		memset((WORD *)EBOOT_FRAMEBUFFER_UA_START, 0x00, (LCD_WIDTH*LCD_HEIGHT*2)); //black
	
		// Display bitmap.
		ptr += (LCD_WIDTH*dwTop)+dwLeft;
	
		RETAILMSG(TRUE, (TEXT("<eboot>dwLeft=%d, dwTop=%d; width=%d, height=%d\r\n"),dwLeft, dwTop, dwBitMapWidth, dwBitMapHeight));

		for(ypos =0; ypos<dwBitMapHeight; ypos++)
		{
			volatile  unsigned short * disp_ptr = ptr;

			for (xpos = 0; xpos < dwBitMapWidth; xpos++)
			{
				WORD pixel = 0x0000;
				BYTE low = 0x00;

				if((nRector)&&((index) >=(SDMMC_SECTOR_SIZE))) //IF READ END?
				{
					++StartSector;
					//bRet = ReadBlock_LOGO(dwBlock,_BitMap_,NULL);

					if(!SDHC_READ(StartSector, 1, (UINT32) _BitMap_))
					{
						RETAILMSG(1,(TEXT("[error] logo  StartSector=%x\r\n"),StartSector));
					}
					
					nRector--;
					
					index = 0;
					//RETAILMSG(1,(TEXT("[logo]  dwBlock=%x\r\n"),dwBlock));
				}

				low = _BitMap_[index++];
				pixel = __MAKEWORD(_BitMap_[index], low);//__MAKEWORD(_BitMap_[dwBitMapDataPos++], _BitMap_[dwBitMapDataPos++]);	
				index++;
				
				// display bitmap.
				*(disp_ptr++) = pixel;
				
				//*(disp_ptr++) = 0xf800;// 0x00f8

			}
			ptr += LCD_WIDTH;
		}
		return;
#endif	
	
	Error_LOGO1:
	
		RETAILMSG(TRUE, (TEXT("<logo>Read data error or logo is not valid bitmap format!\r\n")));
		RETAILMSG(TRUE, (TEXT("<logo>show default  logo !\r\n")));
		ShowLogo_sub(CELOGO);	//显示默认显示图片
	
		return ;




}



static void ShowLogo(void)
{

#ifndef SDMMC_BOOT
	
	// show logo on the center
	DWORD index, xpos, ypos;
	
	DWORD dwLeft, dwTop;
	DWORD dwBitMapWidth, dwBitMapHeight;

    SectorInfo si;

	DWORD i;

	DWORD dwBlock=0x6;
	DWORD IsFlashLogo = 0;

	DWORD logoFileSize = 0;
	DWORD nBlock = 0;
	
	volatile PUSHORT ptr = (PUSHORT)EBOOT_FRAMEBUFFER_UA_START;

	//unsigned short *pBitMap = (unsigned short *)pLogoBipMap;
	
	//unsigned char _BitMap_[2048*64]={0};//_BitMap_[SECTOR_SIZE];

	unsigned char *_BitMap_ = IMAGE_2D_FRAMEBUFFER_UA_START;   

	bool bRet =false;


	DWORD StartSector = dwBlock * g_FlashInfo.wSectorsPerBlock;
	// read 0 sector 
	bRet = ReadBlock_LOGO(dwBlock,_BitMap_,NULL);

	
	if(!bRet)
	{	
		RETAILMSG(1,(TEXT("\r\n[showlogo] ReadBlock!........")));
		goto Error_LOGO;	

	}

// check logo data valid.
		if((0xAAAA== (__MAKEWORD(_BitMap_[0], _BitMap_[1]))) && (0x0000== (__MAKEWORD(_BitMap_[2], _BitMap_[3]))))
		{
			index = 4;
		}
		else
		{
			RETAILMSG(TRUE, (TEXT("<logo>Logo is not valid bitmap format!\r\n")));
			goto Error_LOGO;		
		}
		
		//modified by zhoupeng 2008.12.10		
		// cal the display pos.
		dwBitMapWidth = __MAKEWORD(_BitMap_[5], _BitMap_[4]);
		dwBitMapHeight = __MAKEWORD(_BitMap_[7], _BitMap_[6]);	



		if(LCD_WIDTH < dwBitMapWidth) 
		{
			dwBitMapWidth = LCD_WIDTH;
		}

		if(LCD_HEIGHT < dwBitMapHeight)
		{
			dwBitMapHeight = LCD_HEIGHT;
		}

		index = 8;


	
	
	dwLeft = (LCD_WIDTH-dwBitMapWidth) / 2;
	dwTop = (LCD_HEIGHT - dwBitMapHeight) / 2;


	logoFileSize = dwBitMapWidth * dwBitMapHeight *2 ;//   800*480*2
	
	nBlock = logoFileSize/(g_FlashInfo.dwBytesPerBlock) + ((logoFileSize%g_FlashInfo.dwBytesPerBlock)?1:0);
	nBlock--;	// already read one block

	//RETAILMSG(1,(TEXT("++logoFileSize= %d nblock = %d  dwBytesPerBlock = 0x%x\r\n"),logoFileSize,nBlock,g_FlashInfo.dwBytesPerBlock));

	memset((WORD *)EBOOT_FRAMEBUFFER_UA_START, 0x00, (LCD_WIDTH*LCD_HEIGHT*2));	//black
	// Display bitmap.
	ptr += (LCD_WIDTH*dwTop)+dwLeft;

	RETAILMSG(TRUE, (TEXT("<eboot>dwLeft=%d, dwTop=%d; width=%d, height=%d\r\n"),dwLeft, dwTop, dwBitMapWidth, dwBitMapHeight));

	for(ypos =0; ypos<dwBitMapHeight; ypos++)
	{
		volatile  unsigned short * disp_ptr = ptr;

		for (xpos = 0; xpos < dwBitMapWidth; xpos++)
		{
			WORD pixel = 0x0000;
			BYTE low = 0x00;

			if((nBlock)&&((index) >=(g_FlashInfo.dwBytesPerBlock))) //IF READ END?
			{
				++dwBlock;
				bRet = ReadBlock_LOGO(dwBlock,_BitMap_,NULL);
				nBlock--;
				
				index = 0;
				//RETAILMSG(1,(TEXT("[logo]  dwBlock=%x\r\n"),dwBlock));
			}

			low = _BitMap_[index++];
			pixel = __MAKEWORD(_BitMap_[index], low);//__MAKEWORD(_BitMap_[dwBitMapDataPos++], _BitMap_[dwBitMapDataPos++]);	
			index++;
			
			// display bitmap.
			*(disp_ptr++) = pixel;
			
			//*(disp_ptr++) = 0xf800;// 0x00f8
	
		}
		ptr += LCD_WIDTH;
	}

	return;
#endif

Error_LOGO:

	RETAILMSG(TRUE, (TEXT("<logo>Read data error or logo is not valid bitmap format!\r\n")));
	RETAILMSG(TRUE, (TEXT("<logo>show default  logo !\r\n")));
	ShowLogo_sub(CELOGO);	//显示默认显示图片
	return ;



}


static void InitializeDisplay(void)
{
    tDevInfo DispDevInfo;

    pGPIOReg = (GPIO_REG *)OALPAtoVA(BASE_REG_PA_GPIO, FALSE);
    pDispReg = (DISPLAY_REG *)OALPAtoVA(BASE_REG_PA_LCDC, FALSE);
    pPMUPMReg = (PMU_PM_REG *)OALPAtoVA(BASE_REG_PA_PMU_PM, FALSE);
    pCMUCLKReg = (CMU_CLK_REG *)OALPAtoVA(BASE_REG_PA_CMU_CLK, FALSE);
    pCMUMISCReg = (CMU_MISC_REG *)OALPAtoVA(BASE_REG_PA_CMU_MISC, FALSE);
    pBSPArgs      =(BSP_ARGS*)IMAGE_SHARE_ARGS_UA_START;

	v_pPWMregs = (PWM_REG*)OALPAtoVA(BASE_REG_PA_PWMTIMER,FALSE);



#ifdef USE_DSI
    volatile MIPIDSI_REG *pMIPIDSIReg = (MIPIDSI_REG *)OALPAtoVA(BASE_REG_PA_MIPI_DSIM, FALSE);
#else
   // volatile SPI_REG *pSPIReg = (SPI_REG *)OALPAtoVA(BASE_REG_PA_SPI0, FALSE);
#endif

    //EdbgOutputDebugString("[Eboot] ++InitializeDisplay()\r\n");

#ifdef USE_DSI
    // Initialize Virtual Address
    InitializeMIPIDPHY();
    pCMUCLKReg->CLK_GATE.CLK_GATE_IP1 |= (CLK_ON << BP_CLK_IP_DSIM);
    // Video Output Disable
    Disp_envid_onoff(DISP_ENVID_OFF);
#endif

    // Initialize Display Power Gating
    if(!(pPMUPMReg->STATUS_REG.BLK_PWR_STAT & (BLK_PWR_ON_STAT<<BP_LCD_PWR_STAT))) {
        pPMUPMReg->PWR_CONF.NORMAL_CFG |= (PWR_ON<<BP_LCD_POWER_GATE);
        while(!(pPMUPMReg->STATUS_REG.BLK_PWR_STAT & (BLK_PWR_ON_STAT<<BP_LCD_PWR_STAT)));
        }

    // MDNIE(1), MIE(0), Bypass(2)
    pCMUMISCReg->MULTIMEDIA.DISPLAY_CONTROL = ((pCMUMISCReg->MULTIMEDIA.DISPLAY_CONTROL &
                                               ~(BW_DISPLAY_PATH_SEL<<BP_DISPLAY_PATH_SEL)) |
                                              (DISPLAY_PATH_FIMD<<BP_DISPLAY_PATH_SEL));

#ifdef USE_DSI
    LDI_DSI_initialize_register_address((void *)pMIPIDSIReg, (void *)pDispReg, (void *)pGPIOReg);
#else
    //LDI_initialize_register_address((void *)pSPIReg, (void *)pDispReg, (void *)pGPIOReg);
#endif
    Disp_initialize_register_address((void *)pDispReg, (void *)pGPIOReg, (void *)pCMUCLKReg, (void*)pBSPArgs, (void*)pCMUMISCReg);

    // Set LCD Module Type
#if        (LCD_MODULE == LCD_MODULE_LTS222)
    LDI_set_LCD_module_type(LDI_LTS222QV_RGB);
#elif    (LCD_MODULE == LCD_MODULE_LTV350)
    LDI_set_LCD_module_type(LDI_LTV350QV_RGB);
#elif    (LCD_MODULE == LCD_MODULE_AT070TN92)
    LDI_set_LCD_module_type(AT070TN92_RGB);
#elif    (LCD_MODULE == LCD_MODULE_HT101HD1)
    LDI_set_LCD_module_type(LDI_HT101HD1_RGB);
#elif    (LCD_MODULE == LCD_MODULE_EMUL48_D1)
    LDI_set_LCD_module_type(AT070TN92_RGB);
#elif    (LCD_MODULE == LCD_MODULE_EMUL48_QV)
    LDI_set_LCD_module_type(AT070TN92_RGB);
#elif    (LCD_MODULE == LCD_MODULE_EMUL48_PQV)
    LDI_set_LCD_module_type(AT070TN92_RGB);
#elif    (LCD_MODULE == LCD_MODULE_EMUL48_ML)
    LDI_set_LCD_module_type(AT070TN92_RGB);
#elif    (LCD_MODULE == LCD_MODULE_EMUL48_MP)
    LDI_set_LCD_module_type(AT070TN92_RGB);
#elif    (LCD_MODULE == LCD_MODULE_LTP700)
    LDI_set_LCD_module_type(LDI_LTP700WV_RGB);
#elif    (LCD_MODULE == LCD_MODULE_TL2796)
    LDI_set_LCD_module_type(LDI_TL2796_RGB);
#elif    (LCD_MODULE == LCD_MODULE_DSI_DUMMY)
    LDI_set_LCD_module_type(LDI_DUMMY);	
#elif    (LCD_MODULE == LCD_MODULE_VGA8060)
    LDI_set_LCD_module_type(LDI_VGA8060_RGB);
#elif    (LCD_MODULE == LCD_MODULE_VGA1024)
{
    LDI_set_LCD_module_type(LDI_VGA1024_RGB);
	RETAILMSG(TRUE, (TEXT("[Eboot] InitializeDisplay() : Module Type LDI_VGA1024_768_RGB\r\n")));	

}
#elif    (LCD_MODULE == LCD_MODULE_VGA1280)
{
	LDI_set_LCD_module_type(LDI_VGA1280_1024_RGB);
	RETAILMSG(TRUE, (TEXT("[Eboot] InitializeDisplay() : Module Type LDI_VGA1280_1024_RGB\r\n")));
}
#elif    (LCD_MODULE == LCD_MODULE_VGA1440)
	{
	LDI_set_LCD_module_type(LDI_VGA1440_900_RGB);
	EdbgOutputDebugString("[Eboot:ERR] InitializeDisplay() : Unknown Module Type [%d]\r\n", LCD_MODULE);
	RETAILMSG(TRUE, (TEXT("[Eboot] InitializeDisplay() : Module Type LDI_VGA1440_900_RGB\r\n")));
	}

#else
    EdbgOutputDebugString("[Eboot:ERR] InitializeDisplay() : Unknown Module Type [%d]\r\n", LCD_MODULE);
#endif

    // Get RGB Interface Information from LDI Library
    LDI_fill_output_device_information(&DispDevInfo);

    // Setup Output Device Information
    Disp_set_output_device_information(&DispDevInfo);

    // Initialize Display Controller
    Disp_initialize_output_interface(DISP_VIDOUT_RGBIF);

#if    (LCD_BPP == 16)
    Disp_set_window_mode(DISP_WIN1_DMA, DISP_16BPP_565, LCD_WIDTH, LCD_HEIGHT, 0, 0);
#elif  (LCD_BPP == 32)    // XRGB format (RGB888)
    Disp_set_window_mode(DISP_WIN1_DMA, DISP_24BPP_888, LCD_WIDTH, LCD_HEIGHT, 0, 0);
#else
    EdbgOutputDebugString("[Eboot:ERR] InitializeDisplay() : Unknown Color Depth %d bpp\r\n", LCD_BPP);
#endif

    Disp_set_framebuffer(DISP_WIN1, IMAGE_EBOOT_FRAMEBUFFER_PA_START);
    Disp_window_onfoff(DISP_WIN1, DISP_WINDOW_ON);

#if    (LCD_MODULE == LCD_MODULE_LTS222)
    // This type of LCD need MSM I/F Bypass Mode to be Disabled
   // pMSMIFReg->MIFPCON &= ~(0x1<<3);    // SEL_BYPASS -> Normal Mode
#endif

    // Initialize LCD Module
    LDI_initialize_LCD_module();

    // Video Output Enable
    Disp_envid_onoff(DISP_ENVID_ON);
#if 0 //lqm masked.11.10.01
    // Fill Framebuffer
#if  0//  (LCD_MODULE == LCD_MODULE_LTV350)
//    memcpy((void *)IMAGE_EBOOT_FRAMEBUFFER_UA_START, (void *)InitialImage_rgb16_320x240, 320*240*2);
//#elif    (LCD_MODULE == LCD_MODULE_EMULQV)
//    memcpy((void *)IMAGE_EBOOT_FRAMEBUFFER_UA_START, (void *)InitialImage_rgb16_320x240, 320*240*2);
#elif    (LCD_BPP == 16)
    {
        int i;
        unsigned short *pFB;
        pFB = (unsigned short *)IMAGE_EBOOT_FRAMEBUFFER_UA_START;

        for (i=0; i<LCD_WIDTH*LCD_HEIGHT; i++)
//            *pFB++ = 0x001F;        // Blue
            *pFB++ = 0x07F0;        // Green
    }
#elif    (LCD_BPP == 32)
    {
        int i;
        unsigned int *pFB;
        pFB = (unsigned int *)IMAGE_EBOOT_FRAMEBUFFER_UA_START;

        for (i=0; i<LCD_WIDTH*LCD_HEIGHT; i++)
            *pFB++ = 0x000000FF;        // Blue
    }
#endif

#else


#ifdef SDMMC_BOOT
	ShowLogoFromSD();
#else
	ShowLogo();
#endif


#endif
}



//-----------------------------------------------------------------------------
//  Initialize hardware etc
//  Returned DWORD will be passed to BacklightDeInit and should be used to store context if necessary
//  pDeviceState should be set to the start state of the backlight (usually D0)
//

void EBOOT_BL_InitPWM()
{
	DWORD dwBKLTimerPrescaler;
	DWORD dwBKLTimerInputClockFreq;
	DWORD dwBKLTimerClockFreq;
	DWORD dwBKLTimerClockPeriodNs;

	
	//BKLMSG(BKL_FUNC, (TEXT("+%s\r\n"), _T(__FUNCTION__)));
	
	/*
	input clock frequency =pclk/({prescaler value+1})/{divider value}
	{prescaler value} = 1~255
	{divider value} = 1,3,4,8,16,tclk
	*/
#ifdef PWMTIMEOUT0  // for time0 time1
	 v_pPWMregs->TCFG0 &=  ~(0xFF>>0);
	 v_pPWMregs->TCFG0 |=  (0x8F>>0);
	dwBKLTimerPrescaler = (v_pPWMregs->TCFG0 & 0xff) >> 0; 
#else  // for time2 time3 time4
	 v_pPWMregs->TCFG0 &=  ~(0xFF>>8);
	 v_pPWMregs->TCFG0 |=  (0x8F>>8);
	dwBKLTimerPrescaler = (v_pPWMregs->TCFG0 & 0xff) >> 8; 
#endif
	dwBKLTimerInputClockFreq = GET_PCLKPSYS(pCMUCLKReg->PLL_CON.MPLL_CON, pCMUCLKReg->CLK_DIV.CLK_DIV0);
	dwBKLTimerClockFreq = dwBKLTimerInputClockFreq / (dwBKLTimerPrescaler + 1) / (0 + 1);
	dwBKLTimerClockPeriodNs = (DWORD)((float)(1000000 / (float)dwBKLTimerClockFreq) + 0.5);
#ifdef PWMTIMEOUT0 
	v_pPWMregs->TCFG1 &= ~(0xF << 0);		// PWM timer 0 divider = 1/1
	v_pPWMregs->TCFG1 |= (0 << 0);

#else    // for time2
	v_pPWMregs->TCFG1 &= ~(0xF << 8);		// PWM timer 2 divider = 1/1
	v_pPWMregs->TCFG1 |= (0 << 8);
#endif


	BKL_TCNTB = BKL_TCNTB_VALUE;
	#if 1
	BKLMSG(BKL_INFO, (TEXT("Timer prescaler          : %d\r\n"), dwBKLTimerPrescaler));
	BKLMSG(BKL_INFO, (TEXT("Timer input clock freq   : %d\r\n"), dwBKLTimerInputClockFreq));
	BKLMSG(BKL_INFO, (TEXT("Timer clock freq         : %d\r\n"), dwBKLTimerClockFreq));
	BKLMSG(BKL_INFO, (TEXT("Timer clock period in ns : %d\r\n"), dwBKLTimerClockPeriodNs));
	BKLMSG(BKL_INFO, (TEXT("PWM frequency in hz      : %d\r\n"), dwBKLTimerClockFreq / BKL_TCNTB));
	BKLMSG(BKL_INFO, (TEXT("TCNTB                    : %d\r\n"), BKL_TCNTB));
	#endif
	EBOOT_BL_SetBrightness(80);
	    
	//BKLMSG(BKL_FUNC, (TEXT("-%s\r\n"), _T(__FUNCTION__)));
}


void EBOOT_BL_SetBrightness(DWORD dwValue)
{

	DWORD dwBrightness;
	//BKLMSG(BKL_INFO, (TEXT("+%s\r\n"), _T(__FUNCTION__)));

	// confirm GPIO configuration (TOUT)
#ifdef PWMTIMEOUT0
    Set_PinFunction(pGPIOReg, TOUT0);
	Set_PinPullUD(pGPIOReg, TOUT0, sgip_PULL_DISABLE);
#else   //tout2 output pwm
	Set_PinFunction(pGPIOReg, TOUT2);
	Set_PinPullUD(pGPIOReg, TOUT2, sgip_PULL_DISABLE);
#endif


	if(dwValue == 100)
	{
		dwBrightness = BKL_TCNTB - 1;
	}
	else if(dwValue == 0)
	{
		dwBrightness = 0;
	}
	else
	{
		dwBrightness = ((BKL_TCMPB_MAX - BKL_TCMPB_MIN) * ((float)dwValue / 100)) + BKL_TCMPB_MIN;
	}
	
	if(dwBrightness >= BKL_TCNTB) dwBrightness = BKL_TCNTB - 1;
	BKL_TCMPB = dwBrightness;

  //  BKLMSG(BKL_INFO, (TEXT("Brightness=%d TCMPB=%d\r\n"), dwValue, BKL_TCMPB));

	
	BKL_TCON &= ~(0xF << BKL_TCON_OFFSETBIT);		// clear TCON
	BKL_TCON |= BKL_TCON_AutoReload | BKL_TCON_Update | BKL_TCON_Start;
	BKL_TCON &= ~BKL_TCON_Update;
	
//	BKLMSG(BKL_INFO, (TEXT("-%s\r\n"), _T(__FUNCTION__)));
	
    
}

