/* SPDX-License-Identifier: LGPL-2.1-only OR BSD-3-Clause */
/******************************************************************************
 *
 * This file is provided under a dual license.  When you use or
 * distribute this software, you may choose to be licensed under
 * version 2.1 of the GNU Lesser General Public License
 * ("LGPLv2.1 License") or BSD License.
 *
 * LGPLv2.1 License
 *
 * Copyright(C) 2019 MediaTek Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of version 2.1 of the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html for more
 * details.
 *
 * BSD LICENSE
 *
 * Copyright(C) 2019 MediaTek Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *  * Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *  * Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *  * Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *****************************************************************************/


#include "x_typedef.h"
#include "x_tz.h"
#include "x_bim.h"
#include "x_dram.h"
#if defined(CC_SUPPORT_STR_CORE_OFF)
#include "hw_pdwnc.h"
#endif
EXTERN UINT32 __bss_start;
EXTERN UINT32 __bss_end;
EXTERN VOID INT_Reset(VOID);
EXTERN VOID INT_Vectors(VOID);

EXTERN VOID CHIP_BootEntry0(VOID);
EXTERN VOID CHIP_BootEntry1(VOID);
EXTERN VOID CHIP_BootEntry2(VOID);
EXTERN VOID CHIP_BootEntry3(VOID);

VOID BSP_Start(VOID);
UINT32 au4BSS[4];
#if defined(CC_NAND_BOOT) || defined(CC_EMMC_BOOT)
EXTERN VOID ARM_InvalidateICache(VOID);
EXTERN VOID __aeabi_llsl(VOID);
//EXTERN VOID __aeabi_memclr4(VOID);
EXTERN VOID __aeabi_uidivmod(VOID);
EXTERN VOID x_memcpy(VOID);
EXTERN VOID CHIP_NANDCopyToDRAM(UINT32 *pu4DRAMBuf, UINT32 u4StartOffset, UINT32 u4Len);
#endif /* CC_NANDBOOT */

#if defined(CC_MTK_PRELOADER)
#if defined(CC_SUPPORT_EMI)
#if 0
#define EMI_CONM_OFFSET 	(0x60)
#define EMI_CONN_OFFSET 	(0x68)
#define CHN_EMI_CONC_OFFSET (0x10)

#else
typedef enum
{
	CHN_EMI0,
	CHN_EMI1,
	CHN_EMI2,
	CHN_EMI3,
	CHN_EMI_CNT
} CHN_EMI_TYPE_T;

#define CHN_EMI_NR     CHN_EMI_CNT


static unsigned long gCHNBaseAddr[CHN_EMI_NR] = {
	CHN_EMI0_BASE, //Chn_emi0
	CHN_EMI1_BASE, //Chn_emi1
	CHN_EMI2_BASE, //Chn_emi2
	CHN_EMI3_BASE, //Chn_emi3
};

#define EMI_CONA                   (0x0)
#define EMI_CONB                   (0x8)
#define EMI_CONC                   (0x10)
#define EMI_COND                   (0x18)
#define EMI_CONE                   (0x20)
#define EMI_CONF                   (0x28)
#define EMI_CONG                   (0x30)
#define EMI_CONH                   (0x38)
#define EMI_CONH_2ND               (0x3c)
#define EMI_CONI                   (0x40)
#define EMI_CONJ                   (0x48)
#define EMI_CONM                   (0x60)
#define EMI_CONN                   (0x68)
#define EMI_CONO                   (0x70)
#define EMI_MDCT                   (0x78)
#define EMI_MDCT_2ND               (0x7c)
#define EMI_LPCT0                  (0xa0)
#define EMI_LPCT1                  (0xa4)
#define EMI_LPCT2                  (0xa8)
#define EMI_LPCT5                  (0xb4)
#define EMI_LPCT6                  (0xb8)
#define EMI_IOCL                   (0xd0)
#define EMI_IOCL_2ND               (0xd4)
#define EMI_IOCM                   (0xd8)
#define EMI_IOCM_2ND               (0xdc)
#define EMI_TESTB                  (0xe8)
#define EMI_TESTC                  (0xf0)
#define EMI_TESTD                  (0xf8)
#define EMI_ARBA                   (0x100)
#define EMI_ARBB                   (0x108)
#define EMI_ARBC                   (0x110)
#define EMI_ARBD                   (0x118)
#define EMI_ARBE                   (0x120)
#define EMI_ARBF                   (0x128)
#define EMI_ARBG                   (0x130)
#define EMI_ARBH                   (0x138)
#define EMI_ARBI                   (0x140)
#define EMI_ARBI_2ND               (0x144)
#define EMI_ARBK                   (0x150)
#define EMI_ARBK_2ND               (0x154)
#define EMI_SLCT                   (0x158)
#define EMI_BMEN				   (0x400)

