/* 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.
 *
 *****************************************************************************/


#ifndef MTK_GPIO_H
#define MTK_GPIO_H

#include "x_gpio.h"
#include "x_pdwnc.h"
#include "x_timer.h"
#include "x_pinmux.h"
#include "drv_pwm.h"
#include "eeprom_if.h"
#include "drvcust_if.h"
#include "pmx_if.h"
#include "x_irq.h"
#include "nptv_vdec_if.h"
#include "aud_if.h"
#ifdef CC_AUD_ANALOG_INPUT_SWITCH_PROTECT
#include "../../aud/periph/codec_mt5365.h"
#endif

#ifdef DEFINE_IS_LOG
#undef DEFINE_IS_LOG
#endif
#ifdef CC_MTK_LOADER
#define DEFINE_IS_LOG(level, fmt...)   Printf(fmt)
#else /* CC_MTK_LOADER */
#define DEFINE_IS_LOG	IR_IsLog
#endif /* CC_MTK_LOADER */
#include "x_debug.h"

#define GPIO_POWER_ON_FUNC      (GPIO_MtkPowerOnFunc)
#define GPIO_POWER_OFF_FUNC     (GPIO_MtkPowerOffFunc)
#define GPIO_LED_CTRL_FUNC      (GPIO_MtkLedCtrlFunc)
#ifdef CC_MTK_LOADER
// #define LOADER_UPGRADE_VER_CMP_FUNC (LOADER_MtkUpgradeVerCmpFunc)
#define LOADER_UPGRADE_VER_CMP_FUNC (NULL)
#define LOADER_ENV_INIT_FUNC        (LOADER_MtkEnvInitFunc)
#ifdef LOADER_USB_UPGRADE
#define LOADER_UPGRADE_DLM_CB_FUNC (LOADER_MtkUpgradeDlmCbFunc)
//#define LOADER_UPGRADE_DLM_CB_FUNC (NULL)
#endif
#endif /* CC_MTK_LOADER */


#if defined(LINUX_TURNKEY_SOLUTION) || defined(__KERNEL__)
#define LED_BLINK_ENABLE        0
#else
#define LED_BLINK_ENABLE        1
#endif

static void GPIO_MtkPowerOnFunc(void);
static void GPIO_MtkPowerOffFunc(UINT32 u4PowerDownEn);
static void GPIO_MtkLedCtrlFunc(LED_STATUS_T eLedStatus);
#ifdef CC_MTK_LOADER
static INT32 LOADER_MtkUpgradeVerCmpFunc(CHAR *szCurVer, CHAR *szUpgVer);
static void LOADER_MtkEnvInitFunc(void *prLdrData, UINT32 fgValidFlag);
#ifdef LOADER_USB_UPGRADE
static void LOADER_MtkUpgradeDlmCbFunc(UINT32 u4BufSize);
#endif
#endif /* CC_MTK_LOADER */

#if LED_BLINK_ENABLE
#ifndef CC_MTK_LOADER
static void _LedBlinking_Task(HANDLE_T hHandle, VOID* pTag);
#endif
#endif

#if LED_BLINK_ENABLE
#if defined(CC_MTK_LOADER)
static void _LOADER_TimerOff(void);
static void _LOADER_TimerOn(void);
static void _LOADER_TimerIsr(void);
static void _LOADER_InitGPIOTimer(void);
#endif
#endif

//-----------------------------------------------------------------------------
// Macros
//-----------------------------------------------------------------------------

#define INIT_SET_GPIO(gpio, onval)                  \
    if (DRVCUST_InitQuery(gpio, &i)==0)              \
    {                                               \
        if (DRVCUST_InitQuery(onval, (UINT32 *)&i4Val)==0)     \
        {                                           \
            VERIFY(GPIO_Output((INT32)i, &i4Val) == i4Val);  \
        }                                           \
    }

#define DOWN_SET_GPIO(gpio, onval)                  \
    if (DRVCUST_InitQuery(gpio, &i)==0)              \
    {                                               \
        if (DRVCUST_InitQuery(onval, (UINT32 *)&i4Val)==0)     \
        {                                           \
            i4Val = !i4Val;                         \
            VERIFY(GPIO_Output((INT32)i, &i4Val)== i4Val);  \
        }                                           \
    }


