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

/*-----------------------------------------------------------------------------
 *
 * $Author: zhenyu.shi $
 * $Date: 2015/07/31 $
 * $RCSfile: eeprom_if.c,v $
 * $Revision: #2 $
 *
 *---------------------------------------------------------------------------*/

/** @file eeprom_if.c
 *  This file is the implementation of EEPROM interface definition.
 */

//---------------------------------------------------------------------------
// Include files
//---------------------------------------------------------------------------
#include "x_lint.h"

LINT_EXT_HEADER_BEGIN

#include "storage_if.h"
#include "eeprom_if.h"
#include "nor_if.h"
#include "nor_debug.h"
#include "x_hal_5381.h"
#include "x_bim.h"
#include "x_pinmux.h"
#include "x_ldr_env.h"
#include "drvcust_if.h"
#include "eepdef.h"
#ifdef CC_NAND_ENABLE
#include "nand_if.h"
#endif
#ifdef CC_MSDC_ENABLE
#include "msdc_if.h"
#endif
#include "storage_if.h"
#include "hw_vdoin.h" //           MT5881,MT5399,MT5890,MT5882
#ifdef CC_MT5891
#include "drv_hdmi2.h"
#else
#include "drv_hdmi.h"
#include "hw_hdmi.h"
#endif
LINT_EXT_HEADER_END
//---------------------------------------------------------------------------
// Configurations
//---------------------------------------------------------------------------
#define EEPDTV_LOG_ENABLE           (0)

//---------------------------------------------------------------------------
// Constant definitions
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// Type definitions
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// Macro definitions

//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// Imported variables
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// Imported functions
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// Static function forward declarations
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// Static variables
//---------------------------------------------------------------------------
#ifdef CC_USE_PAPI
static const UINT8 _au1HDCP[320] =
{
    0x00 , 0x14 , 0x7c , 0xe6 , 0x2c , 0x37 , 0xf3 , 0xe8 , 0xa8 , 0x4d , 0x27 , 0x66 , 0xa8 , 0xd0 , 0x2f , 0x13,
    0x55 , 0x79 , 0x97 , 0xe7 , 0x87 , 0x37 , 0x18 , 0x04 , 0xd1 , 0x5f , 0x3b , 0x12 , 0x9f , 0x32 , 0xa4 , 0x6f,
    0x58 , 0x1c , 0x8a , 0xbc , 0x8c , 0x7f , 0xe3 , 0xcb , 0x81 , 0x9e , 0xb4 , 0x45 , 0x7c , 0x66 , 0x6a , 0xcc,
    0xdd , 0x5c , 0xc8 , 0x17 , 0xa3 , 0x90 , 0x43 , 0x91 , 0x8b , 0x01 , 0xf0 , 0x1d , 0xff , 0x8a , 0x1b , 0xde,
    0x94 , 0xd6 , 0xb6 , 0xf6 , 0x6d , 0x15 , 0x7b , 0x42 , 0x13 , 0xa2 , 0x1b , 0x04 , 0xb5 , 0xdd , 0x11 , 0xcc,
    0x42 , 0x28 , 0x66 , 0x65 , 0xf5 , 0x77 , 0xf1 , 0x65 , 0xc3 , 0x8c , 0x9b , 0x2c , 0xad , 0xb4 , 0xe9 , 0x7c,
    0xd1 , 0xbc , 0xd6 , 0x4a , 0x5d , 0xf7 , 0x45 , 0x3e , 0x2a , 0x22 , 0xec , 0xa8 , 0xdf , 0x68 , 0x54 , 0x57,
    0x5a , 0x10 , 0xc8 , 0x38 , 0x9f , 0x94 , 0xa0 , 0xa7 , 0xa0 , 0x71 , 0xa2 , 0x67 , 0x8e , 0x23 , 0xbd , 0x8d,
    0x63 , 0x89 , 0x0d , 0x01 , 0x91 , 0x97 , 0x4c , 0xba , 0x5c , 0x4d , 0x94 , 0x73 , 0x36 , 0x68 , 0x12 , 0x6c,
    0xe8 , 0xfa , 0xb1 , 0x51 , 0xc1 , 0x93 , 0xc6 , 0xce , 0x72 , 0x90 , 0xc1 , 0x6b , 0x4d , 0xf6 , 0x63 , 0x02,
    0xd3 , 0xa6 , 0x9b , 0x80 , 0x35 , 0xb6 , 0xa9 , 0xff , 0x8e , 0xfd , 0xd9 , 0x6f , 0x24 , 0xa6 , 0xdb , 0x4c,
    0xd2 , 0x0c , 0x0f , 0xcf , 0xcd , 0x1a , 0x19 , 0xe4 , 0x62 , 0x9c , 0x6d , 0x17 , 0x6b , 0x57 , 0x39 , 0xcb,
    0x6a , 0x0d , 0x80 , 0x75 , 0xfa , 0xf3 , 0x69 , 0x7d , 0x9f , 0x79 , 0xe3 , 0xc0 , 0x8b , 0x5a , 0xd2 , 0xa8,
    0xc9 , 0xd9 , 0x90 , 0x93 , 0xaa , 0xe6 , 0x1a , 0x1e , 0x17 , 0x93 , 0x03 , 0x2d , 0x43 , 0xc0 , 0xaf , 0x33,
    0x94 , 0x66 , 0xa9 , 0x18 , 0x55 , 0xcc , 0x22 , 0xf5 , 0x23 , 0xc8 , 0xc5 , 0x37 , 0xf1 , 0x81 , 0xd2 , 0x96,
    0xaf , 0x0a , 0x5a , 0xe5 , 0x8a , 0x13 , 0xef , 0x63 , 0x19 , 0x4c , 0xc6 , 0x3f , 0x6c , 0x9a , 0x7a , 0xb2,
    0xa6 , 0xd4 , 0x31 , 0x5a , 0x30 , 0x01 , 0x21 , 0xcd , 0xa2 , 0x86 , 0x74 , 0x04 , 0x46 , 0x3e , 0x38 , 0x08,
    0xe7 , 0x57 , 0xa7 , 0xb4 , 0x41 , 0x73 , 0x02 , 0x78 , 0x93 , 0x34 , 0x93 , 0xce , 0x93 , 0x5a , 0x46 , 0xd3,
    0x0a , 0x14 , 0xf7 , 0x61 , 0x03 , 0xb7 , 0x8f , 0x22 , 0xd2 , 0xf1 , 0x3a , 0x98 , 0xba , 0x28 , 0x62 , 0x53,
    0xca , 0x4c , 0x1d , 0x19 , 0xce , 0x49 , 0x87 , 0xf7 , 0xb5 , 0x26 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
};
#else
#if  !defined(CC_MTK_LOADER)
#ifndef HDMI_NO_INITHDCP
#ifndef CC_MT5891
static UINT8* _pu1HDCP;
#endif
#endif /* HDMI_NO_INITHDCP */
#endif /* !defined(CC_MTK_LOADER) */
#endif /* CC_USE_PAPI */

#ifdef CC_DISABLE_DTVCFG_FROM_EEP
static UINT32 _u4DTVCFGInit = 0;
DTVCFG_T rVirtualDtvCfg;
#endif

/// Eeprom multi-task protection semaphore.
#ifndef CC_MTK_LOADER
static HANDLE_T _hEepLockSema = NULL_HANDLE;
#endif

//---------------------------------------------------------------------------
// Static functions
//---------------------------------------------------------------------------
static UINT8 _EepDtvCalChecksum(const DTVCFG_T* prDtvCfg);
// Init Eeprom semaphore
void EEP_SEMA_Init(void)
{
#ifndef CC_MTK_LOADER
    VERIFY(x_sema_create(&_hEepLockSema, X_SEMA_TYPE_MUTEX, X_SEMA_STATE_UNLOCK) == OSR_OK);
#endif
}

// lock semaphore, wait semaphore
static VOID _EEP_Lock(VOID)
{
#ifndef CC_MTK_LOADER
    VERIFY(x_sema_lock(_hEepLockSema, X_SEMA_OPTION_WAIT) == OSR_OK);
#endif
}

// Unlock Eeprom semaphore, release semaphore
static VOID _EEP_Unlock(VOID)
{
#ifndef CC_MTK_LOADER
    VERIFY(x_sema_unlock(_hEepLockSema) == OSR_OK);
#endif
}

#ifdef CC_HDMI_2_0_HDCP_BIN
enum
{
	HDMI_EEP_PROM =0,
	HDMI_EEP_PRAM,
	HDMI_EEP_HDCP22,
	HDMI_EEP_HDCP14,
	HDMI_EEP_EDID20,
	HDMI_EEP_EDID14,
	MHL_EEP_EDID20,
	MHL_EEP_EDID30
};

UINT32 EEPHDMI_GetSize(UINT8 u1Type)
{
    if(u1Type == HDMI_EEP_EDID14)
    {
	    return FLASH_HDMI_1_4_EDID_SIZE;
    }
	else if(u1Type == HDMI_EEP_HDCP22)
	{
		return FLASH_HDMI_2_0_HDCP2_2_KEY_SIZE;
	}
	else if(u1Type == HDMI_EEP_HDCP14)
	{
		return FLASH_HDMI_1_4_HDCP1_4_KEY_SIZE;
	}
	else if(u1Type == HDMI_EEP_EDID20)
	{
		return FLASH_HDMI_2_0_EDID_SIZE;
	}
	else if(u1Type == MHL_EEP_EDID20)
	{
		return FLASH_MHL_2_0_EDID_SIZE;
	}
	else
	{
		return 0;
	}
}

INT32 EEPHDMI_Read(UINT32 u4PartID,UINT64 u8Offset, UINT32 u4MemPtr, UINT32 u4MemLen,UINT32 u4Size)
{
	INT32 i4Ret = 0;
	_EEP_Lock();

    if (u4MemLen > u4Size)
    {
        _EEP_Unlock();
		return 1;
    }
#if defined(CC_NAND_ENABLE)
		if (u4PartID > 1)
		{
			u8Offset |= (((UINT64)u4PartID) << 32);
			i4Ret = NANDPART_Read(u8Offset, u4MemPtr, u4MemLen);
			_EEP_Unlock();
			return i4Ret;
		}
#endif
#if defined(CC_MSDC_ENABLE) 
		if (u4PartID > 1)
		{
			u8Offset |= (((UINT64)u4PartID) << 32);
			#ifndef CC_UBOOT
			i4Ret = MSDCPART_Read(u8Offset, u4MemPtr, u4MemLen);
			#endif
			_EEP_Unlock();
			return i4Ret;
		}
#endif

    i4Ret = EEPROM_Read(u8Offset, u4MemPtr, u4MemLen);
    _EEP_Unlock();
	return i4Ret;
}

INT32 EEPHDMI_Write(UINT32 u2PartID,UINT64 u8Offset, UINT32 u4MemPtr, UINT32 u4MemLen,UINT32 u4Size)
{
	INT32 i4Ret = 0;
	_EEP_Lock();

	if (u4MemLen > u4Size)
	{
		_EEP_Unlock();
		return 1;
	}
#if defined(CC_NAND_ENABLE)
	if (u2PartID > 1)
	{
		u8Offset |= (((UINT64)u2PartID) << 32);
		i4Ret = NANDPART_Write(u8Offset, u4MemPtr, u4MemLen);
		_EEP_Unlock();
		return i4Ret;
	}
#endif
#if defined(CC_MSDC_ENABLE)
	if (u2PartID > 1)
	{
		u8Offset |= (((UINT64)u2PartID) << 32);
		#ifndef CC_UBOOT
		i4Ret = MSDCPART_Write(u8Offset, u4MemPtr, u4MemLen);
		#endif
		_EEP_Unlock();
		return i4Ret;
	}
#endif
	
	i4Ret = EEPROM_Write(u8Offset, u4MemPtr, u4MemLen);

	_EEP_Unlock();
	return i4Ret;
}
#endif
//---------------------------------------------------------------------------
// Inter-file functions
//---------------------------------------------------------------------------

#if  !defined(CC_MTK_LOADER)

//---------------------------------------------------------------------------
// Public functions
//---------------------------------------------------------------------------
//-------------------------------------------------------------------------
/** EEPNPTV_GetSize
 *  NPTV interface: get EEPROM device size.
 *  @param  VOID
 *  @return  device size in bytes.
 */
//-------------------------------------------------------------------------
INT32 EEPNPTV_GetSize(VOID)
{
    return (INT32)EEPROM_NPTV_DRIVER_SIZE;
}

//-------------------------------------------------------------------------
/** EEPNPTV_Read
 *  NPTV interface: EEPROM read function.
 *  @param  u8Offset 	begin address to read.
 *  @param  u4MemPtr 	user's buffer address.
 *  @param  u4MemLen 	read data length in bytes.
 *  @retval   0		SUCCESS.
 *  @retval   1		FAIL.
 */