#define CHN_EMI_CONA               (0x0)
#define CHN_EMI_CONB               (0x8)
#define CHN_EMI_CONC               (0x10)
#define CHN_EMI_MDCT               (0x18)
#define CHN_EMI_COND               (0x20)
#define CHN_EMI_TESTA              (0x40)
#define CHN_EMI_TESTB              (0x48)
#define CHN_EMI_TESTC              (0x50)
#define CHN_EMI_TESTD              (0x58)
#define CHN_EMI_ARBI               (0x140)
#define CHN_EMI_ARBI_2ND           (0x144)
#define CHN_EMI_ARBJ               (0x148)
#define CHN_EMI_ARBJ_2ND           (0x14c)
#define CHN_EMI_ARBK               (0x150)
#define CHN_EMI_ARBK_2ND           (0x154)
#define CHN_EMI_SLCT               (0x158)
#define CHN_EMI_ARB_RFF            (0x15c)

#define TZ_ULTRA_EN_0              (0x138)  //agent0~3
#define TZ_ULTRA_EN_1			   (0x13c)  //agent4~7
#define TZ_ULTRA_EN_2			   (0x140)  //agent8~11
#define TZ_ULTRA_EN_3              (0x144)	//agent12~15
#define TZ_ULTRA_EN_4              (0x148)	//agent16~19
#define TZ_ULTRA_EN_5              (0x14c)  //agent20~23

#define TZ_PRE_ULTRA_EN_0          (0x150) //agent0~3
#define TZ_PRE_ULTRA_EN_1          (0x154) //agent4~7
#define TZ_PRE_ULTRA_EN_2          (0x158) //agent8~11
#define TZ_PRE_ULTRA_EN_3          (0x15c) //agent12~15
#define TZ_PRE_ULTRA_EN_4          (0x160) //agent16~19
#define TZ_PRE_ULTRA_EN_5          (0x164) //agent20~23

#define ADR_CHK_BUFFER0            (0x138) //
#define ADR_CHK_BUFFER1            (0x13c) //

#define DRAM_3G 0xc0000000
#define DRAM_4G 0x100000000
#define DRAM_5G 0x140000000
#define DRAM_6G 0x180000000

#endif

#define DRAMInfoAddr (TCM_SRAM_ADDR + REG_RW_GPRDW1)
#define FLD_CHA Fld(4,0,AC_MSKB0)//[3:0]
#define FLD_CHB Fld(4,4,AC_MSKB0)//[7:4]
#define FLD_CHC Fld(4,8,AC_MSKB1)//[11:8]
#define FLD_CHD Fld(4,12,AC_MSKB1)//[15:12]
#define FLD_CHE Fld(4,16,AC_MSKB2)//[19:16]
#define FLD_CHF Fld(4,20,AC_MSKB2)//[23:20]

#define UNLIMIT_32BIT               (0x140)
#define MainOnlyVDEC4K120

//-----------------------------------------------------------------------------
/** EMI_GetTotalMemSize()
 *  @return total dram size.
 */