//-----------------------------------------------------------------------------
// Functions
//-----------------------------------------------------------------------------
#include "loader_if.h"

#ifndef PINMUX_INCLUDE_FILE
    #include "mediatek/mtk_pin_setup.h"
#else
    #include PINMUX_INCLUDE_FILE
#endif


#ifdef CC_MTK_LOADER
static void LOADER_EnableHdmiDdc(void)
{
#ifndef CC_HDMI_EDID_DISABLE
    BSP_PinSet(PIN_HDMI_0_SDA, PINMUX_FUNCTION1);
    BSP_PinSet(PIN_HDMI_0_SCL, PINMUX_FUNCTION1);
    BSP_PinSet(PIN_HDMI_1_SDA, PINMUX_FUNCTION1);
    BSP_PinSet(PIN_HDMI_1_SCL, PINMUX_FUNCTION1);
    BSP_PinSet(PIN_HDMI_2_SDA, PINMUX_FUNCTION1);
    BSP_PinSet(PIN_HDMI_2_SCL, PINMUX_FUNCTION1);
    BSP_PinSet(PIN_HDMI_3_SDA, PINMUX_FUNCTION1);
    BSP_PinSet(PIN_HDMI_3_SCL, PINMUX_FUNCTION1);
#endif
}

static void LOADER_DisableHdmiDdc(void)
{
#ifndef CC_HDMI_EDID_DISABLE
    BSP_PinSet(PIN_HDMI_0_SDA, PINMUX_FUNCTION0);
    BSP_PinSet(PIN_HDMI_0_SCL, PINMUX_FUNCTION0);
    BSP_PinSet(PIN_HDMI_1_SDA, PINMUX_FUNCTION0);
    BSP_PinSet(PIN_HDMI_1_SCL, PINMUX_FUNCTION0);
    BSP_PinSet(PIN_HDMI_2_SDA, PINMUX_FUNCTION0);
    BSP_PinSet(PIN_HDMI_2_SCL, PINMUX_FUNCTION0);
    BSP_PinSet(PIN_HDMI_3_SDA, PINMUX_FUNCTION0);
    BSP_PinSet(PIN_HDMI_3_SCL, PINMUX_FUNCTION0);
#endif
}

static void LOADER_HdmiHpdAll(BOOL fgHigh)
{
    UINT32 u4HpdGpioNum = 0;
    vIO32WriteFldAlign(PDWNC_ECBUS_CFG1,2,FLD_RG_CBUS_0_EX1KAB);
    vIO32WriteFldAlign(PDWNC_ECBUS_CFG1,1,FLD_RG_CBUS_0_EX1K);
    vIO32WriteFldAlign(PDWNC_ECBUS_CFG2,2,FLD_RG_HDMI_1_PWR5V_1KAB);
    vIO32WriteFldAlign(PDWNC_ECBUS_CFG2,1,FLD_RG_HDMI_1_PWR5V_1KE);
    vIO32WriteFldAlign(PDWNC_ECBUS_CFG2,2,FLD_RG_HDMI_2_PWR5V_1KAB);
    vIO32WriteFldAlign(PDWNC_ECBUS_CFG2,1,FLD_RG_HDMI_2_PWR5V_1KE);
    vIO32WriteFldAlign(PDWNC_ECBUS_CFG2,2,FLD_RG_HDMI_3_PWR5V_1KAB);
    vIO32WriteFldAlign(PDWNC_ECBUS_CFG2,1,FLD_RG_HDMI_3_PWR5V_1KE);
    if(0 == DRVCUST_InitQuery(eHDMIHPD0GPIONUM,&u4HpdGpioNum))
    {
        if(fgHigh)
        {
            GPIO_GetIn(u4HpdGpioNum);
        }
        else
        {
            GPIO_SetOut(u4HpdGpioNum,0);
        }
    }
    if(0 == DRVCUST_InitQuery(eHDMIHPD1GPIONUM,&u4HpdGpioNum))
    {
        if(fgHigh)
        {
            GPIO_GetIn(u4HpdGpioNum);
        }
        else
        {
            GPIO_SetOut(u4HpdGpioNum,0);
        }
    }
    if(0 == DRVCUST_InitQuery(eHDMIHPD2GPIONUM,&u4HpdGpioNum))
    {
        if(fgHigh)
        {
            GPIO_GetIn(u4HpdGpioNum);
        }
        else
        {
            GPIO_SetOut(u4HpdGpioNum,0);
        }
    }
    if(0 == DRVCUST_InitQuery(eHDMIHPD3GPIONUM,&u4HpdGpioNum))
    {
        if(fgHigh)
        {
            GPIO_GetIn(u4HpdGpioNum);
        }
        else
        {
            GPIO_SetOut(u4HpdGpioNum,0);
        }
    }
}

