/**
 * @file hv_boot_Main.c
 * @brief boot main source code.
 * @details This file provides the following functions: \n
 *          (1) Initialization and de-initialization functions \n
 *          (2) Start and stop functions \n
 *          (3) Feed functions \n
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-08-18
 * @copyright Copyright(c),2022-8, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author                        <th>Date         <th>Change Description
 * <tr><td>HiView SoC Software Team      <td>2022-08-23   <td>init
 * </table>
 */

#include <mips/cpu.h>
#include <mips/hal.h>

#include "hv_chip_Config.h"
#include "hv_chip_Memory.h"
#include "hv_comm_FlashConfig.h"
#include "hv_boot_Lzss.h"
#include "hv_boot_Common.h"

__attribute__((long_call)) extern int main(int argc, char **argv);
__attribute__((long_call)) extern void Hv_Vos_Init(void);

#define PAGEMASK_256M      0x1FFFE000
#define EHINV              (1 << 10)
#define ENTRY_MASK         (7) // GLOBAL, VALID, DIRTY
#define ENTRY_MASK_INVALID (1) // GLOBAL, VALID, DIRTY
#define FLASH_END          0x4000000

#define CONFIG_MONITOR_DATA_SIZE   (0x10000)
/* temp ddr address for code to decompress. */
#define DDR_TEMP_ADDR 0x82000000
unsigned int g_uiFlashUpgradeOffset = 0;
/*
    TLB memory mapping
    PAddr      - VAddr      - kseg0      - uncached kseg0
    -----------------------------------------------------
    0x00000000 - N/A        - 0x80000000 - 0xA0000000
    0x10000000 - N/A        - 0x90000000 - 0xB0000000
    0x80000000 - 0x60000000 - N/A        - N/A
    0x90000000 - 0x70000000 - N/A        - N/A
*/
static void Hv_Boot_InitTlb(void)
{
    unsigned int uiVaddr = 0;
    unsigned int uiEvenAddr = 0;
    unsigned int uiOddAaddr = 0;

    uiVaddr = 0x00000000;
    mips_tlbrwr2(uiVaddr | EHINV, ENTRY_MASK_INVALID, ENTRY_MASK_INVALID, PAGEMASK_256M);

    uiVaddr = 0x20000000;
    mips_tlbrwr2(uiVaddr | EHINV, ENTRY_MASK_INVALID, ENTRY_MASK_INVALID, PAGEMASK_256M);

    uiVaddr = 0x30000000;
    mips_tlbrwr2(uiVaddr | EHINV, ENTRY_MASK_INVALID, ENTRY_MASK_INVALID, PAGEMASK_256M);

    /* mapping 0x80000000 => 0x60000000  mapping 0x90000000 => 0x70000000 */
    uiVaddr     = 0x60000000;
    uiEvenAddr  = 0x80000000;
    uiOddAaddr  = 0x90000000;
    mips_tlbrwr2(uiVaddr | EHINV,
                (uiEvenAddr >> 12 << 6) | ENTRY_MASK,
                (uiOddAaddr >> 12 << 6) | ENTRY_MASK,
                PAGEMASK_256M);
    return;
}

void Hv_Boot_ClearBss(void)
{
    extern void *__bss_start, *__bss_end;

    unsigned int *puiStart  = (unsigned int*)(&__bss_start);
    unsigned int *puiEnd    = (unsigned int*)(&__bss_end);

    while ((unsigned int)puiStart < (unsigned int)puiEnd)
    {
        *puiStart ++ = 0;
    }

    mips_flush_cache();
    return;
}

void Hv_Boot_CopyDdrCodeData(void)
{

    extern void *_text_lma,*__text_start, *__rodata_end;
    extern void *_data_lma, *__data_start, *__data_end;

    unsigned int iIndex     = 0;
    unsigned int uiDataSize = 0;
    unsigned int *puiData   = NULL;
    unsigned int *puiFlash  = NULL;

    /* Copy text and rodata segment from Flash to ddr */
    uiDataSize  = ((unsigned int)(&__rodata_end) - (unsigned int)(&__text_start)) / sizeof(unsigned int);
    puiData     = (unsigned int *)&__text_start;
    puiFlash    = ((unsigned int *)&_text_lma) + g_uiFlashUpgradeOffset;

    for (iIndex = 0; iIndex < uiDataSize ; iIndex++)
    {
        puiData[iIndex] = puiFlash[iIndex];
    }

    /* Copy data segment  from Flash to ddr */
    uiDataSize  = ((unsigned int)(&__data_end) - (unsigned int)(&__data_start)) / sizeof(unsigned int);
    puiData     = (unsigned int *)&__data_start;
    puiFlash    = ((unsigned int *)&_data_lma) + g_uiFlashUpgradeOffset;

    for (iIndex = 0; iIndex < uiDataSize ; iIndex++)
    {
        puiData[iIndex] = puiFlash[iIndex];
    }
    return;
}


