/////////////////////////////////////////////////////////////////////
// IT6613.C
// Driver code for platform independent
/////////////////////////////////////////////////////////////////////
#include "hdmitx.h"
//#include "dss_sha.h"

#define MSCOUNT 1000
#define LOADING_UPDATE_TIMEOUT (3000/32)    // 3sec
// USHORT u8msTimer = 0 ;
// USHORT TimerServF = TRUE ;



//////////////////////////////////////////////////////////////////////
// Authentication status
//////////////////////////////////////////////////////////////////////

// #define TIMEOUT_WAIT_AUTH MS(2000)

#define Switch_HDMITX_Bank(x)   HDMITX_WriteI2C_Byte(0x0f,(x)&1)

#define HDMITX_OrREG_Byte(reg,ormask) HDMITX_WriteI2C_Byte(reg,(HDMITX_ReadI2C_Byte(reg) | (ormask)))
#define HDMITX_AndREG_Byte(reg,andmask) HDMITX_WriteI2C_Byte(reg,(HDMITX_ReadI2C_Byte(reg) & (andmask)))
#define HDMITX_SetREG_Byte(reg,andmask,ormask) HDMITX_WriteI2C_Byte(reg,((HDMITX_ReadI2C_Byte(reg) & (andmask))|(ormask)))

//////////////////////////////////////////////////////////////////////
// General global variables
//////////////////////////////////////////////////////////////////////
// static _IDATA TXVideo_State_Type VState ;
// static _IDATA TXAudio_State_Type AState ;
// static _XDATA MODE_DESCRIPTION ModeID = MODE_InvalidMode;

// BYTE I2C_DEV ;
// BYTE I2C_ADDR ;
//////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////
// // Interrupt Type
// /////////////////////////////////////////////////
// BYTE bIntType = 0 ;
// /////////////////////////////////////////////////
// // Video Property
// /////////////////////////////////////////////////
// BYTE bInputVideoMode ;
// BYTE bOutputVideoMode ;
// BYTE Instance[0].bInputVideoSignalType = 0 /* | T_MODE_CCIR656 | T_MODE_SYNCEMB | T_MODE_INDDR */ ; // for Sync Embedded,CCIR656,InputDDR
// BOOL Instance[0].bAuthenticated = FALSE ;
// /////////////////////////////////////////////////
// // Video Property
// /////////////////////////////////////////////////
// BYTE bOutputAudioMode = 0 ;
// BYTE bAudioChannelSwap = 0 ;
//////////////////////////////////////////////////////////////////////
// BOOL Instance[0].bHDMIMode = FALSE;
// BOOL Instance[0].bIntPOL = FALSE ; // 0 = Low Active
// BOOL bHPD ;

INSTANCE Instance[HDMITX_INSTANCE_MAX] ;

//////////////////////////////////////////////////////////////////////
// Function Prototype
//////////////////////////////////////////////////////////////////////

// static BOOL IsRxSense() ;

static void SetInputMode(BYTE InputMode,BYTE bInputSignalType) ;
static void SetCSCScale(BYTE bInputMode,BYTE bOutputMode) ;
// static void SetupAFE(BYTE ucFreqInMHz) ;
static void SetupAFE(VIDEOPCLKLEVEL PCLKLevel) ;
static void FireAFE() ;


static SYS_STATUS SetAudioFormat(BYTE NumChannel,BYTE AudioEnable,BYTE bSampleFreq,BYTE AudSWL,BYTE AudioCatCode) ;
static SYS_STATUS SetNCTS(ULONG PCLK,ULONG Fs) ;

static void AutoAdjustAudio() ;
static void SetupAudioChannel() ;

static SYS_STATUS SetAVIInfoFrame(AVI_InfoFrame *pAVIInfoFrame) ;
static SYS_STATUS SetAudioInfoFrame(Audio_InfoFrame *pAudioInfoFrame) ;
static SYS_STATUS SetSPDInfoFrame(SPD_InfoFrame *pSPDInfoFrame) ;
static SYS_STATUS SetMPEGInfoFrame(MPEG_InfoFrame *pMPGInfoFrame) ;
static SYS_STATUS ReadEDID(BYTE *pData,BYTE bSegment,BYTE offset,SHORT Count) ;
static void AbortDDC() ;
static void ClearDDCFIFO() ;
static void ClearDDCFIFO() ;
static void GenerateDDCSCLK() ;
static SYS_STATUS HDCP_EnableEncryption() ;
static void HDCP_ResetAuth() ;
static void HDCP_Auth_Fire() ;
static void HDCP_StartAnCipher() ;
static void HDCP_StopAnCipher() ;
static void HDCP_GenerateAn() ;
// RICHARD static SYS_STATUS HDCP_GetVr(ULONG *pVr) ;
static SYS_STATUS HDCP_GetBCaps(PBYTE pBCaps ,PUSHORT pBStatus) ;
static SYS_STATUS HDCP_GetBKSV(BYTE *pBKSV) ;
static SYS_STATUS HDCP_Authenticate() ;
static SYS_STATUS HDCP_Authenticate_Repeater() ;
static SYS_STATUS HDCP_VerifyIntegration() ;
static SYS_STATUS HDCP_GetKSVList(BYTE *pKSVList,BYTE cDownStream) ;
static SYS_STATUS HDCP_CheckSHA(BYTE M0[],USHORT BStatus,BYTE KSVList[],int devno,BYTE Vr[]) ;
static void HDCP_ResumeAuthentication() ;
static void HDCP_Reset() ;


static void ENABLE_NULL_PKT() ;
static void ENABLE_ACP_PKT() ;
static void ENABLE_ISRC1_PKT() ;
static void ENABLE_ISRC2_PKT() ;
static void ENABLE_AVI_INFOFRM_PKT() ;
static void ENABLE_AUD_INFOFRM_PKT() ;
static void ENABLE_SPD_INFOFRM_PKT() ;
static void ENABLE_MPG_INFOFRM_PKT() ;

static void DISABLE_NULL_PKT() ;
static void DISABLE_ACP_PKT() ;
static void DISABLE_ISRC1_PKT() ;
static void DISABLE_ISRC2_PKT() ;
static void DISABLE_AVI_INFOFRM_PKT() ;
static void DISABLE_AUD_INFOFRM_PKT() ;
static void DISABLE_SPD_INFOFRM_PKT() ;
static void DISABLE_MPG_INFOFRM_PKT() ;
static BYTE countbit(BYTE b) ;

#ifdef HDMITX_REG_DEBUG
static void DumpCatHDMITXReg() ;
#endif // DEBUG





//////////////////////////////////////////////////////////////////////
// Function Body.
//////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////
// utility function for main..
//////////////////////////////////////////////////////////////////////



// int aiNonCEAVIC[] = { 2 } ;

// Y,C,RGB offset
// for register 73~75
static _CODE BYTE bCSCOffset_16_235[] =
{
    0x00,0x80,0x00
};

static _CODE BYTE bCSCOffset_0_255[] =
{
    0x10,0x80,0x10
};

#ifdef SUPPORT_INPUTRGB
    static _CODE BYTE bCSCMtx_RGB2YUV_ITU601_16_235[] =
    {
        0xB2,0x04,0x64,0x02,0xE9,0x00,
        0x93,0x3C,0x16,0x04,0x56,0x3F,
        0x49,0x3D,0x9F,0x3E,0x16,0x04
    } ;

    static _CODE BYTE bCSCMtx_RGB2YUV_ITU601_0_255[] =
    {
        0x09,0x04,0x0E,0x02,0xC8,0x00,
        0x0E,0x3D,0x83,0x03,0x6E,0x3F,
        0xAC,0x3D,0xD0,0x3E,0x83,0x03
    } ;

    static _CODE BYTE bCSCMtx_RGB2YUV_ITU709_16_235[] =
    {
        0xB8,0x05,0xB4,0x01,0x93,0x00,
        0x49,0x3C,0x16,0x04,0x9F,0x3F,
        0xD9,0x3C,0x10,0x3F,0x16,0x04
    } ;

    static _CODE BYTE bCSCMtx_RGB2YUV_ITU709_0_255[] =
    {
        0xE5,0x04,0x78,0x01,0x81,0x00,
        0xCE,0x3C,0x83,0x03,0xAE,0x3F,
        0x49,0x3D,0x33,0x3F,0x83,0x03
    } ;
#endif 
/*
#ifdef SUPPORT_INPUTYUV

    static _CODE BYTE bCSCMtx_YUV2RGB_ITU601_16_235[] =
    {
        0x00,0x08,0x6A,0x3A,0x4F,0x3D,
        0x00,0x08,0xF7,0x0A,0x00,0x00,
        0x00,0x08,0x00,0x00,0xDB,0x0D
    } ;

    static _CODE BYTE bCSCMtx_YUV2RGB_ITU601_0_255[] =
    {
        0x4F,0x09,0x81,0x39,0xDF,0x3C,
        0x4F,0x09,0xC2,0x0C,0x00,0x00,
        0x4F,0x09,0x00,0x00,0x1E,0x10
    } ;

    static _CODE BYTE bCSCMtx_YUV2RGB_ITU709_16_235[] =
    {
        0x00,0x08,0x53,0x3C,0x89,0x3E,
        0x00,0x08,0x51,0x0C,0x00,0x00,
        0x00,0x08,0x00,0x00,0x87,0x0E
    } ;

    static _CODE BYTE bCSCMtx_YUV2RGB_ITU709_0_255[] =
    {
        0x4F,0x09,0xBA,0x3B,0x4B,0x3E,
        0x4F,0x09,0x56,0x0E,0x00,0x00,
        0x4F,0x09,0x00,0x00,0xE7,0x10
    } ;
#endif*/

#ifdef SUPPORT_INPUTYUV

     BYTE bCSCMtx_YUV2RGB_ITU601_16_235[] =
    {
        0x00,0x08,0x6A,0x3A,0x4F,0x3D,
        0x00,0x08,0xF7,0x0A,0x00,0x00,
        0x00,0x08,0x00,0x00,0xDB,0x0D
    } ;

     BYTE bCSCMtx_YUV2RGB_ITU601_0_255[] =
    {
        0x4F,0x09,0x81,0x39,0xDF,0x3C,
        0x4F,0x09,0xC2,0x0C,0x00,0x00,
        0x4F,0x09,0x00,0x00,0x1E,0x10
    } ;

     BYTE bCSCMtx_YUV2RGB_ITU709_16_235[] =
    {
        0x00,0x08,0x53,0x3C,0x89,0x3E,
        0x00,0x08,0x51,0x0C,0x00,0x00,
        0x00,0x08,0x00,0x00,0x87,0x0E
    } ;

     BYTE bCSCMtx_YUV2RGB_ITU709_0_255[] =
    {
        0x4F,0x09,0xBA,0x3B,0x4B,0x3E,
        0x4F,0x09,0x56,0x0E,0x00,0x00,
        0x4F,0x09,0x00,0x00,0xE7,0x10
    } ;
#endif



//////////////////////////////////////////////////////////////////////
// external Interface                                                         //
//////////////////////////////////////////////////////////////////////

void
HDMITX_InitInstance(INSTANCE *pInstance)
{
	if(pInstance && 0 < HDMITX_INSTANCE_MAX)
	{
		Instance[0] = *pInstance ;
	}
}

static BYTE InitIT6613_HDCPROM()
{
    BYTE uc[5]  ;
    Switch_HDMITX_Bank(0) ;
    HDMITX_WriteI2C_Byte(0xF8,0xC3) ;	//password
    HDMITX_WriteI2C_Byte(0xF8,0xA5) ;	// password
    HDMITX_WriteI2C_Byte(REG_TX_LISTCTRL,0x60) ; // Richard, ????
    I2C_Read_ByteN(0xE0,0x00,uc,5) ;  // richard note. internal rom is used
    
    if(uc[0] == 1 &&
        uc[1] == 1 &&
        uc[2] == 1 &&
        uc[3] == 1 &&
        uc[4] == 1)
    {
        // with internal eMem
        HDMITX_WriteI2C_Byte(REG_TX_ROM_HEADER,0xE0) ;
        HDMITX_WriteI2C_Byte(REG_TX_LISTCTRL,0x48) ;
    }
    else
    {
        // with external ROM
        HDMITX_WriteI2C_Byte(REG_TX_ROM_HEADER,0xA0) ;  // ROMHeader
        HDMITX_WriteI2C_Byte(REG_TX_LISTCTRL,0x00) ; // Richard, ????
    }
    HDMITX_WriteI2C_Byte(0xF8,0xFF) ;  // password
    
    // richard add
    return ER_SUCCESS;
}

void InitIT6613()
{
	// config interrupt
    HDMITX_WriteI2C_Byte(REG_TX_INT_CTRL,Instance[0].bIntType) ;
    Instance[0].bIntPOL = (Instance[0].bIntType&B_INTPOL_ACTH)?TRUE:FALSE ;

	// Reset 
    HDMITX_WriteI2C_Byte(REG_TX_SW_RST,B_REF_RST|B_VID_RST|B_AUD_RST|B_AREF_RST|B_HDCP_RST) ;
    DelayMS(1) ;
    HDMITX_WriteI2C_Byte(REG_TX_SW_RST,B_VID_RST|B_AUD_RST|B_AREF_RST|B_HDCP_RST) ;
    
#if 0    
    // Enable clock ring (richard add according toe programming guide)
    HDMITX_WriteI2C_Byte(REG_TX_AFE_DRV_CTRL, 0x10);
    
    // Set default DVI mode (richard add according toe programming guide)
//    HDMITX_WriteI2C_Byte(REG_TX_HDMI_MODE, 0x01);  // set HDMI mode    
    HDMITX_WriteI2C_Byte(REG_TX_HDMI_MODE, 0x00);  // set DVI mode    
#endif    

    // Avoid power loading in un play status.
    HDMITX_WriteI2C_Byte(REG_TX_AFE_DRV_CTRL,B_AFE_DRV_RST|B_AFE_DRV_PWD) ;

    // set interrupt mask,mask value 0 is interrupt available.
// richard    HDMITX_WriteI2C_Byte(REG_TX_INT_MASK1,0xB2) ;  // enable interrupt: HPD, DDCBusHangMask, 
    HDMITX_WriteI2C_Byte(REG_TX_INT_MASK1,0xB2) ;  // enable interrupt: HPD, DDCBusHangMask, 
    HDMITX_WriteI2C_Byte(REG_TX_INT_MASK2,0xF8) ;  // enable interrupt: AuthFailMask, AUthDoneMask, KSVListChkMask
    HDMITX_WriteI2C_Byte(REG_TX_INT_MASK3,0x37) ; //  enable interrupt: PktAudMask, PktDBDMask, PkMpgMask, AUdCTSMask, HDCPSynDetMask

    Switch_HDMITX_Bank(0) ;
    DISABLE_NULL_PKT() ;
    DISABLE_ACP_PKT() ;
    DISABLE_ISRC1_PKT() ;
    DISABLE_ISRC2_PKT() ;
    DISABLE_AVI_INFOFRM_PKT() ;
    DISABLE_AUD_INFOFRM_PKT() ;
    DISABLE_SPD_INFOFRM_PKT() ;
    DISABLE_MPG_INFOFRM_PKT();
    

	//////////////////////////////////////////////////////////////////
	// Setup Output Audio format.
	//////////////////////////////////////////////////////////////////
    HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL1,Instance[0].bOutputAudioMode) ; // regE1 bOutputAudioMode should be loaded from ROM image.

	//////////////////////////////////////////////////////////////////
	// Setup HDCP ROM
	//////////////////////////////////////////////////////////////////
	InitIT6613_HDCPROM() ;
// #ifdef EXTERN_HDCPROM
// #pragma message("EXTERN ROM CODED") ;
// 	HDMITX_WriteI2C_Byte(REG_TX_ROM_HEADER,0xA0) ;
// #endif


}

//////////////////////////////////////////////////////////////////////
// export this for dynamic change input signal
//////////////////////////////////////////////////////////////////////
BOOL SetupVideoInputSignal(BYTE inputSignalType)
{
	Instance[0].bInputVideoSignalType = inputSignalType ;
    // SetInputMode(inputColorMode,Instance[0].bInputVideoSignalType) ;
    return TRUE ;
}

BOOL EnableVideoOutput(VIDEOPCLKLEVEL level,BYTE inputColorMode,BYTE outputColorMode,BYTE bHDMI)
{
    // bInputVideoMode,bOutputVideoMode,Instance[0].bInputVideoSignalType,bAudioInputType,should be configured by upper F/W or loaded from EEPROM.
    // should be configured by initsys.c
    WORD i ;
    BYTE uc ;
    // VIDEOPCLKLEVEL level ;

    HDMITX_WriteI2C_Byte(REG_TX_SW_RST,B_VID_RST|B_AUD_RST|B_AREF_RST|B_HDCP_RST) ;

    Instance[0].bHDMIMode = (BYTE)bHDMI ;

    if(Instance[0].bHDMIMode)
    {
        SetAVMute(TRUE) ;
    }

    SetInputMode(inputColorMode,Instance[0].bInputVideoSignalType) ;

    SetCSCScale(inputColorMode,outputColorMode) ;

    if(Instance[0].bHDMIMode)
    {
        HDMITX_WriteI2C_Byte(REG_TX_HDMI_MODE,B_TX_HDMI_MODE) ;
    }
    else
    {
        HDMITX_WriteI2C_Byte(REG_TX_HDMI_MODE,B_TX_DVI_MODE) ;
    }

#ifdef INVERT_VID_LATCHEDGE
    uc = HDMITX_ReadI2C_Byte(REG_TX_CLK_CTRL1) ;
    uc |= B_VDO_LATCH_EDGE ;
    HDMITX_WriteI2C_Byte(REG_TX_CLK_CTRL1, uc) ;
#endif    

    HDMITX_WriteI2C_Byte(REG_TX_SW_RST,          B_AUD_RST|B_AREF_RST|B_HDCP_RST) ;

    // if (pVTiming->VideoPixelClock>80000000)
    // {
    //     level = PCLK_HIGH ;
    // }
    // else if (pVTiming->VideoPixelClock>20000000)
    // {
    //     level = PCLK_MEDIUM ;
    // }
    // else
    // {
    //     level = PCLK_LOW ;
    // }

    SetupAFE(level) ; // pass if High Freq request

    for(i = 0 ; i < 100 ; i++)
    {
        if(HDMITX_ReadI2C_Byte(REG_TX_SYS_STATUS) & B_TXVIDSTABLE)
        {
            break ;

        }
        DelayMS(1) ;
    }
    // Clive suggestion.
    // clear int3 video stable interrupt.
    HDMITX_WriteI2C_Byte(REG_TX_INT_CLR0,0) ;
    HDMITX_WriteI2C_Byte(REG_TX_INT_CLR1,B_CLR_VIDSTABLE) ;
    HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS,B_INTACTDONE) ;
    HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS,0) ;

    FireAFE() ;
	return TRUE ;
}