//-----------------------------------------------------------------------------
UINT64 EMI_GetTotalMemSize()
{
    UINT64 Totalsize;
    UINT32 CHAsize, CHBsize, CHCsize, CHDsize;
#ifdef CC_DRAM_96BIT
    UNIT32 CHEsize, CHFsize; 
#endif
    CHAsize = IO32ReadFldAlign(DRAMInfoAddr, FLD_CHA) + 1;
    CHBsize = IO32ReadFldAlign(DRAMInfoAddr, FLD_CHB) + 1;
    CHCsize = IO32ReadFldAlign(DRAMInfoAddr, FLD_CHC) + 1;
    CHDsize = IO32ReadFldAlign(DRAMInfoAddr, FLD_CHD) + 1;
    Totalsize = CHAsize + CHBsize + CHCsize + CHDsize; 

#ifdef CC_DRAM_96BIT
    CHEsize = IO32ReadFldAlign(DRAMInfoAddr, FLD_CHE) + 1;
    CHFsize = IO32ReadFldAlign(DRAMInfoAddr, FLD_CHF) + 1;
    Totalsize = CHAsize + CHBsize + CHCsize + CHDsize + CHEsize + CHFsize;    
#endif

    CHIP_DisplayString(" ChA = ");
    CHIP_DisplayInteger(CHAsize);
    CHIP_DisplayString(" ChB = ");
    CHIP_DisplayInteger(CHBsize);
    CHIP_DisplayString(" ChC = ");
    CHIP_DisplayInteger(CHCsize);
    CHIP_DisplayString(" ChD = ");
    CHIP_DisplayInteger(CHDsize);

    CHIP_DisplayString(" EMI1 Total = ");
    CHIP_DisplayInteger(Totalsize);
    CHIP_DisplayString("(Gb)\n");


   return ((Totalsize/8)<<30);
}

static void dmarb_init(void)
{

	UINT32 pre_ultra;
//	IO_WRITE32(IO_VIRT, 0xd210, 0x30);
	//====DMARB Init=====
	//bit[2]b'1  disable agent subid to emi
	IO_WRITE32(DRAM_DMARB_BASE, 0x0, 0xE0001B06);

	//enable agent0/angent5/agent15 for waiting SDLE option if r/w the same address	
	IO_WRITE32(DRAM_DMARB_BASE, ADR_CHK_BUFFER0, 0x8f8c8580);
	IO_WRITE32(DRAM_DMARB_BASE, ADR_CHK_BUFFER1, 0x8003008f);

	//enable aout pre-ultra (agent0/sub0)
	pre_ultra = IO_READ32(DRAM_DMARB_TZ_BASE,TZ_PRE_ULTRA_EN_0);
	IO_WRITE32(DRAM_DMARB_TZ_BASE, TZ_PRE_ULTRA_EN_0,pre_ultra | 0xff);

	//enable dsp1 pre-ultra (agent5/sub0)
	pre_ultra = IO_READ32(DRAM_DMARB_TZ_BASE,TZ_PRE_ULTRA_EN_1);
	IO_WRITE32(DRAM_DMARB_TZ_BASE, TZ_PRE_ULTRA_EN_1,pre_ultra | 0xff00);

	//enable dsp0 pre-ultra (agent15/sub0)
	pre_ultra = IO_READ32(DRAM_DMARB_TZ_BASE,TZ_PRE_ULTRA_EN_3);
	IO_WRITE32(DRAM_DMARB_TZ_BASE, TZ_PRE_ULTRA_EN_3,pre_ultra | 0xff000000);

}