static void Hv_Boot_CopyDdrCodeDataCompressed(int uiCompressed)
{
    unsigned int uiDdrAddr = 0;

    extern void *_text_lma, *__text_start, *__data_end;
    unsigned int *puiData   = NULL;
    unsigned int *puiFlash  = NULL;
    unsigned int iIndex     = 0;
    unsigned int uiDataSize = 0;


    uiDataSize  = ((unsigned int)(&__data_end) - (unsigned int)(&__text_start)) / sizeof(unsigned int);
    puiData     = (unsigned int *)&__text_start;
    puiFlash    = ((unsigned int *)&_text_lma) + g_uiFlashUpgradeOffset;

    if (uiCompressed)
    {
        puiData     = (unsigned int *)DDR_TEMP_ADDR;
        uiDataSize  = HV_FLASH_CONFIG_CODE_PART_SIZE / sizeof(unsigned int);
    }

    Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_INFO, ">>> Hv_Boot_CopyDdrCodeDataCompressed enter.\n");
    Hv_Boot_PrintHex(BOOT_DEBUG_LEVEL_DEBUG, uiDataSize);
    Hv_Boot_PrintHex(BOOT_DEBUG_LEVEL_DEBUG, (unsigned int)puiData);
    Hv_Boot_PrintHex(BOOT_DEBUG_LEVEL_DEBUG, (unsigned int)puiFlash);

    for (iIndex = 0; iIndex < uiDataSize ; iIndex++)
    {
        puiData[iIndex] = puiFlash[iIndex];
    }
    Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_DEBUG, ">>> Hv_Boot_CopyDdrCodeDataCompressed over.\n");

    return;
}

extern void Hv_Ddr_Init(void);
void Hv_Boot_InitDDR(void)
{
    Hv_Ddr_Init();
    return;
}