static INT32 LOADER_MtkUpgradeVerCmpFunc(CHAR *szCurVer, CHAR *szUpgVer)
{
    INT32 i4Ret;
    i4Ret = strcmp(szCurVer, szUpgVer); // i4Ret = szCurVer - szUpgVer.
    LOG(0, "CurVer:%s UpgVer:%s\n", szCurVer, szUpgVer);
    return (0 > i4Ret) ? 0 : 1;   // 0 is ok to upgrade, upgrade when szCurVer < szUpgVer.
}

static void LOADER_MtkEnvInitFunc(void *prLdrData, UINT32 fgValidFlag)
{
	UINT32 u4Val ;
    #ifdef CC_QUIET_HOT_BOOT_SUPPORT
    DTVCFG_T rDtvCfg;
    LDR_DATA_T *prLoaderData = prLdrData;
    #else
    UNUSED(prLdrData);
    #endif

    UNUSED(fgValidFlag);
    UNUSED(LOADER_MtkUpgradeVerCmpFunc);

    //Printf("Pinmux Initial setting: totoal (%d) pins\n", sizeof(_gu4SysPinmuxInit)/(sizeof(_gu4SysPinmuxInit[0])));
    if(sizeof(_gu4SysPinmuxInit))
    {
        for(u4Val = 0;u4Val < sizeof(_gu4SysPinmuxInit)/(sizeof(_gu4SysPinmuxInit[0])); u4Val++)
        {
            BSP_PinSet(_gu4SysPinmuxInit[u4Val][0], _gu4SysPinmuxInit[u4Val][1]);
        }
    }
#ifdef CC_AUD_ANALOG_INPUT_SWITCH_PROTECT
    GPIO_SetOut(GPIO_AIN0_L,0);
	GPIO_SetOut(GPIO_AIN0_R,0);
    GPIO_SetOut(GPIO_AIN1_L,0);
	GPIO_SetOut(GPIO_AIN1_R,0);
	GPIO_SetOut(GPIO_AIN2_L,0);
	GPIO_SetOut(GPIO_AIN2_R,0);
	GPIO_SetOut(GPIO_AIN3_L,0);
	GPIO_SetOut(GPIO_AIN3_R,0);
	GPIO_SetOut(GPIO_AIN4_L,0);
	GPIO_SetOut(GPIO_AIN4_R,0);
	GPIO_SetOut(GPIO_AIN5_L,0);
	GPIO_SetOut(GPIO_AIN5_R,0);
	GPIO_SetOut(GPIO_AIN6_L,0);
	GPIO_SetOut(GPIO_AIN6_R,0);
#endif
    if (fgValidFlag)
    {
        return;
    }

    // AUD_CLR_BIT(REG_INT_SDADC2, ADC_R_PD);
    IO_WRITE32(AUDIO_BASE,0x0248, (IO_READ32(AUDIO_BASE,0x0248)) & (~((0x1 << 13))));
    // AUD_CLR_BIT(REG_INT_SDADC2, ADC_L_PD);
    IO_WRITE32(AUDIO_BASE,0x0248, (IO_READ32(AUDIO_BASE,0x0248)) & (~((0x1 << 12))));
    // AUD_WRITE32(REG_INT_DACCTL10,(AUD_READ32(REG_INT_DACCTL10) & ~PD_CTL_MASK)|PD_ON);
    IO_WRITE32(AUDIO_BASE,0x01e8, (IO_READ32(AUDIO_BASE,0x01e8)) & (~(0xff << 4)));
    // AUD_CLR_BIT(REG_INT_DACCTL10,PD_ISOURCE);
    IO_WRITE32(AUDIO_BASE,0x01e8, (IO_READ32(AUDIO_BASE,0x01e8)) & (~((0x1 << 26))));
    // AUD_CLR_BIT(REG_INT_DACCTL10,PD_REF3);
    // AUD_CLR_BIT(REG_INT_DACCTL10,PD_REF2);
    // AUD_CLR_BIT(REG_INT_DACCTL10,PD_REF1);
    // AUD_CLR_BIT(REG_INT_DACCTL10,PD_REF0);
    IO_WRITE32(AUDIO_BASE,0x01e8, (IO_READ32(AUDIO_BASE,0x01e8)) & (~((0xf << 12))));
	u4Val = PDWNC_ReadWakeupReason();

    #ifdef CC_QUIET_HOT_BOOT_SUPPORT
    if (u4Val == PDWNC_WAKE_UP_REASON_AC_POWER)
    {

        UNUSED(EEPDTV_GetCfg(&rDtvCfg));

        if (rDtvCfg.u1Flags & DTVCFG_FLAG_SYSTEM_STATE_ON)
        {
            Printf("\n[QHB] Previous system state is on, not enter QHB.\n");

            rDtvCfg.u1Flags4 &= (UINT8)~DTVCFG_FLAG4_QUIET_HOT_BOOT;
            prLoaderData->rDtvCfg.u1Flags4 &= (UINT8)~DTVCFG_FLAG4_QUIET_HOT_BOOT;
            UNUSED(EEPDTV_SetCfg(&rDtvCfg));
        }
        else
        {
            Printf("\n[QHB] Set QHB flag when AC on & Previous system state is off.\n");

            rDtvCfg.u1Flags4 |= (UINT8)DTVCFG_FLAG4_QUIET_HOT_BOOT;
            prLoaderData->rDtvCfg.u1Flags4 |= (UINT8)DTVCFG_FLAG4_QUIET_HOT_BOOT;
            UNUSED(EEPDTV_SetCfg(&rDtvCfg));
        }
    }
    #endif
	//set default value
	vIO32WriteFldAlign(CKGEN_REG_MSDCPAD_R0R1_CFG0, (IO32ReadFldAlign(CKGEN_REG_MSDCPAD_R0R1_CFG0,FLD_MSDCPAD_R0R1_CFG0)&0xFFFFF000), FLD_MSDCPAD_R0R1_CFG0);

	LOADER_EnableHdmiDdc();
}