static void emi_cen_config(void)
{
	UINT64 Dram_size;

	Dram_size = EMI_GetTotalMemSize();

	if (Dram_size == DRAM_4G)
	{
		/*
		Quad channel
		balance mode
		8:8:8:8(Single, Single, Single, Single) rank
		ch-0~ch-3 Col 10bit, Row 16bit
		*/
		IO_WRITE32(EMI_REG_BASE, EMI_CONA, 0xF050F254);
		//EMI_CONN bit[18]:UB_DRAM_EN 1:enalbe 0:disable
		//EMI_CONN bit[23]:BANK_GROUP_EN 1:DDR4 BG bit support 0:other than DDR4
		IO_WRITE32(EMI_REG_BASE, EMI_CONN, 0x00000000);
	}
	else if (Dram_size == DRAM_3G)
	{
		/*
		Quad channel
		unbalance mode
		8:8:4:4(Single, Single, Single, Single) rank
		ch-0&ch-1: Col 10bit, Row 16bit
		ch-2&ch-3: Col 10bit, Row 15bit
		*/
		IO_WRITE32(EMI_REG_BASE, EMI_CONA, 0xA050F254);
		
		//EMI_CONN bit[18]:UB_DRAM_EN 1:enalbe 0:disable
		//EMI_CONN bit[23]:BANK_GROUP_EN 1:DDR4 BG bit support 0:other than DDR4
		IO_WRITE32(EMI_REG_BASE, EMI_CONN, 0x00040000);
	}
	else if (Dram_size == DRAM_5G)
	{
		/*
		Quad channel
		unbalance mode
		16:16:4:4(dual, dual, Single, Single) rank
		ch-0&ch-1: Col 10bit, Row 16bit
		ch-2&ch-3: Col 10bit, Row 15bit
		*/
		IO_WRITE32(EMI_REG_BASE, EMI_CONA, 0xA052F254);
		
		//EMI_CONN bit[18]:UB_DRAM_EN 1:enalbe 0:disable
		//EMI_CONN bit[23]:BANK_GROUP_EN 1:DDR4 BG bit support 0:other than DDR4
		IO_WRITE32(EMI_REG_BASE, EMI_CONN, 0x00040000);
	}
	else if (Dram_size == DRAM_6G)
	{
		/*
		Quad channel
		unbalance mode
		16:16:8:8(dual, dual, Single, Single) rank
		ch-0&ch-3: Col 10bit, Row 16bit
		*/
		IO_WRITE32(EMI_REG_BASE, EMI_CONA, 0xF052F254);
		
		//EMI_CONN bit[18]:UB_DRAM_EN 1:enalbe 0:disable
		//EMI_CONN bit[23]:BANK_GROUP_EN 1:DDR4 BG bit support 0:other than DDR4
		IO_WRITE32(EMI_REG_BASE, EMI_CONN, 0x00040000);
	}
	else
	{
        CHIP_DisplayString(" Not implement this size ");
	}

	IO_WRITE32(EMI_REG_BASE, EMI_CONB, 0x17283544);
	IO_WRITE32(EMI_REG_BASE, EMI_CONC, 0x0a1a0b1a);
	IO_WRITE32(EMI_REG_BASE, EMI_COND, 0x3657587a);
	IO_WRITE32(EMI_REG_BASE, EMI_CONE, 0xffff0848);

	//==============Scramble address==========================
	IO_WRITE32(EMI_REG_BASE, EMI_CONF, 0x00000000);
	IO_WRITE32(EMI_REG_BASE, EMI_CONG, 0x2b2b2a38);
	IO_WRITE32(EMI_REG_BASE, EMI_CONH, 0x00000000);
	IO_WRITE32(EMI_REG_BASE, EMI_CONI, 0x00008803);
	IO_WRITE32(EMI_REG_BASE, EMI_CONM, 0x000006ff);

	
	IO_WRITE32(EMI_REG_BASE, EMI_MDCT, 0x9a998c10);
	IO_WRITE32(EMI_REG_BASE, EMI_MDCT_2ND, 0x00002300); //ESL :  Reserved Buffer
	IO_WRITE32(EMI_REG_BASE, EMI_IOCL, 0xa8afa8a8);
	IO_WRITE32(EMI_REG_BASE, EMI_IOCL_2ND, 0x25272525);
	IO_WRITE32(EMI_REG_BASE, EMI_IOCM, 0xa8a8a8af);
	IO_WRITE32(EMI_REG_BASE, EMI_IOCM_2ND, 0x25252527);
	IO_WRITE32(EMI_REG_BASE, EMI_TESTB, 0x00000027); //disable MDMCU super
	IO_WRITE32(EMI_REG_BASE, EMI_TESTC, 0x38460000);
	IO_WRITE32(EMI_REG_BASE, EMI_TESTD, 0x00000000);

	//defualt setting	
	IO_WRITE32(EMI_REG_BASE, EMI_ARBA, 0xffff5301);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBB, 0xffff5001);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBC, 0xffff500c);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBD, 0xffff5002);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBE, 0xffff500c);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBF, 0xffff500c);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBG, 0xffff500c);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBH, 0xffff500c);