static void _Boot_DmaCopyFlashToDDR(unsigned int uiFlashAddr, unsigned int uiDdrAddr, unsigned int uiDataSize)
{
    /*use two dma channel for rx/tx,most high speed is 4 division*/
    unsigned int auiCmdAddr[2] = {0};
    unsigned int uiPageCount = 0;
    unsigned int uiSurplusSize = 0;
    unsigned int iIndex     = 0;

    Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_INFO, ">>> Hv_Boot_DmaCopyFlashToDDR.\n");
    Hv_Boot_PrintHex(BOOT_DEBUG_LEVEL_DEBUG, uiDataSize);
    Hv_Boot_PrintHex(BOOT_DEBUG_LEVEL_DEBUG, uiDdrAddr);
    Hv_Boot_PrintHex(BOOT_DEBUG_LEVEL_DEBUG, uiFlashAddr);

    BOOT_WT32(CPU_SYS_DMAC_CTL0_L, 0xa09405);
    BOOT_WT32(CPU_SYS_DMAC_CFG0_L, 0x800000);
    BOOT_WT32(CPU_SYS_DMAC_CFG0_H, 0x82);
    BOOT_WT32(CPU_SYS_DMAC_MASKTFR, 0x101);
    BOOT_WT32(CPU_SYS_DMAC_CLEARTFR, 0x01);
    BOOT_WT32(CPU_SYS_DMACFGREG, 0x01);

    BOOT_W32_FIELD(SYS_REG_SH5_TOP0_REG_SH5_WDG_FILED2, reg_sh5_qspi_xip_en, 0x0);

    BOOT_WT32(CPU_SYS_2_QSPI_SSIENR, 0x00);
    BOOT_RD32(CPU_SYS_2_QSPI_ICR);

    #ifdef HV_FLASH_CONFIG_4LINE_DMA
    /* 8bit read only, four line select */
    BOOT_WT32(CPU_SYS_2_QSPI_CTRLR0, 0x800807);
    #else
    BOOT_WT32(CPU_SYS_2_QSPI_CTRLR0, 0x400807);
    #endif

    /* division set */
    #ifdef HV_FLASH_CONFIG_BOOT_SPEED_100
    BOOT_WT32(CPU_SYS_2_QSPI_BAUDR, 2);
    BOOT_W32_FIELD(CPU_SYS_2_QSPI_RX_SAMPLE_DELAY, RSD, 0x2);
    #else
    BOOT_WT32(CPU_SYS_2_QSPI_BAUDR, 4);
    BOOT_W32_FIELD(CPU_SYS_2_QSPI_RX_SAMPLE_DELAY, RSD, 0x2);
    #endif

    BOOT_WT32(CPU_SYS_2_QSPI_TXFTLR, 0x08);
    BOOT_WT32(CPU_SYS_2_QSPI_RXFTLR, 0x00);

    /* addr 24bit, instru 8bit, standard mode. */
    BOOT_W32_FIELD(CPU_SYS_2_QSPI_SPI_CTRLR0, TRANS_TYPE, 0);
    BOOT_W32_FIELD(CPU_SYS_2_QSPI_SPI_CTRLR0, ADDR_L, 0x6);
    BOOT_W32_FIELD(CPU_SYS_2_QSPI_SPI_CTRLR0, INST_L, 0x2);

    /* read cmd 4line */
    #ifdef HV_FLASH_CONFIG_4LINE_DMA
    auiCmdAddr[0]= 0x6B;
    #else
    /* read cmd 2line */
    auiCmdAddr[0]= 0x3B;
    #endif

    /* read dma enable */
    BOOT_WT32(CPU_SYS_2_QSPI_DMACR, 0x01);
    BOOT_WT32(CPU_SYS_2_QSPI_DMARDLR, 0x07);

    Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_DEBUG, ">>> Read time start.\n");
    uiPageCount = uiDataSize >> 11;
    uiSurplusSize = uiDataSize & 0x7ff;
    Hv_Boot_PrintHex(BOOT_DEBUG_LEVEL_DEBUG, uiPageCount);
    Hv_Boot_PrintHex(BOOT_DEBUG_LEVEL_DEBUG, uiSurplusSize);

    for (iIndex = 0; iIndex < uiPageCount; iIndex++)
    {
        BOOT_WT32(CPU_SYS_DMAC_SAR0, CPU_SYS_2_QSPI_DR0);
        BOOT_WT32(CPU_SYS_DMAC_DAR0, uiDdrAddr & 0x1fffffff);
        BOOT_WT32(CPU_SYS_DMAC_CTL0_H, 0x800);
        BOOT_WT32(CPU_SYS_DMAC_CHENREG, 0x101);
        BOOT_WT32(CPU_SYS_2_QSPI_CTRLR1, 0x7ff);
        BOOT_WT32(CPU_SYS_2_QSPI_SSIENR, 0x01);
        BOOT_WT32(CPU_SYS_2_QSPI_DR0, auiCmdAddr[0]);
        BOOT_WT32(CPU_SYS_2_QSPI_DR0, uiFlashAddr);

        while(!(BOOT_RD32(CPU_SYS_DMAC_STATUSINT) & 0x01));
        BOOT_WT32(CPU_SYS_DMAC_CLEARTFR, 0x1);
        Hv_Boot_Wait_Us(1);
        while((BOOT_RD32(CPU_SYS_2_QSPI_SR) & 0x01) == 0x01);
        Hv_Boot_Wait_Us(1);
        BOOT_WT32(CPU_SYS_2_QSPI_SSIENR,0x0);
        Hv_Boot_Wait_Us(1);
        uiFlashAddr = uiFlashAddr + 0x800;
        uiDdrAddr = uiDdrAddr + 0x800;
    }

    if (uiSurplusSize > 0)
    {
        BOOT_WT32(CPU_SYS_DMAC_SAR0, CPU_SYS_2_QSPI_DR0);
        BOOT_WT32(CPU_SYS_DMAC_DAR0, uiDdrAddr & 0x1fffffff);
        BOOT_WT32(CPU_SYS_DMAC_CTL0_H, uiSurplusSize);
        BOOT_WT32(CPU_SYS_DMAC_CHENREG, 0x101);
        BOOT_WT32(CPU_SYS_2_QSPI_CTRLR1, uiSurplusSize-1);
        BOOT_WT32(CPU_SYS_2_QSPI_SSIENR, 0x01);
        BOOT_WT32(CPU_SYS_2_QSPI_DR0, auiCmdAddr[0]);
        BOOT_WT32(CPU_SYS_2_QSPI_DR0, uiFlashAddr);

        while(!(BOOT_RD32(CPU_SYS_DMAC_STATUSINT) & 0x01));
        BOOT_WT32(CPU_SYS_DMAC_CLEARTFR, 0x1);
        while((BOOT_RD32(CPU_SYS_2_QSPI_SR) & 0x01) == 0x01);
    }

    BOOT_WT32(CPU_SYS_DMAC_MASKTFR,0x100);
    BOOT_WT32(CPU_SYS_DMACFGREG,0x0);

    Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_DEBUG, ">>> Read time end.\n");

    /* togle ssien before xip mode. */
    BOOT_WT32(CPU_SYS_2_QSPI_SSIENR, 0x00);
    //BOOT_RD32(CPU_SYS_2_QSPI_ICR);
    //BOOT_WT32(CPU_SYS_2_QSPI_BAUDR, 0x8);
    //BOOT_WT32(CPU_SYS_2_QSPI_DMACR, 0x00);
    BOOT_WT32(CPU_SYS_2_QSPI_SSIENR, 0x1);

    BOOT_W32_FIELD(SYS_REG_SH5_TOP0_REG_SH5_WDG_FILED2, reg_sh5_qspi_xip_en, 0x1);
    return;
}