//-------------------------------------------------------------------------
INT32 EEPNPTV_Read(UINT64 u8Offset, UINT32 u4MemPtr, UINT32 u4MemLen)
{
    INT32 i4Ret;

#ifdef EEP_RW_USED_STORAGE
    INT32 i4Ret1;
    STORG_DEV_T* prDev;
    UINT32 u4XferCnt = 0;
#endif
    _EEP_Lock();
    // check boundary.
    if ((u8Offset + u4MemLen) > EEPROM_NPTV_DRIVER_SIZE)
    {
        _EEP_Unlock();
        return 1;
    }

    // adjust offset to map to physical offset.
    u8Offset += EEPROM_NPTV_DRIVER_OFFSET;


#ifndef EEP_RW_USED_STORAGE
	i4Ret = EEPROM_Read(u8Offset, u4MemPtr, u4MemLen);
#else
    prDev = STORGOpenDev(STORG_FLAG_EEPROM);

    if (prDev == NULL)
    {
        _EEP_Unlock();
        return 1;
    }

    // send to storage task and do sync IO.
    i4Ret = STORGSendReq(prDev, STORG_OP_READ,
                         NULL, NULL,
                         NULL,
                         u8Offset, u4MemLen,
                         (void*)u4MemPtr, &u4XferCnt);

    if ((i4Ret) || (u4XferCnt != u4MemLen))
    {
        i4Ret = 1;
    }

    i4Ret1 = STORGCloseDev(prDev);
    UNUSED(i4Ret1);
#endif	
    _EEP_Unlock();
    return i4Ret;
}

//-------------------------------------------------------------------------
/** EEPNPTV_Write
 *  NPTV interface: EEPROM write function.
 *  @param  u8Offset 	begin address to write.
 *  @param  u4MemPtr 	user's buffer address.
 *  @param  u4MemLen 	writedata length in bytes.
 *  @retval   0		SUCCESS.
 *  @retval   1		FAIL.
 */
//-------------------------------------------------------------------------
INT32 EEPNPTV_Write(UINT64 u8Offset, UINT32 u4MemPtr, UINT32 u4MemLen)
{
    INT32 i4Ret;
#ifdef EEP_RW_USED_STORAGE
    INT32 i4Ret1;
    STORG_DEV_T* prDev;
    UINT32 u4XferCnt = 0;
#endif
    _EEP_Lock();
    // check boundary.
    if ((u8Offset + u4MemLen) > EEPROM_NPTV_DRIVER_SIZE)
    {
        _EEP_Unlock();
        return 1;
    }

    // adjust offset to map to physical offset.
    u8Offset += EEPROM_NPTV_DRIVER_OFFSET;
#ifndef EEP_RW_USED_STORAGE
    i4Ret = EEPROM_Write(u8Offset, u4MemPtr, u4MemLen);
#else	
    prDev = STORGOpenDev(STORG_FLAG_EEPROM);

    if (prDev == NULL)
    {
        _EEP_Unlock();
        return 1;
    }

    // send to storage task and do sync IO.
    i4Ret = STORGSendReq(prDev, STORG_OP_WRITE,
                         NULL, NULL,
                         NULL,
                         u8Offset, u4MemLen,
                         (void*)u4MemPtr, &u4XferCnt);

    if ((i4Ret) || (u4XferCnt != u4MemLen))
    {
        i4Ret = 1;
    }

    i4Ret1 = STORGCloseDev(prDev);
    UNUSED(i4Ret1);
#endif
    _EEP_Unlock();
    return i4Ret;
}

//-------------------------------------------------------------------------
/** EEPDTV_GetSize
 *  DTV interface: get EEPROM device size.
 *  @param  VOID
 *  @return  device size in bytes.
 */
//-------------------------------------------------------------------------
INT32 EEPDTV_GetSize(VOID)
{
    return (INT32)EEPROM_DTV_DRIVER_SIZE;
}
#ifdef EEP_RW_USED_STORAGE
//-------------------------------------------------------------------------
/** EEPDTV_Read
 *  DTV interface: EEPROM read function.
 *  @param  u8Offset 	begin address to read.
 *  @param  u4MemPtr 	user's buffer address.
 *  @param  u4MemLen 	read data length in bytes.
 *  @retval   0		SUCCESS.
 *  @retval   1		FAIL.
 */
//-------------------------------------------------------------------------
INT32 EEPDTV_Read(UINT64 u8Offset, UINT32 u4MemPtr, UINT32 u4MemLen)
{
    INT32 i4Ret;

#ifdef CC_DISABLE_DTVCFG_FROM_EEP
    _EEP_Lock();
    //Printf("CC_DISABLE_DTVCFG_FROM_EEP: EEPDTV_Read\n");
    i4Ret = 0;
    UNUSED(u8Offset);
    UNUSED(u4MemPtr);
    UNUSED(u4MemLen);
    if (u4MemLen != sizeof(DTVCFG_T))
    {
        Printf("Unknow EEPDTV_Read(%d)\n", u4MemLen);
        _EEP_Unlock();
        return 1;
    }
    if (_u4DTVCFGInit == 0)
    {
        // load default cfg
        //DTVCFG_T *prDtvCfg = (DTVCFG_T *)u4MemPtr;
        x_memset(&rVirtualDtvCfg, 0, sizeof(DTVCFG_T));
        rVirtualDtvCfg.u1Magic1 = DTVCFG_MAGIC_CHAR1;
        rVirtualDtvCfg.u1Magic2 = DTVCFG_MAGIC_CHAR2;
        rVirtualDtvCfg.u1Checksum = _EepDtvCalChecksum(&rVirtualDtvCfg);
        _u4DTVCFGInit = 1;
    }
    x_memcpy((void*)u4MemPtr, (void*)&rVirtualDtvCfg, u4MemLen);

#else // CC_DISABLE_DTVCFG_FROM_EEP

    INT32 i4Ret1;
    STORG_DEV_T* prDev;
    UINT32 u4XferCnt = 0;
    _EEP_Lock();

    // check boundary.
    if ((u8Offset + u4MemLen) > EEPROM_DTV_DRIVER_SIZE)
    {
        _EEP_Unlock();
        return 1;
    }

    // adjust offset to map to physical offset.
    u8Offset += EEPROM_DTV_DRIVER_OFFSET;

    prDev = STORGOpenDev(STORG_FLAG_EEPROM);

    if (prDev == NULL)
    {
        _EEP_Unlock();
        return 1;
    }

    // send to storage task and do sync IO.
    i4Ret = STORGSendReq(prDev, STORG_OP_READ,
                         NULL, NULL,
                         NULL,
                         u8Offset, u4MemLen,
                         (void*)u4MemPtr, &u4XferCnt);

    if ((i4Ret) || (u4XferCnt != u4MemLen))
    {
        i4Ret = 1;
    }

    i4Ret1 = STORGCloseDev(prDev);
    UNUSED(i4Ret1);

#if EEPDTV_LOG_ENABLE
    if (i4Ret == 0)
    {
        INT32 i;
        UINT8* au1Data;

        au1Data = (UINT8*)u4MemPtr;
        Printf("EEPDTV_Read(Off:0x%x, Cnt:%d) OK", (UINT32)((u8Offset - EEPROM_DTV_DRIVER_OFFSET) & 0xff), u4MemLen);
        for (i = 0; i < u4MemLen; i++)
        {
            if (i % 8 == 0)
            {
                Printf("\n0x%08x | 0x%02x", i + (UINT32)((u8Offset - EEPROM_DTV_DRIVER_OFFSET) & 0xff), au1Data[i]);
            }
            else
            {
                Printf(" 0x%02x", au1Data[i]);
            }
        }
        Printf("\n");
    }
    else
    {
        Printf("EEPDTV_Read(Off:0x%x, Cnt:%d) Fail\n", (UINT32)((u8Offset - EEPROM_DTV_DRIVER_OFFSET) & 0xff), u4MemLen);
    }
#endif /* EEPDTV_LOG_ENABLE */
#endif
    _EEP_Unlock();
    return i4Ret;
}

//-------------------------------------------------------------------------
/** EEPDTV_Write
 *  DTV interface: EEPROM write function.
 *  @param  u8Offset 	begin address to write.
 *  @param  u4MemPtr 	user's buffer address.
 *  @param  u4MemLen 	writedata length in bytes.
 *  @retval   0		SUCCESS.
 *  @retval   1		FAIL.
 */
//-------------------------------------------------------------------------
INT32 EEPDTV_Write(UINT64 u8Offset, UINT32 u4MemPtr, UINT32 u4MemLen)
{
    INT32 i4Ret;

#ifdef CC_DISABLE_DTVCFG_FROM_EEP
    //Printf("CC_DISABLE_DTVCFG_FROM_EEP: EEPDTV_Write\n");
    i4Ret = 0;
    UNUSED(u8Offset);
    UNUSED(u4MemPtr);
    UNUSED(u4MemLen);
    _EEP_Lock();

    x_memcpy((void*)&rVirtualDtvCfg, (void*)u4MemPtr, u4MemLen);
    _u4DTVCFGInit = 1;
#else

    INT32 i4Ret1;
    STORG_DEV_T* prDev;
    UINT32 u4XferCnt = 0;
    _EEP_Lock();

    // check boundary.
    if ((u8Offset + u4MemLen) > EEPROM_DTV_DRIVER_SIZE)
    {
        _EEP_Unlock();
        return 1;
    }

    // adjust offset to map to physical offset.
    u8Offset += EEPROM_DTV_DRIVER_OFFSET;

    prDev = STORGOpenDev(STORG_FLAG_EEPROM);

    if (prDev == NULL)
    {
        _EEP_Unlock();
        return 1;
    }

    // send to storage task and do sync IO.
    i4Ret = STORGSendReq(prDev, STORG_OP_WRITE,
                         NULL, NULL,
                         NULL,
                         u8Offset, u4MemLen,
                         (void*)u4MemPtr, &u4XferCnt);

    if ((i4Ret) || (u4XferCnt != u4MemLen))
    {
        i4Ret = 1;
    }

    i4Ret1 = STORGCloseDev(prDev);
    UNUSED(i4Ret1);

#if EEPDTV_LOG_ENABLE
    if (i4Ret == 0)
    {
        INT32 i;
        UINT8* au1Data;

        au1Data = (UINT8*)u4MemPtr;
        Printf("EEPDTV_Write(Off:0x%x, Cnt:%d) OK", (UINT32)((u8Offset - EEPROM_DTV_DRIVER_OFFSET) & 0xff), u4MemLen);
        for (i = 0; i < u4MemLen; i++)
        {
            if (i % 8 == 0)
            {
                Printf("\n0x%08x | 0x%02x", i + (UINT32)((u8Offset - EEPROM_DTV_DRIVER_OFFSET) & 0xff), au1Data[i]);
            }
            else
            {
                Printf(" 0x%02x", au1Data[i]);
            }
        }
        Printf("\n");
    }
    else
    {
        Printf("EEPDTV_Write(Off:0x%x, Cnt:%d) Fail\n", (UINT32)((u8Offset - EEPROM_DTV_DRIVER_OFFSET) & 0xff), u4MemLen);
    }
#endif /* EEPDTV_LOG_ENABLE */
#endif
    _EEP_Unlock();
    return i4Ret;
}
#endif
//-------------------------------------------------------------------------
/** EEPHDCP_Read
 *  HDCP interface: EEPROM read function.
 *  @param  u8Offset 	begin address to read.
 *  @param  u4MemPtr 	user's buffer address.
 *  @param  u4MemLen 	read data length in bytes.
 *  @retval   0		SUCCESS.
 *  @retval   1		FAIL.
 */