BOOL EnableAudioOutput(ULONG VideoPixelClock,BYTE bAudioSampleFreq,BYTE ChannelNumber,BYTE bAudSWL,BYTE bSPDIF)
{
    BYTE bAudioChannelEnable ;
  // richard   unsigned long N ;

    Instance[0].TMDSClock = VideoPixelClock ;
    Instance[0].bAudFs = bAudioSampleFreq ;
    
    ErrorF("EnableAudioOutput(%d,%ld,%x,%d,%d,%d);\n",0,VideoPixelClock,bAudioSampleFreq,ChannelNumber,bAudSWL,bSPDIF) ;

    switch(ChannelNumber)
    {
    case 7:
    case 8:
        bAudioChannelEnable = 0xF ;
        break ;
    case 6:
    case 5:
        bAudioChannelEnable = 0x7 ;
        break ;
    case 4:
    case 3:
        bAudioChannelEnable = 0x3 ;
        break ;
    case 2:
    case 1:
    default:
        bAudioChannelEnable = 0x1 ;
        break ;
    }

    if(bSPDIF) bAudioChannelEnable |= B_AUD_SPDIF ;

    if( bSPDIF )
    {
        Switch_HDMITX_Bank(1) ;
        HDMITX_WriteI2C_Byte(REGPktAudCTS0,0x50) ;
        HDMITX_WriteI2C_Byte(REGPktAudCTS1,0x73) ;
        HDMITX_WriteI2C_Byte(REGPktAudCTS2,0x00) ;
        
        HDMITX_WriteI2C_Byte(REGPktAudN0,0) ;
        HDMITX_WriteI2C_Byte(REGPktAudN1,0x18) ;
        HDMITX_WriteI2C_Byte(REGPktAudN2,0) ;
        Switch_HDMITX_Bank(0) ;
    
        HDMITX_WriteI2C_Byte(0xC5, 2) ; // D[1] = 0, HW auto count CTS
    }
    else
    {
        SetNCTS(VideoPixelClock,bAudioSampleFreq) ;
    }

    /*
    if(VideoPixelClock != 0)
    {
        SetNCTS(VideoPixelClock,bAudioSampleFreq) ;
    }
    else
    {
        switch(bAudioSampleFreq)
        {
		case AUDFS_32KHz: N = 4096; break;
		case AUDFS_44p1KHz: N = 6272; break;
		case AUDFS_48KHz: N = 6144; break;
		case AUDFS_88p2KHz: N = 12544; break;
		case AUDFS_96KHz: N = 12288; break;
		case AUDFS_176p4KHz: N = 25088; break;
		case AUDFS_192KHz: N = 24576; break;
		default: N = 6144;
        }
        Switch_HDMITX_Bank(1) ;
        HDMITX_WriteI2C_Byte(REGPktAudN0,(BYTE)((N)&0xFF)) ;
        HDMITX_WriteI2C_Byte(REGPktAudN1,(BYTE)((N>>8)&0xFF)) ;
        HDMITX_WriteI2C_Byte(REGPktAudN2,(BYTE)((N>>16)&0xF)) ;
        Switch_HDMITX_Bank(0) ;
        HDMITX_WriteI2C_Byte(REG_TX_PKT_SINGLE_CTRL,0) ; // D[1] = 0,HW auto count CTS
    }
    */

	//HDMITX_AndREG_Byte(REG_TX_SW_RST,~(B_AUD_RST|B_AREF_RST)) ;
    SetAudioFormat(ChannelNumber,bAudioChannelEnable,bAudioSampleFreq,bAudSWL,bSPDIF) ;

    #ifdef HDMITX_REG_DEBUG
    DumpCatHDMITXReg() ;
    #endif // HDMITX_REG_DEBUG
    return TRUE ;
}


BOOL
GetEDIDData(int EDIDBlockID,BYTE *pEDIDData)
{
	if(!pEDIDData)
	{
		return FALSE ;
	}

    if(ReadEDID(pEDIDData,EDIDBlockID/2,(EDIDBlockID%2)*128,128) == ER_FAIL)
    {
        return FALSE ;
    }

    return TRUE ;
}


BOOL
EnableHDCP(BYTE bEnable)
{
    if(bEnable)
    {
        if(ER_FAIL == HDCP_Authenticate())
        {
			
            HDCP_ResetAuth() ;    
			return FALSE ;
        }

    }
    else
    {
        HDCP_ResetAuth() ;    
    }
    return TRUE ;
}


BOOL
CheckHDMITX(BYTE *pHPD,BYTE *pHPDChange)
{
    BYTE intdata1,intdata2,intdata3,sysstat;
    BYTE  intclr3 = 0 ;
    BOOL PrevHPD = Instance[0].bHPD ;
    BOOL HPD ;

    sysstat = HDMITX_ReadI2C_Byte(REG_TX_SYS_STATUS) ;  // read system status register
    
  //  OS_PRINTF("sysstat(REG[0x0E])=%02Xh\r\n", sysstat);    

    HPD = ((sysstat & (B_HPDETECT|B_RXSENDETECT)) == (B_HPDETECT|B_RXSENDETECT))?TRUE:FALSE ;

    // 2007/06/20 added by jj_tseng@chipadvanced.com
    if(pHPDChange)
    {
    	*pHPDChange = FALSE ;

    }
    //~jj_tseng@chipadvanced.com 2007/06/20

    if(!HPD)
    {
        Instance[0].bAuthenticated = FALSE ;
    }

    if(sysstat & B_INT_ACTIVE)  // interrupt is activce
    {

        intdata1 = HDMITX_ReadI2C_Byte(REG_TX_INT_STAT1) ;  // reg 0x06
        //ErrorF("INT_Handler: reg%02x = %02x\n",REG_TX_INT_STAT1,intdata1) ;

		if(intdata1 & B_INT_DDCFIFO_ERR)
		{
		    //ErrorF("DDC FIFO Error.\n") ;
		    ClearDDCFIFO() ;
		}


		if(intdata1 & B_INT_DDC_BUS_HANG)
		{
		    ErrorF("DDC BUS HANG.\n") ;
            AbortDDC() ;

            if(Instance[0].bAuthenticated)
            {
                ErrorF("when DDC hang,and aborted DDC,the HDCP authentication need to restart.\n") ;
                HDCP_ResumeAuthentication() ;
            }
		}


		if(intdata1 & (B_INT_HPD_PLUG|B_INT_RX_SENSE))
		{

            if(pHPDChange) *pHPDChange = TRUE ;

            if(!HPD)
            {
                // reset
                HDMITX_WriteI2C_Byte(REG_TX_SW_RST,B_AREF_RST|B_VID_RST|B_AUD_RST|B_HDCP_RST) ;
                DelayMS(1) ;
                HDMITX_WriteI2C_Byte(REG_TX_AFE_DRV_CTRL,B_AFE_DRV_RST|B_AFE_DRV_PWD) ;
                //ErrorF("Unplug,%x %x\n",HDMITX_ReadI2C_Byte(REG_TX_SW_RST),HDMITX_ReadI2C_Byte(REG_TX_AFE_DRV_CTRL)) ;
                // VState = TXVSTATE_Unplug ;
            }
		}


        intdata2 = HDMITX_ReadI2C_Byte(REG_TX_INT_STAT2) ;  // reg 0x07
        //ErrorF("INT_Handler: reg%02x = %02x\n",REG_TX_INT_STAT2,intdata2) ;



		#ifdef SUPPORT_HDCP
		if(intdata2 & B_INT_AUTH_DONE)
		{
            ErrorF("interrupt Authenticate Done.\n") ;
            HDMITX_OrREG_Byte(REG_TX_INT_MASK2,B_T_AUTH_DONE_MASK) ;
            Instance[0].bAuthenticated = TRUE ;
            SetAVMute(FALSE) ;
		}

		if(intdata2 & B_INT_AUTH_FAIL)
		{
            ErrorF("interrupt Authenticate Fail.\n") ;
			AbortDDC();   // @emily add
            HDCP_ResumeAuthentication() ;
        }
        #endif // SUPPORT_HDCP

		intdata3 = HDMITX_ReadI2C_Byte(REG_TX_INT_STAT3) ;  // reg 0x08
		if(intdata3 & B_INT_VIDSTABLE)
		{
			sysstat = HDMITX_ReadI2C_Byte(REG_TX_SYS_STATUS) ;
			if(sysstat & B_TXVIDSTABLE)
			{
				FireAFE() ;
			}
		}
        HDMITX_WriteI2C_Byte(REG_TX_INT_CLR0,0xFF) ;
        HDMITX_WriteI2C_Byte(REG_TX_INT_CLR1,0xFF) ;
        intclr3 = (HDMITX_ReadI2C_Byte(REG_TX_SYS_STATUS))|B_CLR_AUD_CTS | B_INTACTDONE ;
        HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS,intclr3) ; // clear interrupt.
        intclr3 &= ~(B_INTACTDONE) ;
        HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS,intclr3) ; // INTACTDONE reset to zero.
    }
    else
    {
        if(pHPDChange)
        {
            *pHPDChange = (HPD != PrevHPD)?TRUE:FALSE ;

            if(*pHPDChange &&(!HPD))
            {
                HDMITX_WriteI2C_Byte(REG_TX_AFE_DRV_CTRL,B_AFE_DRV_RST|B_AFE_DRV_PWD) ;
            }
        }
    }

    SetupAudioChannel() ; // 2007/12/12 added by jj_tseng
    
    if(pHPD)
    {
        *pHPD = HPD ? TRUE:FALSE ;
    }

    Instance[0].bHPD  = (BYTE)HPD ;
    return HPD ;
}

void
DisableIT6613()
{
    HDMITX_WriteI2C_Byte(REG_TX_SW_RST,B_AREF_RST|B_VID_RST|B_AUD_RST|B_HDCP_RST) ;
    DelayMS(1) ;
    HDMITX_WriteI2C_Byte(REG_TX_AFE_DRV_CTRL,B_AFE_DRV_RST|B_AFE_DRV_PWD) ;
}

void
DisableVideoOutput()
{
	BYTE uc = HDMITX_ReadI2C_Byte(REG_TX_SW_RST) | B_VID_RST ;
	HDMITX_WriteI2C_Byte(REG_TX_SW_RST,uc) ;
    HDMITX_WriteI2C_Byte(REG_TX_AFE_DRV_CTRL,B_AFE_DRV_RST|B_AFE_DRV_PWD) ;
}


void
DisableAudioOutput()
{
	BYTE uc = HDMITX_ReadI2C_Byte(REG_TX_SW_RST) | B_AUD_RST ;
	HDMITX_WriteI2C_Byte(REG_TX_SW_RST,uc) ;
}



BOOL
EnableAVIInfoFrame(BYTE bEnable,BYTE *pAVIInfoFrame)
{
    if(!bEnable)
    {
        DISABLE_AVI_INFOFRM_PKT() ;
        return TRUE ;
    }

    if(SetAVIInfoFrame((AVI_InfoFrame *)pAVIInfoFrame) == ER_SUCCESS)
    {
        return TRUE ;
    }

    return FALSE ;
}

BOOL
EnableAudioInfoFrame(BYTE bEnable,BYTE *pAudioInfoFrame)
{
    if(!bEnable)
    {
        // richard modify, DISABLE_AVI_INFOFRM_PKT() ;
        DISABLE_AUD_INFOFRM_PKT(); 
        return TRUE ;
    }


    if(SetAudioInfoFrame((Audio_InfoFrame *)pAudioInfoFrame) == ER_SUCCESS)
    {
        return TRUE ;
    }

    return FALSE ;
}

void
SetAVMute(BYTE bEnable)
{
    BYTE uc ;

    Switch_HDMITX_Bank(0) ;
    uc = HDMITX_ReadI2C_Byte(REG_TX_GCP) ;
    uc &= ~B_TX_SETAVMUTE ;
    uc |= bEnable?B_TX_SETAVMUTE:0 ;
    HDMITX_WriteI2C_Byte(REG_TX_GCP,uc) ;
    HDMITX_WriteI2C_Byte(REG_TX_PKT_GENERAL_CTRL,B_ENABLE_PKT|B_REPEAT_PKT) ;
}

void
SetOutputColorDepthPhase(BYTE ColorDepth,BYTE bPhase)
{
    BYTE uc ;
    BYTE bColorDepth ;

    if(ColorDepth == 30)
    {
        bColorDepth = B_CD_30 ;
    }
    else if (ColorDepth == 36)
    {
        bColorDepth = B_CD_36 ;
    }
    else if (ColorDepth == 24)
    {
        bColorDepth = B_CD_24 ;
    }
    else
    {
        bColorDepth = 0 ; // not indicated
    }

    Switch_HDMITX_Bank(0) ;
    uc = HDMITX_ReadI2C_Byte(REG_TX_GCP) ;
    uc &= ~B_COLOR_DEPTH_MASK ;
    uc |= bColorDepth&B_COLOR_DEPTH_MASK;
    HDMITX_WriteI2C_Byte(REG_TX_GCP,uc) ;
}

void
Get6613Reg(BYTE *pReg)
{
	int i ;
	BYTE reg ;
    Switch_HDMITX_Bank(0) ;
	for(i = 0 ; i < 0x100 ; i++)
	{
		reg = i & 0xFF ;
		pReg[i] = HDMITX_ReadI2C_Byte(reg) ;
	}
    Switch_HDMITX_Bank(1) ;
	for(reg = 0x30 ; reg < 0xB0 ; i++,reg++)
	{
		pReg[i] = HDMITX_ReadI2C_Byte(reg) ;
	}
    Switch_HDMITX_Bank(0) ;

}
//////////////////////////////////////////////////////////////////////
// SubProcedure process                                                       //
//////////////////////////////////////////////////////////////////////
#ifdef SUPPORT_DEGEN

typedef struct {
    MODE_ID id ;
    BYTE Reg90;
    BYTE Reg92;
    BYTE Reg93;
    BYTE Reg94;
    BYTE Reg9A;
    BYTE Reg9B;
    BYTE Reg9C;
    BYTE Reg9D;
    BYTE Reg9E;
    BYTE Reg9F;
} DEGEN_Setting ;