#ifdef MainOnlyVDEC4K120
	IO_WRITE32(EMI_REG_BASE, EMI_ARBA, 0xffff73c2);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBC, 0xffff70cb);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBD, 0xf03070c3);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBE, 0xffff70c8);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBF, 0xffff70c8);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBG, 0xffff704f);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBH, 0xffff704f);
#endif
#ifdef MainOnlyVDEC8K60
	IO_WRITE32(EMI_REG_BASE, EMI_ARBA, 0xffff73c2);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBC, 0xffff70d2);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBD, 0xf04070c2);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBE, 0xffff70ca);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBF, 0xffff70c9);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBG, 0xffff704c);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBH, 0xffff704c);
#endif
#ifdef MainOnlyVDEC4K60TO120
	IO_WRITE32(EMI_REG_BASE, EMI_ARBA, 0xffff73c2);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBC, 0xffff70c5);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBD, 0xf04070c2);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBE, 0xffff70cd);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBF, 0xffff70d0);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBG, 0xffff704d);
	IO_WRITE32(EMI_REG_BASE, EMI_ARBH, 0xffff704d);
#endif
	IO_WRITE32(EMI_REG_BASE, EMI_ARBI, 0x00006108);
	IO_WRITE32(EMI_REG_BASE, EMI_SLCT, 0xff01ff00);//[31:23] enable read high priority
	IO_WRITE32(EMI_REG_BASE, EMI_BMEN, 0x00000001);

    //enable EMI1 master to access > 4GB address
    IO_WRITE32(BUSCFG_BASE, UNLIMIT_32BIT, 0xff);
        
    //-------------------END CEN_EMI Setting--------------------;
}

static void emi_chn_config(void)
{
	int i;
	UINT64 Dram_size;

	Dram_size = EMI_GetTotalMemSize();

	//-------------------BEGIN CHANNEL EMI Setting--------------------;
	for (i = 0; i < CHN_EMI_NR; i++)
	{
		if (Dram_size == DRAM_4G)
		{
			//8:8:8:8
			IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_CONA, 0x0400F050);
		}
		else if (Dram_size == DRAM_3G)
		{
			//8:8:4:4
			if(i == CHN_EMI0 || i == CHN_EMI1)
				IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_CONA, 0x0400F050);
			else
				IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_CONA, 0x0400A050);
		}
		else if (Dram_size == DRAM_5G)
		{
			//16:16:4:4
			if(i == CHN_EMI0 || i == CHN_EMI1)
				IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_CONA, 0x0400F051);
			else
				IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_CONA, 0x0400A050);
		}
		else if (Dram_size == DRAM_6G)
		{
			//16:16:8:8
			if(i == CHN_EMI0 || i == CHN_EMI1)
				IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_CONA, 0x0400F051);
			else
				IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_CONA, 0x0400F050);
		}
		else
		{
            CHIP_DisplayString(" Not implement this size ");
		}
		IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_CONB, 0xffff1048);
		IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_CONC, 0x00000001);
		IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_COND, 0x00000000); //disable bg promot  // 0x400f800f;
		//IO_WRITE32(gCHNBaseAddr[i],CHN_EMI_MDCT,0x88028c17);
		IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_TESTB, 0x00240027);
		IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_TESTC, 0x38460000);
		IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_TESTD, 0x00000000);
		IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_ARBI, 0x20406188);
		IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_ARBI_2ND, 0x20406188);
		IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_ARBJ, 0x3719595e);
		IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_ARBJ_2ND,0x3719595e);
		IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_ARBK, 0x64f3fc79);
		IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_ARBK_2ND, 0x64f3fc79);
		IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_SLCT, 0x00000000); // disable M3 LLAT EN
		IO_WRITE32(gCHNBaseAddr[i], CHN_EMI_ARB_RFF, 0x82410222); // [31]=1: ultra read first, [28:24] write threshold=2 //STRICT_MSK_ULTRA_EN [5]=1
	}
	//-------------------END CHANNEL EMI Setting--------------------;
}