//-------------------------------------------------------------------------
INT32 EEPHDCP_Read(UINT64 u8Offset, UINT32 u4MemPtr, UINT32 u4MemLen)
{

#ifndef HDMI_NO_INITHDCP
    INT32 i4Ret;
    UINT8 u1SystemEEPROMDevBus, u1SystemEEPROMDevAddr, u1HdcpEEPROMDevBus, u1HdcpEEPROMDevAddr;
    _EEP_Lock();
#if defined(CC_SOEM_BOARD)
#if HDCP_WithSerialNum
    // check boundary.
    if ((u8Offset + u4MemLen) > ( EEPROM_HDMI_HDCP_SIZE + 20))
    {
        _EEP_Unlock();
        return 1;
    }
#endif
#else
    // check boundary.
    if ((u8Offset + u4MemLen) > EEPROM_HDMI_HDCP_SIZE)
    {
        _EEP_Unlock();
        return 1;
    }
#endif

#if defined(CC_NAND_ENABLE)
    // check if HDCP is stored in NAND
    i4Ret = (INT32)DRVCUST_OptGet(eHDCPNANDPartId);
    if (i4Ret > 1)
    {
        u8Offset |= (((UINT64)(UINT32)i4Ret) << 32);
        i4Ret = NANDPART_Read(u8Offset, u4MemPtr, u4MemLen);
        _EEP_Unlock();
        return i4Ret;
    }
#elif defined(CC_SAKURA_CUST_DRV)
#if defined(CC_MSDC_ENABLE)
    // check if HDCP is stored in eMMC
    i4Ret = (INT32)DRVCUST_OptGet(eHDCPNANDPartId);
    if (i4Ret > 1)
    {
        u8Offset |= (((UINT64)(UINT32)i4Ret) << 32);
        i4Ret = MSDCPART_Read(u8Offset, u4MemPtr, u4MemLen);
        _EEP_Unlock();
        return i4Ret;
    }
#endif
#else
    // check if HDCP is stored in NOR
#ifndef CC_NOR_DISABLE
    i4Ret = (INT32)DRVCUST_OptGet(eHDCPNorPartId);
    if (i4Ret > 1)
    {
        u8Offset |= (((UINT64)(UINT32)i4Ret) << 32);
        i4Ret = NORPART_Read(u8Offset, u4MemPtr, u4MemLen);
        _EEP_Unlock();
        return i4Ret;
    }
#endif
#endif
    u1SystemEEPROMDevBus = (UINT8) DRVCUST_InitGet(eSystemEepromBus);
    u1SystemEEPROMDevAddr = (UINT8) DRVCUST_InitGet(eSystemEepromAddress);
    u1HdcpEEPROMDevBus = (UINT8) DRVCUST_InitGet(eHdcpEepromBus);
    u1HdcpEEPROMDevAddr = (UINT8) DRVCUST_InitGet(eHdcpEepromAddress);

    u8Offset += (UINT64) DRVCUST_InitGet(eHdcpEepromOffset);

    // check if HDCP eeprom is the same as system eeprom
    if ((u1SystemEEPROMDevBus != u1HdcpEEPROMDevBus) ||
        (u1SystemEEPROMDevAddr != u1HdcpEEPROMDevAddr))
    {
        UINT16 u2HdcpEEPROMClkDiv;
        UINT32 u4HdcpEEPROMSize;

        u2HdcpEEPROMClkDiv = (UINT16) DRVCUST_InitGet(eHdcpEepromClkDiv);
        u4HdcpEEPROMSize = DRVCUST_InitGet(eHdcpEepromSize);

        _EEP_Unlock();
        return EEPROM_X_Read(u8Offset, u4MemPtr, u4MemLen,
                             u1HdcpEEPROMDevBus, u2HdcpEEPROMClkDiv, u1HdcpEEPROMDevAddr, u4HdcpEEPROMSize);
    }

    // adjust offset to map to physical offset.
    u8Offset += EEPROM_HDMI_HDCP_OFFSET;

    i4Ret = EEPROM_Read(u8Offset, u4MemPtr, u4MemLen);
    _EEP_Unlock();
    return i4Ret;
#else // HDMI_NO_INITHDCP
    return 0;
#endif // HDMI_NO_INITHDCP
}

//-------------------------------------------------------------------------
/** EEPHDCP_Write
 *  HDCP interface: EEPROM write function.
 *  @param  u8Offset 	begin address to write.
 *  @param  u4MemPtr 	user's buffer address.
 *  @param  u4MemLen 	writedata length in bytes.
 *  @retval   0		SUCCESS.
 *  @retval   1		FAIL.
 */
//-------------------------------------------------------------------------
INT32 EEPHDCP_Write(UINT64 u8Offset, UINT32 u4MemPtr, UINT32 u4MemLen)
{

#ifndef HDMI_NO_INITHDCP
    INT32 i4Ret;
    UINT8 u1SystemEEPROMDevBus, u1SystemEEPROMDevAddr, u1HdcpEEPROMDevBus, u1HdcpEEPROMDevAddr;
    _EEP_Lock();

#if defined(CC_SOEM_BOARD)
#if HDCP_WithSerialNum
    // check boundary.
    if ((u8Offset + u4MemLen) > ( EEPROM_HDMI_HDCP_SIZE + 20))
    {
        _EEP_Unlock();
        return 1;
    }
#endif
#else
    // check boundary.
    if ((u8Offset + u4MemLen) > EEPROM_HDMI_HDCP_SIZE)
    {
        _EEP_Unlock();
        return 1;
    }
#endif

#if defined(CC_NAND_ENABLE)
    // check if HDCP is stored in NOR
    i4Ret = (INT32)DRVCUST_OptGet(eHDCPNANDPartId);
    if (i4Ret > 1)
    {
        u8Offset |= (((UINT64)(UINT32)i4Ret) << 32);
        i4Ret = NANDPART_Write(u8Offset, u4MemPtr, u4MemLen);
        _EEP_Unlock();
        return i4Ret;
    }
#elif defined(CC_SAKURA_CUST_DRV)
#if defined(CC_MSDC_ENABLE)
    // check if HDCP is stored in eMMC
    i4Ret = (INT32)DRVCUST_OptGet(eHDCPNANDPartId);
    if (i4Ret > 1)
    {
        u8Offset |= (((UINT64)(UINT32)i4Ret) << 32);
        i4Ret = MSDCPART_Write(u8Offset, u4MemPtr, u4MemLen);
        _EEP_Unlock();
        return i4Ret;
    }
#endif
#else
    // check if HDCP is stored in NOR
#ifndef CC_NOR_DISABLE
    i4Ret = (INT32)DRVCUST_OptGet(eHDCPNorPartId);
    if (i4Ret > 1)
    {
        u8Offset |= (((UINT64)(UINT32)i4Ret) << 32);

        i4Ret = NORPART_Erase(u8Offset, 1);
        i4Ret |= NORPART_Write(u8Offset, u4MemPtr, u4MemLen);
        _EEP_Unlock();
        return i4Ret;
    }
#endif
#endif
    u1SystemEEPROMDevBus = (UINT8) DRVCUST_InitGet(eSystemEepromBus);
    u1SystemEEPROMDevAddr = (UINT8) DRVCUST_InitGet(eSystemEepromAddress);
    u1HdcpEEPROMDevBus = (UINT8) DRVCUST_InitGet(eHdcpEepromBus);
    u1HdcpEEPROMDevAddr = (UINT8) DRVCUST_InitGet(eHdcpEepromAddress);

    u8Offset += (UINT64) DRVCUST_InitGet(eHdcpEepromOffset);

    // check if HDCP eeprom is the same as system eeprom
    if ((u1SystemEEPROMDevBus != u1HdcpEEPROMDevBus) ||
        (u1SystemEEPROMDevAddr != u1HdcpEEPROMDevAddr))
    {
        UINT32 u4HdcpEEPROMWPGpio, u4HdcpEEPROMWPEnablePolarity;
        UINT32 u4HdcpEEPROMSize;
        UINT16 u2HdcpEEPROMClkDiv;

        u2HdcpEEPROMClkDiv = (UINT16) DRVCUST_InitGet(eHdcpEepromClkDiv);
        u4HdcpEEPROMSize = DRVCUST_InitGet(eHdcpEepromSize);

        if (0 == DRVCUST_InitQuery(eHdcpEepromWPGpio, &u4HdcpEEPROMWPGpio) &&
            (0 == DRVCUST_InitQuery(eHdcpEepromWPEnablePolarity, &u4HdcpEEPROMWPEnablePolarity)))
        {
            _EEP_Unlock();
            return EEPROM_X_Write(u8Offset, u4MemPtr, u4MemLen,
                                  u1HdcpEEPROMDevBus, u2HdcpEEPROMClkDiv, u1HdcpEEPROMDevAddr, u4HdcpEEPROMSize,
                                  (INT32)u4HdcpEEPROMWPGpio, (INT32)u4HdcpEEPROMWPEnablePolarity);
        }
        else
        {
            _EEP_Unlock();
            return EEPROM_X_Write(u8Offset, u4MemPtr, u4MemLen,
                                  u1HdcpEEPROMDevBus, u2HdcpEEPROMClkDiv, u1HdcpEEPROMDevAddr, u4HdcpEEPROMSize,
                                  -1, -1);
        }
    }

    // adjust offset to map to physical offset.
    u8Offset += EEPROM_HDMI_HDCP_OFFSET;

    i4Ret = EEPROM_Write(u8Offset, u4MemPtr, u4MemLen);

    _EEP_Unlock();
    return i4Ret;
#else // HDMI_NO_INITHDCP

    return 0;
#endif // HDMI_NO_INITHDCP
}

//-------------------------------------------------------------------------
/** EEPHDCP2x_Read
 *  HDCP interface: EEPROM read function.
 *  @param  u8Offset 	begin address to read.
 *  @param  u4MemPtr 	user's buffer address.
 *  @param  u4MemLen 	read data length in bytes.
 *  @retval   0		SUCCESS.
 *  @retval   1		FAIL.
 */
//-------------------------------------------------------------------------
INT32 EEPHDCP2x_Read(UINT64 u8Offset, UINT32 u4MemPtr, UINT32 u4MemLen)
{
    INT32 i4Ret;
    _EEP_Lock();

    // check boundary.
    if ((u8Offset + u4MemLen) > EEPROM_HDCP2X_SIZE)
    {
        _EEP_Unlock();
        return 1;
    }
#if defined(CC_NAND_ENABLE) && defined(CUST_SOEM_DRV)
    // check if HDCP is stored in NAND
    i4Ret = (INT32)DRVCUST_OptGet(eHDCP2xNANDPartId);
    if (i4Ret > 1)
    {
        u8Offset |= (((UINT64)(UINT32)i4Ret) << 32);
        i4Ret = NANDPART_Read(u8Offset, u4MemPtr, u4MemLen);
        _EEP_Unlock();
        return i4Ret;
    }
#endif
#if defined(CC_MSDC_ENABLE) && defined(CC_SAKURA_CUST_DRV)
    // check if HDCP is stored in eMMC
    i4Ret = (INT32)DRVCUST_OptGet(eHDCP2xNANDPartId);
    if (i4Ret > 1)
    {
        u8Offset |= (((UINT64)(UINT32)i4Ret) << 32);
        i4Ret = MSDCPART_Read(u8Offset, u4MemPtr, u4MemLen);
        _EEP_Unlock();
        return i4Ret;
    }
#endif
    // adjust offset to map to physical offset.
    u8Offset += EEPROM_HDCP2X_OFFSET;

    i4Ret = EEPROM_Read(u8Offset, u4MemPtr, u4MemLen);

    _EEP_Unlock();
    return i4Ret;
}


//-------------------------------------------------------------------------
/** EEPHDCP2x_Write
 *  HDCP interface: EEPROM write function.
 *  @param  u8Offset 	begin address to write.
 *  @param  u4MemPtr 	user's buffer address.
 *  @param  u4MemLen 	writedata length in bytes.
 *  @retval   0		SUCCESS.
 *  @retval   1		FAIL.
 */
//-------------------------------------------------------------------------
INT32 EEPHDCP2x_Write(UINT64 u8Offset, UINT32 u4MemPtr, UINT32 u4MemLen)
{
    INT32 i4Ret;
    _EEP_Lock();

    // check boundary.
    if ((u8Offset + u4MemLen) > EEPROM_HDCP2X_SIZE)
    {
        _EEP_Unlock();
        return 1;
    }
#if defined(CC_NAND_ENABLE)&& defined(CUST_SOEM_DRV)
    // check if HDCP is stored in NOR
    i4Ret = (INT32)DRVCUST_OptGet(eHDCP2xNANDPartId);
    if (i4Ret > 1)
    {
        u8Offset |= (((UINT64)(UINT32)i4Ret) << 32);
        i4Ret = NANDPART_Write(u8Offset, u4MemPtr, u4MemLen);
        _EEP_Unlock();
        return i4Ret;
    }
#endif
#if defined(CC_MSDC_ENABLE)&& defined(CC_SAKURA_CUST_DRV)
    // check if HDCP is stored in eMMC
    i4Ret = (INT32)DRVCUST_OptGet(eHDCP2xNANDPartId);
    if (i4Ret > 1)
    {
        u8Offset |= (((UINT64)(UINT32)i4Ret) << 32);
        i4Ret = MSDCPART_Write(u8Offset, u4MemPtr, u4MemLen);
        _EEP_Unlock();
        return i4Ret;
    }
#endif
    // adjust offset to map to physical offset.
    u8Offset += EEPROM_HDCP2X_OFFSET;

    i4Ret = EEPROM_Write(u8Offset, u4MemPtr, u4MemLen);

    _EEP_Unlock();
    return i4Ret;
}