static _CODE DEGEN_Setting DeGen_Table[] = {
    {CEA_640x480p60      ,0x01,0x8E,0x0E,0x30,0x22,0x02,0x20,0xFF,0xFF,0xFF},
    // HDES = 142, HDEE = 782, VDES = 34, VDEE = 514
    {CEA_720x480p60      ,0x01,0x78,0x48,0x30,0x23,0x03,0x20,0xFF,0xFF,0xFF},
    // HDES = 120, HDEE = 840, VDES = 35, VDEE = 515
    {CEA_1280x720p60     ,0x07,0x02,0x02,0x61,0x18,0xE8,0x20,0xFF,0xFF,0xFF},
    // HDES = 258, HDEE = 1538, VDES = 24, VDEE = 744
//    {CEA_1920x1080i60    ,0x07,0xBE,0x3E,0x80,0x13,0x2F,0x20,0x45,0x61,0x42},
//    // HDES = 190, HDEE = 2110, VDES = 19, VDEE = 559, VDS2 = 581, VDE2 = 1121
    {CEA_1920x1080i60    ,0x07,0xBE,0x3E,0x80,0x13,0x2F,0x20,0x46,0x62,0x42},
    // HDES = 190, HDEE = 2110, VDES = 19, VDEE = 559, VDS2 = 582, VDE2 = 1122

    {CEA_720x480i60      ,0x01,0x75,0x45,0x30,0x11,0x01,0x10,0x17,0x07,0x21},
    // HDES = 117, HDEE = 837, VDES = 17, VDEE = 257, VDS2 = 279, VDE2 = 519
    {CEA_720x240p60      ,0x01,0x75,0x45,0x30,0x11,0x01,0x10,0xFF,0xFF,0xFF},
    // HDES = 117, HDEE = 837, VDES = 17, VDEE = 257
    {CEA_1440x480i60     ,0x01,0xEC,0x8C,0x60,0x11,0x01,0x10,0x17,0x07,0x21},
    // HDES = 236, HDEE = 1676, VDES = 17, VDEE = 257, VDS2 = 279, VDE2 = 519
    {CEA_1440x240p60     ,0x01,0xEC,0x8C,0x60,0x11,0x01,0x10,0xFF,0xFF,0xFF},
    // HDES = 236, HDEE = 1676, VDES = 17, VDEE = 257
    {CEA_2880x480i60     ,0x01,0x16,0x56,0xD2,0x11,0x01,0x10,0x17,0x07,0x21},
    // HDES = 534, HDEE = 3414, VDES = 17, VDEE = 257, VDS2 = 279, VDE2 = 519
    {CEA_2880x240p60     ,0x01,0x16,0x56,0xD2,0x11,0x01,0x10,0xFF,0xFF,0xFF},
    // HDES = 534, HDEE = 3414, VDES = 17, VDEE = 257
    {CEA_1440x480p60     ,0x01,0xF2,0x92,0x60,0x23,0x03,0x20,0xFF,0xFF,0xFF},
    // HDES = 242, HDEE = 1682, VDES = 35, VDEE = 515
    {CEA_1920x1080p60    ,0x07,0xBE,0x3E,0x80,0x28,0x60,0x40,0xFF,0xFF,0xFF},
    // HDES = 190, HDEE = 2110, VDES = 40, VDEE = 1120
    {CEA_720x576p50      ,0x01,0x82,0x52,0x30,0x2b,0x6b,0x20,0xFF,0xFF,0xFF},
    // HDES = 130, HDEE = 850, VDES = 43, VDEE = 619
    {CEA_1280x720p50     ,0x07,0x02,0x02,0x61,0x18,0xE8,0x20,0xFF,0xFF,0xFF},
    // HDES = 258, HDEE = 1538, VDES = 24, VDEE = 744
    {CEA_1920x1080i50    ,0x07,0xBE,0x3E,0x80,0x13,0x2F,0x20,0x46,0x62,0x42},
    // HDES = 190, HDEE = 2110, VDES = 19, VDEE = 559, VDS2 = 582, VDE2 = 1122
    {CEA_720x576i50      ,0x01,0x82,0x52,0x30,0x15,0x35,0x10,0x4D,0x6D,0x21},
    // HDES = 130, HDEE = 850, VDES = 21, VDEE = 309, VDS2 = 333, VDE2 = 621
    {CEA_1440x576i50     ,0x01,0x06,0xA6,0x61,0x15,0x35,0x10,0x4D,0x6D,0x21},
    // HDES = 262, HDEE = 1702, VDES = 21, VDEE = 309, VDS2 = 333, VDE2 = 621
    {CEA_720x288p50      ,0x01,0x82,0x52,0x30,0x15,0x35,0x10,0xFF,0xFF,0xFF},
    // HDES = 130, HDEE = 850, VDES = 21, VDEE = 309
    {CEA_1440x288p50     ,0x01,0x06,0xA6,0x61,0x15,0x35,0x10,0xFF,0xFF,0xFF},
    // HDES = 262, HDEE = 1702, VDES = 21, VDEE = 309
    {CEA_2880x576i50     ,0x01,0x0E,0x4E,0xD2,0x15,0x35,0x10,0x4D,0x6D,0x21},
    // HDES = 526, HDEE = 3406, VDES = 21, VDEE = 309, VDS2 = 333, VDE2 = 621
    {CEA_2880x288p50     ,0x01,0x0E,0x4E,0xD2,0x15,0x35,0x10,0xFF,0xFF,0xFF},
    // HDES = 526, HDEE = 3406, VDES = 21, VDEE = 309
    {CEA_1440x576p50     ,0x05,0x06,0xA6,0x61,0x2B,0x6B,0x20,0xFF,0xFF,0xFF},
    // HDES = 262, HDEE = 1702, VDES = 43, VDEE = 619
    {CEA_1920x1080p50    ,0x07,0xBE,0x3E,0x80,0x28,0x60,0x40,0xFF,0xFF,0xFF},
    // HDES = 190, HDEE = 2110, VDES = 40, VDEE = 1120
    {CEA_1920x1080p24    ,0x07,0xBE,0x3E,0x80,0x28,0x60,0x40,0xFF,0xFF,0xFF},
    // HDES = 190, HDEE = 2110, VDES = 40, VDEE = 1120
    {CEA_1920x1080p25    ,0x07,0xBE,0x3E,0x80,0x28,0x60,0x40,0xFF,0xFF,0xFF},
    // HDES = 190, HDEE = 2110, VDES = 40, VDEE = 1120
    {CEA_1920x1080p30    ,0x07,0xBE,0x3E,0x80,0x28,0x60,0x40,0xFF,0xFF,0xFF},
    // HDES = 190, HDEE = 2110, VDES = 40, VDEE = 1120
    {VESA_640x350p85     ,0x03,0x9E,0x1E,0x30,0x3E,0x9C,0x10,0xFF,0xFF,0xFF},
    // HDES = 158, HDEE = 798, VDES = 62, VDEE = 412
    {VESA_640x400p85     ,0x05,0x9E,0x1E,0x30,0x2B,0xBB,0x10,0xFF,0xFF,0xFF},
    // HDES = 158, HDEE = 798, VDES = 43, VDEE = 443
    {VESA_720x400p85     ,0x05,0xB2,0x82,0x30,0x2C,0xBC,0x10,0xFF,0xFF,0xFF},
    // HDES = 178, HDEE = 898, VDES = 44, VDEE = 444
    {VESA_640x480p60     ,0x01,0x8E,0x0E,0x30,0x22,0x02,0x20,0xFF,0xFF,0xFF},
    // HDES = 142, HDEE = 782, VDES = 34, VDEE = 514
    {VESA_640x480p72     ,0x01,0xA6,0x26,0x30,0x1E,0xFE,0x10,0xFF,0xFF,0xFF},
    // HDES = 166, HDEE = 806, VDES = 30, VDEE = 510
    {VESA_640x480p75     ,0x01,0xB6,0x36,0x30,0x12,0xF2,0x10,0xFF,0xFF,0xFF},
    // HDES = 182, HDEE = 822, VDES = 18, VDEE = 498
    {VESA_640x480p85     ,0x01,0x86,0x06,0x30,0x1B,0xFB,0x10,0xFF,0xFF,0xFF},
    // HDES = 134, HDEE = 774, VDES = 27, VDEE = 507
    {VESA_800x600p56     ,0x07,0xC6,0xE6,0x30,0x17,0x6F,0x20,0xFF,0xFF,0xFF},
    // HDES = 198, HDEE = 998, VDES = 23, VDEE = 623
    {VESA_800x600p60     ,0x07,0xD6,0xF6,0x30,0x1A,0x72,0x20,0xFF,0xFF,0xFF},
    // HDES = 214, HDEE = 1014, VDES = 26, VDEE = 626
    {VESA_800x600p72     ,0x07,0xB6,0xD6,0x30,0x1C,0x74,0x20,0xFF,0xFF,0xFF},
    // HDES = 182, HDEE = 982, VDES = 28, VDEE = 628
    {VESA_800x600p75     ,0x07,0xEE,0x0E,0x40,0x17,0x6F,0x20,0xFF,0xFF,0xFF},
    // HDES = 238, HDEE = 1038, VDES = 23, VDEE = 623
    {VESA_800X600p85     ,0x07,0xD6,0xF6,0x30,0x1D,0x75,0x20,0xFF,0xFF,0xFF},
    // HDES = 214, HDEE = 1014, VDES = 29, VDEE = 629
    {VESA_840X480p60     ,0x07,0xDE,0x2E,0x40,0x1E,0xFE,0x10,0xFF,0xFF,0xFF},
    // HDES = 222, HDEE = 1070, VDES = 30, VDEE = 510
    {VESA_1024x768p60    ,0x01,0x26,0x26,0x51,0x22,0x22,0x30,0xFF,0xFF,0xFF},
    // HDES = 294, HDEE = 1318, VDES = 34, VDEE = 802
    {VESA_1024x768p70    ,0x01,0x16,0x16,0x51,0x22,0x22,0x30,0xFF,0xFF,0xFF},
    // HDES = 278, HDEE = 1302, VDES = 34, VDEE = 802
    {VESA_1024x768p75    ,0x07,0x0E,0x0E,0x51,0x1E,0x1E,0x30,0xFF,0xFF,0xFF},
    // HDES = 270, HDEE = 1294, VDES = 30, VDEE = 798
    {VESA_1024x768p85    ,0x07,0x2E,0x2E,0x51,0x26,0x26,0x30,0xFF,0xFF,0xFF},
    // HDES = 302, HDEE = 1326, VDES = 38, VDEE = 806
    {VESA_1152x864p75    ,0x07,0x7E,0xFE,0x51,0x22,0x82,0x30,0xFF,0xFF,0xFF},
    // HDES = 382, HDEE = 1534, VDES = 34, VDEE = 898
    {VESA_1280x768p60R   ,0x03,0x6E,0x6E,0x50,0x12,0x12,0x30,0xFF,0xFF,0xFF},
    // HDES = 110, HDEE = 1390, VDES = 18, VDEE = 786
    {VESA_1280x768p60    ,0x05,0x3E,0x3E,0x61,0x1A,0x1A,0x30,0xFF,0xFF,0xFF},
    // HDES = 318, HDEE = 1598, VDES = 26, VDEE = 794
    {VESA_1280x768p75    ,0x05,0x4E,0x4E,0x61,0x21,0x21,0x30,0xFF,0xFF,0xFF},
    // HDES = 334, HDEE = 1614, VDES = 33, VDEE = 801
    {VESA_1280x768p85    ,0x05,0x5E,0x5E,0x61,0x25,0x25,0x30,0xFF,0xFF,0xFF},
    // HDES = 350, HDEE = 1630, VDES = 37, VDEE = 805
    {VESA_1280x960p60    ,0x07,0xA6,0xA6,0x61,0x26,0xE6,0x30,0xFF,0xFF,0xFF},
    // HDES = 422, HDEE = 1702, VDES = 38, VDEE = 998
    {VESA_1280x960p85    ,0x07,0x7E,0x7E,0x61,0x31,0xF1,0x30,0xFF,0xFF,0xFF},
    // HDES = 382, HDEE = 1662, VDES = 49, VDEE = 1009
    {VESA_1280x1024p60   ,0x07,0x66,0x66,0x61,0x28,0x28,0x40,0xFF,0xFF,0xFF},
    // HDES = 358, HDEE = 1638, VDES = 40, VDEE = 1064
    {VESA_1280x1024p75   ,0x07,0x86,0x86,0x61,0x28,0x28,0x40,0xFF,0xFF,0xFF},
    // HDES = 390, HDEE = 1670, VDES = 40, VDEE = 1064
    {VESA_1280X1024p85   ,0x07,0x7E,0x7E,0x61,0x2E,0x2E,0x40,0xFF,0xFF,0xFF},
    // HDES = 382, HDEE = 1662, VDES = 46, VDEE = 1070
    {VESA_1360X768p60    ,0x07,0x6E,0xBE,0x61,0x17,0x17,0x30,0xFF,0xFF,0xFF},
    // HDES = 366, HDEE = 1726, VDES = 23, VDEE = 791
    {VESA_1400x768p60R   ,0x03,0x6E,0xE6,0x50,0x1A,0x34,0x40,0xFF,0xFF,0xFF},
    // HDES = 110, HDEE = 1510, VDES = 26, VDEE = 1076
    {VESA_1400x768p60    ,0x05,0x76,0xEE,0x61,0x23,0x3D,0x40,0xFF,0xFF,0xFF},
    // HDES = 374, HDEE = 1774, VDES = 35, VDEE = 1085
    {VESA_1400x1050p75   ,0x05,0x86,0xFE,0x61,0x2D,0x47,0x40,0xFF,0xFF,0xFF},
    // HDES = 390, HDEE = 1790, VDES = 45, VDEE = 1095
    {VESA_1400x1050p85   ,0x05,0x96,0x0E,0x71,0x33,0x4D,0x40,0xFF,0xFF,0xFF},
    // HDES = 406, HDEE = 1806, VDES = 51, VDEE = 1101
    {VESA_1440x900p60R   ,0x03,0x6E,0x0E,0x60,0x16,0x9A,0x30,0xFF,0xFF,0xFF},
    // HDES = 110, HDEE = 1550, VDES = 22, VDEE = 922
    {VESA_1440x900p60    ,0x05,0x7E,0x1E,0x71,0x1E,0xA2,0x30,0xFF,0xFF,0xFF},
    // HDES = 382, HDEE = 1822, VDES = 30, VDEE = 930
    {VESA_1440x900p75    ,0x05,0x8E,0x2E,0x71,0x26,0xAA,0x30,0xFF,0xFF,0xFF},
    // HDES = 398, HDEE = 1838, VDES = 38, VDEE = 938
    {VESA_1440x900p85    ,0x05,0x96,0x36,0x71,0x2C,0xB0,0x30,0xFF,0xFF,0xFF},
    // HDES = 406, HDEE = 1846, VDES = 44, VDEE = 944
    {VESA_1600x1200p60   ,0x07,0xEE,0x2E,0x81,0x30,0xE0,0x40,0xFF,0xFF,0xFF},
    // HDES = 494, HDEE = 2094, VDES = 48, VDEE = 1248
    {VESA_1600x1200p65   ,0x07,0xEE,0x2E,0x81,0x30,0xE0,0x40,0xFF,0xFF,0xFF},
    // HDES = 494, HDEE = 2094, VDES = 48, VDEE = 1248
    {VESA_1600x1200p70   ,0x07,0xEE,0x2E,0x81,0x30,0xE0,0x40,0xFF,0xFF,0xFF},
    // HDES = 494, HDEE = 2094, VDES = 48, VDEE = 1248
    {VESA_1600x1200p75   ,0x07,0xEE,0x2E,0x81,0x30,0xE0,0x40,0xFF,0xFF,0xFF},
    // HDES = 494, HDEE = 2094, VDES = 48, VDEE = 1248
    {VESA_1600x1200p85   ,0x07,0xEE,0x2E,0x81,0x30,0xE0,0x40,0xFF,0xFF,0xFF},
    // HDES = 494, HDEE = 2094, VDES = 48, VDEE = 1248
    {VESA_1680x1050p60R  ,0x03,0x6E,0xFE,0x60,0x1A,0x34,0x40,0xFF,0xFF,0xFF},
    // HDES = 110, HDEE = 1790, VDES = 26, VDEE = 1076
    {VESA_1680x1050p60   ,0x05,0xC6,0x56,0x81,0x23,0x3D,0x40,0xFF,0xFF,0xFF},
    // HDES = 454, HDEE = 2134, VDES = 35, VDEE = 1085
    {VESA_1680x1050p75   ,0x05,0xD6,0x66,0x81,0x2D,0x47,0x40,0xFF,0xFF,0xFF},
    // HDES = 470, HDEE = 2150, VDES = 45, VDEE = 1095
    {VESA_1680x1050p85   ,0x05,0xDE,0x6E,0x81,0x33,0x4D,0x40,0xFF,0xFF,0xFF},
    // HDES = 478, HDEE = 2158, VDES = 51, VDEE = 1101
    {VESA_1792x1344p60   ,0x05,0x0E,0x0E,0x92,0x30,0x70,0x50,0xFF,0xFF,0xFF},
    // HDES = 526, HDEE = 2318, VDES = 48, VDEE = 1392
    {VESA_1792x1344p75   ,0x05,0x36,0x36,0x92,0x47,0x87,0x50,0xFF,0xFF,0xFF},
    // HDES = 566, HDEE = 2358, VDES = 71, VDEE = 1415
    {VESA_1856x1392p60   ,0x05,0x3E,0x7E,0x92,0x2D,0x9D,0x50,0xFF,0xFF,0xFF},
    // HDES = 574, HDEE = 2430, VDES = 45, VDEE = 1437
    {VESA_1856x1392p75   ,0x05,0x3E,0x7E,0x92,0x6A,0xDA,0x50,0xFF,0xFF,0xFF},
    // HDES = 574, HDEE = 2430, VDES = 106, VDEE = 1498
    {VESA_1920x1200p60R  ,0x03,0x6E,0xEE,0x70,0x1F,0xCF,0x40,0xFF,0xFF,0xFF},
    // HDES = 110, HDEE = 2030, VDES = 31, VDEE = 1231
    {VESA_1920x1200p60   ,0x05,0x16,0x96,0x92,0x29,0xD9,0x40,0xFF,0xFF,0xFF},
    // HDES = 534, HDEE = 2454, VDES = 41, VDEE = 1241
    {VESA_1920x1200p75   ,0x05,0x26,0xA6,0x92,0x33,0xE3,0x40,0xFF,0xFF,0xFF},
    // HDES = 550, HDEE = 2470, VDES = 51, VDEE = 1251
    {VESA_1920x1200p85   ,0x05,0x2E,0xAE,0x92,0x3A,0xEA,0x40,0xFF,0xFF,0xFF},
    // HDES = 558, HDEE = 2478, VDES = 58, VDEE = 1258
    {VESA_1920x1440p60   ,0x05,0x26,0xA6,0x92,0x3A,0xDA,0x50,0xFF,0xFF,0xFF},
    // HDES = 550, HDEE = 2470, VDES = 58, VDEE = 1498
    {VESA_1920x1440p75   ,0x05,0x3E,0xBE,0x92,0x3A,0xDA,0x50,0xFF,0xFF,0xFF},
    // HDES = 574, HDEE = 2494, VDES = 58, VDEE = 1498
    {UNKNOWN_MODE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}
} ;

BOOL ProgramDEGenModeByID(MODE_ID id,BYTE bInputSignalType)
{
    int i ;
    if( (bInputSignalType & (T_MODE_DEGEN|T_MODE_SYNCGEN|T_MODE_SYNCEMB) )==(T_MODE_DEGEN))
    {
        for( i = 0 ; DeGen_Table[i].id != UNKNOWN_MODE ; i++ )
        {
            if( id == DeGen_Table[i].id ) break ;
        }
        if( DeGen_Table[i].id == UNKNOWN_MODE )
        {
            return FALSE ;
        }
        
        Switch_HDMITX_Bank(0) ;
        HDMITX_WriteI2C_Byte(0x90,DeGen_Table[i].Reg90) ;
        HDMITX_WriteI2C_Byte(0x92,DeGen_Table[i].Reg92) ;
        HDMITX_WriteI2C_Byte(0x93,DeGen_Table[i].Reg93) ;
        HDMITX_WriteI2C_Byte(0x94,DeGen_Table[i].Reg94) ;
        HDMITX_WriteI2C_Byte(0x9A,DeGen_Table[i].Reg9A) ;
        HDMITX_WriteI2C_Byte(0x9B,DeGen_Table[i].Reg9B) ;
        HDMITX_WriteI2C_Byte(0x9C,DeGen_Table[i].Reg9C) ;
        HDMITX_WriteI2C_Byte(0x9D,DeGen_Table[i].Reg9D) ;
        HDMITX_WriteI2C_Byte(0x9E,DeGen_Table[i].Reg9E) ;
        HDMITX_WriteI2C_Byte(0x9F,DeGen_Table[i].Reg9F) ;
        return TRUE ;
        
    }
    return FALSE ;
}

#endif

#ifdef SUPPORT_SYNCEMBEDDED
/* ****************************************************** */
// sync embedded table setting,defined as comment.
/* ****************************************************** */
struct SyncEmbeddedSetting {
    BYTE fmt ;
    BYTE RegHVPol ; // Reg90
	BYTE RegHfPixel ; // Reg91
    BYTE RegHSSL ; // Reg95
    BYTE RegHSEL ; // Reg96
    BYTE RegHSH ; // Reg97
    BYTE RegVSS1 ; // RegA0
    BYTE RegVSE1 ; // RegA1
    BYTE RegVSS2 ; // RegA2
    BYTE RegVSE2 ; // RegA3

    ULONG PCLK ;
    BYTE VFreq ;
} ;