static void Hv_Boot_DmaCopyFlashToDDR(int uiCompressed)
{
    unsigned int uiDdrAddr = 0;
    unsigned int uiFlashAddr = 0;

    extern void *_text_lma, *__text_start, *__data_end;

    unsigned int iIndex     = 0;
    unsigned int uiDataSize = 0;

    uiDataSize  = ((unsigned int)(&__data_end) - (unsigned int)(&__text_start));
    uiDdrAddr   = (unsigned int )&__text_start;
    uiFlashAddr = (unsigned int)((unsigned int)&_text_lma - 0xBfc00000) + g_uiFlashUpgradeOffset;

    if (uiCompressed)
    {
        uiDdrAddr   = DDR_TEMP_ADDR;
        uiDataSize  = HV_FLASH_CONFIG_CODE_PART_SIZE;
    }
    if (uiFlashAddr + uiDataSize > FLASH_END)
    {
        uiDataSize = FLASH_END - uiFlashAddr;
    }
    _Boot_DmaCopyFlashToDDR(uiFlashAddr, uiDdrAddr, uiDataSize);
    return;
}

static void Hv_Boot_CopyPqFlashToDDR(void)
{
    unsigned int uiDdrAddr      = DDR_TEMP_ADDR;
    unsigned int uiFlashAddr    = HV_FLASH_CONFIG_PQ_DATA_PART_START;
    unsigned int uiDataSize     = HV_FLASH_CONFIG_PQ_DATA_PART_SIZE;
    if (uiFlashAddr + uiDataSize > FLASH_END)
    {
        uiDataSize = FLASH_END - uiFlashAddr;
    }
    _Boot_DmaCopyFlashToDDR(uiFlashAddr, uiDdrAddr, uiDataSize);
    return;
}

static void Hv_Boot_CopyLogoFlashToDDR(void)
{
    unsigned int uiDdrAddr      = HV_MEMORY_CONFIG_OSD_LOGO_DDR_START;
    unsigned int uiFlashAddr    = HV_FLASH_CONFIG_LOGO_PART_START;
    unsigned int uiDataSize     = HV_FLASH_CONFIG_LOGO_PART_SIZE;
    if (uiFlashAddr + uiDataSize > FLASH_END)
    {
        uiDataSize = FLASH_END - uiFlashAddr;
    }
    _Boot_DmaCopyFlashToDDR(uiFlashAddr, uiDdrAddr, uiDataSize);
    return;
}
static void Hv_Boot_CopyFireFlashToDDR(void)
{
    unsigned int uiDdrAddr      = HV_MEMORY_CONFIG_MONITOR_HOTFIX_START;
    unsigned int uiFlashAddr    = HV_FLASH_CONFIG_HOTFIX_START;
    unsigned int uiDataSize     = HV_FLASH_CONFIG_HOTFIX_SIZE;
    if (uiFlashAddr + uiDataSize > FLASH_END)
    {
        uiDataSize = FLASH_END - uiFlashAddr;
    }
    _Boot_DmaCopyFlashToDDR(uiFlashAddr, uiDdrAddr, uiDataSize);
    return;
}
static void Hv_Boot_CopyCfgFlashToDDR(void)
{
    unsigned int uiDdrAddr      = HV_MEMORY_CONFIG_AUDIO_DDR_START;
    unsigned int uiFlashAddr    = HV_FLASH_CONFIG_MONITOR_DATA_PART_START;
    unsigned int uiDataSize     = CONFIG_MONITOR_DATA_SIZE;
    if (uiFlashAddr + uiDataSize > FLASH_END)
    {
        uiDataSize = FLASH_END - uiFlashAddr;
    }
    _Boot_DmaCopyFlashToDDR(uiFlashAddr, uiDdrAddr, uiDataSize);

    return;
}