void EMI_4CH_Init(void)
{
	emi_cen_config();	
	emi_chn_config();
	return;
}
#endif

#if defined(CC_DRAM_96BIT)
void EMI_2CH_Init(void)
{
}
#endif

void EMI_Init(void)
{
    dmarb_init();    
	EMI_4CH_Init();  //EMI init after dramc calibration (hotboot resume must init again)
#if defined(CC_DRAM_96BIT)
	EMI_2CH_Init();  //EMI2 init after dramc calibration (hotboot resume must init again)
#endif	
}

#if defined(CC_SUPPORT_SMI)

#define PERLOARD_SMI_LARB_MMU_ENABLE (0)   //1: enable larb mmu, 0:disable larb mmu

typedef enum
{
	P_SMI_LARB0,
	P_SMI_LARB1,
	P_SMI_LARB2,
	P_SMI_LARB3,
	P_SMI_LARB4,
	P_SMI_LARB5,
	P_SMI_LARB6,
	P_SMI_LARB7,
	P_SMI_LARB8,
	P_SMI_LARB9,
	P_SMI_LARB10,
	P_SMI_LARB11,
	P_SMI_LARB12,
	P_SMI_LARB13,
	P_SMI_LARB14,
	P_SMI_LARB15,
	P_SMI_LARB16,
	P_SMI_LARB17,
	P_SMI_LARB18,
	P_SMI_LARB19,
	P_SMI_LARB20,
	P_SMI_LARB21,
	P_SMI_LARB22,
	P_SMI_LARB23,
	P_SMI_LARB_CNT
} P_SMI_LARB_TYPE_T;

#define P_SMI_LARB_NR     P_SMI_LARB_CNT

#define P_SMI_LARB0_PORT_NUM  12
#define P_SMI_LARB1_PORT_NUM  12
#define P_SMI_LARB2_PORT_NUM  13
#define P_SMI_LARB3_PORT_NUM  2
#define P_SMI_LARB4_PORT_NUM  13
#define P_SMI_LARB5_PORT_NUM  13
#define P_SMI_LARB6_PORT_NUM  12
#define P_SMI_LARB7_PORT_NUM  15
#define P_SMI_LARB8_PORT_NUM  24
#define P_SMI_LARB9_PORT_NUM  22
#define P_SMI_LARB10_PORT_NUM  9
#define P_SMI_LARB11_PORT_NUM  16
#define P_SMI_LARB12_PORT_NUM  14
#define P_SMI_LARB13_PORT_NUM  7
#define P_SMI_LARB14_PORT_NUM  7
#define P_SMI_LARB15_PORT_NUM  9
#define P_SMI_LARB16_PORT_NUM  7
#define P_SMI_LARB17_PORT_NUM  7
#define P_SMI_LARB18_PORT_NUM  8
#define P_SMI_LARB19_PORT_NUM  11
#define P_SMI_LARB20_PORT_NUM  10
#define P_SMI_LARB21_PORT_NUM  12
#define P_SMI_LARB22_PORT_NUM  12
#define P_SMI_LARB23_PORT_NUM  6

#define P_SMI_LARB_NON_SEC_CON            (0x380) //new
#define P_SMI_LARB_SEC_CON                (0xF80) //new
#define P_SMI_LARB_CMD_THRT_CON           (0x24)

unsigned long gPLarbBaseAddr[P_SMI_LARB_NR] = {
	SMI_LARB0_BASE,  //larb0
	SMI_LARB1_BASE,  //larb1
	SMI_LARB2_BASE,  //larb2
	SMI_LARB3_BASE,  //larb3
	SMI_LARB4_BASE,  //larb4
	SMI_LARB5_BASE,  //larb5
	SMI_LARB6_BASE,  //larb6
	SMI_LARB7_BASE,  //larb7
	SMI_LARB8_BASE,  //larb8
	SMI_LARB9_BASE,  //larb9
	SMI_LARB10_BASE, //larb10
	SMI_LARB11_BASE, //larb11
	SMI_LARB12_BASE, //larb12
	SMI_LARB13_BASE, //larb13
	SMI_LARB14_BASE, //larb14
	SMI_LARB15_BASE, //larb15
	SMI_LARB16_BASE, //larb16
	SMI_LARB17_BASE, //larb17
	SMI_LARB18_BASE, //larb18
	SMI_LARB19_BASE, //larb19
	SMI_LARB20_BASE, //larb20
	SMI_LARB21_BASE, //larb21
	SMI_LARB22_BASE, //larb22
	SMI_LARB23_BASE, //larb23
};