static _CODE struct SyncEmbeddedSetting SyncEmbTable[] = {
 // {FMT,0x90,0x91,
 //                 0x95,0x96,0x97,0xA0,0xA1,0xA2,0xA3,PCLK,VFREQ},
    {   1,0xF0,0x31,0x0E,0x6E,0x00,0x0A,0xC0,0xFF,0xFF,25175000,60},
    {   2,0xF0,0x31,0x0E,0x4c,0x00,0x09,0xF0,0xFF,0xFF,27000000,60},
    {   3,0xF0,0x31,0x0E,0x4c,0x00,0x09,0xF0,0xFF,0xFF,27000000,60},
    {   4,0x76,0x33,0x6c,0x94,0x00,0x05,0xA0,0xFF,0xFF,74175000,60},
    {   5,0x26,0x4A,0x56,0x82,0x00,0x02,0x70,0x34,0x92,74175000,60},
    {   6,0xE0,0x1B,0x11,0x4F,0x00,0x04,0x70,0x0A,0xD1,27000000,60},
    {   7,0xE0,0x1B,0x11,0x4F,0x00,0x04,0x70,0x0A,0xD1,27000000,60},
    {   8,0x00,0xff,0x11,0x4F,0x00,0x04,0x70,0xFF,0xFF,27000000,60},
    {   9,0x00,0xff,0x11,0x4F,0x00,0x04,0x70,0xFF,0xFF,27000000,60},
    {  10,0xe0,0x1b,0x11,0x4F,0x00,0x04,0x70,0x0A,0xD1,54000000,60},
    {  11,0xe0,0x1b,0x11,0x4F,0x00,0x04,0x70,0x0A,0xD1,54000000,60},
    {  12,0x00,0xff,0x11,0x4F,0x00,0x04,0x70,0xFF,0xFF,54000000,60},
    {  13,0x00,0xff,0x11,0x4F,0x00,0x04,0x70,0xFF,0xFF,54000000,60},
    {  14,0x00,0xff,0x1e,0x9A,0x00,0x09,0xF0,0xFF,0xFF,54000000,60},
    {  15,0x00,0xff,0x1e,0x9A,0x00,0x09,0xF0,0xFF,0xFF,54000000,60},
    {  16,0x06,0xff,0x56,0x82,0x00,0x04,0x90,0xFF,0xFF,148350000,60},
    {  17,0x00,0xff,0x0a,0x4A,0x00,0x05,0xA0,0xFF,0xFF,27000000,50},
    {  18,0x00,0xff,0x0a,0x4A,0x00,0x05,0xA0,0xFF,0xFF,27000000,50},
    {  19,0x06,0xff,0xB6,0xDE,0x11,0x05,0xA0,0xFF,0xFF,74250000,50},
    {  20,0x66,0x73,0x0e,0x3A,0x22,0x02,0x70,0x34,0x92,74250000,50},
    {  21,0xA0,0x1B,0x0a,0x49,0x00,0x02,0x50,0x3A,0xD1,27000000,50},
    {  22,0xA0,0x1B,0x0a,0x49,0x00,0x02,0x50,0x3A,0xD1,27000000,50},
    {  23,0x00,0xff,0x0a,0x49,0x00,0x02,0x50,0xFF,0xFF,27000000,50},
    {  24,0x00,0xff,0x0a,0x49,0x00,0x02,0x50,0xFF,0xFF,27000000,50},
    {  25,0xA0,0x1B,0x0a,0x49,0x00,0x02,0x50,0x3A,0xD1,54000000,50},
    {  26,0xA0,0x1B,0x0a,0x49,0x00,0x02,0x50,0x3A,0xD1,54000000,50},
    {  27,0x00,0xff,0x0a,0x49,0x00,0x02,0x50,0xFF,0xFF,54000000,50},
    {  28,0x00,0xff,0x0a,0x49,0x00,0x02,0x50,0xFF,0xFF,54000000,50},
    {  29,0x04,0xff,0x16,0x96,0x00,0x05,0xA0,0xFF,0xFF,54000000,50},
    {  30,0x04,0xff,0x16,0x96,0x00,0x05,0xA0,0xFF,0xFF,54000000,50},
    {  31,0x06,0xff,0x0e,0x3a,0x22,0x04,0x90,0xFF,0xFF,148500000,50},
    {0xFF,0xFF,0xff,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0,0}
} ;

BOOL
ProgramSyncEmbeddedVideoMode(BYTE VIC,BYTE bInputSignalType)
{
    int i ;
    // if Embedded Video,need to generate timing with pattern register

    ErrorF("ProgramSyncEmbeddedVideoMode(%d,%x)\n",VIC,bInputSignalType) ;

    if( bInputSignalType & T_MODE_SYNCEMB )
    {
        for(i = 0 ; SyncEmbTable[i].fmt != 0xFF ; i++)
        {
            if(VIC == SyncEmbTable[i].fmt)
            {
                break ;
            }
        }
    
        if(SyncEmbTable[i].fmt == 0xFF)
        {
            return FALSE ;
        }
    
        HDMITX_WriteI2C_Byte(REG_TX_HVPol,SyncEmbTable[i].RegHVPol) ; // Reg90
        HDMITX_WriteI2C_Byte(REG_TX_HfPixel,SyncEmbTable[i].RegHfPixel) ; // Reg91
    
    	HDMITX_WriteI2C_Byte(REG_TX_HSSL,SyncEmbTable[i].RegHSSL) ; // Reg95
    	HDMITX_WriteI2C_Byte(REG_TX_HSEL,SyncEmbTable[i].RegHSEL) ; // Reg96
    	HDMITX_WriteI2C_Byte(REG_TX_HSH,SyncEmbTable[i].RegHSH) ; // Reg97
        HDMITX_WriteI2C_Byte(REG_TX_VSS1,SyncEmbTable[i].RegVSS1) ; // RegA0
        HDMITX_WriteI2C_Byte(REG_TX_VSE1,SyncEmbTable[i].RegVSE1) ; // RegA1
    
        HDMITX_WriteI2C_Byte(REG_TX_VSS2,SyncEmbTable[i].RegVSS2) ; // RegA2
        HDMITX_WriteI2C_Byte(REG_TX_VSE2,SyncEmbTable[i].RegVSE2) ; // RegA3
    }

    return TRUE ;
}
#endif // SUPPORT_SYNCEMBEDDED

//~jj_tseng@chipadvanced.com 2007/01/02


//////////////////////////////////////////////////////////////////////
// Function: SetInputMode
// Parameter: InputMode,bInputSignalType
//      InputMode - use [1:0] to identify the color space for reg70[7:6],
//                  definition:
//                     #define F_MODE_RGB444  0
//                     #define F_MODE_YUV422 1
//                     #define F_MODE_YUV444 2
//                     #define F_MODE_CLRMOD_MASK 3
//      bInputSignalType - defined the CCIR656 D[0],SYNC Embedded D[1],and
//                     DDR input in D[2].
// Return: N/A
// Remark: program Reg70 with the input value.
// Side-Effect: Reg70.
//////////////////////////////////////////////////////////////////////

static void
SetInputMode(BYTE InputMode,BYTE bInputSignalType)
{
    BYTE ucData ;

    ErrorF("SetInputMode(%02X,%02X)\n",InputMode,bInputSignalType) ;

    ucData = HDMITX_ReadI2C_Byte(REG_TX_INPUT_MODE) ;

    ucData &= ~(M_INCOLMOD|B_2X656CLK|B_SYNCEMB|B_INDDR|B_PCLKDIV2) ;

    switch(InputMode & F_MODE_CLRMOD_MASK)
    {
    case F_MODE_YUV422:
        ucData |= B_IN_YUV422 ;
        break ;
    case F_MODE_YUV444:
        ucData |= B_IN_YUV444 ;
        break ;
    case F_MODE_RGB444:
    default:
        ucData |= B_IN_RGB ;
        break ;
    }

    if(bInputSignalType & T_MODE_PCLKDIV2)
    {
        ucData |= B_PCLKDIV2 ; ErrorF("PCLK Divided by 2 mode\n") ;
    }
    if(bInputSignalType & T_MODE_CCIR656)
    {
        ucData |= B_2X656CLK ; ErrorF("CCIR656 mode\n") ;
    }

    if(bInputSignalType & T_MODE_SYNCEMB)
    {
        ucData |= B_SYNCEMB ; ErrorF("Sync Embedded mode\n") ;
    }

    if(bInputSignalType & T_MODE_INDDR)
    {
        ucData |= B_INDDR ; ErrorF("Input DDR mode\n") ;
    }

    HDMITX_WriteI2C_Byte(REG_TX_INPUT_MODE,ucData) ;
}

//////////////////////////////////////////////////////////////////////
// Function: SetCSCScale
// Parameter: bInputMode -
//             D[1:0] - Color Mode
//             D[4] - Colorimetry 0: ITU_BT601 1: ITU_BT709
//             D[5] - Quantization 0: 0_255 1: 16_235
//             D[6] - Up/Dn Filter 'Required'
//                    0: no up/down filter
//                    1: enable up/down filter when csc need.
//             D[7] - Dither Filter 'Required'
//                    0: no dither enabled.
//                    1: enable dither and dither free go "when required".
//            bOutputMode -
//             D[1:0] - Color mode.
// Return: N/A
// Remark: reg72~reg8D will be programmed depended the input with table.
// Side-Effect:
//////////////////////////////////////////////////////////////////////

static void
SetCSCScale(BYTE bInputMode,BYTE bOutputMode)
{
    BYTE ucData,csc ;
    BYTE filter = 0 ; // filter is for Video CTRL DN_FREE_GO,EN_DITHER,and ENUDFILT


	// (1) YUV422 in,RGB/YUV444 output (Output is 8-bit,input is 12-bit)
	// (2) YUV444/422  in,RGB output (CSC enable,and output is not YUV422)
	// (3) RGB in,YUV444 output   (CSC enable,and output is not YUV422)
    //
    // YUV444/RGB24 <-> YUV422 need set up/down filter.

    switch(bInputMode&F_MODE_CLRMOD_MASK)
    {
    #ifdef SUPPORT_INPUTYUV444
    case F_MODE_YUV444:
        ErrorF("Input mode is YUV444 ") ;
        switch(bOutputMode&F_MODE_CLRMOD_MASK)
        {
        case F_MODE_YUV444:
            ErrorF("Output mode is YUV444\n") ;
            csc = B_CSC_BYPASS ;
            break ;

        case F_MODE_YUV422:
            ErrorF("Output mode is YUV422\n") ;
            if(bInputMode & F_MODE_EN_UDFILT) // YUV444 to YUV422 need up/down filter for processing.
            {
                filter |= B_TX_EN_UDFILTER ;
            }
            csc = B_CSC_BYPASS ;
            break ;
        case F_MODE_RGB444:
            ErrorF("Output mode is RGB24\n") ;
            csc = B_CSC_YUV2RGB ;
            if(bInputMode & F_MODE_EN_DITHER) // YUV444 to RGB24 need dither
            {
                filter |= B_TX_EN_DITHER | B_TX_DNFREE_GO ;
            }

            break ;
        }
        break ;
    #endif

    #ifdef SUPPORT_INPUTYUV422
    case F_MODE_YUV422:
        ErrorF("Input mode is YUV422\n") ;
        switch(bOutputMode&F_MODE_CLRMOD_MASK)
        {
        case F_MODE_YUV444:
            ErrorF("Output mode is YUV444\n") ;
            csc = B_CSC_BYPASS ;
            if(bInputMode & F_MODE_EN_UDFILT) // YUV422 to YUV444 need up filter
            {
                filter |= B_TX_EN_UDFILTER ;
            }

            if(bInputMode & F_MODE_EN_DITHER) // YUV422 to YUV444 need dither
            {
                filter |= B_TX_EN_DITHER | B_TX_DNFREE_GO ;
            }

            break ;
        case F_MODE_YUV422:
            ErrorF("Output mode is YUV422\n") ;
            csc = B_CSC_BYPASS ;

            break ;

        case F_MODE_RGB444:
            ErrorF("Output mode is RGB24\n") ;
            csc = B_CSC_YUV2RGB ;
            if(bInputMode & F_MODE_EN_UDFILT) // YUV422 to RGB24 need up/dn filter.
            {
                filter |= B_TX_EN_UDFILTER ;
            }

            if(bInputMode & F_MODE_EN_DITHER) // YUV422 to RGB24 need dither
            {
                filter |= B_TX_EN_DITHER | B_TX_DNFREE_GO ;
            }

            break ;
        }
        break ;
    #endif

    #ifdef SUPPORT_INPUTRGB
    case F_MODE_RGB444:
        ErrorF("Input mode is RGB24\n") ;
        switch(bOutputMode&F_MODE_CLRMOD_MASK)
        {
        case F_MODE_YUV444:
            ErrorF("Output mode is YUV444\n") ;
            csc = B_CSC_RGB2YUV ;

            if(bInputMode & F_MODE_EN_DITHER) // RGB24 to YUV444 need dither
            {
                filter |= B_TX_EN_DITHER | B_TX_DNFREE_GO ;
            }
            break ;

        case F_MODE_YUV422:
            ErrorF("Output mode is YUV422\n") ;
            if(bInputMode & F_MODE_EN_UDFILT) // RGB24 to YUV422 need down filter.
            {
                filter |= B_TX_EN_UDFILTER ;
            }

            if(bInputMode & F_MODE_EN_DITHER) // RGB24 to YUV422 need dither
            {
                filter |= B_TX_EN_DITHER | B_TX_DNFREE_GO ;
            }
            csc = B_CSC_RGB2YUV ;
            break ;

        case F_MODE_RGB444:
            ErrorF("Output mode is RGB24\n") ;
            csc = B_CSC_BYPASS ;
            break ;
        }
        break ;
    #endif
    }

    #ifdef SUPPORT_INPUTRGB
    // set the CSC metrix registers by colorimetry and quantization
    if(csc == B_CSC_RGB2YUV)
    {
        ErrorF("CSC = RGB2YUV %x ",csc) ;
        switch(bInputMode&(F_MODE_ITU709|F_MODE_16_235))
        {
        case F_MODE_ITU709|F_MODE_16_235:
            ErrorF("ITU709 16-235 ") ;
            HDMITX_WriteI2C_ByteN(REG_TX_CSC_YOFF,bCSCOffset_16_235,SIZEOF_CSCOFFSET) ;
            HDMITX_WriteI2C_ByteN(REG_TX_CSC_MTX11_L,bCSCMtx_RGB2YUV_ITU709_16_235,SIZEOF_CSCMTX) ;
            break ;
        case F_MODE_ITU709|F_MODE_0_255:
            ErrorF("ITU709 0-255 ") ;
            HDMITX_WriteI2C_ByteN(REG_TX_CSC_YOFF,bCSCOffset_0_255,SIZEOF_CSCOFFSET) ;
            HDMITX_WriteI2C_ByteN(REG_TX_CSC_MTX11_L,bCSCMtx_RGB2YUV_ITU709_0_255,SIZEOF_CSCMTX) ;
            break ;
        case F_MODE_ITU601|F_MODE_16_235:
            ErrorF("ITU601 16-235 ") ;
            HDMITX_WriteI2C_ByteN(REG_TX_CSC_YOFF,bCSCOffset_16_235,SIZEOF_CSCOFFSET) ;
            HDMITX_WriteI2C_ByteN(REG_TX_CSC_MTX11_L,bCSCMtx_RGB2YUV_ITU601_16_235,SIZEOF_CSCMTX) ;
            break ;
        case F_MODE_ITU601|F_MODE_0_255:
        default:
            ErrorF("ITU601 0-255 ") ;
            
            HDMITX_WriteI2C_ByteN(REG_TX_CSC_YOFF,bCSCOffset_0_255,SIZEOF_CSCOFFSET) ;
            HDMITX_WriteI2C_ByteN(REG_TX_CSC_MTX11_L,bCSCMtx_RGB2YUV_ITU601_0_255,SIZEOF_CSCMTX) ;
            break ;
        }

    }
    #endif

    #ifdef SUPPORT_INPUTYUV
    if (csc == B_CSC_YUV2RGB)
    {
        int i;
        ErrorF("CSC = YUV2RGB %x ",csc) ;

        switch(bInputMode&(F_MODE_ITU709|F_MODE_16_235))
        {
        case F_MODE_ITU709|F_MODE_16_235:
            ErrorF("ITU709 16-235 ") ;
            HDMITX_WriteI2C_ByteN(REG_TX_CSC_YOFF,bCSCOffset_16_235,SIZEOF_CSCOFFSET) ;
            HDMITX_WriteI2C_ByteN(REG_TX_CSC_MTX11_L,bCSCMtx_YUV2RGB_ITU709_16_235,SIZEOF_CSCMTX) ;
            break ;
        case F_MODE_ITU709|F_MODE_0_255:
            ErrorF("ITU709 0-255 ") ;
            HDMITX_WriteI2C_ByteN(REG_TX_CSC_YOFF,bCSCOffset_0_255,SIZEOF_CSCOFFSET) ;
            HDMITX_WriteI2C_ByteN(REG_TX_CSC_MTX11_L,bCSCMtx_YUV2RGB_ITU709_0_255,SIZEOF_CSCMTX) ;
            break ;
        case F_MODE_ITU601|F_MODE_16_235:
            ErrorF("ITU601 16-235 ") ;
            HDMITX_WriteI2C_ByteN(REG_TX_CSC_YOFF,bCSCOffset_16_235,SIZEOF_CSCOFFSET) ;
            HDMITX_WriteI2C_ByteN(REG_TX_CSC_MTX11_L,bCSCMtx_YUV2RGB_ITU601_16_235,SIZEOF_CSCMTX) ;
            break ;
        case F_MODE_ITU601|F_MODE_0_255:
        default:
            //????? debug
            ErrorF("ITU601 0-255 ") ;
            HDMITX_WriteI2C_ByteN(REG_TX_CSC_YOFF,bCSCOffset_0_255,SIZEOF_CSCOFFSET) ;
            HDMITX_WriteI2C_ByteN(REG_TX_CSC_MTX11_L,bCSCMtx_YUV2RGB_ITU601_0_255,SIZEOF_CSCMTX) ;
            break ;
        }
    }
    #endif

    ucData = HDMITX_ReadI2C_Byte(REG_TX_CSC_CTRL) & ~(M_CSC_SEL|B_TX_DNFREE_GO|B_TX_EN_DITHER|B_TX_EN_UDFILTER) ;
    ucData |= filter|csc ;
    HDMITX_WriteI2C_Byte(REG_TX_CSC_CTRL,ucData) ;
    // set output Up/Down Filter,Dither control

}


//////////////////////////////////////////////////////////////////////
// Function: SetupAFE
// Parameter: VIDEOPCLKLEVEL level
//            PCLK_LOW - for 13.5MHz (for mode less than 1080p)
//            PCLK MEDIUM - for 25MHz~74MHz
//            PCLK HIGH - PCLK > 80Hz (for 1080p mode or above)
// Return: N/A
// Remark: set reg62~reg65 depended on HighFreqMode
//         reg61 have to be programmed at last and after video stable input.
// Side-Effect:
//////////////////////////////////////////////////////////////////////

static void
// SetupAFE(BYTE ucFreqInMHz)
SetupAFE(VIDEOPCLKLEVEL level)
{
    // @emily turn off reg61 before SetupAFE parameters.
    HDMITX_WriteI2C_Byte(REG_TX_AFE_DRV_CTRL,B_AFE_DRV_RST) ;/* 0x10 */
    // HDMITX_WriteI2C_Byte(REG_TX_AFE_DRV_CTRL,0x3) ;
    ErrorF("SetupAFE()\n") ;

    //TMDS Clock < 80MHz	TMDS Clock > 80MHz
    //Reg61	0x03	0x03

    //Reg62	0x18	0x88
    //Reg63	Default	Default
    //Reg64	0x08	0x80
    //Reg65	Default	Default
    //Reg66	Default	Default
    //Reg67	Default	Default

    switch(level)
    {
    case PCLK_HIGH:
        HDMITX_WriteI2C_Byte(REG_TX_AFE_XP_CTRL,0x88) ; // reg62
        HDMITX_WriteI2C_Byte(REG_TX_AFE_ISW_CTRL, 0x10) ; // reg63
        HDMITX_WriteI2C_Byte(REG_TX_AFE_IP_CTRL,0x84) ; // reg64
        break ;
    default:
        HDMITX_WriteI2C_Byte(REG_TX_AFE_XP_CTRL,0x18) ; // reg62
        HDMITX_WriteI2C_Byte(REG_TX_AFE_ISW_CTRL, 0x10) ; // reg63
        HDMITX_WriteI2C_Byte(REG_TX_AFE_IP_CTRL,0x0C) ; // reg64
        break ;
    }
    //HDMITX_AndREG_Byte(REG_TX_SW_RST,~(B_REF_RST|B_VID_RST|B_AREF_RST|B_HDMI_RST)) ;
    DelayMS(1) ;
    HDMITX_AndREG_Byte(REG_TX_SW_RST,B_VID_RST|B_AREF_RST|B_AUD_RST|B_HDCP_RST) ;
    DelayMS(100) ;
    HDMITX_AndREG_Byte(REG_TX_SW_RST,          B_AREF_RST|B_AUD_RST|B_HDCP_RST) ;
    // REG_TX_AFE_DRV_CTRL have to be set at the last step of setup .
}


