//-----------------------------------------------------------------------------
//
// 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.
//
//-----------------------------------------------------------------------------
//
//  Copyright (C) 2004-2007, Freescale Semiconductor, Inc. All Rights Reserved.
//  THIS SOURCE CODE, AND ITS USE AND DISTRIBUTION, IS SUBJECT TO THE TERMS
//  AND CONDITIONS OF THE APPLICABLE LICENSE AGREEMENT
//
//-----------------------------------------------------------------------------
//
//  File:  init.c
//
//  EVB board initialization code.
//
//-----------------------------------------------------------------------------

#include <bsp.h>
#include <kitl_cfg.h>

#include "imx31_refclock.h"

#include <pehdr.h>
#pragma warning(push)
#pragma warning(disable: 4201)
#include <Romldr.h>
#pragma warning(pop)

extern DWORD GetCp15ControlRegister(void);
extern DWORD GetCp15AuxiliaryControlRegister(void);
extern DWORD GetCp15MainIDRegister(void);

//-----------------------------------------------------------------------------
// Types
#ifndef BSP_NO_TRUST
typedef BOOL (* OEMLoadInit_t)(LPWSTR lpszName);
typedef DWORD (* OEMLoadModule_t)(LPBYTE lpData, DWORD cbData);
#endif // BSP_NO_TRUST

//-----------------------------------------------------------------------------
// Local Functions
void DumpLoLoParameter(void);
static BOOL OALCheckExtraContiguousRAM(void);
static BOOL Config_uP_GPIO_x(void);

//-----------------------------------------------------------------------------
// External Functions
#ifndef BSP_NO_TRUST
extern BOOL InitPubKey(const BYTE *KeyBlob, DWORD cbKeyBlob);
extern BOOL OEMCertifyModuleInit(LPWSTR lpModuleName);
extern DWORD OEMCertifyModule(LPBYTE lpData, DWORD cbData);
#endif // BSP_NO_TRUST

extern VOID InitDebugSerial(void);
extern UINT32 OALTimerGetClkFreq(void);
extern UINT32 OALTimerGetClkPrescalar(void);
extern BOOL OALPmicInit(UINT32 mVnormal, UINT32 mVstandby, UINT32 mVpll);
extern BOOL RNGA_Init(void);
extern VOID OALInitDebugSerial();
extern VOID OEMWaitForDebugEmpty(void);
BOOL InitPeripheralRegisterAddress(void);

//-----------------------------------------------------------------------------
// External Variables

extern PCSP_CCM_REGS   g_pCCM;
//extern PCSP_PBC_REGS   g_pPBC;
extern PCSP_IOMUX_REGS g_pIOMUX;
extern PCSP_GPIO_REGS g_ppGPIO[GPIO_PORT_MAX];

#ifndef BSP_NO_TRUST
extern OEMLoadInit_t pOEMLoadInit;
extern OEMLoadModule_t pOEMLoadModule;

/*
 * This is the public used to verify the signature of trusted applications.
 */
static const unsigned char g_bSignPublicKeyBlob[] = {
    0x06,0x02,0x00,0x00,0x00,0x24,0x00,0x00,0x52,0x53,0x41,0x31,0x00,0x02,
    0x00,0x00,0x01,0x00,0x01,0x00,0x53,0x93,0xe8,0x12,0x13,0x63,0x44,0x9e,
    0x07,0xd7,0xb7,0xa3,0x20,0x2c,0x2f,0xe7,0x95,0x23,0xba,0xec,0x79,0xa9,
    0x37,0xd3,0x09,0xd7,0x53,0x47,0x27,0x76,0x10,0x1d,0xbd,0x22,0x61,0xd0,
    0x82,0x91,0x26,0xf6,0x1f,0x94,0x74,0x24,0xbc,0xe6,0xd1,0x07,0x86,0x2f,
    0xad,0x60,0x50,0x7e,0x55,0xb5,0x58,0x46,0xcd,0xe9,0xf5,0x89,0xb1,0xe5
};
#endif // BSP_NO_TRUST

UINT32 *g_pL2CC = NULL;
PCSP_SDMA_REGS g_pSDMA;
UINT32 g_SREV;
PDDK_CLK_CONFIG g_pDdkClkConfig;
UINT8 g_UPID[8];
UINT8 *g_pIIM;