#ifdef CC_HDMI_2_0_HDCP_BIN
INT32 EEPHDMI20HDCP22_Write(UINT32 u4MemPtr, UINT32 u4MemLen)
{
	UINT32 u4Ret;
	UINT64 u8Offset;
	u4Ret = (UINT32)DRVCUST_InitGet(eHDMI20HDCPNANDPartId);

	if(u4Ret == 0)
	{
		u8Offset = EEPROM_HDMI_HDCP22_OFFSET;
	}
	else
	{
		u8Offset = (UINT64)DRVCUST_OptGet(eHDMI20HDCP22NANDOffSet);
	}
	
	return EEPHDMI_Write(u4Ret,u8Offset,u4MemPtr,u4MemLen,EEPHDMI_GetSize(HDMI_EEP_HDCP22));
}

INT32 EEPHDMI20HDCP14_Write(UINT32 u4MemPtr, UINT32 u4MemLen)
{
	UINT32 u4Ret;
	UINT64 u8Offset;
#ifdef CC_MT5891
	u4Ret = (UINT32)DRVCUST_OptGet(eHDMI14HDCPNANDPartId);
#else
    u4Ret = (UINT32)DRVCUST_InitGet(eHDMI20HDCPNANDPartId);
#endif

	if(u4Ret == 0)
	{
		u8Offset = EEPROM_HDMI_HDCP14_OFFSET;
	}
	else
	{
		u8Offset = (UINT64)DRVCUST_OptGet(eHDMI14HDCP14NANDOffSet);
	}

	return EEPHDMI_Write(u4Ret,u8Offset,u4MemPtr,u4MemLen,EEPHDMI_GetSize(HDMI_EEP_HDCP14));
}

INT32 EEPHDMI20HDCP14_Read(UINT32 u4MemPtr, UINT32 u4MemLen)
{
	UINT32 u4Ret;
	UINT64 u8Offset;
#ifdef CC_MT5891
	u4Ret = (UINT32)DRVCUST_OptGet(eHDMI14HDCPNANDPartId);
#else
    u4Ret = (UINT32)DRVCUST_InitGet(eHDMI20HDCPNANDPartId);
#endif
	
	if(u4Ret == 0)
	{
		u8Offset = EEPROM_HDMI_HDCP14_OFFSET;
	}
	else
	{
		u8Offset = (UINT64)DRVCUST_OptGet(eHDMI14HDCP14NANDOffSet);
	}
	
	return EEPHDMI_Read(u4Ret,u8Offset,u4MemPtr,u4MemLen,EEPHDMI_GetSize(HDMI_EEP_HDCP14));
}

INT32 EEPHDMI14EDID_Write(UINT32 u4MemPtr, UINT32 u4MemLen)
{
	UINT32 u4Ret;
	UINT64 u8Offset;
	u4Ret = (UINT32)DRVCUST_InitGet(eHDMI14EDIDNANDPartId);
	if(u4Ret != 0)
	{
		u8Offset = (UINT64)DRVCUST_OptGet(eHDMI14EDIDNANDOffSet);		
	}
	else
	{
		u8Offset = EEPROM_HDMI_EDID14_OFFSET;
	}

	return EEPHDMI_Write(u4Ret,u8Offset,u4MemPtr,u4MemLen,EEPHDMI_GetSize(HDMI_EEP_EDID14));
}

INT32 EEPHDMI20EDID_Write(UINT32 u4MemPtr, UINT32 u4MemLen)
{
	UINT32 u4Ret;
	UINT64 u8Offset;
	u4Ret = (UINT32)DRVCUST_InitGet(eHDMI20EDIDNANDPartId);
	if(u4Ret != 0)
	{
		u8Offset = (UINT64)DRVCUST_OptGet(eHDMI20EDIDNANDOffSet);
		
		if(u8Offset < 1)
		{
			u4Ret =0;
			u8Offset += EEPROM_HDMI_EDID20_OFFSET;
		}
	}
	else
	{
		u8Offset = EEPROM_HDMI_EDID20_OFFSET;
	}

	return EEPHDMI_Write(u4Ret,u8Offset,u4MemPtr,u4MemLen,EEPHDMI_GetSize(HDMI_EEP_EDID20));
}
INT32 EEPMHL20EDID_Write(UINT32 u4MemPtr, UINT32 u4MemLen)
{
	UINT32 u4Ret;
	UINT64 u8Offset;
	u4Ret = (UINT32)DRVCUST_InitGet(eHDMI20EDIDNANDPartId);

	if(u4Ret != 0)
	{
		u8Offset = (UINT64)DRVCUST_OptGet(eMHL20EDIDNANDOffsSet);
		if(u8Offset < 1)
		{
			u4Ret =0; //from EEPROM
			u8Offset += EEPROM_HDMI_MHL_EDID_OFFSET;
		}
	}
	else
	{
		u8Offset = EEPROM_HDMI_MHL_EDID_OFFSET;
	}
	
	return EEPHDMI_Write(u4Ret,u8Offset,u4MemPtr,u4MemLen,EEPHDMI_GetSize(MHL_EEP_EDID20));
}
#endif

//-------------------------------------------------------------------------
/** EEPHDCP_SetSram
 *  HDCP interface: Turn on/off interanl HDCP slave enable bit
 *  @param  u4On 	1: HDMI will access internal SRAM.
 *                             0: HDMI will access external EEPROM.
 *  @param  u4DevAddr  internal HDCP Slave device address.
 *  @retval   0		SUCCESS.
 *  @retval   1		FAIL.
 */
//-------------------------------------------------------------------------
INT32 EEPHDCP_SetSramDevice(UINT32 u4On, UINT32 u4DevAddr)
{
#ifndef CC_MT5891
#ifndef HDMI_NO_INITHDCP
    UINT32 u4Data;
    _EEP_Lock();

    if (u4On)
    {
        // device address only 8 bits.
        if ((u4DevAddr > 0x100) || (u4DevAddr < 2))
        {
            _EEP_Unlock();
            return 1;
        }

        u4Data = 0x100 | u4DevAddr;

#if 1
		/*
			For IC: MT5396 ,MT5368, MT5389 ,MT5398,MT5880 ,
			MT5881,MT5399,MT5890,MT5882
		*/
        // en/adr
        vIO32Write4B(HDCP_DEV0, u4Data);
        vIO32Write4B(HDCP_DEV1, u4Data);
        vIO32Write4B(HDCP_DEV2, u4Data);
        vIO32Write4B(HDCP_DEV3, u4Data);
        // kskm
        vRegWrite4B((EPST + 0xc00), 0xff001800);
        vRegWrite4B((KS_MASK + 0xc00), 0x000000C3);
        vRegWrite4B((EPST + 0x800), 0xff001800);
        vRegWrite4B((KS_MASK + 0x800), 0x000000C3);
        vRegWrite4B((EPST + 0x400), 0xff001800);
        vRegWrite4B((KS_MASK + 0x400), 0x000000C3);
        vRegWrite4B(EPST, 0xff001800);
        vRegWrite4B(KS_MASK, 0x000000C3);
        // reload KSV
        vRegWrite4BMsk((EPST + 0xc00), Fld2Msk32(LD_KSV), Fld2Msk32(LD_KSV));
        vRegWrite4BMsk((EPST + 0x800), Fld2Msk32(LD_KSV), Fld2Msk32(LD_KSV));
        vRegWrite4BMsk((EPST + 0x400), Fld2Msk32(LD_KSV), Fld2Msk32(LD_KSV));
        vRegWrite4BMsk(EPST, Fld2Msk32(LD_KSV), Fld2Msk32(LD_KSV));
        vRegWrite4BMsk((EPST + 0xc00), 0, Fld2Msk32(LD_KSV));
        vRegWrite4BMsk((EPST + 0x800), 0, Fld2Msk32(LD_KSV));
        vRegWrite4BMsk((EPST + 0x400), 0, Fld2Msk32(LD_KSV));
        vRegWrite4BMsk(EPST, 0, Fld2Msk32(LD_KSV));
        // HDCP rst
        vRegWrite4BMsk((SRST + 0xc00), Fld2Msk32(HDCP_RST), Fld2Msk32(HDCP_RST));
        vRegWrite4BMsk((SRST + 0xc00), 0, Fld2Msk32(HDCP_RST));
        vRegWrite4BMsk((SRST + 0x800), Fld2Msk32(HDCP_RST), Fld2Msk32(HDCP_RST));
        vRegWrite4BMsk((SRST + 0x800), 0, Fld2Msk32(HDCP_RST));
        vRegWrite4BMsk((SRST + 0x400), Fld2Msk32(HDCP_RST), Fld2Msk32(HDCP_RST));
        vRegWrite4BMsk((SRST + 0x400), 0, Fld2Msk32(HDCP_RST));
        vRegWrite4BMsk(SRST, Fld2Msk32(HDCP_RST), Fld2Msk32(HDCP_RST));
        vRegWrite4BMsk(SRST, 0, Fld2Msk32(HDCP_RST));
        // ddc en
        vRegWrite1B((SYS_CTRL_1 + 0xc00), 0x95);
        vRegWrite1B((SYS_CTRL_1 + 0x800), 0x95);
        vRegWrite1B((SYS_CTRL_1 + 0x400), 0x95);
        vRegWrite1B(SYS_CTRL_1, 0x95);
#else
        IO_WRITE32(BIM_BASE, REG_RW_HDCP_DEV, u4Data);
#endif
    }
    else
    {
#if 1
        u4Data = u4IO32Read4B(HDCP_DEV0);
		/*
			For IC: MT5396 ,MT5368, MT5389 ,MT5398,MT5880 ,
			MT5881,MT5399,MT5890,MT5882
		*/
#else
        u4Data = IO_READ32(BIM_BASE, REG_RW_HDCP_DEV);
#endif

        u4Data &= ~0x100;

#if 1
        vIO32Write4B(HDCP_DEV0, u4Data);
        vIO32Write4B(HDCP_DEV1, u4Data);
        vIO32Write4B(HDCP_DEV2, u4Data);
        vIO32Write4B(HDCP_DEV3, u4Data);
		/*
			For IC: MT5396 ,MT5368, MT5389 ,MT5398,MT5880 ,
			MT5881,MT5399,MT5890,MT5882
		*/
#else
        IO_WRITE32(BIM_BASE, REG_RW_HDCP_DEV, u4Data);
#endif
    }
    _EEP_Unlock();
#endif // HDMI_NO_INITHDCP
#endif
    return 0;
}

//-------------------------------------------------------------------------
/** EEPHDCP_Init
 *  HDCP interface: load EEPROM HDCP content to internal HDCP SRAM.
 *  @param  void.
 *  @retval   0		SUCCESS.
 *  @retval   1		FAIL.
 */