void Hv_Boot_WatchdogInit(void)
{
    BOOT_WT32(SYS_REG_SH5_TOP0_REG_SH5_WDG_FILED5, 5000);
    /* wdt reload */
    BOOT_W32_FIELD(SYS_REG_SH5_TOP0_REG_SH5_WDG_FILED7, reg_sh5_wdg_reload_en, 1);
    BOOT_W32_FIELD(SYS_REG_SH5_TOP0_REG_SH5_WDG_FILED7, reg_sh5_wdg_reload_en, 0);

    unsigned int uiVal = BOOT_RD32(SYS_REG_SH5_TOP0_REG_SH5_WDG_FILED4);

    /* count enable */
    uiVal |= 0x00000001;
    /* wdg reset enable to reset whole system */
    uiVal |= 0x00000008;

    /* set count period 1ms from APB_CLK */
    BOOT_WT32(SYS_REG_SH5_TOP0_REG_SH5_WDG_FILED6, (HV_CHIP_CLK_APB / 1000));

    /* start the wdt */
    BOOT_WT32(SYS_REG_SH5_TOP0_REG_SH5_WDG_FILED4, uiVal);
}

static unsigned char s_ucBootType   = 0;
static unsigned char s_cAcFlag      = 0;
void Hv_Boot_Check_BootReason(void)
{
    int iData = 0;

    iData = BOOT_RD32(STANDBY_STANDBY_MCU_REG_STBY_MCU6);
    if (4 == (iData&0xff))/* wakeup */
    {
        iData = BOOT_RD32(STANDBY_STANDBY_MCU_REG_STBY_MCU7);
        s_ucBootType = (iData&0xff);
        BOOT_WT32(SW_DUMMY_JTAG, s_ucBootType);
    }
    return;
}
unsigned char Hv_Boot_Get_BootReason(void)
{
    return s_ucBootType;
}
unsigned char Hv_Boot_Get_BootType(void)
{
    return s_cAcFlag;
}
static void BootPwrOff(void)
{
    /* E_MAILBOX_CMD_RISC_TO_PM_NORMAL */
    BOOT_WT32(STANDBY_STANDBY_MCU_REG_STBY_MCU10, 7);
    BOOT_WT32(STANDBY_STANDBY_MCU_REG_STBY_MCU15, 1);
    Hv_Boot_Wait_Ms(20);
    /* E_MAILBOX_CMD_RISC_TO_PM_POWER_OFF_ACK */
    BOOT_WT32(STANDBY_STANDBY_MCU_REG_STBY_MCU10, 5);
    BOOT_WT32(STANDBY_STANDBY_MCU_REG_STBY_MCU15, 1);
    Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_WAR, ">>> poweroff\n");
    while(1);
}

void Hv_Boot_Check_SecondPowerOn(void)
{

    unsigned int uiData = 0;
    unsigned int uiLoop = 0;
    unsigned int uiAddr = HV_FLASH_CONFIG_START_XIP+HV_FLASH_CONFIG_MONITOR_DATA_PART_START+HV_FLASH_CONFIG_TIMER_START;

    BOOT_R32_DECL_VAR();
    s_cAcFlag = BOOT_R32_FIELD(STANDBY_AON_REG_PMU_REG3, reg_first_start_flag);
    if (s_cAcFlag)
    {
        BOOT_W32_FIELD(STANDBY_AON_REG_PMU_REG3, reg_first_start_flag, 0);
        #if (HV_PROJECT_CONFIG_AC_POWER_STATE == 1)
        BootPwrOff();
        #elif (HV_PROJECT_CONFIG_AC_POWER_STATE == 2)
        return;
        #else
        ;
        #endif
    }
    else
    {
        return;
    }

    for (uiLoop = 0; uiLoop<4096; uiLoop+=16)
    {
        /* magic TIMD or HT7315 */
        if ((BOOT_RD32(uiAddr+uiLoop+4) != 0x54494D45)
            && (BOOT_RD32(uiAddr+uiLoop+4) != 0x48547315))
        {
            break;
        }
        uiData = BOOT_RD32(uiAddr+uiLoop+0xc);
    }

    if (8 == (uiData&0xff))/* poweroff */
    {
        BootPwrOff();
    }
    return;
}