#ifdef LOADER_USB_UPGRADE
#include "x_dlm.h"

#ifdef LOADER_MTK_UPGRADE
static INT32 LOADER_MtkAllUpgrade(DLM_ACCESS_T e_flag, UCHAR *pauc_buffer, INT32* ui4_len)
{
    static UINT32 u4Flag = 0;
    UINT32 u4ImageWriteAddr = 0;

    if (!u4Flag)
    {
        u4Flag = 1;
        return LDR_FlashWrite(e_flag, pauc_buffer, ui4_len, 1, u4ImageWriteAddr);
    }
    else
    {
        return LDR_FlashWrite(e_flag, pauc_buffer, ui4_len, 0, 0);
    }
}

static INT32 LOADER_MtkFirmUpgrade(DLM_ACCESS_T e_flag, UCHAR *pauc_buffer, INT32* ui4_len)
{
    static UINT32 u4Flag = 0;
    UINT32 u4ImageWriteAddr = LOADER_MAX_SIZE;

    if (!u4Flag)
    {
        u4Flag = 1;
        return LDR_FlashWrite(e_flag, pauc_buffer, ui4_len, 1, u4ImageWriteAddr);
    }
    else
    {
        return LDR_FlashWrite(e_flag, pauc_buffer, ui4_len, 0, 0);
    }
}
#endif