//-------------------------------------------------------------------------
INT32 EEPHDCP_Init(void)
{
#ifndef CC_MT5891
#ifndef HDMI_NO_INITHDCP
    INT32 i4Ret;

    UINT32 i;
    UINT32 u4Data;
#ifdef CC_USE_PAPI
    // write to hdcp sram pointer.
    IO_WRITE32(BIM_BASE, REG_RW_HDCP_ADDR, 0);

    printk("EEPHDCP_Init using pre-defined array!\n");
    for (i = 0; i < EEPROM_HDMI_HDCP_SIZE; i = i + 4)
    {
        u4Data = *(UINT32*)(&_au1HDCP[i]);

        // write to hdcp sram pointer.
        IO_WRITE32(BIM_BASE, REG_RW_HDCP_DATA, u4Data);
    }
#else
    UINT8* pu1Ptr;

    // write to hdcp sram pointer.
#if 1
	/*
		For IC: MT5396 ,MT5368, MT5389 ,MT5398,MT5880 ,
		MT5881,MT5399,MT5890,MT5882
	*/
    vIO32Write4B(HDCP_ADDR, 0);
#else
    IO_WRITE32(BIM_BASE, REG_RW_HDCP_ADDR, 0);
#endif

    _pu1HDCP = x_mem_alloc(EEPROM_HDMI_HDCP_SIZE + 4);
    if (!_pu1HDCP)
    {

        return 1;
    }
    pu1Ptr = (UINT8*)(((((UINT32)_pu1HDCP - 1) >> 2) << 2) + 0x4);
    // read hdcp from eeprom.
    i4Ret = EEPHDCP_Read((UINT64)0, (UINT32)pu1Ptr, EEPROM_HDMI_HDCP_SIZE);
    if (i4Ret)
    {
        x_mem_free(_pu1HDCP);

        return 1;
    }
    for (i = 0; i < EEPROM_HDMI_HDCP_SIZE; i = i + 4)
    {
        u4Data = *(UINT32*)(&pu1Ptr[i]);

        // write to hdcp sram pointer.
#if 1
        vIO32Write4B(HDCP_DATA, u4Data);
		/*
			For IC: MT5396 ,MT5368, MT5389 ,MT5398,MT5880 ,
			MT5881,MT5399,MT5890,MT5882
		*/
#else
        IO_WRITE32(BIM_BASE, REG_RW_HDCP_DATA, u4Data);
#endif
    }
#ifdef CC_SUPPORT_STR
    for (i = 0; i < EEPROM_HDMI_HDCP_SIZE; i++)
    {
        _au1ResumeHDCP[i] = *(UINT8*)(&pu1Ptr[i]);
    }
#endif
    x_mem_free(_pu1HDCP);
#endif /* CC_USE_PAPI */
#endif // HDMI_NO_INITHDCP
#endif
    return 0;
}
#endif /* CC_MTK_LOADER */
#if defined(CC_MTK_LOADER) || !defined(EEP_RW_USED_STORAGE)
// Here is loader's eeprom dtvcfg access function.
INT32 EEPDTV_Read(UINT64 u8Offset, UINT32 u4MemPtr, UINT32 u4MemLen)
{
    INT32 i4Ret;
    _EEP_Lock();
#ifdef CC_DISABLE_DTVCFG_FROM_EEP
    //Printf("CC_DISABLE_DTVCFG_FROM_EEP: EEPDTV_Read\n");
    i4Ret = 0;
    UNUSED(u8Offset);
    UNUSED(u4MemPtr);
    UNUSED(u4MemLen);
    if (u4MemLen != sizeof(DTVCFG_T))
    {
        Printf("Unknow EEPDTV_Read(%d)\n", u4MemLen);
        _EEP_Unlock();
        return 1;
    }
    if (_u4DTVCFGInit == 0)
    {
        // load default cfg
        //DTVCFG_T *prDtvCfg = (DTVCFG_T *)u4MemPtr;
        x_memset(&rVirtualDtvCfg, 0, sizeof(DTVCFG_T));
        rVirtualDtvCfg.u1Magic1 = DTVCFG_MAGIC_CHAR1;
        rVirtualDtvCfg.u1Magic2 = DTVCFG_MAGIC_CHAR2;
        rVirtualDtvCfg.u1Checksum = _EepDtvCalChecksum(&rVirtualDtvCfg);
        _u4DTVCFGInit = 1;
    }
    x_memcpy((void*)u4MemPtr, (void*)&rVirtualDtvCfg, u4MemLen);

#else // CC_DISABLE_DTVCFG_FROM_EEP
    // check boundary.
    if ((u8Offset + u4MemLen) > EEPROM_DTV_DRIVER_SIZE)
    {
        _EEP_Unlock();
        return 1;
    }

    // adjust offset to map to physical offset.
    u8Offset += EEPROM_DTV_DRIVER_OFFSET;

    i4Ret = EEPROM_Read(u8Offset, u4MemPtr, u4MemLen);

#if EEPDTV_LOG_ENABLE
    if (i4Ret == 0)
    {
        INT32 i;
        UINT8* au1Data;

        au1Data = (UINT8*)u4MemPtr;
        Printf("EEPDTV_Read(Off:0x%x, Cnt:%d) OK", (UINT32)((u8Offset - EEPROM_DTV_DRIVER_OFFSET) & 0xff), u4MemLen);
        for (i = 0; i < u4MemLen; i++)
        {
            if (i % 8 == 0)
            {
                Printf("\n0x%08x | 0x%02x", i + (UINT32)((u8Offset - EEPROM_DTV_DRIVER_OFFSET) & 0xff), au1Data[i]);
            }
            else
            {
                Printf(" 0x%02x", au1Data[i]);
            }
        }
        Printf("\n");
    }
    else
    {
        Printf("EEPDTV_Read(Off:0x%x, Cnt:%d) Fail\n", (UINT32)((u8Offset - EEPROM_DTV_DRIVER_OFFSET) & 0xff), u4MemLen);
    }
#endif /* EEPDTV_LOG_ENABLE */
#endif  // CC_DISABLE_DTVCFG_FROM_EEP

    _EEP_Unlock();
    return i4Ret;
}

INT32 EEPDTV_Write(UINT64 u8Offset, UINT32 u4MemPtr, UINT32 u4MemLen)
{
    INT32 i4Ret;
    _EEP_Lock();
#ifdef CC_DISABLE_DTVCFG_FROM_EEP
    //Printf("CC_DISABLE_DTVCFG_FROM_EEP: EEPDTV_Write\n");
    i4Ret = 0;
    UNUSED(u8Offset);
    UNUSED(u4MemPtr);
    UNUSED(u4MemLen);

    x_memcpy((void*)&rVirtualDtvCfg, (void*)u4MemPtr, u4MemLen);
    _u4DTVCFGInit = 1;
#else
    // check boundary.
    if ((u8Offset + u4MemLen) > EEPROM_DTV_DRIVER_SIZE)
    {
        _EEP_Unlock();
        return 1;
    }

    // adjust offset to map to physical offset.
    u8Offset += EEPROM_DTV_DRIVER_OFFSET;

    i4Ret = EEPROM_Write(u8Offset, u4MemPtr, u4MemLen);

#if EEPDTV_LOG_ENABLE
    if (i4Ret == 0)
    {
        INT32 i;
        UINT8* au1Data;

        au1Data = (UINT8*)u4MemPtr;
        Printf("EEPDTV_Write(Off:0x%x, Cnt:%d) OK", (UINT32)((u8Offset - EEPROM_DTV_DRIVER_OFFSET) & 0xff), u4MemLen);
        for (i = 0; i < u4MemLen; i++)
        {
            if (i % 8 == 0)
            {
                Printf("\n0x%08x | 0x%02x", i + (UINT32)((u8Offset - EEPROM_DTV_DRIVER_OFFSET) & 0xff), au1Data[i]);
            }
            else
            {
                Printf(" 0x%02x", au1Data[i]);
            }
        }
        Printf("\n");
    }
    else
    {
        Printf("EEPDTV_Write(Off:0x%x, Cnt:%d) Fail\n", (UINT32)((u8Offset - EEPROM_DTV_DRIVER_OFFSET) & 0xff), u4MemLen);
    }
#endif /* EEPDTV_LOG_ENABLE */
#endif

    _EEP_Unlock();
    return i4Ret;
}
#endif /* CC_MTK_LOADER */

#ifdef CC_HDMI_2_0_HDCP_BIN
INT32 EEPHDMI20HDCP22_Read(UINT32 u4MemPtr, UINT32 u4MemLen)
{
	UINT32 u4Ret;
	UINT64 u8Offset;
	u4Ret = (UINT32)DRVCUST_InitGet(eHDMI20HDCPNANDPartId);

	if(u4Ret == 0)
	{
		u8Offset = EEPROM_HDMI_HDCP22_OFFSET;
	}
	else
	{
		u8Offset = (UINT64)DRVCUST_InitGet(eHDMI20HDCP22NANDOffSet);
	}
	
	return EEPHDMI_Read(u4Ret,u8Offset,u4MemPtr,u4MemLen,EEPHDMI_GetSize(HDMI_EEP_HDCP22));
}

#ifndef CC_HDMI_EDID_DISABLE

INT32 EEPHDMI14EDID_Read(UINT32 u4MemPtr, UINT32 u4MemLen)
{
 	UINT32 u4Ret;
	UINT64 u8Offset;
	u4Ret = (UINT32)DRVCUST_InitGet(eHDMI14EDIDNANDPartId);
	if(u4Ret != 0)
	{
		u8Offset = DRVCUST_InitGet(eHDMI14EDIDNANDOffSet);
	}
	else
	{
		u8Offset = EEPROM_HDMI_EDID14_OFFSET;
	}

	
	return EEPHDMI_Read(u4Ret,u8Offset,u4MemPtr,u4MemLen,EEPHDMI_GetSize(HDMI_EEP_EDID14));
}

INT32 EEPHDMI20EDID_Read(UINT32 u4MemPtr, UINT32 u4MemLen)
{
 	UINT32 u4Ret;
	UINT64 u8Offset;
	u4Ret = (UINT32)DRVCUST_InitGet(eHDMI20EDIDNANDPartId);
	if(u4Ret != 0)
	{
		u8Offset = DRVCUST_InitGet(eHDMI20EDIDNANDOffSet);
		if(u8Offset == 0)
		{
			u4Ret =0;
			u8Offset += EEPROM_HDMI_EDID20_OFFSET;
		}
	}
	else
	{
		u8Offset = EEPROM_HDMI_EDID20_OFFSET;
	}

	
	return EEPHDMI_Read(u4Ret,u8Offset,u4MemPtr,u4MemLen,EEPHDMI_GetSize(HDMI_EEP_EDID20));
}

INT32 EEPMHL20EDID_Read(UINT32 u4MemPtr, UINT32 u4MemLen)
{
	UINT32 u4Ret;
	UINT64 u8Offset;
	u4Ret = (UINT32)DRVCUST_InitGet(eHDMI20EDIDNANDPartId);

	if(u4Ret != 0)
	{
		u8Offset = (UINT64)DRVCUST_InitGet(eMHL20EDIDNANDOffsSet);
		if(u8Offset < 1)
		{
			u4Ret =0; //from EEPROM
			u8Offset += EEPROM_HDMI_MHL_EDID_OFFSET;
		}
	}
	else
	{
		u8Offset = EEPROM_HDMI_MHL_EDID_OFFSET;
	}

	return EEPHDMI_Read(u4Ret,u8Offset,u4MemPtr,u4MemLen,EEPHDMI_GetSize(HDMI_EEP_EDID20));
}
#endif
#endif

#ifndef CC_VGA_EDID_DISABLE
//-------------------------------------------------------------------------
/** EEPVGAEDID_Read
 *  VGAEDID interface: EEPROM read function.
 *  @param  u8Offset 	begin address to read.
 *  @param  u4MemPtr 	user's buffer address.
 *  @param  u4MemLen 	read data length in bytes.
 *  @retval   0		SUCCESS.
 *  @retval   1		FAIL.
 */
//-------------------------------------------------------------------------
INT32 EEPVGAEDID_Read(UINT64 u8Offset, UINT32 u4MemPtr, UINT32 u4MemLen)
{
    INT32 i4Ret;
    _EEP_Lock();

    // check boundary.
    if ((u8Offset + u4MemLen) > VGA_EDID_STORAGE_SIZE)
    {
        _EEP_Unlock();
        return 1;
    }
#if defined(CC_NAND_ENABLE)
    // check if VGA EDID is stored in NAND
    i4Ret = (INT32)DRVCUST_InitGet(eVGAEDIDNANDPartId);
    if (i4Ret > 1)
    {
        UINT32 u4PartOffset = 0;
        u4PartOffset = (INT32) DRVCUST_InitGet(eVGAEDIDNANDOffset);
        u4PartOffset += u8Offset ;
        Printf("read from nand flash %ld %lu\n", i4Ret, u4PartOffset);
#ifdef CC_MTK_LOADER
        i4Ret = Loader_ReadNandFlash(i4Ret, (UINT32)u4PartOffset, (VOID*) u4MemPtr, u4MemLen);
#else
        i4Ret = STORG_SyncNandRead(i4Ret, (UINT32)u4PartOffset, (VOID*)u4MemPtr, u4MemLen);
#endif

#if 0
        if (i4Ret == u4MemLen)
        {
            return 0 ;
        }
        else
        {
            return -1 ;
        }
#endif
        _EEP_Unlock();
        return 0 ;
    }
#else
#ifndef CC_NOR_DISABLE
#ifndef CC_UBOOT
    i4Ret = (INT32)DRVCUST_InitGet(eVGAEDIDNorPartId);
    if (i4Ret > 1)
    {
        UINT32 u4PartOffset = 0;
        u4PartOffset = (INT32) DRVCUST_InitGet(eVGAEDIDNorOffset);
        u8Offset += u4PartOffset;
        Printf("read from nor %x %x\n", i4Ret, u8Offset);
        u8Offset |= (((UINT64)(UINT32)i4Ret) << 32);
        i4Ret = NORPART_Read(u8Offset, u4MemPtr, u4MemLen);
        _EEP_Unlock();
        return 0;
    }
#endif
#endif
#endif

    Printf("read from eeprom ioff %lu phy_off %lu\n", (UINT32)u8Offset, (UINT32)u8Offset+EEPROM_VGA_EDID_OFFSET);
    // adjust offset to map to physical offset.
    u8Offset += EEPROM_VGA_EDID_OFFSET;

    i4Ret = EEPROM_Read(u8Offset, u4MemPtr, u4MemLen);

    _EEP_Unlock();
    return i4Ret;
}

#ifndef CC_MTK_LOADER
//-------------------------------------------------------------------------
/** EEPVGAEDID_Write
 *  VGA EDID interface: EEPROM write function.
 *  @param  u8Offset 	begin address to write.
 *  @param  u4MemPtr 	user's buffer address.
 *  @param  u4MemLen 	writedata length in bytes.
 *  @retval   0		SUCCESS.
 *  @retval   1		FAIL.
 */