// Define a static data structure that we can use to pass data between
// the OAL and KITL. We will assign the address of this data structure
// to the "pKitlInfo" data member in OEMGlobals.
//
// Note that we make a "static" declaration here so that all external
// accesses to this data structure will be forced to use the pKitlInfo
// pointer for consistency.
//
static _OALKITLSharedDataStruct g_OALKITLSharedData = { 0 };

#if !(UNDER_CE >= 600)
// WinCE 6.00 does not define lpNKHaltSystem.
extern void (*lpNKHaltSystem)(void);
#endif


//-----------------------------------------------------------------------------
// Global Variables

// WinCE 6.0: These global variables are now required.

//  Global:  g_oalRtcResetTime
//
//  RTC init time after a RTC reset has occured.
//
SYSTEMTIME g_oalRtcResetTime = {2005, 1, 1, 31, 12, 0, 0, 0};

//
//  Global:  dwOEMDrWatsonSize
//
//  Global variable which specify DrWatson buffer size. It can be fixed
//  in config.bib via FIXUPVAR.
//
#define DR_WATSON_SIZE_NOT_FIXEDUP (-1)
DWORD dwOEMDrWatsonSize = (DWORD) DR_WATSON_SIZE_NOT_FIXEDUP;


//-----------------------------------------------------------------------------
//
// Function: OEMHaltSystem
//
// Function turns on leds to indicate error condition before system halt.
//
// Parameters:
//
// Returns:
//
//
//-----------------------------------------------------------------------------
void OEMHaltSystem(void)
{/*
    CSP_PBC_REGS *pPBC;

    // On both on board leds
    pPBC = (PCSP_PBC_REGS)OALPAtoVA((UINT32)BSP_BASE_REG_PA_PBC_BASE, FALSE);
    OUTREG16(&pPBC->BCTRL1_SET, CSP_BITFMASK(PBC_BCTRL1_SET_LED0));
    OUTREG16(&pPBC->BCTRL1_SET, CSP_BITFMASK(PBC_BCTRL1_SET_LED1));*/
}

//------------------------------------------------------------------------------
//
//  Function: OEMInitDebugSerial
//
//  Initializes the debug serial port
//
//------------------------------------------------------------------------------
VOID OEMInitDebugSerial()
{
   BSP_ARGS *pBSPArgs;

   // Disable all OAL log zones until serial debug properly configured
   OALLogSetZones(0);

   pBSPArgs = (PBSP_ARGS)OALPAtoVA(IMAGE_SHARE_ARGS_RAM_PA_START, FALSE);
   if (pBSPArgs == NULL) {
      return;
   }
   if (!InitPeripheralRegisterAddress()) {
      return;
   }

   // Init global BSP args
   OALBSPArgsSetup(pBSPArgs);

   hal_param_resolve_globals();

   OALBSPArgsEnableKITL(pBSPArgs, gLoLoOption.fKITLEnable);
   OALBSPArgsEnableShareEth(pBSPArgs, gLoLoOption.fShareEthEnable);
   OALBSPArgsSetIPAddress(pBSPArgs, !gLoLoOption.fIsIPAssigned, gLoLoOption.dwIP);

   Config_uP_GPIO_x();

   OALInitDebugSerial();

   return;
}