static INT32 _LdrEeepromUpgrade(DLM_ACCESS_T e_flag, UCHAR *pauc_buffer, INT32* pi4_len)
{
    UINT32  u4i=0;
    UINT32  u4MemLen=0;
    UINT32  u4DatBegin=0, u4MaskBegin=0;
    UINT8   uiTmp=0;
    UINT32  u4BufLen =0;

    #define EEPROM_SIZE_LEN 4

    if (NULL == pauc_buffer || NULL == pi4_len)
    {
        return DLM_OPEN_FILE_FAILED;
    }

    /* u4MemLen shoube be equal to EEPROM size */
    u4MemLen = GET_UINT32_FROM_PTR_LITTLE_END(pauc_buffer);

    u4BufLen = (UINT32)*pi4_len;

    if (u4BufLen != ((u4MemLen * 2) + EEPROM_SIZE_LEN))
    {
        LOG(0, "\n<NVM Upgrade>:The Buf Length=%d , mem_len=%d ERROR!!!!\n", u4BufLen, u4MemLen);
        return DLM_OPEN_FILE_FAILED;
    }

    u4DatBegin = EEPROM_SIZE_LEN;
    u4MaskBegin = u4MemLen + EEPROM_SIZE_LEN;

    for (u4i = 0; u4i < u4MemLen; u4i++)
    {
        if (pauc_buffer[u4i + u4MaskBegin] == 0)
        {
            continue;
        }

        if (pauc_buffer[u4i + u4MaskBegin] == 0xFF)
        {
            uiTmp = pauc_buffer[u4i+u4DatBegin];
        }
        else
        {
            EEPROM_Read((UINT64)(u4i), (UPTR) &uiTmp, 1);

            uiTmp = ((uiTmp & (~pauc_buffer[u4i+u4MaskBegin])) |
                     (pauc_buffer[u4DatBegin + u4i]& pauc_buffer[u4i + u4MaskBegin]));
        }

        EEPROM_Write((UINT64)(u4i), (UPTR) &uiTmp, 1);

        LOG(0, "<_LdrEepromUpgrade>: Offset:  0x%2x;  Write Data: 0x%2x\n", u4i, uiTmp);
    }
    return DLM_OK;
}

static void LOADER_MtkUpgradeDlmCbFunc(UINT32 u4BufSize)
{
    UNUSED(LOADER_MtkUpgradeDlmCbFunc);

    x_dlm_reg_append_callback((UCHAR *)"eepr", u4BufSize, _LdrEeepromUpgrade);
    #ifdef LOADER_MTK_UPGRADE
    x_dlm_reg_append_callback("all", u4BufSize, LOADER_MtkAllUpgrade);
    x_dlm_reg_append_callback("firm", u4BufSize, LOADER_MtkFirmUpgrade);
    #endif
    //x_dlm_reg_append_callback("nor1", u4BufSize, LOADER_MtkFirmUpgrade);
}

#endif  /* LOADER_USB_UPGRADE */
#endif /* CC_MTK_LOADER */



#if LED_BLINK_ENABLE
#if defined(CC_MTK_LOADER)//#ifdef CC_MTK_LOADER
static PFN_IRQ_HANDLER _pfnTimerLedIsr = NULL;

static void _LOADER_TimerOff(void)
{
    UINT32 u4Val;

    // disable timer 0
    u4Val = BIM_READ32(REG_RW_TIMER_CTRL);
    u4Val &= ~((TMR1_CNTDWN_EN) | (TMR1_AUTOLD_EN));
    BIM_WRITE32(REG_RW_TIMER_CTRL, u4Val);
}

static void _LOADER_TimerOn(void)
{
    UINT32 u4Val;

    // Enable timer 0
    u4Val = BIM_READ32(REG_RW_TIMER_CTRL);
    u4Val |= ((TMR1_CNTDWN_EN) | (TMR1_AUTOLD_EN));
    BIM_WRITE32(REG_RW_TIMER_CTRL, u4Val);
}



static void _LOADER_TimerIsr(void)
{
    static UINT32 _fgLed = 0;
    UINT32 i, u4Val, u4BlinkingLedGpio, u4BlinkingLedOnVal;

    if (BIM_IsIrqPending(VECTOR_T1))
    {
        if (DRVCUST_InitQuery(ePanelPowerGpio, &i) == 0)
        {
            UNUSED(DRVCUST_InitQuery(ePanelPowerOnVal, &u4Val));
            UNUSED(DRVCUST_InitQuery(eBootBlinkingLed, &u4BlinkingLedGpio));
//Led_blinking function is only enabled while panel has not been turned on
            if(1)//if(GPIO_GetIn(i) != u4Val)
            {
                _fgLed = !_fgLed;
                GPIO_SetOut(u4BlinkingLedGpio, _fgLed);
                //Printf("[LedBlinkikng] toggle..\n");
            }
            else//always turn on the led (it shoule be POWER LED in gerneal case)
            {
                UNUSED(DRVCUST_InitQuery(eBootBlinkingLedOnVal, &u4BlinkingLedOnVal));
                GPIO_SetOut(u4BlinkingLedGpio, u4BlinkingLedOnVal);
                _LOADER_TimerOff();
            }
        }
		HAL_ClrTimerIntr(VECTOR_T1);
        BIM_ClearIrq(VECTOR_T1);
    }

    if (_pfnTimerLedIsr) { _pfnTimerLedIsr(); }
}