//-------------------------------------------------------------------------
INT32 EEPVGAEDID_Write(UINT64 u8Offset, UINT32 u4MemPtr, UINT32 u4MemLen)
{
    INT32 i4Ret;
    _EEP_Lock();

    // check boundary.
    if ((u8Offset + u4MemLen) > VGA_EDID_STORAGE_SIZE)
    {
        _EEP_Unlock();
        return 1;
    }
#if defined(CC_NAND_ENABLE)
    // check if VGAEDID is stored in NAND
    i4Ret = (INT32)DRVCUST_InitGet(eVGAEDIDNANDPartId);
    if (i4Ret > 1)
    {
        UINT32 u4BlkSize = 0;
        VOID* pvTmpBuffer = NULL;

        Printf("write to nand flash\n");
        //write should be block align , don't add the offset here
        u4BlkSize = STORG_NandGetBlkSize();
        pvTmpBuffer = x_mem_alloc(u4BlkSize);
        x_memset((void*)pvTmpBuffer, 0xff, u4BlkSize);
        x_memcpy((void*)(pvTmpBuffer), (void*)u4MemPtr, u4MemLen);

        i4Ret = STORG_SyncNandWriteBlock(i4Ret, (UINT32)u8Offset, pvTmpBuffer, u4BlkSize);

        x_mem_free(pvTmpBuffer);
        if (i4Ret == u4BlkSize)
        {
            _EEP_Unlock();
            return 0 ;
        }
        else
        {
            _EEP_Unlock();
            return -1 ;
        }
    }
#else
#ifndef CC_NOR_DISABLE
    i4Ret = (INT32)DRVCUST_OptGet(eVGAEDIDNorPartId);
    if (i4Ret > 1)
    {
        UINT32 u4PartOffset = 0;
        u4PartOffset = (INT32) DRVCUST_InitGet(eVGAEDIDNorOffset);
        u8Offset += u4PartOffset;
        Printf("write to nor %x %x\n", i4Ret, u8Offset);
        u8Offset |= (((UINT64)(UINT32)i4Ret) << 32);
        i4Ret = NORPART_Erase(u8Offset, 1);
        i4Ret |= NORPART_Write(u8Offset, u4MemPtr, u4MemLen);
        _EEP_Unlock();
        return 0;
    }
#endif
#endif

    // adjust offset to map to physical offset.
    u8Offset += EEPROM_VGA_EDID_OFFSET;

    i4Ret = EEPROM_Write(u8Offset, u4MemPtr, u4MemLen);

    _EEP_Unlock();
    return i4Ret;
}
#endif
#endif //CC_VGA_EDID_DISABLE

#ifndef CC_HDMI_EDID_DISABLE
//-------------------------------------------------------------------------
/** EEPHDMIEDID_Read
 *  HDMIEDID interface: EEPROM read function.
 *  @param  u8Offset 	begin address to read.
 *  @param  u4MemPtr 	user's buffer address.
 *  @param  u4MemLen 	read data length in bytes.
 *  @retval   0		SUCCESS.
 *  @retval   1		FAIL.
 */
//-------------------------------------------------------------------------
INT32 EEPHDMIEDID_Read(UINT64 u8Offset, UINT32 u4MemPtr, UINT32 u4MemLen)
{
    INT32 i4Ret;
    _EEP_Lock();

    // check boundary.
    if ((u8Offset + u4MemLen) > HDMI_EDID_STORAGE_SIZE)
    {
        _EEP_Unlock();
        return 1;
    }
#if defined(CC_NAND_ENABLE)
    // check if HDMI EDID is stored in NAND
    i4Ret = (INT32)DRVCUST_InitGet(eHDMIEDIDNANDPartId);
    if (i4Ret > 1)
    {
        UINT64 u4PartOffset = 0;
        u4PartOffset = (INT32) DRVCUST_InitGet(eHDMIEDIDNANDOffset);
        u4PartOffset += u8Offset ;
        Printf("read from nand flash %ld %llu\n", i4Ret, u4PartOffset);
#ifdef CC_MTK_LOADER
        i4Ret = Loader_ReadNandFlash(i4Ret, (UINT32)u4PartOffset, (VOID*) u4MemPtr, u4MemLen);
#else
#if defined(CC_SOEM_BOARD)
        u4PartOffset |= (((UINT64)i4Ret) << 32);
        if (NANDPART_Read(u4PartOffset, (UINT32)u4MemPtr, u4MemLen) != 0)
        {
            Printf("Read nand flash fail\n ");
        }
#else
        i4Ret = STORG_SyncNandRead(i4Ret, (UINT32)u4PartOffset, (VOID*)u4MemPtr, u4MemLen);
#endif
#endif
#if 0
        if (i4Ret == u4MemLen)
        {
            _EEP_Unlock();
            return 0 ;
        }
        else
        {
            _EEP_Unlock();
            return -1 ;
        }
#endif
        _EEP_Unlock();
        return 0 ;
    }
#else

#ifndef CC_NOR_DISABLE
#ifndef CC_UBOOT
    i4Ret = (INT32)DRVCUST_InitGet(eHDMIEDIDNorPartId);
    if (i4Ret > 1)
    {
        UINT32 u4PartOffset = 0;
        u4PartOffset = (INT32) DRVCUST_InitGet(eHDMIEDIDNorOffset);
        u8Offset += u4PartOffset;
        Printf("read from nor %x %x\n", i4Ret, u8Offset);
        u8Offset |= (((UINT64)(UINT32)i4Ret) << 32);
        i4Ret = NORPART_Read(u8Offset, u4MemPtr, u4MemLen);
        _EEP_Unlock();
        return 0;
    }
#endif
#endif
#endif

    Printf("read from eeprom ioff %x phy_off %x\n", (UINT32)u8Offset, (UINT32)u8Offset + EEPROM_HDMI_EDID_OFFSET);

    // adjust offset to map to physical offset.
    u8Offset += EEPROM_HDMI_EDID_OFFSET;

    i4Ret = EEPROM_Read(u8Offset, u4MemPtr, u4MemLen);

    _EEP_Unlock();
    return i4Ret;
}

#ifndef CC_MTK_LOADER
//-------------------------------------------------------------------------
/** EEPHDMIEDID_Write
 *  HDMI EDID interface: EEPROM write function.
 *  @param  u8Offset 	begin address to write.
 *  @param  u4MemPtr 	user's buffer address.
 *  @param  u4MemLen 	writedata length in bytes.
 *  @retval   0		SUCCESS.
 *  @retval   1		FAIL.
 */
//-------------------------------------------------------------------------
INT32 EEPHDMIEDID_Write(UINT64 u8Offset, UINT32 u4MemPtr, UINT32 u4MemLen)
{
    INT32 i4Ret;
    _EEP_Lock();

    // check boundary.
    if ((u8Offset + u4MemLen) > HDMI_EDID_STORAGE_SIZE)
    {
        _EEP_Unlock();
        return 1;
    }
#if defined(CC_NAND_ENABLE)
    // check if HDCP is stored in NOR
    i4Ret = (INT32)DRVCUST_InitGet(eHDMIEDIDNANDPartId);
    if (i4Ret > 1)
    {
        UINT32 u4BlkSize = 0;
#if defined(CC_SOEM_BOARD)	// for sony use.
        Printf("write to nand flash ID:%d,OFFSET:%d\n", i4Ret, (UINT32)u8Offset);
        u8Offset |= (((UINT64)i4Ret) << 32);
        if (0 != NANDPART_Write(u8Offset, u4MemPtr, u4MemLen))
        {
            Printf("write to nand flash %d fails\n", i4Ret);
            _EEP_Unlock();
            return -1 ;
        }
        _EEP_Unlock();
        return 0 ;

#else
        VOID* pvTmpBuffer = NULL;

        Printf("write to nand flash\n");
        //write should be block align , don't add the offset here
        u4BlkSize = STORG_NandGetBlkSize();
        pvTmpBuffer = x_mem_alloc(u4BlkSize);
        x_memset((void*)pvTmpBuffer, 0xff, u4BlkSize);
        x_memcpy((void*)(pvTmpBuffer), (void*)u4MemPtr, u4MemLen);

        i4Ret = STORG_SyncNandWriteBlock(i4Ret, (UINT32)u8Offset, pvTmpBuffer, u4BlkSize);

        x_mem_free(pvTmpBuffer);
#endif
        if (i4Ret == u4BlkSize)
        {
            _EEP_Unlock();
            return 0 ;
        }
        else
        {
            _EEP_Unlock();
            return -1 ;
        }
    }

#else

#ifndef CC_NOR_DISABLE
    i4Ret = (INT32)DRVCUST_OptGet(eHDMIEDIDNorPartId);
    if (i4Ret > 1)
    {
        UINT32 u4PartOffset = 0;
        u4PartOffset = (INT32) DRVCUST_InitGet(eHDMIEDIDNorOffset);
        u8Offset += u4PartOffset;
        Printf("write to nor %x %x\n", i4Ret, u8Offset);
        u8Offset |= (((UINT64)(UINT32)i4Ret) << 32);
        i4Ret = NORPART_Erase(u8Offset, 1);
        i4Ret |= NORPART_Write(u8Offset, u4MemPtr, u4MemLen);
        _EEP_Unlock();
        return 0;
    }
#endif //CC_NOR_DISABLE
#endif //CC_NAND_ENABLE

    // adjust offset to map to physical offset.
    u8Offset += EEPROM_HDMI_EDID_OFFSET;

    i4Ret = EEPROM_Write(u8Offset, u4MemPtr, u4MemLen);

    _EEP_Unlock();
    return i4Ret;
}


#endif //CC_MTK_LOADER
#endif //CC_HDMI_EDID_DISABLE

//-------------------------------------------------------------------------
/** _EepDtvCalChecksum()
 *  Calculate DTVCFG_T checksum value.
 *  @param prDtvCfg the DtvCfg data structure pointer.
 *  @return the UINT8 checksum value.
 */
//-------------------------------------------------------------------------
static UINT8 _EepDtvCalChecksum(const DTVCFG_T* prDtvCfg)
{
    UINT8 u1Ret;

    ASSERT(prDtvCfg != NULL);
    u1Ret = 0;
    u1Ret += (prDtvCfg->u1Magic1 + prDtvCfg->u1Magic2);
    u1Ret += (prDtvCfg->u1Flags + prDtvCfg->u1Upgrade);
    #ifdef CC_S_PLATFORM
    u1Ret += (prDtvCfg->u1Upgrade_Ext + prDtvCfg->u1Flags2 + 
		      prDtvCfg->u1Flags3 + prDtvCfg->u1Flags4 + 
		      prDtvCfg->u1Flags5 + prDtvCfg->u1Flags6);
    #else
    u1Ret += (prDtvCfg->u1Upgrade_Ext + prDtvCfg->u1Flags2 + prDtvCfg->u1Flags3 + prDtvCfg->u1Flags4);
    #endif
    return u1Ret;
}

//-------------------------------------------------------------------------
/** _EepDtvIsValid()
 *  Check whether the DTVCFG_T is valid.
 *  @param prDtvCfg the test DtvCfg data structure.
 *  @return 0 is invalid, otherwise is valid.
 *      Valid must magic chars are correct and checksum is correct.
 */
//-------------------------------------------------------------------------
static UINT32 _EepDtvIsValid(const DTVCFG_T* prDtvCfg)
{
    ASSERT(prDtvCfg != NULL);
    if (prDtvCfg->u1Magic1 != DTVCFG_MAGIC_CHAR1)
    {
        return 0;
    }
    if (prDtvCfg->u1Magic2 != DTVCFG_MAGIC_CHAR2)
    {
        return 0;
    }
    if (prDtvCfg->u1Checksum != _EepDtvCalChecksum(prDtvCfg))
    {
        return 0;
    }
    return 1;
}

//-------------------------------------------------------------------------
/** _EepDtvDecideTriple()
 *  Calculate the u1Vals to a decision.
 *  @param u1Val1/2/3.
 *  @return the final data.
 */
//-------------------------------------------------------------------------
static UINT8 _EepDtvDecideTriple(UINT8 u1Val1, UINT8 u1Val2, UINT8 u1Val3)
{
    UINT8 u1Ret = 0;
    INT32 i, i4Count;

    for (i = 0; i < 8; i++)
    {
        i4Count = 0;
        if (u1Val1 & (1U << i))
        {
            i4Count++;
        }
        if (u1Val2 & (1U << i))
        {
            i4Count++;
        }
        if (u1Val3 & (1U << i))
        {
            i4Count++;
        }
        if (i4Count > 1)
        {
            u1Ret |= (1U << i);
        }
    }
    return u1Ret;
}