//------------------------------------------------------------------------------
//
//  Function:  OEMInit
//
//  This is Windows CE OAL initialization function. It is called from kernel
//  after basic initialization is made.
//
void OEMInit()
{
	BSP_ARGS *pBspArgs = (BSP_ARGS *)IMAGE_SHARE_ARGS_UA_START;
	UINT32 countsPerMsec;
	UINT32 mV;
	DWORD myCpuId;
	ulong mydwArchitectureID;
	// Set up the debug zones according to the fix-up variable
	// initialOALLogZones.
	//   initialOALLogZones = ((1<<OAL_LOG_ERROR)|(1<<OAL_LOG_WARN)|(1<<OAL_LOG_INFO)|(1<<OAL_LOG_FUNC));
	//   initialOALLogZones = ((1<<OAL_LOG_ERROR)|(1<<OAL_LOG_WARN)|(1<<OAL_LOG_INFO)|(1<<OAL_LOG_FUNC)|(1<<OAL_LOG_POWER)|(1<<OAL_LOG_RTC));
	OALLogSetZones(initialOALLogZones);

	OALMSG(OAL_FUNC, (L"+OEMInit\r\n"));

	DumpLoLoParameter();

	// Set memory size for DrWatson kernel support.
	dwNKDrWatsonSize = 0;
	if (dwOEMDrWatsonSize != DR_WATSON_SIZE_NOT_FIXEDUP) {
		dwNKDrWatsonSize = dwOEMDrWatsonSize;
	}

	// Define optional kernel supported features.
	pOEMIsProcessorFeaturePresent = OALIsProcessorFeaturePresent;

	#if (UNDER_CE >= 600) // WinCE 6.00 uses g_pOemGlobal data structure.
	// Initialize system halt handler.
	g_pOemGlobal->pfnHaltSystem = OEMHaltSystem;

	// Give kernel access to the profiling functions.
	g_pOemGlobal->pfnProfileTimerEnable  = OEMProfileTimerEnable;
	g_pOemGlobal->pfnProfileTimerDisable = OEMProfileTimerDisable;
	#else
	// Initialize system halt handler.
	lpNKHaltSystem = OEMHaltSystem;
	#endif

	// Expose the processor type. (Note that the i.MX31 is actually an ARM11
	// core but Microsoft currently only defines an ARM7, ARM8, or ARM9
	// processor type. So we should use an ARM9 processor type for now).
	CEProcessorType = PROCESSOR_ARM920;

	// Initilize cache globals
	OALCacheGlobalsInit();

	// Initialize the shared OAL+KITL data structure. This allows KITL.DLL
	// to access these pointers to the hardware control registers.
	g_OALKITLSharedData.g_pCCM   = g_pCCM;
	//   g_OALKITLSharedData.g_pPBC   = g_pPBC;
	g_OALKITLSharedData.g_pIOMUX = g_pIOMUX;

	// Provide a pointer that KITL can use to access the shared data structure.
	g_pOemGlobal->pKitlInfo = (LPVOID)&g_OALKITLSharedData;

	// Reset GPF flags set by bootloader or RVD.  Rev 1.1 silicon now uses
	// these flags for internal CCM control.
	INSREG32BF(&(g_OALKITLSharedData.g_pCCM)->RCSR, CCM_RCSR_GPF, 0);

	if (!IMX31RefClockInit()) {
		OALMSG(OAL_ERROR, (__WFUNCTION__ L": IMX31RefClockInit Failed!\r\n"));
	}

	// Map access to IIM
	g_pIIM = (UINT8 *) OALPAtoUA(CSP_BASE_REG_PA_IIM);
	if (g_pIIM == NULL)
	{
	   // Error message is all we can do since OEMInit has no return
		OALMSG(OAL_ERROR, (L"ERROR: OEMInit: IIM null pointer!\r\n"));
	}

	// Read 64-bit unique part ID
	g_UPID[0] = (UINT8) (INREG32(&g_pIIM[0x1004]) & 0xFF);
	g_UPID[1] = (UINT8) (INREG32(&g_pIIM[0x1008]) & 0xFF);
	g_UPID[2] = (UINT8) (INREG32(&g_pIIM[0x100C]) & 0xFF);
	g_UPID[3] = (UINT8) (INREG32(&g_pIIM[0x1010]) & 0xFF);
	g_UPID[4] = (UINT8) (INREG32(&g_pIIM[0x1014]) & 0xFF);
	g_UPID[5] = (UINT8) (INREG32(&g_pIIM[0x1018]) & 0xFF);
	g_UPID[6] = (UINT8) (INREG32(&g_pIIM[0x101C]) & 0xFF);
	g_UPID[7] = (UINT8) (INREG32(&g_pIIM[0x1020]) & 0xFF);

	g_pDdkClkConfig = (PDDK_CLK_CONFIG) IMAGE_WINCE_DDKCLK_RAM_UA_START;

	// Init the global clock configuration
	memset(g_pDdkClkConfig, 0, sizeof(DDK_CLK_CONFIG));

	OEMWaitForDebugEmpty();

	// Configure CCM clock gating.  Gate all clocks
	// except those needed by OAL.
	//
	// CGR[0]:
	//  CG3 (EPIT1) = run all = (3 << 6)    = 0x000000C0
	//  CG7 (SDMA) = run all = (3 << 14)    = 0x0000C000
	//                                      ------------
	//                                        0x0000C0C0
	//
	// CGR[1]:
	//                                      ------------
	//                                        0x00000000
	//
	// NOTE:  For PMC we keep the IPU clocks enabled since
	//        the bootloader will configure and enable the
	//        display.
	//
	// CGR[1] (PMC ONLY):
	//  CG11 (IPU) = run all = (3 << 22)    = 0x00C00000
	//                                      ------------
	//                                        0x00C00000
	//
	// CGR[2]:
	//  CG4 (EMI) = run all = (3 << 8)      = 0x00000300
	//  CG15-CG7 = reserved                 = 0xFFFFC000
	//                                      ------------
	//                                        0xFFFFC300
	#ifdef BSP_OAL_TIMER32K
	OUTREG32(&(g_OALKITLSharedData.g_pCCM)->CGR[0], 0x0000C040);
	#else
	OUTREG32(&(g_OALKITLSharedData.g_pCCM)->CGR[0], 0x0000C0C0);
	++g_pDdkClkConfig->setpointReqCount[DDK_DVFC_SETPOINT_MEDIUM];
	#endif

	#if 0
	OUTREG32(&(g_OALKITLSharedData.g_pCCM)->CGR[1], 0x00000000);
	#else
	// reserve IPU clock for skiplcdcinit
	OUTREG32(&(g_OALKITLSharedData.g_pCCM)->CGR[1], (INREG32(&(g_OALKITLSharedData.g_pCCM)->CGR[1]) & 0x00C00000));
	#endif
	OUTREG32(&(g_OALKITLSharedData.g_pCCM)->CGR[2], 0xEFFFC300);

	// Configure well bias parameters for suspend mode
	INSREG32BF(&(g_OALKITLSharedData.g_pCCM)->PMCR1, CCM_PMCR1_CPSPA, 0xC);

	// Update global BSP args struct with user switches on ADS board
	OALBspArgsInit((BSP_ARGS *)IMAGE_SHARE_ARGS_UA_START);

	// If user selected to leave L2 disabled, let it remain
	// unmapped so OEMCacheRangeFlush will not perform
	// maintenance
	if (pBspArgs->bL2enable) {
	  // Map access to L2CC
		g_pL2CC = OALPAtoUA(CSP_BASE_REG_PA_L2CC);
		if (g_pL2CC == NULL) {
		 // Error message is all we can do since OEMInit has no return
			OALMSG(OAL_ERROR, (L"ERROR: OEMInit:  L2CC null pointer!\r\n"));
		}
	}
	else {
		OALMSG(OAL_INFO, (L"OAL:  L2 cache is disabled\r\n"));
	}

	#if defined(BSP_POCKETPC) || defined(BSP_SMARTPHONE) || (UNDER_CE >= 600)
	// Tell filesys.exe that we want a clean boot.
	NKForceCleanBoot();
	#endif

	#ifndef BSP_NO_TRUST
	// Set the module signature verification hooks.
	pOEMLoadInit = OEMCertifyModuleInit;
	pOEMLoadModule = OEMCertifyModule;

	// Initialize the signature verification public key.
	InitPubKey(g_bSignPublicKeyBlob, sizeof(g_bSignPublicKeyBlob));
	#endif // BSP_NO_TRUST

	// Initialize interrupts
	if (!OALIntrInit()) {
		OALMSG(OAL_ERROR, (
		  L"ERROR: OEMInit: failed to initialize interrupts\r\n"
		));
		goto cleanUp;
	}

	// Initialize the system clock.
	countsPerMsec = OALTimerGetClkFreq() / ((OALTimerGetClkPrescalar() + 1) * 1000);
	if (!OALTimerInit(RESCHED_PERIOD, countsPerMsec, countsPerMsec / 100 + 2)) {
		OALMSG(OAL_ERROR, (
		  L"ERROR: OEMInit: Failed to initialize system clock\r\n"
		));
		goto cleanUp;
	}

	// Initialize SDMA with address of shared region
	g_pSDMA = OALPAtoUA(CSP_BASE_REG_PA_SDMA);
	if (g_pSDMA == NULL) {
	  // Error message is all we can do since OEMInit has no return
		OALMSG(OAL_ERROR, (L"ERROR: OEMInit:  SDMA null pointer!\r\n"));
		goto cleanUp;
	}
	else {
		// Set the channel 0 pointer to the shared region physical address
		OUTREG32(&g_pSDMA->MC0PTR, BSP_SDMA_MC0PTR);

		// Configure SDMA/AHB clock ratio
		if (pBspArgs->clockFreq[DDK_CLOCK_SIGNAL_AHB] ==
		  pBspArgs->clockFreq[DDK_CLOCK_SIGNAL_IPG]) {
			INSREG32BF(&g_pSDMA->CONFIG, SDMA_CONFIG_ACR, SDMA_CONFIG_ACR_AHB1X);
		}
		else {
			INSREG32BF(&g_pSDMA->CONFIG, SDMA_CONFIG_ACR, SDMA_CONFIG_ACR_AHB2X);
		}

		// Configure SDMA for static context switch
		INSREG32BF(&g_pSDMA->CONFIG, SDMA_CONFIG_CSM, SDMA_CONFIG_CSM_STATIC);
	}
	/*
	// Choose voltage setpoint based on ARM clock rate
	if (pBspArgs->clockFreq[DDK_CLOCK_SIGNAL_ARM] <= 133000000)
	{
	  OALMSG(OAL_INFO, (TEXT("Voltage setpoint is 1.0 V.\r\n")));
	  mV = BSP_PMIC_LOW_mV;
	}
	else if(pBspArgs->clockFreq[DDK_CLOCK_SIGNAL_ARM] <= 399000000)
	{
	  OALMSG(OAL_INFO, (TEXT("Voltage setpoint is 1.2 V.\r\n")));
	  mV = BSP_PMIC_HIGH_mV;
	}
	else
	{
	  OALMSG(OAL_INFO, (TEXT("Voltage setpoint is 1.6 V.\r\n")));
	  mV = BSP_PMIC_TURBO_mV;
	}*/

	mV = BSP_PMIC_NORMAL_VOLT;

	// Initialize the PMIC interface
	OALPmicInit(mV, BSP_PMIC_STANDBY_VOLT, BSP_PMIC_PLL_mV);

	// PMIC supply voltages are now configured and we can safely bump
	// up ARM clock speed
	if (pBspArgs->bHighSpeedEnable) {
		pBspArgs->clockFreq[DDK_CLOCK_SIGNAL_ARM] =
		  pBspArgs->clockFreq[DDK_CLOCK_SIGNAL_MCUPLL];
		OALMSG(OAL_INFO,
		  (TEXT("OAL: SWITCHING TO HIGH SPEED ARM CLOCK  = %d Hz\r\n"),
		  pBspArgs->clockFreq[DDK_CLOCK_SIGNAL_ARM]));
		INSREG32BF(&g_pCCM->PDR0, CCM_PDR0_MCU_PODF, 0);
	}

	// Initialize the KITL connection if required
	KITLIoctl(IOCTL_KITL_STARTUP, NULL, 0, NULL, 0, NULL);

	// Initialize RNGA module
	RNGA_Init();

	//----------------------------------------------------------------------
	// Print some version, cache and branch prediction info
	//----------------------------------------------------------------------
	OALMSG(1, (L"\r\n"));
	OALMSG(1, (L" ----------------------------------------- \r\n"));
	OALMSG(1, (L"  LogicPD i.MX31 SOM Revision Information \r\n"));
	OALMSG(1, (L"  ....................................... \r\n"));
	OALMSG(1, (L"    BSP Revision            : 1.0.0 \r\n"));
	OALMSG(1, (L"    Built for Hardware      : "));
	OALMSG(1, (L"i.MX31 SOM-LV\r\n"));
	OALMSG(1, (L" ----------------------------------------- \r\n"));
	OALMSG(1, (L"  LogicPD i.MX31 SOM CoProc Information \r\n"));
	OALMSG(1, (L"  ....................................... \r\n"));
	OALMSG(1, (L"    L1 Cache                : %s \r\n",
				(0x00001004==(GetCp15ControlRegister()& 0x00001004))? L"Enabled": L"Disabled"));
	OALMSG(1, (L"    L2 Cache                : %s \r\n",
					(0x00000001==(INREG32((OALPAtoUA(CSP_BASE_REG_PA_L2CC+0x100)))& 0x00000001))? L"Enabled": L"Disabled"));
	OALMSG(1, (L"    Program Flow Prediction : %s \r\n",
				(0x00000800==(GetCp15ControlRegister()& 0x00000800))? L"Enabled": L"Disabled"));
	#if DEBUG
/*
	OALMSG(1, (L"    CP15 Control Register   : 0x%08x \r\n",
				GetCp15ControlRegister()));
	OALMSG(1, (L"    CP15 Aux Control Reg    : 0x%08x \r\n",
				GetCp15AuxiliaryControlRegister()));
	OALMSG(1, (L"    L2CC Control Reg        : 0x%08x \r\n",
					INREG32((OALPAtoUA(CSP_BASE_REG_PA_L2CC+0x100)))));
	OALMSG(1, (L"    L2CC Aux Control Reg    : 0x%08x \r\n",
					INREG32((OALPAtoUA(CSP_BASE_REG_PA_L2CC+0x104)))));
	// Dump Cache Settings:
	OALMSG(1, (L"    Cache Settings          :\r\n"));
	OALMSG(1, (L"    L1 Flags:\r\n"));
	OALMSG(1, (L"    CF_UNIFIED              : %s \r\n",
		(g_oalCacheInfo.L1Flags & CF_UNIFIED)? L"Set": L"Not Set"));
	OALMSG(1, (L"    CF_WRITETHROUGH         : %s \r\n",
		(g_oalCacheInfo.L1Flags & CF_WRITETHROUGH)? L"Set": L"Not Set"));
	OALMSG(1, (L"    CF_COHERENT             : %s \r\n",
		(g_oalCacheInfo.L1Flags & CF_COHERENT)? L"Set": L"Not Set"));
	OALMSG(1, (L"    L1 I-cache size         : 0x%08x \r\n", g_oalCacheInfo.L1ISize));
	OALMSG(1, (L"    L1 D-cache size         : 0x%08x \r\n", g_oalCacheInfo.L1DSize));
	OALMSG(1, (L"    L2 Flags:\r\n"));
	OALMSG(1, (L"    CF_UNIFIED              : %s \r\n",
		(g_oalCacheInfo.L2Flags & CF_UNIFIED)? L"Set": L"Not Set"));
	OALMSG(1, (L"    CF_WRITETHROUGH         : %s \r\n",
		(g_oalCacheInfo.L2Flags & CF_WRITETHROUGH)? L"Set": L"Not Set"));
	OALMSG(1, (L"    CF_COHERENT             : %s \r\n",
		(g_oalCacheInfo.L2Flags & CF_COHERENT)? L"Set": L"Not Set"));
	OALMSG(1, (L"    L2 I-cache size         : 0x%08x \r\n", g_oalCacheInfo.L2ISize));
	OALMSG(1, (L"    L2 D-cache size         : 0x%08x \r\n", g_oalCacheInfo.L2DSize));
	OALMSG(1,
		  (TEXT("    L1 cache details        :\r\n flags %x\r\nI: %d sets/way, %d ways, %d line size, %d size\r\nD: %d sets/way, %d ways, %d line size, %d size\r\n"),
			 g_oalCacheInfo.L1Flags,
			 g_oalCacheInfo.L1ISetsPerWay, g_oalCacheInfo.L1INumWays,
			 g_oalCacheInfo.L1ILineSize, g_oalCacheInfo.L1ISize,
			 g_oalCacheInfo.L1DSetsPerWay, g_oalCacheInfo.L1DNumWays,
			 g_oalCacheInfo.L1DLineSize, g_oalCacheInfo.L1DSize));

	OALMSG(1,
		 (TEXT("    L2 cache details:\r\n flags %x\r\nI: %d sets/way, %d ways, %d line size, %d size\r\nD: %d sets/way, %d ways, %d line size, %d size\r\n"),
			 g_oalCacheInfo.L2Flags,
			 g_oalCacheInfo.L2ISetsPerWay, g_oalCacheInfo.L2INumWays,
			 g_oalCacheInfo.L2ILineSize, g_oalCacheInfo.L2ISize,
			 g_oalCacheInfo.L2DSetsPerWay, g_oalCacheInfo.L2DNumWays,
			 g_oalCacheInfo.L2DLineSize, g_oalCacheInfo.L2DSize));
*/
	#endif //#if DEBUG
	OALMSG(1, (L" ----------------------------------------- \r\n"));
	OALMSG(1, (L"  LogicPD i.MX31 SOM Processor Information \r\n"));
	OALMSG(1, (L"  ....................................... \r\n"));
	g_SREV = INREG32(&g_pIIM[0x24]); // Read silicon rev
	OALMSG(1, (L"    Silicon Rev             : 0x%08x \r\n",g_SREV));
	myCpuId = GetCp15MainIDRegister();
	mydwArchitectureID = (myCpuId >> 16) & 0xf;
	OALMSG(1, (L"    CPU Main ID Register    : 0x%08x \r\n", myCpuId));
	OALMSG(1, (L"    Architecture ID         : 0x%02x \r\n", mydwArchitectureID));
	if ( mydwArchitectureID = 0x7 )
		OALMSG(1, (L"    ARM Ver                 : ARMv6\r\n"));
	else if ( mydwArchitectureID > 0x7 )
		OALMSG(1, (L"    ARM Ver                 : ARMv7 or greater\r\n"));
	else
		OALMSG(1, (L"    ARM Ver                 : ARMv4 or earlier\r\n"));

	OALMSG(1, (L" ----------------------------------------- \r\n"));
	OALMSG(1, (L"\r\n"));
	OALMSG(1, (L"OEM Initialization Done.\r\n"));

cleanUp:

	OALMSG(OAL_FUNC, (L"-OEMInit\r\n"));
}