//////////////////////////////////////////////////////////////////////
// Function: FireAFE
// Parameter: N/A
// Return: N/A
// Remark: write reg61 with 0x04
//         When program reg61 with 0x04,then audio and video circuit work.
// Side-Effect: N/A
//////////////////////////////////////////////////////////////////////
static void
FireAFE()
{
    BYTE reg;
    Switch_HDMITX_Bank(0) ;

    HDMITX_WriteI2C_Byte(REG_TX_AFE_DRV_CTRL,0) ;

    for(reg = 0x61 ; reg <= 0x67 ; reg++)
    {
        ErrorF("Reg[%02X] = %02X\n",reg,HDMITX_ReadI2C_Byte(reg)) ;
    }
}

//////////////////////////////////////////////////////////////////////
// Audio Output
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
// Function: SetAudioFormat
// Parameter:
//    NumChannel - number of channel,from 1 to 8
//    AudioEnable - Audio source and type bit field,value of bit field are
//        ENABLE_SPDIF    (1<<4)
//        ENABLE_I2S_SRC3  (1<<3)
//        ENABLE_I2S_SRC2  (1<<2)
//        ENABLE_I2S_SRC1  (1<<1)
//        ENABLE_I2S_SRC0  (1<<0)
//    SampleFreq - the audio sample frequence in Hz
//    AudSWL - Audio sample width,only support 16,18,20,or 24.
//    AudioCatCode - The audio channel catalogy code defined in IEC 60958-3
// Return: ER_SUCCESS if done,ER_FAIL for otherwise.
// Remark: program audio channel control register and audio channel registers
//         to enable audio by input.
// Side-Effect: register bank will keep in bank zero.
//////////////////////////////////////////////////////////////////////


static SYS_STATUS
SetAudioFormat(BYTE NumChannel,BYTE AudioEnable,BYTE bSampleFreq,BYTE AudSWL,BYTE AudioCatCode)
{
    BYTE fs = bSampleFreq ;
    BYTE SWL ;

    BYTE SourceValid ;
    BYTE SoruceNum ;


    ErrorF("SetAudioFormat(%d channel,%02X,SampleFreq %d,AudSWL %d,%02X)\n",NumChannel,AudioEnable,bSampleFreq,AudSWL,AudioCatCode) ;


//richard remove    Instance[0].bOutputAudioMode |= 0x41 ;
    if(NumChannel > 6)
    {
        SourceValid = B_AUD_ERR2FLAT | B_AUD_S3VALID | B_AUD_S2VALID | B_AUD_S1VALID ;
        SoruceNum = 4 ;
    }
    else if (NumChannel > 4)
    {
        SourceValid = B_AUD_ERR2FLAT | B_AUD_S2VALID | B_AUD_S1VALID ;
        SoruceNum = 3 ;
    }
    else if (NumChannel > 2)
    {
        SourceValid = B_AUD_ERR2FLAT | B_AUD_S1VALID ;
        SoruceNum = 2 ;
    }
    else
    {
        SourceValid = B_AUD_ERR2FLAT ; // only two channel.
        SoruceNum = 1 ;
        Instance[0].bOutputAudioMode &= ~0x40 ;
    }

    AudioEnable &= ~ (M_AUD_SWL|B_SPDIFTC) ;

    switch(AudSWL)
    {
    case 16:
        SWL = AUD_SWL_16 ;
        AudioEnable |= M_AUD_16BIT ;
        break ;
    case 18:
        SWL = AUD_SWL_18 ;
        AudioEnable |= M_AUD_18BIT ;
        break ;
    case 20:
        SWL = AUD_SWL_20 ;
        AudioEnable |= M_AUD_20BIT ;
        break ;
    case 24:
        SWL = AUD_SWL_24 ;
        AudioEnable |= M_AUD_24BIT ;
        break ;
    default:
        return ER_FAIL ;
    }


    Switch_HDMITX_Bank(0) ;
    HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL0,AudioEnable&0xF0) ;

    HDMITX_AndREG_Byte(REG_TX_SW_RST,~(B_AUD_RST|B_AREF_RST)) ;
    HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL1,Instance[0].bOutputAudioMode) ; // regE1 bOutputAudioMode should be loaded from ROM image.
    HDMITX_WriteI2C_Byte(REG_TX_AUDIO_FIFOMAP,0xE4) ; // default mapping.
    HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL3,(Instance[0].bAudioChannelSwap&0xF)|(AudioEnable&B_AUD_SPDIF)) ;
    HDMITX_WriteI2C_Byte(REG_TX_AUD_SRCVALID_FLAT,SourceValid) ;

    // suggested to be 0x41

//     Switch_HDMITX_Bank(1) ;
//     HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_MODE,0 |((NumChannel == 1)?1:0)) ; // 2 audio channel without pre-emphasis,if NumChannel set it as 1.
//     HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_CAT,AudioCatCode) ;
//     HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_SRCNUM,SoruceNum) ;
//     HDMITX_WriteI2C_Byte(REG_TX_AUD0CHST_CHTNUM,0x21) ;
//     HDMITX_WriteI2C_Byte(REG_TX_AUD1CHST_CHTNUM,0x43) ;
//     HDMITX_WriteI2C_Byte(REG_TX_AUD2CHST_CHTNUM,0x65) ;
//     HDMITX_WriteI2C_Byte(REG_TX_AUD3CHST_CHTNUM,0x87) ;
//     HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_CA_FS,0x00|fs) ; // choose clock
//     fs = ~fs ; // OFS is the one's complement of FS
//     HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_OFS_WL,(fs<<4)|SWL) ;
//     Switch_HDMITX_Bank(0) ;

    Switch_HDMITX_Bank(1) ;
    HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_MODE,0 |((NumChannel == 1)?1:0)) ; // 2 audio channel without pre-emphasis,if NumChannel set it as 1.
    HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_CAT,AudioCatCode) ;
    HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_SRCNUM,SoruceNum) ;
    HDMITX_WriteI2C_Byte(REG_TX_AUD0CHST_CHTNUM,0) ;
    HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_CA_FS,0x00|fs) ; // choose clock
    fs = ~fs ; // OFS is the one's complement of FS
    HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_OFS_WL,(fs<<4)|SWL) ;
    Switch_HDMITX_Bank(0) ;
    
    // richard modify (could be bug), if(!(AudioEnable | B_AUD_SPDIF))
    if(!(AudioEnable & B_AUD_SPDIF))
    {
        HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL0,AudioEnable) ;
    }

    Instance[0].bAudioChannelEnable = AudioEnable ;
    
    // HDMITX_AndREG_Byte(REG_TX_SW_RST,B_AUD_RST) ;    // enable Audio
    return ER_SUCCESS;
}



static void
AutoAdjustAudio()
{
    unsigned long SampleFreq ;
    unsigned long N ;
    unsigned long CTS ;
    BYTE fs, uc ;

//    bPendingAdjustAudioFreq = TRUE ;

//     if( CAT6611_AudioChannelEnable & B_AUD_SPDIF )
//     {
//         if(!(HDMITX_ReadI2C_Byte(REG_TX_CLK_STATUS2) & B_OSF_LOCK))
//         {
//             return ;
//         }
//     }
    
    Switch_HDMITX_Bank(1) ;
    
    N = ((unsigned long)HDMITX_ReadI2C_Byte(REGPktAudN2)&0xF) << 16 ;
    N |= ((unsigned long)HDMITX_ReadI2C_Byte(REGPktAudN1)) <<8 ;
    N |= ((unsigned long)HDMITX_ReadI2C_Byte(REGPktAudN0)) ;
    
    CTS = ((unsigned long)HDMITX_ReadI2C_Byte(REGPktAudCTSCnt2)&0xF) << 16 ;
    CTS |= ((unsigned long)HDMITX_ReadI2C_Byte(REGPktAudCTSCnt1)) <<8 ;
    CTS |= ((unsigned long)HDMITX_ReadI2C_Byte(REGPktAudCTSCnt0)) ;
    Switch_HDMITX_Bank(0) ;
    
    // CTS = TMDSCLK * N / ( 128 * SampleFreq ) 
    // SampleFreq = TMDSCLK * N / (128*CTS) 
    
    if( CTS == 0 ) 
    {
        return  ;
    }
    
    SampleFreq = Instance[0].TMDSClock/CTS ;
    SampleFreq *= N ;
    SampleFreq /= 128 ;
            
    if( SampleFreq>31000 && SampleFreq<=38050 )
    {
        Instance[0].bAudFs = AUDFS_32KHz ;
        fs = AUDFS_32KHz ;;
    }
    else if (SampleFreq < 46050 ) // 44.1KHz
    {
        Instance[0].bAudFs = AUDFS_44p1KHz ;
        fs = AUDFS_44p1KHz ;;
    }
    else if (SampleFreq < 68100 ) // 48KHz
    {
        Instance[0].bAudFs = AUDFS_48KHz ;
        fs = AUDFS_48KHz ;;
    }
    else if (SampleFreq < 92100 ) // 88.2 KHz
    {
        Instance[0].bAudFs = AUDFS_88p2KHz ;
        fs = AUDFS_88p2KHz ;;
    }
    else if (SampleFreq < 136200 ) // 96KHz
    {
        Instance[0].bAudFs = AUDFS_96KHz ;
        fs = AUDFS_96KHz ;;
    }
    else if (SampleFreq < 184200 ) // 176.4KHz
    {
        Instance[0].bAudFs = AUDFS_176p4KHz ;
        fs = AUDFS_176p4KHz ;;
    }
    else if (SampleFreq < 240200 ) // 192KHz
    {
        Instance[0].bAudFs = AUDFS_192KHz ;
        fs = AUDFS_192KHz ;;
    }
    else 
    {
        Instance[0].bAudFs = AUDFS_OTHER;
        fs = AUDFS_OTHER;;
    }

//    bPendingAdjustAudioFreq = FALSE ;
    
    SetNCTS(Instance[0].TMDSClock, Instance[0].bAudFs) ; // set N, CTS by new generated clock.
    
    Switch_HDMITX_Bank(1) ; // adjust the new fs in channel status registers
    HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_CA_FS,0x00|fs) ; // choose clock
    fs = ~fs ; // OFS is the one's complement of FS
    uc = HDMITX_ReadI2C_Byte(REG_TX_AUDCHST_OFS_WL) ;
    uc &= 0xF ;
    uc |= fs << 4 ;
    HDMITX_WriteI2C_Byte(REG_TX_AUDCHST_OFS_WL,uc) ;
    
    Switch_HDMITX_Bank(0) ;

}

static void
SetupAudioChannel()
{
    static BYTE bEnableAudioChannel=FALSE ;
    if( (HDMITX_ReadI2C_Byte(REG_TX_SW_RST) & (B_AUD_RST|B_AREF_RST)) == 0) // audio enabled
    {
        Switch_HDMITX_Bank(0) ;

        if((HDMITX_ReadI2C_Byte(REG_TX_AUDIO_CTRL0) & 0xf) == 0)
        {
            if(HDMITX_ReadI2C_Byte(REG_TX_CLK_STATUS2) & B_OSF_LOCK)
            {
                SetNCTS(Instance[0].TMDSClock, Instance[0].bAudFs) ; // to enable automatic progress setting for N/CTS
                DelayMS(5);
                AutoAdjustAudio() ;
                Switch_HDMITX_Bank(0) ;
                HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL0, Instance[0].bAudioChannelEnable) ;
                bEnableAudioChannel=TRUE ;
            }
        }
        else
        {
            if((HDMITX_ReadI2C_Byte(REG_TX_CLK_STATUS2) & B_OSF_LOCK)==0)
            {
                // AutoAdjustAudio() ;
                // ForceSetNCTS(CurrentPCLK, CurrentSampleFreq) ;
                if( bEnableAudioChannel == TRUE )
                {
                    Switch_HDMITX_Bank(0) ;
                    HDMITX_WriteI2C_Byte(REG_TX_AUDIO_CTRL0, Instance[0].bAudioChannelEnable&0xF0) ;
                }
                bEnableAudioChannel=FALSE ;
            }
        }
    }
}
//////////////////////////////////////////////////////////////////////
// Function: SetNCTS
// Parameter: PCLK - video clock in Hz.
//            Fs - audio sample frequency in Hz
// Return: ER_SUCCESS if success
// Remark: set N value,the CTS will be auto generated by HW.
// Side-Effect: register bank will reset to bank 0.
//////////////////////////////////////////////////////////////////////

static SYS_STATUS
SetNCTS(ULONG PCLK,ULONG Fs)
{
    ULONG n,MCLK ;

    MCLK = Fs * 256 ; // MCLK = fs * 256 ;

    ErrorF("SetNCTS(%ld,%ld): MCLK = %ld\n",PCLK,Fs,MCLK) ;

    if( PCLK )
    {
    	switch (Fs) {
    		case AUDFS_32KHz:
    			switch (PCLK) {
    				case 74175000: n = 11648; break;
    				case 14835000: n = 11648; break;
    				default: n = 4096;
    			}
    			break;
    		case AUDFS_44p1KHz:
    			switch (PCLK) {
    				case 74175000: n = 17836; break;
    				case 14835000: n = 8918; break;
    				default: n = 6272;
    			}
    			break;
    		case AUDFS_48KHz:
    			switch (PCLK) {
    				case 74175000: n = 11648; break;
    				case 14835000: n = 5824; break;
    				default: n = 6144;
    			}
    			break;
    		case AUDFS_88p2KHz:
    			switch (PCLK) {
    				case 74175000: n = 35672; break;
    				case 14835000: n = 17836; break;
    				default: n = 12544;
    			}
    			break;
    		case AUDFS_96KHz:
    			switch (PCLK) {
    				case 74175000: n = 23296; break;
    				case 14835000: n = 11648; break;
    				default: n = 12288;
    			}
    			break;
    		case AUDFS_176p4KHz:
    			switch (PCLK) {
    				case 74175000: n = 71344; break;
    				case 14835000: n = 35672; break;
    				default: n = 25088;
    			}
    			break;
    		case AUDFS_192KHz:
    			switch (PCLK) {
    				case 74175000: n = 46592; break;
    				case 14835000: n = 23296; break;
    				default: n = 24576;
    			}
    			break;
    		default: n = MCLK / 2000;
    	}
    }
    else
    {
        switch(Fs)
        {
		case AUDFS_32KHz: n = 4096; break;
		case AUDFS_44p1KHz: n = 6272; break;
		case AUDFS_48KHz: n = 6144; break;
		case AUDFS_88p2KHz: n = 12544; break;
		case AUDFS_96KHz: n = 12288; break;
		case AUDFS_176p4KHz: n = 25088; break;
		case AUDFS_192KHz: n = 24576; break;
		default: n = 6144;
        }

    }


    ErrorF("N = %ld\n",n) ;
    Switch_HDMITX_Bank(1) ;
    HDMITX_WriteI2C_Byte(REGPktAudN0,(BYTE)((n)&0xFF)) ;
    HDMITX_WriteI2C_Byte(REGPktAudN1,(BYTE)((n>>8)&0xFF)) ;
    HDMITX_WriteI2C_Byte(REGPktAudN2,(BYTE)((n>>16)&0xF)) ;
    Switch_HDMITX_Bank(0) ;

    HDMITX_WriteI2C_Byte(REG_TX_PKT_SINGLE_CTRL,0) ; // D[1] = 0,HW auto count CTS

    HDMITX_SetREG_Byte(REG_TX_CLK_CTRL0,~M_EXT_MCLK_SEL,B_EXT_256FS) ;
    return ER_SUCCESS ;
}

//////////////////////////////////////////////////////////////////////
// DDC Function.
//////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////
// Function: ClearDDCFIFO
// Parameter: N/A
// Return: N/A
// Remark: clear the DDC FIFO.
// Side-Effect: DDC master will set to be HOST.
//////////////////////////////////////////////////////////////////////

static void
ClearDDCFIFO()
{
    HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL,B_MASTERDDC|B_MASTERHOST) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_CMD,CMD_FIFO_CLR) ;
}

static void
GenerateDDCSCLK()
{
    HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL,B_MASTERDDC|B_MASTERHOST) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_CMD,CMD_GEN_SCLCLK) ;
}
//////////////////////////////////////////////////////////////////////
// Function: AbortDDC
// Parameter: N/A
// Return: N/A
// Remark: Force abort DDC and reset DDC bus.
// Side-Effect:
//////////////////////////////////////////////////////////////////////

static void
AbortDDC()
{
    BYTE CPDesire,SWReset,DDCMaster ;
    BYTE uc, timeout ;
    // save the SW reset,DDC master,and CP Desire setting.
    SWReset = HDMITX_ReadI2C_Byte(REG_TX_SW_RST) ;
    CPDesire = HDMITX_ReadI2C_Byte(REG_TX_HDCP_DESIRE) ;
    DDCMaster = HDMITX_ReadI2C_Byte(REG_TX_DDC_MASTER_CTRL) ;


    HDMITX_WriteI2C_Byte(REG_TX_HDCP_DESIRE,CPDesire&(~B_CPDESIRE)) ; // @emily change order
    HDMITX_WriteI2C_Byte(REG_TX_SW_RST,SWReset|B_HDCP_RST) ;		 // @emily change order
    HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL,B_MASTERDDC|B_MASTERHOST) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_CMD,CMD_DDC_ABORT) ;

    for( timeout = 0 ; timeout < 200 ; timeout++ )
    {
        uc = HDMITX_ReadI2C_Byte(REG_TX_DDC_STATUS) ;
        if (uc&B_DDC_DONE)
        {
            break ; // success
        }
        
        if( uc & (B_DDC_NOACK|B_DDC_WAITBUS|B_DDC_ARBILOSE) )
        {
            ErrorF("AbortDDC Fail by reg16=%02X\n",uc) ;
            break ;
        }
        DelayMS(1) ; // delay 1 ms to stable.
    }

    // restore the SW reset,DDC master,and CP Desire setting.
    HDMITX_WriteI2C_Byte(REG_TX_SW_RST,SWReset) ;
    HDMITX_WriteI2C_Byte(REG_TX_HDCP_DESIRE,CPDesire) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL,DDCMaster) ;
}

//////////////////////////////////////////////////////////////////////
// Packet and InfoFrame
//////////////////////////////////////////////////////////////////////