static void _LOADER_InitGPIOTimer(void)
{
    UINT32 u4BusClock;
    UINT32 u4TimerClock;
    UINT32 u4LedBlinkingPeriod;
    if (DRVCUST_InitQuery(eBootBlinkingLedPeriod, &u4LedBlinkingPeriod) == 0)
    {
        _pfnTimerLedIsr = RegisterIrqHandler(_LOADER_TimerIsr);

#if 1 //#ifdef  CC_MT5387
        u4BusClock = GET_XTAL_CLK()/1000;
        u4TimerClock = u4BusClock;
#else
        u4BusClock = BSP_GetDomainClock(SRC_BUS_CLK);
        u4TimerClock = (UINT32)(u4BusClock / 1000);
#endif
        u4TimerClock *= u4LedBlinkingPeriod;
        //Printf("[LedBlinkikng] u4TimerClock is %d\n", u4TimerClock);
        // Setup Timer 0 and triger 1st interrupt.
        BIM_WRITE32(REG_RW_TIMER1_LLMT, u4TimerClock);
        BIM_WRITE32(REG_RW_TIMER1_HLMT, 0);
        BIM_WRITE32(REG_RW_TIMER1_LOW , u4TimerClock);
        BIM_WRITE32(REG_RW_TIMER1_HIGH, 0);

        _LOADER_TimerOff();

        BIM_EnableIrq(VECTOR_T1);

        HalEnableIRQ();
    }
}


#else
static HANDLE_T _hLedBlinkingTimer = NULL;
static void _LedBlinking_Task(HANDLE_T hHandle, VOID* pTag)
{
    static UINT32 _fgLed = 0;
    static UINT32 _StopBlinking = 0;
    UINT32 i, u4Val, u4BlinkingLedGpio, u4BlinkingLedOnVal;

    UNUSED(hHandle);
    UNUSED(pTag);
    if(_StopBlinking  == 1)
        return;
    if (DRVCUST_InitQuery(/*ePanelPowerGpio*/eBackLightGpio, &i) == 0)
    {
        UNUSED(DRVCUST_InitQuery(/*ePanelPowerOnVal*/eBackLightOnVal, &u4Val));
        UNUSED(DRVCUST_InitQuery(eBootBlinkingLed, &u4BlinkingLedGpio));
//Led_blinking function is only enabled while panel has not been turned on
        if((GPIO_Output(i, NULL) != u4Val) && (GPIO_Enable(i, NULL) == 1))
        {
            _fgLed = !_fgLed;
            GPIO_SetOut(u4BlinkingLedGpio, _fgLed);
             //Printf("[LdrLedBlinkikng Timer] Led toggle!\n");
        }
        else//always turn on the led (it shoule be POWER LED in gerneal case)
        {
             Printf("[LedBlinkikng] Panel is turned on, stop blinking led!!!\n");
            UNUSED(DRVCUST_InitQuery(eBootBlinkingLedOnVal, &u4BlinkingLedOnVal));
            GPIO_SetOut(u4BlinkingLedGpio, u4BlinkingLedOnVal);
            x_timer_stop(_hLedBlinkingTimer);
            VERIFY(x_timer_delete(_hLedBlinkingTimer) == OSR_OK);
            _hLedBlinkingTimer = NULL;
            _StopBlinking = 1;
        }
    }
}
#endif
#endif