static void perloader_disable_larb_mmu(int larbIndex)
{
	char i = 0;
	switch (larbIndex) {
	case P_SMI_LARB0:
		for (i = 0 ; i < P_SMI_LARB0_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB1:
		for (i = 0 ; i < P_SMI_LARB1_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB2:
		for (i = 0 ; i < P_SMI_LARB2_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB3:
		for (i = 0 ; i < P_SMI_LARB3_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB4:
		for (i = 0 ; i < P_SMI_LARB4_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB5:
		for (i = 0 ; i < P_SMI_LARB5_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB6:
		for (i = 0 ; i < P_SMI_LARB6_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB7:
		for (i = 0 ; i < P_SMI_LARB7_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB8:
		for (i = 0 ; i < P_SMI_LARB8_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB9:
		for (i = 0 ; i < P_SMI_LARB9_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB10:
		for (i = 0 ; i < P_SMI_LARB10_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB11:
		for (i = 0 ; i < P_SMI_LARB11_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB12:
		for (i = 0 ; i < P_SMI_LARB12_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB13:
		for (i = 0 ; i < P_SMI_LARB13_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB14:
		for (i = 0 ; i < P_SMI_LARB14_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB15:
		for (i = 0 ; i < P_SMI_LARB15_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB16:
		for (i = 0 ; i < P_SMI_LARB16_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB17:
		for (i = 0 ; i < P_SMI_LARB17_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB18:
		for (i = 0 ; i < P_SMI_LARB18_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
#ifdef CC_DRAM_96BIT
	case P_SMI_LARB19:
		for (i = 0 ; i < P_SMI_LARB19_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB20:
		for (i = 0 ; i < P_SMI_LARB20_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB21:
		for (i = 0 ; i < P_SMI_LARB21_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB22:
		for (i = 0 ; i < P_SMI_LARB22_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
	case P_SMI_LARB23:
		for (i = 0 ; i < P_SMI_LARB23_PORT_NUM ; i++)
		{
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_NON_SEC_CON + (4 * i), 0x0); //non-secure
			IO_WRITE32(gPLarbBaseAddr[larbIndex], P_SMI_LARB_SEC_CON + (4 * i), 0x0); // secure
		}
		return ;
#endif
	default:
		return ;
	}
}

static void preloader_set_throtting(void)
{
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB0], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB1], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB2], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB3], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB4], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB5], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB6], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB7], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB8], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB9], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB10], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB11], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB12], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB13], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB14], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB15], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB16], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB17], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB18], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
#ifdef DRAM_96BIT
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB19], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB20], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB21], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB22], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
	IO_WRITE32(gPLarbBaseAddr[P_SMI_LARB23], P_SMI_LARB_CMD_THRT_CON, ((0x6 << 0) + (0x4 << 4) + (0x2 << 8) + (0x1 << 16) + (0x1 << 17) + (0x1 << 18) + (0x3 << 20)));
#endif
}

void SMI_Init(void)
{
	char i;

	if (!PERLOARD_SMI_LARB_MMU_ENABLE)
	{
		//disable larb0~23
		for (i = 0; i < P_SMI_LARB_NR; i++)
			perloader_disable_larb_mmu(i);
	}

	//set SMI throtting
	preloader_set_throtting();

	return;
}
#endif

#endif

VOID BSPLinkSymbol(UINT32 fgDisplay)
{
	if (fgDisplay)
	{
		INT_Reset();
		INT_Vectors();
		BSPLinkSymbol(au4BSS[0]);
#if defined(CC_NAND_BOOT) || defined(CC_EMMC_BOOT)
		__aeabi_llsl();     // for llshl.o(c_5.l)
		x_memcpy();         // mem_mgr.o
		__aeabi_uidivmod(); // aeabi_sdiv.o(.text_udiv)
		//  __aeabi_memclr4();  // rt_memclr_w.o
#endif /* CC_NANDBOOT */
	}
}