// ////////////////////////////////////////////////////////////////////////////////
// // Function: SetAVMute()
// // Parameter: N/A
// // Return: N/A
// // Remark: set AVMute as TRUE and enable GCP sending.
// // Side-Effect: N/A
// ////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// void
// SetAVMute()
// {
//     Switch_HDMITX_Bank(0) ;
//     HDMITX_WriteI2C_Byte(REG_TX_GCP,B_SET_AVMUTE) ;
//     HDMITX_WriteI2C_Byte(REG_TX_PKT_GENERAL_CTRL,B_ENABLE_PKT|B_REPEAT_PKT) ;
// }

// ////////////////////////////////////////////////////////////////////////////////
// // Function: SetAVMute(FALSE)
// // Parameter: N/A
// // Return: N/A
// // Remark: clear AVMute as TRUE and enable GCP sending.
// // Side-Effect: N/A
// ////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// void
// SetAVMute(FALSE)
// {
//     Switch_HDMITX_Bank(0) ;
//     HDMITX_WriteI2C_Byte(REG_TX_GCP,B_CLR_AVMUTE) ;
//     HDMITX_WriteI2C_Byte(REG_TX_PKT_GENERAL_CTRL,B_ENABLE_PKT|B_REPEAT_PKT) ;
// }



//////////////////////////////////////////////////////////////////////
// Function: ReadEDID
// Parameter: pData - the pointer of buffer to receive EDID ucdata.
//            bSegment - the segment of EDID readback.
//            offset - the offset of EDID ucdata in the segment. in byte.
//            count - the read back bytes count,cannot exceed 32
// Return: ER_SUCCESS if successfully getting EDID. ER_FAIL otherwise.
// Remark: function for read EDID ucdata from reciever.
// Side-Effect: DDC master will set to be HOST. DDC FIFO will be used and dirty.
//////////////////////////////////////////////////////////////////////

static SYS_STATUS
ReadEDID(BYTE *pData,BYTE bSegment,BYTE offset,SHORT Count)
{
    SHORT RemainedCount,ReqCount ;
    BYTE bCurrOffset ;
    SHORT TimeOut ;
    BYTE *pBuff = pData ;
    BYTE ucdata ;

    // ErrorF("ReadEDID(%08lX,%d,%d,%d)\n",(ULONG)pData,bSegment,offset,Count) ;
    if(!pData)
    {
        ErrorF("ReadEDID(): Invallid pData pointer %08lX\n",(ULONG)pData) ;
        return ER_FAIL ;
    }

    if(HDMITX_ReadI2C_Byte(REG_TX_INT_STAT1) & B_INT_DDC_BUS_HANG)
    {
    	ErrorF("Called AboutDDC()\n") ;
        AbortDDC() ;

    }

    ClearDDCFIFO() ;

    RemainedCount = Count ;
    bCurrOffset = offset ;

    Switch_HDMITX_Bank(0) ;

    while(RemainedCount > 0)
    {

        ReqCount = (RemainedCount > DDC_FIFO_MAXREQ)?DDC_FIFO_MAXREQ:RemainedCount ;
        ErrorF("ReadEDID(): ReqCount = %d,bCurrOffset = %d\n",ReqCount,bCurrOffset) ;

        HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL,B_MASTERDDC|B_MASTERHOST) ;
        HDMITX_WriteI2C_Byte(REG_TX_DDC_CMD,CMD_FIFO_CLR) ;

        for(TimeOut = 0 ; TimeOut < 200 ; TimeOut++)
    	{
		    ucdata = HDMITX_ReadI2C_Byte(REG_TX_DDC_STATUS) ;
		    
		    if(ucdata&B_DDC_DONE)
		    {
		        break ;  
		    }
		    
		    if((ucdata & B_DDC_ERROR)||(HDMITX_ReadI2C_Byte(REG_TX_INT_STAT1) & B_INT_DDC_BUS_HANG))
		    {
		    	ErrorF("Called AboutDDC()\n") ;
		        AbortDDC() ;
				return ER_FAIL ;
		    }
    	}

        HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL,B_MASTERDDC|B_MASTERHOST) ;
        HDMITX_WriteI2C_Byte(REG_TX_DDC_HEADER,DDC_EDID_ADDRESS) ; // for EDID ucdata get
        HDMITX_WriteI2C_Byte(REG_TX_DDC_REQOFF,bCurrOffset) ;
        HDMITX_WriteI2C_Byte(REG_TX_DDC_REQCOUNT,(BYTE)ReqCount) ;
        HDMITX_WriteI2C_Byte(REG_TX_DDC_EDIDSEG,bSegment) ;
        HDMITX_WriteI2C_Byte(REG_TX_DDC_CMD,CMD_EDID_READ) ;

        bCurrOffset += ReqCount ;
        RemainedCount -= ReqCount ;

        for(TimeOut = 250 ; TimeOut > 0 ; TimeOut --)
        {
            DelayMS(1) ;
            ucdata = HDMITX_ReadI2C_Byte(REG_TX_DDC_STATUS) ;
            if(ucdata & B_DDC_DONE)
            {
                break ;
            }

            if(ucdata & B_DDC_ERROR)
            {
                ErrorF("ReadEDID(): DDC_STATUS = %02X,fail.\n",ucdata) ;
                return ER_FAIL ;
            }
        }

        if(TimeOut == 0)
        {
            ErrorF("ReadEDID(): DDC TimeOut. \n",ucdata) ;
            return ER_FAIL ;
        }

        do
        {
            *(pBuff++) = HDMITX_ReadI2C_Byte(REG_TX_DDC_READFIFO) ;
            ReqCount -- ;
        }while(ReqCount > 0) ;

    }

    return ER_SUCCESS ;
}



#ifdef SUPPORT_HDCP
//////////////////////////////////////////////////////////////////////
// Authentication
//////////////////////////////////////////////////////////////////////
static void
HDCP_ClearAuthInterrupt()
{
    BYTE uc ;
    uc = HDMITX_ReadI2C_Byte(REG_TX_INT_MASK2) & (~(B_KSVLISTCHK_MASK|B_T_AUTH_DONE_MASK|B_AUTH_FAIL_MASK));
    HDMITX_WriteI2C_Byte(REG_TX_INT_CLR0,B_CLR_AUTH_FAIL|B_CLR_AUTH_DONE|B_CLR_KSVLISTCHK) ;
    HDMITX_WriteI2C_Byte(REG_TX_INT_CLR1,0) ;
    HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS,B_INTACTDONE) ;
}

static void
HDCP_ResetAuth()
{
    HDMITX_WriteI2C_Byte(REG_TX_LISTCTRL,0) ;
    HDMITX_WriteI2C_Byte(REG_TX_HDCP_DESIRE,0) ;
    HDMITX_OrREG_Byte(REG_TX_SW_RST,B_HDCP_RST) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL,B_MASTERDDC|B_MASTERHOST) ;
    HDCP_ClearAuthInterrupt() ;
    AbortDDC() ;
}
//////////////////////////////////////////////////////////////////////
// Function: HDCP_EnableEncryption
// Parameter: N/A
// Return: ER_SUCCESS if done.
// Remark: Set regC1 as zero to enable continue authentication.
// Side-Effect: register bank will reset to zero.
//////////////////////////////////////////////////////////////////////

static SYS_STATUS
HDCP_EnableEncryption()
{
    Switch_HDMITX_Bank(0) ;
	return HDMITX_WriteI2C_Byte(REG_TX_ENCRYPTION,B_ENABLE_ENCRYPTION);
}


//////////////////////////////////////////////////////////////////////
// Function: HDCP_Auth_Fire()
// Parameter: N/A
// Return: N/A
// Remark: write anything to reg21 to enable HDCP authentication by HW
// Side-Effect: N/A
//////////////////////////////////////////////////////////////////////

static void
HDCP_Auth_Fire()
{
    // ErrorF("HDCP_Auth_Fire():\n") ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL,B_MASTERDDC|B_MASTERHDCP) ; // MASTERHDCP,no need command but fire.
	HDMITX_WriteI2C_Byte(REG_TX_AUTHFIRE,1);
}

//////////////////////////////////////////////////////////////////////
// Function: HDCP_StartAnCipher
// Parameter: N/A
// Return: N/A
// Remark: Start the Cipher to free run for random number. When stop,An is
//         ready in Reg30.
// Side-Effect: N/A
//////////////////////////////////////////////////////////////////////

static void
HDCP_StartAnCipher()
{
    HDMITX_WriteI2C_Byte(REG_TX_AN_GENERATE,B_START_CIPHER_GEN) ;
    DelayMS(1) ; // delay 1 ms
}

//////////////////////////////////////////////////////////////////////
// Function: HDCP_StopAnCipher
// Parameter: N/A
// Return: N/A
// Remark: Stop the Cipher,and An is ready in Reg30.
// Side-Effect: N/A
//////////////////////////////////////////////////////////////////////

static void
HDCP_StopAnCipher()
{
    HDMITX_WriteI2C_Byte(REG_TX_AN_GENERATE,B_STOP_CIPHER_GEN) ;
}

//////////////////////////////////////////////////////////////////////
// Function: HDCP_GenerateAn
// Parameter: N/A
// Return: N/A
// Remark: start An ciper random run at first,then stop it. Software can get
//         an in reg30~reg38,the write to reg28~2F
// Side-Effect:
//////////////////////////////////////////////////////////////////////

static void
HDCP_GenerateAn()
{
    BYTE Data[8] ;

    HDCP_StartAnCipher() ;
    // HDMITX_WriteI2C_Byte(REG_TX_AN_GENERATE,B_START_CIPHER_GEN) ;
    // DelayMS(1) ; // delay 1 ms
    // HDMITX_WriteI2C_Byte(REG_TX_AN_GENERATE,B_STOP_CIPHER_GEN) ;

    HDCP_StopAnCipher() ;

    Switch_HDMITX_Bank(0) ;
    // new An is ready in reg30
    HDMITX_ReadI2C_ByteN(REG_TX_AN_GEN,Data,8) ;
    HDMITX_WriteI2C_ByteN(REG_TX_AN,Data,8) ;

}


//////////////////////////////////////////////////////////////////////
// Function: HDCP_GetBCaps
// Parameter: pBCaps - pointer of byte to get BCaps.
//            pBStatus - pointer of two bytes to get BStatus
// Return: ER_SUCCESS if successfully got BCaps and BStatus.
// Remark: get B status and capability from HDCP reciever via DDC bus.
// Side-Effect:
//////////////////////////////////////////////////////////////////////

static SYS_STATUS
HDCP_GetBCaps(PBYTE pBCaps ,PUSHORT pBStatus)
{
    BYTE ucdata ;
    BYTE TimeOut ;

    Switch_HDMITX_Bank(0) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL,B_MASTERDDC|B_MASTERHOST) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_HEADER,DDC_HDCP_ADDRESS) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_REQOFF,0x40) ; // BCaps offset
    HDMITX_WriteI2C_Byte(REG_TX_DDC_REQCOUNT,3) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_CMD,CMD_DDC_SEQ_BURSTREAD) ;

    for(TimeOut = 200 ; TimeOut > 0 ; TimeOut --)
    {
        DelayMS(1) ;

        ucdata = HDMITX_ReadI2C_Byte(REG_TX_DDC_STATUS) ;
        if(ucdata & B_DDC_DONE)
        {
            //ErrorF("HDCP_GetBCaps(): DDC Done.\n") ;
            break ;
        }

        if(ucdata & B_DDC_ERROR)
        {
            ErrorF("HDCP_GetBCaps(): DDC fail by reg16=%02X.\n",ucdata) ;
            return ER_FAIL ;
        }
    }

    if(TimeOut == 0)
    {
        return ER_FAIL ;
    }

    HDMITX_ReadI2C_ByteN(REG_TX_BSTAT,(PBYTE)pBStatus,2) ;
    *pBCaps = HDMITX_ReadI2C_Byte(REG_TX_BCAP) ;
    return ER_SUCCESS ;

}


//////////////////////////////////////////////////////////////////////
// Function: HDCP_GetBKSV
// Parameter: pBKSV - pointer of 5 bytes buffer for getting BKSV
// Return: ER_SUCCESS if successfuly got BKSV from Rx.
// Remark: Get BKSV from HDCP reciever.
// Side-Effect: N/A
//////////////////////////////////////////////////////////////////////

static SYS_STATUS
HDCP_GetBKSV(BYTE *pBKSV)
{
    BYTE ucdata ;
    BYTE TimeOut ;

    Switch_HDMITX_Bank(0) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL,B_MASTERDDC|B_MASTERHOST) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_HEADER,DDC_HDCP_ADDRESS) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_REQOFF,0x00) ; // BKSV offset
    HDMITX_WriteI2C_Byte(REG_TX_DDC_REQCOUNT,5) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_CMD,CMD_DDC_SEQ_BURSTREAD) ;

    for(TimeOut = 200 ; TimeOut > 0 ; TimeOut --)
    {
        DelayMS(1) ;

        ucdata = HDMITX_ReadI2C_Byte(REG_TX_DDC_STATUS) ;
        if(ucdata & B_DDC_DONE)
        {
            ErrorF("HDCP_GetBCaps(): DDC Done.\n") ;
            break ;
        }

        if(ucdata & B_DDC_ERROR)
        {
            ErrorF("HDCP_GetBCaps(): DDC No ack or arbilose,%x,maybe cable did not connected. Fail.\n",ucdata) ;
            return ER_FAIL ;
        }
    }

    if(TimeOut == 0)
    {
        return ER_FAIL ;
    }

    HDMITX_ReadI2C_ByteN(REG_TX_BKSV,(PBYTE)pBKSV,5) ;

    return ER_SUCCESS ;
}

//////////////////////////////////////////////////////////////////////
// Function:HDCP_Authenticate
// Parameter: N/A
// Return: ER_SUCCESS if Authenticated without error.
// Remark: do Authentication with Rx
// Side-Effect:
//  1. Instance[0].bAuthenticated global variable will be TRUE when authenticated.
//  2. Auth_done interrupt and AUTH_FAIL interrupt will be enabled.
//////////////////////////////////////////////////////////////////////
static BYTE
countbit(BYTE b)
{
    BYTE i,count ;
    for( i = 0, count = 0 ; i < 8 ; i++ )
    {
        if( b & (1<<i) )
        {
            count++ ;
        }
    }
    return count ;
}

static void
HDCP_Reset()
{
    BYTE uc ;
    uc = HDMITX_ReadI2C_Byte(REG_TX_SW_RST) | B_HDCP_RST ;
    HDMITX_WriteI2C_Byte(REG_TX_SW_RST,uc) ;
    HDMITX_WriteI2C_Byte(REG_TX_HDCP_DESIRE,0) ;
    HDMITX_WriteI2C_Byte(REG_TX_LISTCTRL,0) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL,B_MASTERHOST) ;
    ClearDDCFIFO() ;
    AbortDDC() ;
}

static SYS_STATUS
HDCP_Authenticate()
{
    BYTE ucdata ;
    BYTE BCaps ;
    USHORT BStatus ;
    USHORT TimeOut ;

  // richard   BYTE revoked = FALSE ;
    BYTE BKSV[5] ;

    Instance[0].bAuthenticated = FALSE ;

    // Authenticate should be called after AFE setup up.

    ErrorF("HDCP_Authenticate():\n") ;
	HDCP_Reset() ;
    // ClearDDCFIFO() ;
    // AbortDDC() ;

    if(HDCP_GetBCaps(&BCaps,&BStatus) != ER_SUCCESS)
    {
        ErrorF("HDCP_GetBCaps fail.\n") ;
        return ER_FAIL ;
    }


	if(Instance[0].bHDMIMode)
	{
		if((BStatus & B_CAP_HDMI_MODE)==0)
		{
			ErrorF("Not a HDMI mode,do not authenticate and encryption. BCaps = %x BStatus = %x\n",BCaps,BStatus) ;
			return ER_FAIL ;
		}
	}

	ErrorF("BCaps = %02X BStatus = %04X\n",BCaps,BStatus) ;
    /*
    if((BStatus & M_DOWNSTREAM_COUNT)> 6)
    {
        ErrorF("Down Stream Count %d is over maximum supported number 6,fail.\n",(BStatus & M_DOWNSTREAM_COUNT)) ;
        return ER_FAIL ;
    }
    */

    HDCP_GetBKSV(BKSV) ;
	ErrorF("BKSV %02X %02X %02X %02X %02X\n",BKSV[0],BKSV[1],BKSV[2],BKSV[3],BKSV[4]) ;
	
	for(TimeOut = 0, ucdata = 0 ; TimeOut < 5 ; TimeOut ++)
	{
	    ucdata += countbit(BKSV[TimeOut]) ;
	}
	if( ucdata != 20 ) return ER_FAIL ;
	
	
    #ifdef SUPPORT_REVOKE_KSV
    HDCP_VerifyRevocationList(SRM1,BKSV,&revoked) ;
    if(revoked)
    {
        ErrorF("BKSV is revoked\n") ; return ER_FAIL ;
    }
    ErrorF("BKSV %02X %02X %02X %02X %02X is NOT %srevoked\n",BKSV[0],BKSV[1],BKSV[2],BKSV[3],BKSV[4],revoked?"not ":"") ;
    #endif // SUPPORT_DSSSHA

    Switch_HDMITX_Bank(0) ; // switch bank action should start on direct register writting of each function.

    // 2006/08/11 added by jjtseng
    // enable HDCP on CPDired enabled.
    HDMITX_AndREG_Byte(REG_TX_SW_RST,~(B_HDCP_RST)) ;
    //~jjtseng 2006/08/11

//    if(BCaps & B_CAP_HDCP_1p1)
//    {
//        ErrorF("RX support HDCP 1.1\n") ;
//        HDMITX_WriteI2C_Byte(REG_TX_HDCP_DESIRE,B_ENABLE_HDPC11|B_CPDESIRE) ;
//    }
//    else
//    {
//        ErrorF("RX not support HDCP 1.1\n") ;
    HDMITX_WriteI2C_Byte(REG_TX_HDCP_DESIRE,B_CPDESIRE) ;
//    }


    // HDMITX_WriteI2C_Byte(REG_TX_INT_CLR0,B_CLR_AUTH_DONE|B_CLR_AUTH_FAIL|B_CLR_KSVLISTCHK) ;
    // HDMITX_WriteI2C_Byte(REG_TX_INT_CLR1,0) ; // don't clear other settings.
    // ucdata = HDMITX_ReadI2C_Byte(REG_TX_SYS_STATUS) ;
    // ucdata = (ucdata & M_CTSINTSTEP) | B_INTACTDONE ;
    // HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS,ucdata) ; // clear action.

    // HDMITX_AndREG_Byte(REG_TX_INT_MASK2,~(B_AUTH_FAIL_MASK|B_T_AUTH_DONE_MASK)) ;    // enable GetBCaps Interrupt
    HDCP_ClearAuthInterrupt() ;
    ErrorF("int2 = %02X DDC_Status = %02X\n",HDMITX_ReadI2C_Byte(REG_TX_INT_STAT2),HDMITX_ReadI2C_Byte(REG_TX_DDC_STATUS)) ;


    HDCP_GenerateAn() ;
    HDMITX_WriteI2C_Byte(REG_TX_LISTCTRL,0) ;
    Instance[0].bAuthenticated = FALSE ;

    if((BCaps & B_CAP_HDMI_REPEATER) == 0)
    {
        HDCP_Auth_Fire();
        // wait for status ;
        
        for(TimeOut = 250 ; TimeOut > 0 ; TimeOut --)
        {
            DelayMS(5) ; // delay 1ms
            ucdata = HDMITX_ReadI2C_Byte(REG_TX_AUTH_STAT) ;
            ErrorF("reg46 = %02x reg16 = %02x\n",ucdata,HDMITX_ReadI2C_Byte(0x16)) ;

            if(ucdata & B_T_AUTH_DONE)
            {
                Instance[0].bAuthenticated = TRUE ;
                break ;
            }
            
            ucdata = HDMITX_ReadI2C_Byte(REG_TX_INT_STAT2) ;
            if(ucdata & B_INT_AUTH_FAIL)
            {
                /*
                HDMITX_WriteI2C_Byte(REG_TX_INT_CLR0,B_CLR_AUTH_FAIL) ;
                HDMITX_WriteI2C_Byte(REG_TX_INT_CLR1,0) ;
                HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS,B_INTACTDONE) ;
                HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS,0) ;
                */
                ErrorF("HDCP_Authenticate(): Authenticate fail\n") ;
                Instance[0].bAuthenticated = FALSE ;
                return ER_FAIL ;
            }
        }

        if(TimeOut == 0)
        {
             ErrorF("HDCP_Authenticate(): Time out. return fail\n") ;
             Instance[0].bAuthenticated = FALSE ;
             return ER_FAIL ;
        }
        return ER_SUCCESS ;
    }

    return HDCP_Authenticate_Repeater() ;
}