static void GPIO_MtkLedCtrlFunc(LED_STATUS_T eLedStatus)
{
    UINT32 i;
    INT32 i4Val;
#if LED_BLINK_ENABLE
#ifndef CC_MTK_LOADER
    UINT32 u4LedBlinkingPeriod;
#endif
#endif

    switch(eLedStatus)
    {
    case eLedLoaderPowerOn:
        INIT_SET_GPIO(ePowerLedGpio, ePowerLedOnVal);
        INIT_SET_GPIO(eBackupLedGpio, eBackupLedOnVal);
#if LED_BLINK_ENABLE
#if defined(CC_MTK_LOADER)//#ifdef CC_MTK_LOADER
        if (DRVCUST_InitQuery(eFlagBootBlinkingLedSupport, &i) == 0)
        {
            Printf("[LdrLedBlinkikng] Start ot Init/Turn on timer!\n");
            _LOADER_InitGPIOTimer();
            _LOADER_TimerOn();
        }
        else
        {
            Printf("Not support [LdrLedBlinkikng]!!\n");
        }
#endif
#endif
        break;
    case eLedLoaderPowerOff:
        DOWN_SET_GPIO(eBackupLedGpio, eBackupLedOnVal);
        DOWN_SET_GPIO(ePowerLedGpio, ePowerLedOnVal);
        break;
    case eLedSystemPowerOn:
        INIT_SET_GPIO(ePowerLedGpio, ePowerLedOnVal);
        INIT_SET_GPIO(eBackupLedGpio, eBackupLedOnVal);

//start to blink led at tv stage
#if LED_BLINK_ENABLE
#ifndef CC_MTK_LOADER
        if (DRVCUST_InitQuery(eFlagBootBlinkingLedSupport, &i) == 0)
        {
            UNUSED(DRVCUST_InitQuery(eBootBlinkingLedPeriod, &u4LedBlinkingPeriod));
            if (x_timer_create(&_hLedBlinkingTimer) != OSR_OK)
            {
                Printf("[LedBlinkikng] Create timer fail !\n");
            }

            if (x_timer_start(_hLedBlinkingTimer, u4LedBlinkingPeriod, X_TIMER_FLAG_REPEAT,
                              _LedBlinking_Task, NULL) != OSR_OK)
            {
                Printf("[LedBlinkikng] Start timer fail !\n");
            }
        }
        else
        {
            Printf("Not support [LedBlinkikng]!!\n");
        }
#endif
#endif
        break;
    case eLedSystemPowerOff:
        DOWN_SET_GPIO(eBackupLedGpio, eBackupLedOnVal);
        DOWN_SET_GPIO(ePowerLedGpio, ePowerLedOnVal);
        break;
    case eLedDarkLed:
        INIT_SET_GPIO(eBackupLedGpio, eBackupLedDarkVal);
        INIT_SET_GPIO(ePowerLedGpio, ePowerLedDarkVal);
        break;
    case eLedIrOn:
        INIT_SET_GPIO(ePowerLedGpio, ePowerLedOnVal);
        INIT_SET_GPIO(eBackupLedGpio, eBackupLedOnVal);
        break;
    case eLedIrOff:
        DOWN_SET_GPIO(eBackupLedGpio, eBackupLedOnVal);
        DOWN_SET_GPIO(ePowerLedGpio, ePowerLedOnVal);
        break;
    case eLedVgaStandby:
        break;
    default:
        break;
    }
}

static void GPIO_MtkPowerOnFunc()
{
    UINT32 i,polarity;
    INT32 i4Val;
#ifdef CC_MTK_LOADER
    //Audio mute circuit mute in loader
    if (DRVCUST_InitQuery(eAudioMuteGpioNum, &i) == 0)
    {
        UNUSED(DRVCUST_InitQuery(eAudioMuteGpioPolarity, &polarity));
        GPIO_SetOut(i, polarity);
      	//GPIO_SetOut(204, 0);
    }

    GPIO_MtkLedCtrlFunc(eLedLoaderPowerOn);

    // release reset of Demod chip
    /*if (DRVCUST_InitQuery(eDemodResetGpio, &i) == 0)
    {
        GPIO_SetOut(i, 0);
        HAL_Delay_us(20000); //delay 20ms
        GPIO_SetOut(i, 1);
        Printf("Reset Demod GPIO=%x, 0->1\r\n",i);
    }*/

	//Reset WIFI dongle.
	if (DRVCUST_InitQuery(eResetWLanGpio, &i) == 0)
	{
		GPIO_SetOut(i, 0); //pull low to reset.
		HAL_Delay_us(15000); //delay 10ms
		GPIO_SetOut(i, 1); //pull high.
	}

#else /* CC_MTK_LOADER */
    UINT32 u4Val;
    if(sizeof(_gu4SysPinmuxInit))
    {
        for(u4Val = 0;u4Val < sizeof(_gu4SysPinmuxInit)/(sizeof(_gu4SysPinmuxInit[0])); u4Val++)
        {
            BSP_PinSet(_gu4SysPinmuxInit[u4Val][0], _gu4SysPinmuxInit[u4Val][1]);
        }
    }
    GPIO_MtkLedCtrlFunc(eLedSystemPowerOn);

    // Mute OSD before driver init.
    PMX_SetBg(0x00000000, FALSE);
    #ifdef CC_LOADER_LOGO_LONG_TIME
    #else
    IO_WRITE32(OSD_BASE, 0x208, IO_READ32(OSD_BASE, 0x208) & 0xffff00ffU);
    IO_WRITE32(OSD_BASE, 0x308, IO_READ32(OSD_BASE, 0x308) & 0xffff00ffU);
    #endif
    UNUSED(polarity);

#endif /* CC_MTK_LOADER */


	//Set Wukong DTMB Reset GPIO default value to low
	//GPIO_SetOut(159, 0);  //only for wukong!!!

    INIT_SET_GPIO(ePowerCtrlGpio, ePowerCtrlOnVal);
    INIT_SET_GPIO(eDvdCtrlGpio, eDvdCtrlOnVal);

}