//-------------------------------------------------------------------------
/** _EepDtvSyncData()
 *  Copy final DTVCFG_T to the location.
 *  @param prDtvCfg the final DTVCFG data.
 *  @param fgSync1 copy DTVCFG to location 1.
 *  @param fgSync2 copy DTVCFG to location 2.
 *  @param fgSync3 copy DTVCFG to location 3.
 */
//-------------------------------------------------------------------------
static INT32 _EepDtvSyncData(DTVCFG_T* prDtvCfg, UINT32 fgSync1, UINT32 fgSync2, UINT32 fgSync3)
{
    DTVCFG_T rDtvCfg;
    UINT8 au1Magic[2];
#ifdef CC_MTK_LOADER
    LDR_ENV_T* prLdrEnv = (LDR_ENV_T*)CC_LDR_ENV_OFFSET;
#endif
    x_memset((void*)&rDtvCfg, 0, sizeof(DTVCFG_T));
    ASSERT(prDtvCfg != NULL);
    prDtvCfg->u1Magic1 = DTVCFG_MAGIC_CHAR1;
    prDtvCfg->u1Magic2 = DTVCFG_MAGIC_CHAR2;
    prDtvCfg->u1Checksum = _EepDtvCalChecksum(prDtvCfg);

    if (fgSync1)
    {
        if (EEPDTV_Read((UINT64)0, (UINT32)(void*)&rDtvCfg, sizeof(DTVCFG_T)) != 0)
        {
            return 1;
        }
        if (rDtvCfg.u1Flags != prDtvCfg->u1Flags)
        {
            if (EEPDTV_Write((UINT64)EEPDTV_DTVCFG_FLAGS, (UINT32)(void*)&prDtvCfg->u1Flags, 1) != 0)
            {
                return 1;
            }
        }
        if ((rDtvCfg.u1Checksum != prDtvCfg->u1Checksum) || (rDtvCfg.u1Upgrade != prDtvCfg->u1Upgrade) ||
            (rDtvCfg.u1Upgrade_Ext != prDtvCfg->u1Upgrade_Ext) || (rDtvCfg.u1Flags2 != prDtvCfg->u1Flags2) ||
            #ifdef CC_S_PLATFORM
            (rDtvCfg.u1Flags3 != prDtvCfg->u1Flags3) || (rDtvCfg.u1Flags4 != prDtvCfg->u1Flags4) ||
            (rDtvCfg.u1Flags5 != prDtvCfg->u1Flags5) || (rDtvCfg.u1Flags6 != prDtvCfg->u1Flags6))
            #else
            (rDtvCfg.u1Flags3 != prDtvCfg->u1Flags3) || (rDtvCfg.u1Flags4 != prDtvCfg->u1Flags4))
            #endif
        {
            #ifdef CC_S_PLATFORM
            if (EEPDTV_Write((UINT64)EEPDTV_DTVCFG_UPGRADE, (UINT32)(void*)&prDtvCfg->u1Upgrade, 8) != 0)
            #else
            if (EEPDTV_Write((UINT64)EEPDTV_DTVCFG_UPGRADE, (UINT32)(void*)&prDtvCfg->u1Upgrade, 6) != 0)
            #endif
            {
                return 1;
            }
        }
        if ((rDtvCfg.u1Magic1 != DTVCFG_MAGIC_CHAR1) || (rDtvCfg.u1Magic2 != DTVCFG_MAGIC_CHAR2))
        {
            au1Magic[0] = DTVCFG_MAGIC_CHAR1;
            au1Magic[1] = DTVCFG_MAGIC_CHAR2;
            if (EEPDTV_Write((UINT64)EEPDTV_DTVCFG_MAGIC1, (UINT32)(void*)au1Magic, 2) != 0)
            {
                return 1;
            }
        }
    }

    if (fgSync2)
    {
        #ifdef CC_S_PLATFORM
        if (EEPDTV_Read((UINT64)(sizeof(DTVCFG_T)), (UINT32)(void*)&rDtvCfg, sizeof(DTVCFG_T)) != 0)
        #else
        if (EEPDTV_Read((UINT64)9, (UINT32)(void*)&rDtvCfg, sizeof(DTVCFG_T)) != 0)
        #endif
        {
            return 1;
        }
        if (rDtvCfg.u1Flags != prDtvCfg->u1Flags)
        {
            #ifdef CC_S_PLATFORM
            if (EEPDTV_Write((UINT64)EEPDTV_DTVCFG_FLAGS + 11, (UINT32)(void *)&prDtvCfg->u1Flags, 1) != 0)
            #else
            if (EEPDTV_Write((UINT64)EEPDTV_DTVCFG_FLAGS + 9, (UINT32)(void*)&prDtvCfg->u1Flags, 1) != 0)
            #endif
            {
                return 1;
            }
        }
        if ((rDtvCfg.u1Checksum != prDtvCfg->u1Checksum) || (rDtvCfg.u1Upgrade != prDtvCfg->u1Upgrade) ||
            (rDtvCfg.u1Upgrade_Ext != prDtvCfg->u1Upgrade_Ext) || (rDtvCfg.u1Flags2 != prDtvCfg->u1Flags2) ||
            #ifdef CC_S_PLATFORM
            (rDtvCfg.u1Flags3 != prDtvCfg->u1Flags3) || (rDtvCfg.u1Flags4 != prDtvCfg->u1Flags4) ||
            (rDtvCfg.u1Flags5 != prDtvCfg->u1Flags5) || (rDtvCfg.u1Flags6 != prDtvCfg->u1Flags6))
            #else
            (rDtvCfg.u1Flags3 != prDtvCfg->u1Flags3) || (rDtvCfg.u1Flags4 != prDtvCfg->u1Flags4))
            #endif
        {
            #ifdef CC_S_PLATFORM
            if (EEPDTV_Write((UINT64)EEPDTV_DTVCFG_UPGRADE + 11, (UINT32)(void*)&prDtvCfg->u1Upgrade, 6) != 0)
            #else
            if (EEPDTV_Write((UINT64)EEPDTV_DTVCFG_UPGRADE + 9, (UINT32)(void*)&prDtvCfg->u1Upgrade, 6) != 0)
            #endif
            {
                return 1;
            }
        }
        if ((rDtvCfg.u1Magic1 != DTVCFG_MAGIC_CHAR1) || (rDtvCfg.u1Magic2 != DTVCFG_MAGIC_CHAR2))
        {
            au1Magic[0] = DTVCFG_MAGIC_CHAR1;
            au1Magic[1] = DTVCFG_MAGIC_CHAR2;
            #ifdef CC_S_PLATFORM
            if (EEPDTV_Write((UINT64)EEPDTV_DTVCFG_MAGIC1 + 11, (UINT32)(void*)&prDtvCfg->u1Magic1, 2) != 0)
            #else
            if (EEPDTV_Write((UINT64)EEPDTV_DTVCFG_MAGIC1 + 9, (UINT32)(void*)&prDtvCfg->u1Magic1, 2) != 0)
            #endif
            {
                return 1;
            }
        }
    }

    if (fgSync3)
    {
        #ifdef CC_S_PLATFORM
        if (EEPDTV_Read((UINT64)(sizeof(DTVCFG_T)*2), (UINT32)(void *)&rDtvCfg, sizeof(DTVCFG_T))!=0)
        #else
        if (EEPDTV_Read((UINT64)18, (UINT32)(void*)&rDtvCfg, sizeof(DTVCFG_T)) != 0)
        #endif
        {
            return 1;
        }
        if (rDtvCfg.u1Flags != prDtvCfg->u1Flags)
        {
            #ifdef CC_S_PLATFORM
            if (EEPDTV_Write((UINT64)EEPDTV_DTVCFG_FLAGS + 22, (UINT32)(void*)&prDtvCfg->u1Flags, 1) != 0)
            #else
            if (EEPDTV_Write((UINT64)EEPDTV_DTVCFG_FLAGS + 18, (UINT32)(void*)&prDtvCfg->u1Flags, 1) != 0)
            #endif
            {
                return 1;
            }
        }
        if ((rDtvCfg.u1Checksum != prDtvCfg->u1Checksum) || (rDtvCfg.u1Upgrade != prDtvCfg->u1Upgrade) ||
            (rDtvCfg.u1Upgrade_Ext != prDtvCfg->u1Upgrade_Ext) || (rDtvCfg.u1Flags2 != prDtvCfg->u1Flags2) ||
            #ifdef CC_S_PLATFORM
            (rDtvCfg.u1Flags3 != prDtvCfg->u1Flags3) || (rDtvCfg.u1Flags4 != prDtvCfg->u1Flags4) || 
            (rDtvCfg.u1Flags5 != prDtvCfg->u1Flags5) || (rDtvCfg.u1Flags6 != prDtvCfg->u1Flags6))
            #else
            (rDtvCfg.u1Flags3 != prDtvCfg->u1Flags3) || (rDtvCfg.u1Flags4 != prDtvCfg->u1Flags4))
            #endif
        {
            #ifdef CC_S_PLATFORM
            if (EEPDTV_Write((UINT64)EEPDTV_DTVCFG_UPGRADE + 22, (UINT32)(void*)&prDtvCfg->u1Upgrade, 6) != 0)
            #else
            if (EEPDTV_Write((UINT64)EEPDTV_DTVCFG_UPGRADE + 18, (UINT32)(void*)&prDtvCfg->u1Upgrade, 6) != 0)
            #endif
            {
                return 1;
            }
        }
        if ((rDtvCfg.u1Magic1 != DTVCFG_MAGIC_CHAR1) || (rDtvCfg.u1Magic2 != DTVCFG_MAGIC_CHAR2))
        {
            au1Magic[0] = DTVCFG_MAGIC_CHAR1;
            au1Magic[1] = DTVCFG_MAGIC_CHAR2;
            #ifdef CC_S_PLATFORM
            if (EEPDTV_Write((UINT64)EEPDTV_DTVCFG_MAGIC1 + 22, (UINT32)(void*)&prDtvCfg->u1Magic1, 2) != 0)
            #else
            if (EEPDTV_Write((UINT64)EEPDTV_DTVCFG_MAGIC1 + 18, (UINT32)(void*)&prDtvCfg->u1Magic1, 2) != 0)
            #endif
            {
                return 1;
            }
        }
    }
#ifdef CC_MTK_LOADER
    // save dtvcfg in dram cache
    x_memcpy((void*)prLdrEnv->au1DtvCfg, (void*)prDtvCfg, sizeof(DTVCFG_T));
#endif
    return 0;
}

//-------------------------------------------------------------------------
/** _EepDtvCorrection()
 *  Make DtvCfg triple redudancy sync.
 *  @param prDtvCfg Output - the final decision DtvCfg data structure pointer.
 *  @retval   0		SUCCESS.
 *  @retval   1		FAIL.
 */