//////////////////////////////////////////////////////////////////////
// Function: HDCP_VerifyIntegration
// Parameter: N/A
// Return: ER_SUCCESS if success,if AUTH_FAIL interrupt status,return fail.
// Remark: no used now.
// Side-Effect:
//////////////////////////////////////////////////////////////////////

static SYS_STATUS
HDCP_VerifyIntegration()
{
 // richard   BYTE ucdata ;
    // if any interrupt issued a Auth fail,returned the Verify Integration fail.

    if(HDMITX_ReadI2C_Byte(REG_TX_INT_STAT1) & B_INT_AUTH_FAIL)
    {
        HDCP_ClearAuthInterrupt() ;
        Instance[0].bAuthenticated = FALSE ;
        return ER_FAIL ;
    }

    if(Instance[0].bAuthenticated == TRUE)
    {
        return ER_SUCCESS ;
    }

    return ER_FAIL ;
}

//////////////////////////////////////////////////////////////////////
// Function: HDCP_Authenticate_Repeater
// Parameter: BCaps and BStatus
// Return: ER_SUCCESS if success,if AUTH_FAIL interrupt status,return fail.
// Remark:
// Side-Effect: as Authentication
//////////////////////////////////////////////////////////////////////
static _XDATA BYTE KSVList[32] ;
static _XDATA BYTE Vr[20] ;
static _XDATA BYTE M0[8] ;

static void
HDCP_CancelRepeaterAuthenticate()
{
    ErrorF("HDCP_CancelRepeaterAuthenticate") ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL,B_MASTERDDC|B_MASTERHOST) ;
    AbortDDC() ;
    HDMITX_WriteI2C_Byte(REG_TX_LISTCTRL,B_LISTFAIL|B_LISTDONE) ;
    HDCP_ClearAuthInterrupt() ;
}

static void
HDCP_ResumeRepeaterAuthenticate()
{
    HDMITX_WriteI2C_Byte(REG_TX_LISTCTRL,B_LISTDONE) ;
	HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL,B_MASTERHDCP) ;
}


static SYS_STATUS
HDCP_GetKSVList(BYTE *pKSVList,BYTE cDownStream)
{
    BYTE TimeOut = 100 ;
	BYTE ucdata ;
	
	if(cDownStream == 0 || pKSVList == NULL)
	{
	    return ER_FAIL ;
	}
	
    HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL,B_MASTERHOST) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_HEADER,0x74) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_REQOFF,0x43) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_REQCOUNT,cDownStream * 5) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_CMD,CMD_DDC_SEQ_BURSTREAD) ;


    for(TimeOut = 200 ; TimeOut > 0 ; TimeOut --)
    {

        ucdata = HDMITX_ReadI2C_Byte(REG_TX_DDC_STATUS) ;
        if(ucdata & B_DDC_DONE)
        {
            ErrorF("HDCP_GetKSVList(): DDC Done.\n") ;
            break ;
        }

        if(ucdata & B_DDC_ERROR)
        {
            ErrorF("HDCP_GetKSVList(): DDC Fail by REG_TX_DDC_STATUS = %x.\n",ucdata) ;
            return ER_FAIL ;
        }
        DelayMS(5) ;
    }

    if(TimeOut == 0)
    {
        return ER_FAIL ;
    }

    ErrorF("HDCP_GetKSVList(): KSV") ;
    for(TimeOut = 0 ; TimeOut < cDownStream * 5 ; TimeOut++)
    {
        pKSVList[TimeOut] = HDMITX_ReadI2C_Byte(REG_TX_DDC_READFIFO) ;
        ErrorF(" %02X",pKSVList[TimeOut]) ;
    }
    ErrorF("\n") ;
	return ER_SUCCESS ;
}

static SYS_STATUS
HDCP_GetVr(BYTE *pVr)
{
    BYTE TimeOut  ;
	BYTE ucdata ;
	
	if(pVr == NULL)
	{
	   // richard  return NULL ;
       return ER_FAIL;
	}
	
    HDMITX_WriteI2C_Byte(REG_TX_DDC_MASTER_CTRL,B_MASTERHOST) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_HEADER,0x74) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_REQOFF,0x20) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_REQCOUNT,20) ;
    HDMITX_WriteI2C_Byte(REG_TX_DDC_CMD,CMD_DDC_SEQ_BURSTREAD) ;


    for(TimeOut = 200 ; TimeOut > 0 ; TimeOut --)
    {
        ucdata = HDMITX_ReadI2C_Byte(REG_TX_DDC_STATUS) ;
        if(ucdata & B_DDC_DONE)
        {
            ErrorF("HDCP_GetVr(): DDC Done.\n") ;
            break ;
        }

        if(ucdata & B_DDC_ERROR)
        {
            ErrorF("HDCP_GetVr(): DDC fail by REG_TX_DDC_STATUS = %x.\n",ucdata) ;
            return ER_FAIL ;
        }
        DelayMS(5) ;
    }

    if(TimeOut == 0)
    {
        ErrorF("HDCP_GetVr(): DDC fail by timeout.\n",ucdata) ;
        return ER_FAIL ;
    }

    Switch_HDMITX_Bank(0) ;

    for(TimeOut = 0 ; TimeOut < 5 ; TimeOut++)
    {
        HDMITX_WriteI2C_Byte(REG_TX_SHA_SEL ,TimeOut) ;
        pVr[TimeOut*4+3]  = (ULONG)HDMITX_ReadI2C_Byte(REG_TX_SHA_RD_BYTE1) ;
        pVr[TimeOut*4+2] = (ULONG)HDMITX_ReadI2C_Byte(REG_TX_SHA_RD_BYTE2) ;
        pVr[TimeOut*4+1] = (ULONG)HDMITX_ReadI2C_Byte(REG_TX_SHA_RD_BYTE3) ;
        pVr[TimeOut*4] = (ULONG)HDMITX_ReadI2C_Byte(REG_TX_SHA_RD_BYTE4) ;
		ErrorF("V' = %02X %02X %02X %02X\n",pVr[TimeOut*4],pVr[TimeOut*4+1],pVr[TimeOut*4+2],pVr[TimeOut*4+3]) ; 
    }
    
    return ER_SUCCESS ;
}

static SYS_STATUS
HDCP_GetM0(BYTE *pM0)
{
	int i ;

    if(!pM0)
    {
        return ER_FAIL ;
    }
    
    HDMITX_WriteI2C_Byte(REG_TX_SHA_SEL,5) ; // read m0[31:0] from reg51~reg54
    pM0[0] = HDMITX_ReadI2C_Byte(REG_TX_SHA_RD_BYTE1) ;
    pM0[1] = HDMITX_ReadI2C_Byte(REG_TX_SHA_RD_BYTE2) ;
    pM0[2] = HDMITX_ReadI2C_Byte(REG_TX_SHA_RD_BYTE3) ;
    pM0[3] = HDMITX_ReadI2C_Byte(REG_TX_SHA_RD_BYTE4) ;
    HDMITX_WriteI2C_Byte(REG_TX_SHA_SEL,0) ; // read m0[39:32] from reg55
    pM0[4] = HDMITX_ReadI2C_Byte(REG_TX_AKSV_RD_BYTE5) ;
    HDMITX_WriteI2C_Byte(REG_TX_SHA_SEL,1) ; // read m0[47:40] from reg55
    pM0[5] = HDMITX_ReadI2C_Byte(REG_TX_AKSV_RD_BYTE5) ;
    HDMITX_WriteI2C_Byte(REG_TX_SHA_SEL,2) ; // read m0[55:48] from reg55
    pM0[6] = HDMITX_ReadI2C_Byte(REG_TX_AKSV_RD_BYTE5) ;
    HDMITX_WriteI2C_Byte(REG_TX_SHA_SEL,3) ; // read m0[63:56] from reg55
    pM0[7] = HDMITX_ReadI2C_Byte(REG_TX_AKSV_RD_BYTE5) ;

    ErrorF("M[] =") ;
	for(i = 0 ; i < 8 ; i++){
		ErrorF("0x%02x,",pM0[i]) ;
	}
	ErrorF("\n") ;
    return ER_SUCCESS ;
}

static _XDATA BYTE SHABuff[64] ;
static _XDATA BYTE V[20] ;

static _XDATA ULONG w[80];
static _XDATA ULONG sha[5] ;

#define rol(x,y) (((x) << (y)) | (((ULONG)x) >> (32-y)))

static void SHATransform(ULONG * h); // richard add
void SHATransform(ULONG * h)
{
	LONG t;

      
	for (t = 16; t < 80; t++) {
		ULONG tmp = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16];
		w[t] = rol(tmp,1);
		printf("w[%2d] = %08lX\n",t,w[t]) ;
	}

	h[0] = 0x67452301 ;
	h[1] = 0xefcdab89;
	h[2] = 0x98badcfe;
	h[3] = 0x10325476;
	h[4] = 0xc3d2e1f0;

	for (t = 0; t < 20; t++) {
		ULONG tmp =
			rol(h[0],5) + ((h[1] & h[2]) | (h[3] & ~h[1])) + h[4] + w[t] + 0x5a827999;
		printf("%08lX %08lX %08lX %08lX %08lX\n",h[0],h[1],h[2],h[3],h[4]) ;

		h[4] = h[3];
		h[3] = h[2];
		h[2] = rol(h[1],30);
		h[1] = h[0];
		h[0] = tmp;
		
	}
	for (t = 20; t < 40; t++) {
		ULONG tmp = rol(h[0],5) + (h[1] ^ h[2] ^ h[3]) + h[4] + w[t] + 0x6ed9eba1;
		printf("%08lX %08lX %08lX %08lX %08lX\n",h[0],h[1],h[2],h[3],h[4]) ;
		h[4] = h[3];
		h[3] = h[2];
		h[2] = rol(h[1],30);
		h[1] = h[0];
		h[0] = tmp;
	}
	for (t = 40; t < 60; t++) {
		ULONG tmp = rol(h[0],
						 5) + ((h[1] & h[2]) | (h[1] & h[3]) | (h[2] & h[3])) + h[4] + w[t] +
			0x8f1bbcdc;
		printf("%08lX %08lX %08lX %08lX %08lX\n",h[0],h[1],h[2],h[3],h[4]) ;
		h[4] = h[3];
		h[3] = h[2];
		h[2] = rol(h[1],30);
		h[1] = h[0];
		h[0] = tmp;
	}
	for (t = 60; t < 80; t++) {
		ULONG tmp = rol(h[0],5) + (h[1] ^ h[2] ^ h[3]) + h[4] + w[t] + 0xca62c1d6;
		printf("%08lX %08lX %08lX %08lX %08lX\n",h[0],h[1],h[2],h[3],h[4]) ;
		h[4] = h[3];
		h[3] = h[2];
		h[2] = rol(h[1],30);
		h[1] = h[0];
		h[0] = tmp;
	}
	printf("%08lX %08lX %08lX %08lX %08lX\n",h[0],h[1],h[2],h[3],h[4]) ;

	h[0] += 0x67452301 ;
	h[1] += 0xefcdab89;
	h[2] += 0x98badcfe;
	h[3] += 0x10325476;
	h[4] += 0xc3d2e1f0;
	printf("%08lX %08lX %08lX %08lX %08lX\n",h[0],h[1],h[2],h[3],h[4]) ;
}

/* ----------------------------------------------------------------------
 * Outer SHA algorithm: take an arbitrary length byte string,
 * convert it into 16-word blocks with the prescribed padding at
 * the end,and pass those blocks to the core SHA algorithm.
 */


void SHA_Simple(void *p,LONG len,BYTE *output)
{
	// SHA_State s;
    int i, t ;
    ULONG c ;
    char *pBuff = p ;
    
    
    for( i = 0 ; i < len ; i++ )
    {
        t = i/4 ;
        if( i%4 == 0 )
        {
            w[t] = 0 ;
        }
        c = pBuff[i] ;
        c <<= (3-(i%4))*8 ;
        w[t] |= c ;
        printf("pBuff[%d] = %02x, c = %08lX, w[%d] = %08lX\n",i,pBuff[i],c,t,w[t]) ;
    }
    t = i/4 ;
    if( i%4 == 0 )
    {
        w[t] = 0 ;
    }
    c = 0x80 << ((3-i%4)*24) ;
    w[t]|= c ; t++ ;
    for( ; t < 15 ; t++ )
    {
        w[t] = 0 ;
    }
    w[15] = len*8  ;
    
    for( t = 0 ; t< 16 ; t++ )
    {
        printf("w[%2d] = %08lX\n",t,w[t]) ;
    }

    SHATransform(sha) ;
    
    for( i = 0 ; i < 5 ; i++ )
    {
        output[i*4]   = (BYTE)((sha[i]>>24)&0xFF) ;
        output[i*4+1] = (BYTE)((sha[i]>>16)&0xFF) ;
        output[i*4+2] = (BYTE)((sha[i]>>8)&0xFF) ;
        output[i*4+3] = (BYTE)(sha[i]&0xFF) ;
    }
}

static SYS_STATUS
HDCP_CheckSHA(BYTE pM0[],USHORT BStatus,BYTE pKSVList[],int cDownStream,BYTE Vr[])
{
    int i,n ;
    
    for(i = 0 ; i < cDownStream*5 ; i++)
    {
        SHABuff[i] = pKSVList[i] ;
    }
    SHABuff[i++] = BStatus & 0xFF ;
    SHABuff[i++] = (BStatus>>8) & 0xFF ;
    for(n = 0 ; n < 8 ; n++,i++)
    {
        SHABuff[i] = pM0[n] ;
    }
    n = i ;
    // SHABuff[i++] = 0x80 ; // end mask
    for(; i < 64 ; i++)
    {
        SHABuff[i] = 0 ;
    }
    // n = cDownStream * 5 + 2 /* for BStatus */ + 8 /* for M0 */ ;
    // n *= 8 ;
    // SHABuff[62] = (n>>8) & 0xff ;
    // SHABuff[63] = (n>>8) & 0xff ;
    for(i = 0 ; i < 64 ; i++)
	{
		if(i % 16 == 0) printf("SHA[]: ") ;
		printf(" %02X",SHABuff[i]) ;
		if((i%16)==15) printf("\n") ;
	}
    SHA_Simple(SHABuff,n,V) ;
    printf("V[] =") ;
    for(i = 0 ; i < 20 ; i++)
    {
        printf(" %02X",V[i]) ;
    }
    printf("\nVr[] =") ;
    for(i = 0 ; i < 20 ; i++)
    {
        printf(" %02X",Vr[i]) ;
    }
        
    for(i = 0 ; i < 20 ; i++)
    {
        if(V[i] != Vr[i])
        {
            return ER_FAIL ;
        }
    }
    return ER_SUCCESS ;
}