#define TIME_START(x) \
    BIM_WRITE32((x), 0x12345678); \
    IO_WRITE32MSK(BIM_BASE, REG_RW_TIMER_CTRL, 0, TMR1_CNTDWN_EN | TMR1_AUTOLD_EN); \
    BIM_WRITE32(REG_RW_TIMER1_LLMT, 0xffffffff); \
    BIM_WRITE32(REG_RW_TIMER1_LOW , 0xffffffff); \
    IO_WRITE32MSK(BIM_BASE, REG_RW_TIMER_CTRL, TMR1_CNTDWN_EN | TMR1_AUTOLD_EN, TMR1_CNTDWN_EN | TMR1_AUTOLD_EN);

#define TIME_END(x) \
    IO_WRITE32MSK(BIM_BASE, REG_RW_TIMER_CTRL, 0, TMR1_CNTDWN_EN | TMR1_AUTOLD_EN); \
    BIM_WRITE32((x), ~BIM_READ32(REG_RW_TIMER1_LOW));

VOID BSP_Start()
{
#ifndef CONFIG_64BIT
	BIM_WRITE32(0x008, BIM_READ32(0x008) & (~0x900));
#endif
#ifdef CC_FPGA_SIM

	HalInitMMU(TCMGET_CHANNELA_SIZE() * 0x100000 - 0x4000);
	DhrystoneTest(10);
	do
	{
	}
	while (1);

#endif

	CHIP_BootEntry0();
#if defined(CC_MTK_PRELOADER)
	memset(&__bss_start, 0, (UINT32)(&__bss_end) - (UINT32)(&__bss_start));
#endif
#if defined(CC_SUPPORT_STR_CORE_OFF) && defined(CC_MTK_PRELOADER)
	// Check for resume from suspend to dram
	extern void CHIP_ResumeFormSuspendMode();
	CHIP_ResumeFormSuspendMode();
#if (defined(CC_MT5891) || defined(CC_MT5886) || defined(CC_MT5893)|| defined(CC_MT5895))&&(!defined(CC_MTK_HOTBOOT_PRELOADER))&&(!defined(CC_MTK_HOTBOOT_START))
	extern UINT32 CHIP_CheckWdtResume(void);
	if (!CHIP_CheckWdtResume())
	{
#endif
#endif   /* CC_SUPPORT_STR_CORE_OFF && CC_MTK_PRELOADER */
#if (!defined(CC_MTK_HOTBOOT_PRELOADER))&&(!defined(CC_MTK_HOTBOOT_START))
		if (!BSP_IsFPGA())
		{
			CHIP_BootEntry1();
#if defined(CC_MTK_PRELOADER)
#if defined(CC_SUPPORT_EMI)
	        CHIP_DisplayString("EMI_init start\n");
            EMI_Init();
            CHIP_DisplayString("EMI_init finish\n");
#endif
#if defined(CC_SUPPORT_SMI)
            CHIP_DisplayString("SMI_init start\n");
			SMI_Init();  //SMI disable MMU,before osd will access dram on loader or kernel early init
            CHIP_DisplayString("SMI_init finish\n");
#endif
#endif
			//CHIP_BootEntry2();
		}
#if defined(CC_SUPPORT_STR_CORE_OFF) && defined(CC_MTK_PRELOADER) && (defined(CC_MT5891) || defined(CC_MT5886)|| defined(CC_MT5893)|| defined(CC_MT5895))
	}
#endif   /* CC_SUPPORT_STR_CORE_OFF && CC_MTK_PRELOADER */
	CHIP_BootEntry3();
#endif
}

#if defined(CC_MTK_PRELOADER) && defined(CC_TRUSTZONE_SUPPORT)
void *CHIP_TzEntry(void)
{
	return (void *)TRUSTZONE_ENTRY;
}
#endif // CC_TRUSTZONE_SUPPORT