//------------------------------------------------------------------------------
void DumpLoLoParameter(void)
{
   DWORD ii;
   BSP_ARGS *pBSPArgs;

   pBSPArgs = (PBSP_ARGS)OALPAtoVA(IMAGE_SHARE_ARGS_RAM_PA_START, FALSE);

   OALMSG(OAL_INFO, (L"LoLo Parameter: "));
   for (ii=0; ii<pBSPArgs->dwLoLoBootArgsLen; ii++) {
      OALMSG(OAL_INFO, (L"%c", pBSPArgs->LoLoBootArgs[ii]));
   }
   OALMSG(OAL_INFO, (L"\r\n"));

   return;
}

/*!------------------------------------------------------------------------
 *
 * \brief	Copies boot parameter string into driver globals area.
 *
 * \b Purpose:
 *
 * The LogicLoader passes us the address of the boot argument string
 * inside r2. We need to copy that string out into our driver globals
 * are so the rest of the OAL can access it.
 *
 * \param a1
 *    Pointer to string.
 *
 *-----------------------------------------------------------------------*/
void OALCopyBootArgs(UINT8 *pBootArgsSrc)
{
   DWORD ii;
   PBSP_ARGS pBSPArgs=(PBSP_ARGS)IMAGE_SHARE_ARGS_RAM_PA_START;
   UINT8 *pu8Ptr;

#ifdef BSP_BOOT_LOLO
   // Copy LogicLoader boot parameter
   for (ii=0; ii<ARRAYSIZE(pBSPArgs->LoLoBootArgs); ii++) {
      pBSPArgs->LoLoBootArgs[ii] = pBootArgsSrc[ii];
      if (pBootArgsSrc[ii] == '\0') {
         break;
      }
   }
   pBSPArgs->dwLoLoBootArgsLen = ii;
#endif

   // Clear kitl argument
   pu8Ptr = (UINT8*)&pBSPArgs->kitl;
   for (ii=0; ii<sizeof(pBSPArgs->kitl); ii++) {
      *pu8Ptr++ = 0;
   }

   return;
}
/*-------------------------------------------------------------------------
 * End function _copy_boot_args()
 *------------------------------------------------------------------------*/