int _start(void)
{
    int iRet = 0;
    char cGpioIndex = 16;
    int iPqCompressSize = 0;
    char *pucAddr = NULL;

#ifdef SW_DUMMY_DEBUG
    while(HV_RD32(SW_DUMMY_JTAG)==0x11223344);
#endif

    mips_bissr(SR_CU1);

    Hv_Chip_DebugUartInit(115200);
    Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_WAR, ">>> BOOT RISC0\n");

    /* find upgrade section. */
    if (*(char *)(HV_FLASH_CONFIG_START_XIP + HV_FLASH_CONFIG_PM_DATA_START + 4 + 5) == 0xaa)
    {
        Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_WAR, ">>> user second part.\n");
    }

#ifdef CONFIG_USER_WATCHDOG_ON
    Hv_Boot_WatchdogInit();
#endif

    Hv_Boot_Check_BootReason();
    Hv_Boot_Check_SecondPowerOn();

    if (11 != s_ucBootType)
    {
#if HV_BOARD_CONFIG_LED_R_POL
        BOOT_W32_FIELD(STANDBY_STANDBY_PERI_REG_PWM0, reg_pwm_pol, 0);
#else
        BOOT_W32_FIELD(STANDBY_STANDBY_PERI_REG_PWM0, reg_pwm_pol, 1);
#endif
        BOOT_W32_FIELD(STANDBY_STANDBY_PERI_REG_PWM0, reg_pwm_ch_en, 0);
        BOOT_W32_FIELD(STANDBY_STANDBY_PERI_REG_PWM0, reg_pwm_output_mode, 1);
#if (HV_BOARD_CONFIG_GPIO_LED_B == 61)
        /* pin61-gpio21-bit16*/
        BOOT_W32_FIELD(RX_SH08_TOP_RX_CTRL_0, reg_gpio21_func_sel, 0);
        cGpioIndex = 16;
#endif
#if HV_BOARD_CONFIG_LED_B_POL
        BOOT_W32_FIELD(CPU_SYS_GPIO0_GPIO_OUT0_SET, gpio0_out_set, (1<<cGpioIndex));
        BOOT_W32_FIELD(CPU_SYS_GPIO0_GPIO_OE0_SET, gpio0_oe_set, (1<<cGpioIndex));
#else
        BOOT_W32_FIELD(CPU_SYS_GPIO0_GPIO_OUT0_CLR, gpio0_out_clr, (1<<cGpioIndex));
        BOOT_W32_FIELD(CPU_SYS_GPIO0_GPIO_OE0_SET, gpio0_oe_set, (1<<cGpioIndex));
#endif
    }
    Hv_Boot_InitDDR();
    Hv_Boot_Wait_Ms(1);
    Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_INFO, ">>> boot_ddr_init over\n");


    Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_INFO, ">>> copy_ddr_code_data...\n");
#ifdef CONFIG_CODE_COMPRESSED
    extern void *_text_lma,*__text_start;
    extern void *__data_start;

    Hv_Boot_DmaCopyFlashToDDR(1);
    iRet = Hv_Boot_LzssDecompress((char *)DDR_TEMP_ADDR, ((char *)&__text_start), 1, 0);
    if ( iRet != 0)
    {
        Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_INFO, ">>> decompress code error\n");
    }
#else
    Hv_Boot_DmaCopyFlashToDDR(0);
#endif

#ifdef CONFIG_PQ_COMPRESSED
    Hv_Boot_CopyPqFlashToDDR();
    Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_DEBUG, ">>> decompress pq...\n");
    Hv_Boot_LzssDecompress((char *)DDR_TEMP_ADDR,((char *)HV_MEMORY_CONFIG_PQ_DATA_START), 1, 0);
#endif
    Hv_Boot_ClearBss();

    Hv_Boot_CopyLogoFlashToDDR();
    Hv_Boot_CopyFireFlashToDDR();
    Hv_Boot_CopyCfgFlashToDDR();

    /* set stack to the symbol of __stack */
    __asm__ __volatile__ ("la $29, __stack");

    Hv_Boot_InitTlb();

    Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_INFO, ">>> risc init\n");
    Hv_Vos_Init();

    Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_WAR, ">>> enter main");
    iRet = main(0, 0);

    Hv_Boot_Print_String(BOOT_DEBUG_LEVEL_INFO, ">>> over\n");

    return iRet;
}