//-------------------------------------------------------------------------
INT32 EEPDTV_Correction(DTVCFG_T* prDtvCfg)
{
    static UINT32 _fgEepDtvInit = 0;
    INT32 i4Ret;
    DTVCFG_T rDtvCfg1, rDtvCfg2, rDtvCfg3;
	#ifdef CC_S_PLATFORM
	#ifdef REPLACE_EEPROM_WITH_FLASH//d141112_Haibo:do not do correction since the eeprom write will always return fail under this condition
    #ifdef CC_UBOOT
    _fgEepDtvInit=1;
    #endif
    #endif
	#endif
    x_memset((void*)&rDtvCfg1, 0, sizeof(DTVCFG_T));
    x_memset((void*)&rDtvCfg2, 0, sizeof(DTVCFG_T));
    x_memset((void*)&rDtvCfg3, 0, sizeof(DTVCFG_T));
    ASSERT(prDtvCfg != NULL);
    if (_fgEepDtvInit)
    {
        return 0;
    }
    _fgEepDtvInit = 1;

    // read the first DtvCfg location.
    i4Ret = EEPDTV_Read((UINT64) 0, (UINT32)(void*)&rDtvCfg1, sizeof(DTVCFG_T));
    if (i4Ret)
    {
        return i4Ret;
    }

    // Get the redudancy information.
    #ifdef CC_S_PLATFORM
    i4Ret = EEPDTV_Read((UINT64)11, (UINT32)(void*)&rDtvCfg2, sizeof(DTVCFG_T));
    #else
    i4Ret = EEPDTV_Read((UINT64)9, (UINT32)(void*)&rDtvCfg2, sizeof(DTVCFG_T));
    #endif
    if (i4Ret)
    {
        return i4Ret;
    }
    #ifdef CC_S_PLATFORM
    i4Ret = EEPDTV_Read((UINT64)22, (UINT32)(void*)&rDtvCfg3, sizeof(DTVCFG_T));
    #else
    i4Ret = EEPDTV_Read((UINT64)18, (UINT32)(void*)&rDtvCfg3, sizeof(DTVCFG_T));
    #endif
    if (i4Ret)
    {
        return i4Ret;
    }

    // Check non-configured eeprom.
    if (((rDtvCfg1.u1Magic1 != DTVCFG_MAGIC_CHAR1) || (rDtvCfg1.u1Magic2 != DTVCFG_MAGIC_CHAR2)) &&
        (!_EepDtvIsValid(&rDtvCfg2)) && (!_EepDtvIsValid(&rDtvCfg3)))
    {
        // no initial value on 1, and 2/3 are invalid.
        prDtvCfg->u1Flags = 0;
        prDtvCfg->u1Upgrade = 0;
        prDtvCfg->u1Upgrade_Ext = 0;
        prDtvCfg->u1Flags2 = 0;
        prDtvCfg->u1Flags3 = 0;
        prDtvCfg->u1Flags4 = 0;
        #ifdef CC_S_PLATFORM
	prDtvCfg->u1Flags5 = 0;
	prDtvCfg->u1Flags6 = 0;
        #endif
        return _EepDtvSyncData(prDtvCfg, 1, 1, 1);
    }
    // Check upgrade from old non-checksum version or only 1 is valid.
    else if ((!_EepDtvIsValid(&rDtvCfg1)) && (!_EepDtvIsValid(&rDtvCfg2)) && (!_EepDtvIsValid(&rDtvCfg3)))
    {
        // 0, 0, 0
        prDtvCfg->u1Flags = rDtvCfg1.u1Flags;
        prDtvCfg->u1Upgrade = rDtvCfg1.u1Upgrade;
        prDtvCfg->u1Upgrade_Ext = rDtvCfg1.u1Upgrade_Ext;
        prDtvCfg->u1Flags2 = rDtvCfg1.u1Flags2;
        prDtvCfg->u1Flags3 = rDtvCfg1.u1Flags3;
        prDtvCfg->u1Flags4 = rDtvCfg1.u1Flags4;
        #ifdef CC_S_PLATFORM
	prDtvCfg->u1Flags5 = rDtvCfg1.u1Flags5;
	prDtvCfg->u1Flags6 = rDtvCfg1.u1Flags6;
        #endif
        return _EepDtvSyncData(prDtvCfg, 1, 1, 1);
    }
    // only 3 is valid.
    else if ((!_EepDtvIsValid(&rDtvCfg1)) && (!_EepDtvIsValid(&rDtvCfg2)))
    {
        // 0, 0, 1
        prDtvCfg->u1Flags = rDtvCfg3.u1Flags;
        prDtvCfg->u1Upgrade = rDtvCfg3.u1Upgrade;
        prDtvCfg->u1Upgrade_Ext = rDtvCfg3.u1Upgrade_Ext;
        prDtvCfg->u1Flags2 = rDtvCfg3.u1Flags2;
        prDtvCfg->u1Flags3 = rDtvCfg2.u1Flags3;
        prDtvCfg->u1Flags4 = rDtvCfg2.u1Flags4;
        #ifdef CC_S_PLATFORM
	prDtvCfg->u1Flags5 = rDtvCfg2.u1Flags5;
	prDtvCfg->u1Flags6 = rDtvCfg2.u1Flags6;
        #endif
        return _EepDtvSyncData(prDtvCfg, 1, 1, 0);
    }
    // only 2 is valid.
    else if ((!_EepDtvIsValid(&rDtvCfg1)) && (_EepDtvIsValid(&rDtvCfg2)))
    {
        // 0, 1, 0/0, 1, 1 both use 2.
        prDtvCfg->u1Flags = rDtvCfg2.u1Flags;
        prDtvCfg->u1Upgrade = rDtvCfg2.u1Upgrade;
        prDtvCfg->u1Upgrade_Ext = rDtvCfg2.u1Upgrade_Ext;
        prDtvCfg->u1Flags2 = rDtvCfg2.u1Flags2;
        prDtvCfg->u1Flags3 = rDtvCfg2.u1Flags3;
        prDtvCfg->u1Flags4 = rDtvCfg2.u1Flags4;
        #ifdef CC_S_PLATFORM
	prDtvCfg->u1Flags5 = rDtvCfg2.u1Flags5;
	prDtvCfg->u1Flags6 = rDtvCfg2.u1Flags6;
        #endif
        return _EepDtvSyncData(prDtvCfg, 1, 0, 1);
    }
    // then if each of 2/3 is invalid.
    else if ((_EepDtvIsValid(&rDtvCfg1)) && ((!_EepDtvIsValid(&rDtvCfg2)) || (!_EepDtvIsValid(&rDtvCfg3))))
    {
        // 1, 0, 0/1, 1, 0/1, 0, 1, all use 1
        prDtvCfg->u1Flags = rDtvCfg1.u1Flags;
        prDtvCfg->u1Upgrade = rDtvCfg1.u1Upgrade;
        prDtvCfg->u1Upgrade_Ext = rDtvCfg1.u1Upgrade_Ext;
        prDtvCfg->u1Flags2 = rDtvCfg1.u1Flags2;
        prDtvCfg->u1Flags3 = rDtvCfg2.u1Flags3;
        prDtvCfg->u1Flags4 = rDtvCfg2.u1Flags4;
        #ifdef CC_S_PLATFORM
	prDtvCfg->u1Flags5 = rDtvCfg2.u1Flags5;
	prDtvCfg->u1Flags6 = rDtvCfg2.u1Flags6;
        #endif
        return _EepDtvSyncData(prDtvCfg, 0, 1, 1);
    }

    // Here is all of them are valid.
    prDtvCfg->u1Flags = _EepDtvDecideTriple(rDtvCfg1.u1Flags, rDtvCfg2.u1Flags, rDtvCfg3.u1Flags);
    prDtvCfg->u1Upgrade = _EepDtvDecideTriple(rDtvCfg1.u1Upgrade, rDtvCfg2.u1Upgrade, rDtvCfg3.u1Upgrade);
    prDtvCfg->u1Upgrade_Ext = rDtvCfg1.u1Upgrade_Ext;
    prDtvCfg->u1Flags2 = rDtvCfg1.u1Flags2;
    prDtvCfg->u1Flags3 = rDtvCfg2.u1Flags3;
    prDtvCfg->u1Flags4 = rDtvCfg2.u1Flags4;
    #ifdef CC_S_PLATFORM
    prDtvCfg->u1Flags5 = rDtvCfg2.u1Flags5;
    prDtvCfg->u1Flags6 = rDtvCfg2.u1Flags6;
    #endif
    return _EepDtvSyncData(prDtvCfg, 1, 1, 1);
}

//-------------------------------------------------------------------------
/** EEPDTV_GetCfg()
 *  @param prDtvCfg the output DtvCfg data structure pointer.
 *  @retval   0		SUCCESS.
 *  @retval   1		FAIL.
 */
//-------------------------------------------------------------------------
INT32 EEPDTV_GetCfg(DTVCFG_T* prDtvCfg)
{
    INT32 i4Ret;
#ifdef CC_MTK_LOADER
    static BOOL fgInit = FALSE;
    LDR_ENV_T* prLdrEnv = (LDR_ENV_T*)CC_LDR_ENV_OFFSET;
#endif
    ASSERT(prDtvCfg != NULL);
    if (EEPDTV_Correction(prDtvCfg))
    {
        return 1;
    }

#ifdef CC_MTK_LOADER
    if (!fgInit)
    {
        // read the first DtvCfg location.
        i4Ret = EEPDTV_Read((UINT64) 0, (UINT32)(void*)prLdrEnv->au1DtvCfg, sizeof(DTVCFG_T));
        if (i4Ret)
        {
            return i4Ret;
        }
        fgInit = TRUE;
    }

    // load dtvcfg from dram cache
    x_memcpy((void*)prDtvCfg, (void*)prLdrEnv->au1DtvCfg, sizeof(DTVCFG_T));
#else
    i4Ret = EEPDTV_Read((UINT64) 0, (UINT32)(void*)prDtvCfg, sizeof(DTVCFG_T));
    if (i4Ret)
    {
        return i4Ret;
    }
#endif
    return 0;
}

//-------------------------------------------------------------------------
/** EEPDTV_SetCfg()
 *  @param prDtvCfg the input DtvCfg data structure pointer.
 *  @retval   0		SUCCESS.
 *  @retval   1		FAIL.
 */
//-------------------------------------------------------------------------
INT32 EEPDTV_SetCfg(DTVCFG_T* prDtvCfg)
{
    DTVCFG_T rDtvCfg;

    ASSERT(prDtvCfg != NULL);
    if (EEPDTV_Correction(&rDtvCfg) != 0)
    {
        return 1;
    }

    prDtvCfg->u1Magic1 = DTVCFG_MAGIC_CHAR1;
    prDtvCfg->u1Magic2 = DTVCFG_MAGIC_CHAR2;
    prDtvCfg->u1Checksum = _EepDtvCalChecksum(prDtvCfg);
    return _EepDtvSyncData(prDtvCfg, 1, 1, 1);
}

#if defined(CC_MTK_LOADER)

#define MISC_MAC_ADDR_SIZE      7
#define ETH_MAC2STR(a)  (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]

INT32 EEPEtherMAC_Read(UCHAR* pMacAddr)
{
    UCHAR* pucMisc;
    UINT8 ucChksum;
    UINT32 i;
    INT32 i4Ret;

    /* pointer must be 32 byte alignment */
    pucMisc = (UINT8*)x_mem_alloc(MISC_MAC_ADDR_SIZE + MISC_MAC_ADDR_SIZE);
    if (pucMisc == NULL)
    {
        return -1;
    }

    i4Ret = EEPROM_Read(EEP_ETH_MAC_ADDR_START + EEPROM_NPTV_DRIVER_OFFSET, (UINT32)pucMisc, MISC_MAC_ADDR_SIZE + MISC_MAC_ADDR_SIZE);
    if (i4Ret)
    {
        Printf("get MAC address fail 0x%02x\n", (unsigned int)i4Ret);
        x_mem_free((UINT8*)pucMisc);
        return (-1);
    }
    //check 1st MAC
    ucChksum = 0;
    for (i = 0; i < MISC_MAC_ADDR_SIZE; i++)
    {
        ucChksum += (UINT8) * (pucMisc + i);
    }
    if (ucChksum || ((pucMisc[0] == 0) && (pucMisc[1] == 0) && (pucMisc[2] == 0) && (pucMisc[3] == 0) && (pucMisc[4] == 0) && (pucMisc[5] == 0)))
    {
        Printf("#1st MAC address in EEP is invalid! (%02x:%02x:%02x:%02x:%02x:%02x), checksum(%02x).\n", ETH_MAC2STR(pucMisc), pucMisc[MISC_MAC_ADDR_SIZE - 1]);
        //check 2nd MAC
        ucChksum = 0;
        for (i = 0; i < MISC_MAC_ADDR_SIZE; i++)
        {
            ucChksum += (UINT8) * (pucMisc + i + MISC_MAC_ADDR_SIZE);
        }
        if (ucChksum || ((pucMisc[MISC_MAC_ADDR_SIZE] == 0) && (pucMisc[MISC_MAC_ADDR_SIZE + 1] == 0) && (pucMisc[MISC_MAC_ADDR_SIZE + 2] == 0)
                         && (pucMisc[MISC_MAC_ADDR_SIZE + 3] == 0) && (pucMisc[MISC_MAC_ADDR_SIZE + 4] == 0) && (pucMisc[MISC_MAC_ADDR_SIZE + 5] == 0)))
        {
            Printf("#2nd MAC address in EEP is invalid! (%02x:%02x:%02x:%02x:%02x:%02x), checksum(%02x).\n", ETH_MAC2STR(pucMisc + MISC_MAC_ADDR_SIZE), pucMisc[MISC_MAC_ADDR_SIZE * 2 - 1]);
            Printf("Both MAC address in EEP is invalid. Please set mac by cmd: setmac !!!\n");
            x_mem_free((UINT8*)pucMisc);
            return (-1);
        }
        else
        {
            Printf("2nd MAC in EEP is valid (%02x:%02x:%02x:%02x:%02x:%02x)\n", ETH_MAC2STR(pucMisc + MISC_MAC_ADDR_SIZE));
            x_memcpy(pMacAddr, (pucMisc + MISC_MAC_ADDR_SIZE), 6);
        }
    }
    else
    {
        Printf("1st MAC in EEP is valid (%02x:%02x:%02x:%02x:%02x:%02x)\n", ETH_MAC2STR(pucMisc));
        x_memcpy(pMacAddr, pucMisc, 6);
    }
    Printf("1st : (%02x:%02x:%02x:%02x:%02x:%02x)\n", ETH_MAC2STR(pucMisc));
    Printf("2nd : (%02x:%02x:%02x:%02x:%02x:%02x)\n", ETH_MAC2STR(pucMisc + MISC_MAC_ADDR_SIZE));

    x_mem_free((UINT8*)pucMisc);

    return (0);
}
#endif