//------------------------------------------------------------------------------
//
//  Function:  Config_uP_GPIO_x
//
//  Config all uP_GPIO_x (x=0..7) as GPIO Input mode.
//
BOOL Config_uP_GPIO_x(void)
{
   // Clear GPR register
   OUTREG32(&g_pIOMUX->GPR, 0);

   // Config system GPIO pin
   // Config uP_GPIO_0
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, uP_GPIO_0);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, uP_GPIO_0);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, uP_GPIO_0);

   // Config uP_GPIO_1
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, uP_GPIO_1);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, uP_GPIO_1);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, uP_GPIO_1);

   // Config uP_GPIO_2
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, uP_GPIO_2);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, uP_GPIO_2);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, uP_GPIO_2);

   // Config uP_GPIO_3
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, uP_GPIO_3);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, uP_GPIO_3);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, uP_GPIO_3);

   // Config uP_GPIO_4
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, uP_GPIO_4);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, uP_GPIO_4);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, uP_GPIO_4);

   // Config uP_GPIO_5
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, uP_GPIO_5);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, uP_GPIO_5);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, uP_GPIO_5);

   // Config uP_GPIO_6
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, uP_GPIO_6);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, uP_GPIO_6);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, uP_GPIO_6);

   // Config uP_GPIO_7
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, uP_GPIO_7);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, uP_GPIO_7);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, uP_GPIO_7);

   // Config system IRQ pin
   // Config uP_nIRQA
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, uP_nIRQA);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, uP_nIRQA);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, uP_nIRQA);

   // Config uP_nIRQB
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, uP_nIRQB);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, uP_nIRQB);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, uP_nIRQB);

   // Config uP_nIRQC
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, uP_nIRQC);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, uP_nIRQC);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, uP_nIRQC);

   // Config uP_nIRQD
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, uP_nIRQD);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, uP_nIRQD);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, uP_nIRQD);

   // Config system pin
   // Config uP_nWAKEUP
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, uP_nWAKEUP);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, uP_nWAKEUP);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, uP_nWAKEUP);

   // Config uP_SW_nRESET
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, uP_SW_nRESET);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, uP_SW_nRESET);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, uP_SW_nRESET);

   // Config PMIC pin
   // Config PMIC_LOWBATT_INT
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, PMIC_LOWBATT_INT);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, PMIC_LOWBATT_INT);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, PMIC_LOWBATT_INT);

   // Config PMIC_PRIINT
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, PMIC_PRIINT);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, PMIC_PRIINT);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, PMIC_PRIINT);

   // Config PMIC_PWRRDY
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, PMIC_PWRRDY);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, PMIC_PWRRDY);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, PMIC_PWRRDY);