static SYS_STATUS
HDCP_Authenticate_Repeater()
{
    BYTE uc ;
    #ifdef SUPPORT_DSSSHA    
    BYTE revoked ;
    int i ;
    #else
    int i; // richard add
    BYTE revoked; // richard add
    #endif // _DSS_SHA_
	// BYTE test;
	// BYTE test06;
	// BYTE test07;
	// BYTE test08;
    BYTE cDownStream ;

    BYTE BCaps;
    USHORT BStatus ;
    USHORT TimeOut ;

	ErrorF("Authentication for repeater\n") ;
    // emily add for test,abort HDCP
    // 2007/10/01 marked by jj_tseng@chipadvanced.com
    // HDMITX_WriteI2C_Byte(0x20,0x00) ;
    // HDMITX_WriteI2C_Byte(0x04,0x01) ;
	// HDMITX_WriteI2C_Byte(0x10,0x01) ;
	// HDMITX_WriteI2C_Byte(0x15,0x0F) ;
	// DelayMS(100);
    // HDMITX_WriteI2C_Byte(0x04,0x00) ;
	// HDMITX_WriteI2C_Byte(0x10,0x00) ;
	// HDMITX_WriteI2C_Byte(0x20,0x01) ;
	// DelayMS(100);
	// test07 = HDMITX_ReadI2C_Byte(0x7)  ;
	// test06 = HDMITX_ReadI2C_Byte(0x6);
	// test08 = HDMITX_ReadI2C_Byte(0x8);
	//~jj_tseng@chipadvanced.com
	// end emily add for test
    //////////////////////////////////////
    // Authenticate Fired
    //////////////////////////////////////
  
    HDCP_GetBCaps(&BCaps,&BStatus) ;
	DelayMS(2);
    HDCP_Auth_Fire();
	DelayMS(550); // emily add for test

    for(TimeOut = 250*6 ; TimeOut > 0 ; TimeOut --)
    {

        uc = HDMITX_ReadI2C_Byte(REG_TX_INT_STAT1) ;
        if(uc & B_INT_DDC_BUS_HANG)
        {
            ErrorF("DDC Bus hang\n") ;
            goto HDCP_Repeater_Fail ;
        }

        uc = HDMITX_ReadI2C_Byte(REG_TX_INT_STAT2) ;

        if(uc & B_INT_AUTH_FAIL)
        {
			/*
            HDMITX_WriteI2C_Byte(REG_TX_INT_CLR0,B_CLR_AUTH_FAIL) ;
            HDMITX_WriteI2C_Byte(REG_TX_INT_CLR1,0) ;
            HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS,B_INTACTDONE) ;
            HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS,0) ;
			*/
            ErrorF("HDCP_Authenticate_Repeater(): B_INT_AUTH_FAIL.\n") ;
            goto HDCP_Repeater_Fail ;
        }
        // emily add for test
		// test =(HDMITX_ReadI2C_Byte(0x7)&0x4)>>2 ;
        if(uc & B_INT_KSVLIST_CHK)
        {
            HDMITX_WriteI2C_Byte(REG_TX_INT_CLR0,B_CLR_KSVLISTCHK) ;
            HDMITX_WriteI2C_Byte(REG_TX_INT_CLR1,0) ;
            HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS,B_INTACTDONE) ;
            HDMITX_WriteI2C_Byte(REG_TX_SYS_STATUS,0) ;
            ErrorF("B_INT_KSVLIST_CHK\n") ;
            break ;
        }

        DelayMS(5) ;
    }

    if(TimeOut == 0)
    {
        ErrorF("Time out for wait KSV List checking interrupt\n") ;
        goto HDCP_Repeater_Fail ;
    }

    ///////////////////////////////////////
    // clear KSVList check interrupt.
    ///////////////////////////////////////

    for(TimeOut = 500 ; TimeOut > 0 ; TimeOut --)
    {
		if((TimeOut % 100) == 0)
		{
		    ErrorF("Wait KSV FIFO Ready %d\n",TimeOut) ;
		}
		
        if(HDCP_GetBCaps(&BCaps,&BStatus) == ER_FAIL)
        {
            ErrorF("Get BCaps fail\n") ;
            goto HDCP_Repeater_Fail ;
        }

        if(BCaps & B_CAP_KSV_FIFO_RDY)
        {
			 ErrorF("FIFO Ready\n") ;
			 break ;
        }
        DelayMS(5) ;

    }

    if(TimeOut == 0)
    {
        ErrorF("Get KSV FIFO ready TimeOut\n") ;
        goto HDCP_Repeater_Fail ;
    }

	ErrorF("Wait timeout = %d\n",TimeOut) ;
	
    ClearDDCFIFO() ;
    GenerateDDCSCLK() ;
    cDownStream =  (BStatus & M_DOWNSTREAM_COUNT) ;
    
    if(cDownStream == 0 || cDownStream > 6 || BStatus & (B_MAX_CASCADE_EXCEEDED|B_DOWNSTREAM_OVER))
    {
        ErrorF("Invalid Down stream count,fail\n") ;
        goto HDCP_Repeater_Fail ;
    }
    

    if(HDCP_GetKSVList(KSVList,cDownStream) == ER_FAIL)
    {
        goto HDCP_Repeater_Fail ;
    }

    for(i = 0 ; i < cDownStream ; i++)
    {
		revoked=FALSE ; uc = 0 ;
		for( TimeOut = 0 ; TimeOut < 5 ; TimeOut++ )
		{
		    // check bit count
		    uc += countbit(KSVList[i*5+TimeOut]) ;
		}
		if( uc != 20 ) revoked = TRUE ;
    #ifdef SUPPORT_REVOKE_KSV    
        HDCP_VerifyRevocationList(SRM1,&KSVList[i*5],&revoked) ;
    #endif
        if(revoked)
        {
            ErrorF("KSVFIFO[%d] = %02X %02X %02X %02X %02X is revoked\n",i,KSVList[i*5],KSVList[i*5+1],KSVList[i*5+2],KSVList[i*5+3],KSVList[i*5+4]) ; 
			 goto HDCP_Repeater_Fail ;
        }
    }

    
    if(HDCP_GetVr(Vr) == ER_FAIL)
    {
        goto HDCP_Repeater_Fail ; 
    }

    if(HDCP_GetM0(M0) == ER_FAIL)
    {
        goto HDCP_Repeater_Fail ;
    }
    
    // do check SHA
    if(HDCP_CheckSHA(M0,BStatus,KSVList,cDownStream,Vr) == ER_FAIL)
    {
        goto HDCP_Repeater_Fail ;
    }
    
    
    HDCP_ResumeRepeaterAuthenticate() ;
	Instance[0].bAuthenticated = TRUE ;
    return ER_SUCCESS ;
    
HDCP_Repeater_Fail:
    HDCP_CancelRepeaterAuthenticate() ;
    return ER_FAIL ;
}

//////////////////////////////////////////////////////////////////////
// Function: HDCP_ResumeAuthentication
// Parameter: N/A
// Return: N/A
// Remark: called by interrupt handler to restart Authentication and Encryption.
// Side-Effect: as Authentication and Encryption.
//////////////////////////////////////////////////////////////////////

static void
HDCP_ResumeAuthentication()
{
    SetAVMute(TRUE) ;
    if(HDCP_Authenticate() == ER_SUCCESS)
	{
		HDCP_EnableEncryption() ;
	}
	SetAVMute(FALSE) ;
}



#endif // SUPPORT_HDCP


static void
ENABLE_NULL_PKT()
{

    HDMITX_WriteI2C_Byte(REG_TX_NULL_CTRL,B_ENABLE_PKT|B_REPEAT_PKT);
}


static void
ENABLE_ACP_PKT()
{

    HDMITX_WriteI2C_Byte(REG_TX_ACP_CTRL,B_ENABLE_PKT|B_REPEAT_PKT);
}


static void
ENABLE_ISRC1_PKT()
{

    HDMITX_WriteI2C_Byte(REG_TX_ISRC1_CTRL,B_ENABLE_PKT|B_REPEAT_PKT);
}


static void
ENABLE_ISRC2_PKT()
{

    HDMITX_WriteI2C_Byte(REG_TX_ISRC2_CTRL,B_ENABLE_PKT|B_REPEAT_PKT);
}


static void
ENABLE_AVI_INFOFRM_PKT()
{

    HDMITX_WriteI2C_Byte(REG_TX_AVI_INFOFRM_CTRL,B_ENABLE_PKT|B_REPEAT_PKT);
}


static void
ENABLE_AUD_INFOFRM_PKT()
{

    HDMITX_WriteI2C_Byte(REG_TX_AUD_INFOFRM_CTRL,B_ENABLE_PKT|B_REPEAT_PKT);
}


static void
ENABLE_SPD_INFOFRM_PKT()
{

    HDMITX_WriteI2C_Byte(REG_TX_SPD_INFOFRM_CTRL,B_ENABLE_PKT|B_REPEAT_PKT);
}


static void
ENABLE_MPG_INFOFRM_PKT()
{

    HDMITX_WriteI2C_Byte(REG_TX_MPG_INFOFRM_CTRL,B_ENABLE_PKT|B_REPEAT_PKT);
}

static void
DISABLE_NULL_PKT()
{

    HDMITX_WriteI2C_Byte(REG_TX_NULL_CTRL,0);
}


static void
DISABLE_ACP_PKT()
{

    HDMITX_WriteI2C_Byte(REG_TX_ACP_CTRL,0);
}


static void
DISABLE_ISRC1_PKT()
{

    HDMITX_WriteI2C_Byte(REG_TX_ISRC1_CTRL,0);
}


static void
DISABLE_ISRC2_PKT()
{

    HDMITX_WriteI2C_Byte(REG_TX_ISRC2_CTRL,0);
}


static void
DISABLE_AVI_INFOFRM_PKT()
{

    HDMITX_WriteI2C_Byte(REG_TX_AVI_INFOFRM_CTRL,0);
}


static void
DISABLE_AUD_INFOFRM_PKT()
{

    HDMITX_WriteI2C_Byte(REG_TX_AUD_INFOFRM_CTRL,0);
}


static void
DISABLE_SPD_INFOFRM_PKT()
{

    HDMITX_WriteI2C_Byte(REG_TX_SPD_INFOFRM_CTRL,0);
}


static void
DISABLE_MPG_INFOFRM_PKT()
{

    HDMITX_WriteI2C_Byte(REG_TX_MPG_INFOFRM_CTRL,0);
}



//////////////////////////////////////////////////////////////////////
// Function: SetAVIInfoFrame()
// Parameter: pAVIInfoFrame - the pointer to HDMI AVI Infoframe ucData
// Return: N/A
// Remark: Fill the AVI InfoFrame ucData,and count checksum,then fill into
//         AVI InfoFrame registers.
// Side-Effect: N/A
//////////////////////////////////////////////////////////////////////

static SYS_STATUS
SetAVIInfoFrame(AVI_InfoFrame *pAVIInfoFrame)
{
    int i ;
    byte ucData ;

    if(!pAVIInfoFrame)
    {
        return ER_FAIL ;
    }

    Switch_HDMITX_Bank(1) ;
	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB1,pAVIInfoFrame->pktbyte.AVI_DB[0]);
	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB2,pAVIInfoFrame->pktbyte.AVI_DB[1]);
	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB3,pAVIInfoFrame->pktbyte.AVI_DB[2]);
	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB4,pAVIInfoFrame->pktbyte.AVI_DB[3]);
	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB5,pAVIInfoFrame->pktbyte.AVI_DB[4]);
	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB6,pAVIInfoFrame->pktbyte.AVI_DB[5]);
	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB7,pAVIInfoFrame->pktbyte.AVI_DB[6]);
	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB8,pAVIInfoFrame->pktbyte.AVI_DB[7]);
	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB9,pAVIInfoFrame->pktbyte.AVI_DB[8]);
	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB10,pAVIInfoFrame->pktbyte.AVI_DB[9]);
	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB11,pAVIInfoFrame->pktbyte.AVI_DB[10]);
	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB12,pAVIInfoFrame->pktbyte.AVI_DB[11]);
	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_DB13,pAVIInfoFrame->pktbyte.AVI_DB[12]);
    for(i = 0,ucData = 0; i < 13 ; i++)
    {
        ucData -= pAVIInfoFrame->pktbyte.AVI_DB[i] ;
    }
	ErrorF("SetAVIInfo(): ") ;
    //ErrorF("%02X ",HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB1)) ;
    //ErrorF("%02X ",HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB2)) ;
    //ErrorF("%02X ",HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB3)) ;
    //ErrorF("%02X ",HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB4)) ;
    //ErrorF("%02X ",HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB5)) ;
    //ErrorF("%02X ",HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB6)) ;
    //ErrorF("%02X ",HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB7)) ;
    //ErrorF("%02X ",HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB8)) ;
    //ErrorF("%02X ",HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB9)) ;
    //ErrorF("%02X ",HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB10)) ;
    //ErrorF("%02X ",HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB11)) ;
    //ErrorF("%02X ",HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB12)) ;
    //ErrorF("%02X ",HDMITX_ReadI2C_Byte(REG_TX_AVIINFO_DB13)) ;
	ErrorF("\n") ;
    ucData -= 0x80+AVI_INFOFRAME_VER+AVI_INFOFRAME_TYPE+AVI_INFOFRAME_LEN ;
	HDMITX_WriteI2C_Byte(REG_TX_AVIINFO_SUM,ucData);


    Switch_HDMITX_Bank(0) ;
    ENABLE_AVI_INFOFRM_PKT();
    return ER_SUCCESS ;
}

//////////////////////////////////////////////////////////////////////
// Function: SetAudioInfoFrame()
// Parameter: pAudioInfoFrame - the pointer to HDMI Audio Infoframe ucData
// Return: N/A
// Remark: Fill the Audio InfoFrame ucData,and count checksum,then fill into
//         Audio InfoFrame registers.
// Side-Effect: N/A
//////////////////////////////////////////////////////////////////////

static SYS_STATUS
SetAudioInfoFrame(Audio_InfoFrame *pAudioInfoFrame)
{
    int i ;
    BYTE ucData ;

    if(!pAudioInfoFrame)
    {
        return ER_FAIL ;
    }

    Switch_HDMITX_Bank(1) ;
    HDMITX_WriteI2C_Byte(REG_TX_PKT_AUDINFO_CC,pAudioInfoFrame->pktbyte.AUD_DB[0]);
    HDMITX_WriteI2C_Byte(REG_TX_PKT_AUDINFO_SF,pAudioInfoFrame->pktbyte.AUD_DB[1]);
    HDMITX_WriteI2C_Byte(REG_TX_PKT_AUDINFO_CA,pAudioInfoFrame->pktbyte.AUD_DB[3]);
    HDMITX_WriteI2C_Byte(REG_TX_PKT_AUDINFO_DM_LSV,pAudioInfoFrame->pktbyte.AUD_DB[4]) ;

    for(i = 0,ucData = 0 ; i< 5 ; i++)
    {
        ucData -= pAudioInfoFrame->pktbyte.AUD_DB[i] ;
    }
    ucData -= 0x80+AUDIO_INFOFRAME_VER+AUDIO_INFOFRAME_TYPE+AUDIO_INFOFRAME_LEN ;

    HDMITX_WriteI2C_Byte(REG_TX_PKT_AUDINFO_SUM,ucData) ;


    Switch_HDMITX_Bank(0) ;
    ENABLE_AUD_INFOFRM_PKT();
    return ER_SUCCESS ;
}

//////////////////////////////////////////////////////////////////////
// Function: SetSPDInfoFrame()
// Parameter: pSPDInfoFrame - the pointer to HDMI SPD Infoframe ucData
// Return: N/A
// Remark: Fill the SPD InfoFrame ucData,and count checksum,then fill into
//         SPD InfoFrame registers.
// Side-Effect: N/A
//////////////////////////////////////////////////////////////////////

static SYS_STATUS
SetSPDInfoFrame(SPD_InfoFrame *pSPDInfoFrame)
{
    int i ;
    BYTE ucData ;

    if(!pSPDInfoFrame)
    {
        return ER_FAIL ;
    }

    Switch_HDMITX_Bank(1) ;
    for(i = 0,ucData = 0 ; i < 25 ; i++)
    {
        ucData -= pSPDInfoFrame->pktbyte.SPD_DB[i] ;
        HDMITX_WriteI2C_Byte(REG_TX_PKT_SPDINFO_PB1+i,pSPDInfoFrame->pktbyte.SPD_DB[i]) ;
    }
    ucData -= 0x80+SPD_INFOFRAME_VER+SPD_INFOFRAME_TYPE+SPD_INFOFRAME_LEN ;
    HDMITX_WriteI2C_Byte(REG_TX_PKT_SPDINFO_SUM,ucData) ; // checksum
    Switch_HDMITX_Bank(0) ;
    ENABLE_SPD_INFOFRM_PKT();
    return ER_SUCCESS ;
}

//////////////////////////////////////////////////////////////////////
// Function: SetMPEGInfoFrame()
// Parameter: pMPEGInfoFrame - the pointer to HDMI MPEG Infoframe ucData
// Return: N/A
// Remark: Fill the MPEG InfoFrame ucData,and count checksum,then fill into
//         MPEG InfoFrame registers.
// Side-Effect: N/A
//////////////////////////////////////////////////////////////////////

static SYS_STATUS
SetMPEGInfoFrame(MPEG_InfoFrame *pMPGInfoFrame)
{
    int i ;
    BYTE ucData ;

    if(!pMPGInfoFrame)
    {
        return ER_FAIL ;
    }

    Switch_HDMITX_Bank(1) ;

    HDMITX_WriteI2C_Byte(REG_TX_PKT_MPGINFO_FMT,pMPGInfoFrame->info.FieldRepeat|(pMPGInfoFrame->info.MpegFrame<<1)) ;
    HDMITX_WriteI2C_Byte(REG_TX_PKG_MPGINFO_DB0,pMPGInfoFrame->pktbyte.MPG_DB[0]) ;
    HDMITX_WriteI2C_Byte(REG_TX_PKG_MPGINFO_DB1,pMPGInfoFrame->pktbyte.MPG_DB[1]) ;
    HDMITX_WriteI2C_Byte(REG_TX_PKG_MPGINFO_DB2,pMPGInfoFrame->pktbyte.MPG_DB[2]) ;
    HDMITX_WriteI2C_Byte(REG_TX_PKG_MPGINFO_DB3,pMPGInfoFrame->pktbyte.MPG_DB[3]) ;

    for(ucData = 0,i = 0 ; i < 5 ; i++)
    {
        ucData -= pMPGInfoFrame->pktbyte.MPG_DB[i] ;
    }
    ucData -= 0x80+MPEG_INFOFRAME_VER+MPEG_INFOFRAME_TYPE+MPEG_INFOFRAME_LEN ;

    HDMITX_WriteI2C_Byte(REG_TX_PKG_MPGINFO_SUM,ucData) ;

    Switch_HDMITX_Bank(0) ;
    ENABLE_SPD_INFOFRM_PKT() ;

    return ER_SUCCESS ;
}


//////////////////////////////////////////////////////////////////////
// Function: DumpCatHDMITXReg()
// Parameter: N/A
// Return: N/A
// Remark: Debug function,dumps the registers of CAT6611.
// Side-Effect: N/A
//////////////////////////////////////////////////////////////////////

#ifdef HDMITX_REG_DEBUG
static void
DumpCatHDMITXReg()
{
    int i,j ;
    BYTE reg ;
    BYTE bank ;
    BYTE ucData ;

    ErrorF("       ") ;
    for(j = 0 ; j < 16 ; j++)
    {
        ErrorF(" %02X",j) ;
        if((j == 3)||(j==7)||(j==11))
        {
            ErrorF("  ") ;
        }
    }
    ErrorF("\n        -----------------------------------------------------\n") ;

    Switch_HDMITX_Bank(0) ;

    for(i = 0 ; i < 0x100 ; i+=16)
    {
        ErrorF("[%3X]  ",i) ;
        for(j = 0 ; j < 16 ; j++)
        {
            ucData = HDMITX_ReadI2C_Byte((BYTE)((i+j)&0xFF)) ;
            ErrorF(" %02X",ucData) ;
            if((j == 3)||(j==7)||(j==11))
            {
                ErrorF(" -") ;
            }
        }
        ErrorF("\n") ;
        if((i % 0x40) == 0x30)
        {
            ErrorF("        -----------------------------------------------------\n") ;
        }
    }

    Switch_HDMITX_Bank(1) ;
    for(i = 0x130; i < 0x1B0 ; i+=16)
    {
        ErrorF("[%3X]  ",i) ;
        for(j = 0 ; j < 16 ; j++)
        {
            ucData = HDMITX_ReadI2C_Byte((BYTE)((i+j)&0xFF)) ;
            ErrorF(" %02X",ucData) ;
            if((j == 3)||(j==7)||(j==11))
            {
                ErrorF(" -") ;
            }
        }
        ErrorF("\n") ;
        if(i == 0x160)
        {
            ErrorF("        -----------------------------------------------------\n") ;
        }

    }
    Switch_HDMITX_Bank(0) ;
}
#endif