static void GPIO_MtkPowerOffFunc(UINT32 u4PowerDownEn)
{
    UINT32 i, fgLedOff;
    INT32 i4Val, i4Ret;
    DTVCFG_T rDtvCfg;

    //load edid
#ifdef CC_MTK_LOADER
    LOADER_DisableHdmiDdc();
    vInternalEDIDInit();
    LOADER_EnableHdmiDdc();
    LOADER_HdmiHpdAll(TRUE);
#endif

#ifndef CC_MTK_LOADER
    //Printf("[AUD]turn off amp and codec in dc off case.\n");
    ADAC_GpioAmpEnable(FALSE);
    ADAC_GpioCodecMute(TRUE);
#endif

    if (DRVCUST_InitGet(eFlagSupportPowerLedOff))
    {
        i4Ret = EEPDTV_GetCfg(&rDtvCfg);
        if (i4Ret == 0)
        {
            fgLedOff = (rDtvCfg.u1Flags & DTVCFG_FLAG_POWER_LEDOFF) ? 1 : 0;
        }
        else
        {
            fgLedOff = 0;
        }
    }
    else
    {
        fgLedOff = 0;
    }

    if (!DRVCUST_InitGet(eSupportDarkLed))
    {
        if (!fgLedOff)
        {
#ifdef CC_MTK_LOADER
            GPIO_MtkLedCtrlFunc(eLedLoaderPowerOff);
#else /* CC_MTK_LOADER */
            GPIO_MtkLedCtrlFunc(eLedSystemPowerOff);
#endif /* CC_MTK_LOADER */
        }
    }

    DOWN_SET_GPIO(eBackLightGpio, eBackLightOnVal);
    DOWN_SET_GPIO(ePanelPowerGpio, ePanelPowerOnVal);
    DOWN_SET_GPIO(ePowerCtrlGpio, ePowerCtrlOnVal);
    DOWN_SET_GPIO(eDvdCtrlGpio, eDvdCtrlOnVal);

    if (DRVCUST_InitGet(eSupportDarkLed))
    {
        if (!(u4PowerDownEn & WAK_IRRX))
        {
            GPIO_MtkLedCtrlFunc(eLedDarkLed);
        }
        else
        {
#ifdef CC_MTK_LOADER
            GPIO_MtkLedCtrlFunc(eLedLoaderPowerOff);
#else /* CC_MTK_LOADER */
            GPIO_MtkLedCtrlFunc(eLedSystemPowerOff);
#endif /* CC_MTK_LOADER */
        }
    }

    //DOWN_SET_GPIO(eUSBVbus0Gpio, eUSBVbus0EnablePolarity);
    //DOWN_SET_GPIO(eUSBVbus1Gpio, eUSBVbus1EnablePolarity);
    //DOWN_SET_GPIO(eUSBVbus2Gpio, eUSBVbus2EnablePolarity);
    //DOWN_SET_GPIO(eUSBVbus3Gpio, eUSBVbus3EnablePolarity);

}

#else
#error "reinclude mtk_gpio.h..."
#endif