#if 0
   // Config PMIC_USEROFF as OUT0
   SET_GPIOSPINNAME_LOW(g_ppGPIO, PMIC_USEROFF);
   CONFIG_GPIOSPINNAME_OUTPUT(g_ppGPIO, PMIC_USEROFF);
#else
   // Config PMIC_USEROFF
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, PMIC_USEROFF);
#endif
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, PMIC_USEROFF);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, PMIC_USEROFF);

   // Config PCMCIA pin
   // Config PCC_PCMCIA_nEN
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, PCC_PCMCIA_nEN);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, PCC_PCMCIA_nEN);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, PCC_PCMCIA_nEN);

   // Config PCC_POWER_nEN
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, PCC_POWER_nEN);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, PCC_POWER_nEN);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, PCC_POWER_nEN);

   // Config USB pin
   // Config USBHSH_nCS
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, USBHSH_nCS);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, USBHSH_nCS);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, USBHSH_nCS);

   // Config USBOTG_nCS
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, USBOTG_nCS);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, USBOTG_nCS);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, USBOTG_nCS);

#if 0
   // Skip LCD GPIO config for skiplcdcinit command
   // Config LCD pin
   // Config LCD_BACKLIGHT_PWR
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, LCD_BACKLIGHT_PWR);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, LCD_BACKLIGHT_PWR);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, LCD_BACKLIGHT_PWR);

   // Config LCD_DON
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, LCD_DON);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, LCD_DON);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, LCD_DON);

   // Config LCD_PANEL_PWR
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, LCD_PANEL_PWR);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, LCD_PANEL_PWR);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, LCD_PANEL_PWR);
#endif

   // Config External Ethernet chip pin
   // Config WRLAN_nINT
   CONFIG_GPIOSPINNAME_INPUT(g_ppGPIO, WRLAN_nINT);
   CONFIG_GPIOPINNAME_MUX(g_pIOMUX, WRLAN_nINT);
   CONFIG_GPIOPINNAME_PAD(g_pIOMUX, WRLAN_nINT);

   return TRUE;
}
//------------------------------------------------------------------------------
