#include "ms933x_comm.h"
#include "ms933x.h"
#include "ms933x_app.h"
#include "ms933x_edid.h"
extern void mculib_i2c_init(void);

///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
//user function define

//#define MS933X_DRV_API
#define MS933X_CHIP                 (MS9332_CHIP)

#define RX_HDCP_SUPPORT_ENABLE      (1) //suggest enable
#define TX_HDCP_SUPPORT_ENABLE      (1) //

//if need support hdcp repeater function, pls set to 1
#define HDCP_RPT_SUPPORT_ENABLE     (0)


//ms933x hdmi network cable board config
//source->net_hdmi_tx_board->long_network_cable->net_hdmi_rx_board->sink
#define MS933X_HDMI_NET_CABLE_TX_ENABLE     (0) //net_hdmi_tx_board
#define MS933X_HDMI_NET_CALBE_RX_ENABLE     (0) //net_hdmi_rx_board, normal use ms9331 chip on the board.

///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////

#define MS933X_SDK_VERSION  "MS933XC_1TO2&4_DEMO_MS8006_V2.3.3_250409"

#define g_u16Timer          (50)  //unit ms, g_u16Timer must >= 20.

//auto judge source color space(YUV444/YUV422) and sink capability. if sink not support, fixed convert to RGB.
//net_hdmi_tx_board do not needed.
#define HDMI_VIDEO_CSC_AUTO_ENABLE              (!MS933X_HDMI_NET_CABLE_TX_ENABLE)

//if support hdcp_repeater, must disable. else suggest enable this function.
#define HDMI_RX_HPD_DELAY_OFF_ENABLE            (!HDCP_RPT_SUPPORT_ENABLE)

#define HDMI_RX_TMDS_ERROR_SERVICE_ENABLE       (1) //when rx tmds data error, reconfig rx_phy

#define HDMI_RX_TIMING_ERROR_SERVICE_ENABLE     (0) //when rx timing unstable timeout, toggle rx_hpd

//0: process cts change immediately; 1: process cts change when audio fifo over/under flow.
#define HDMI_RX_AUDIO_CTS_CHNAGE_HANDEL_MODE    (0)

//when tx hdcp failed, whether need to retry. if support hdcp_repeater, must enable
#define HDMI_TX_HDCP_RETRY_ENABLE               (HDCP_RPT_SUPPORT_ENABLE)

//
#define HDMI_SPD_INFO_CTRL_ENABLE               (0) //spd infoframe support

//
#define HDMI_RX_CLK_INT_ENABLE                  (1) //used

#define HDMI_RX_MDT_INT_ENABLE                  (0) //unsupport

#define HDMI_RX_PKT_INT_ENABLE                  (0) //unsupport

//
#define HDMI_TX_TMDS_AUTO_CTRL_ENABLE           (1) //when rx_tmds_clk change, chip auto disable hdmi_tx tmds.

//if not net_hdmi_rx_board. must set to 0
#define HDMI_RX_CEA_TIMING_USE_MANUAL_ENABLE    (MS933X_HDMI_NET_CALBE_RX_ENABLE)

//if not net_hdmi_rx_board. must set to 0
#define HDMI_RX_ERROR_COUNTER_DEBUG_ENABLE      (MS933X_HDMI_NET_CALBE_RX_ENABLE)

#define HDMI_RX_TIMING_PARSE_ENABLE             (0)
//
#define MS933X_SLAVER_I2C_ERROR_SERVICE_ENABLE  (0) //mculib_i2c accress MS933X NACK error service. when occur, Hardware PIN_reset to MS933X.
//
#define MS933X_TX_DDC_ERROR_SERVICE_ENABLE      (1) //when occur tx ddc error, Hardware PIN_reset to MS933X

///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////

#define MS9331_CHIP         (0x81)
#define MS9332_CHIP         (0x09)
#define MS9333_CHIP         (0x89)
#define MS9334_CHIP         (0x0F)
#define MS9330_CHIP         (0x8F) //for test_chip only

#define SYS_HDMI_TX_CHN_EN              (MS933X_CHIP & 0x0F)

#define SYS_AUDIO_PAD_OUTPUT_ENABLE     (MS933X_CHIP & 0x80) //i2s and spdif pad output function enable

#define HDMI_TX_CHN_NUM     (4)
#define HDMI_TX_SH_CHN_NUM  (4)

#define DEBUG_EDID_FILE_SAVE    (0)

//
static VIDEOTIMING_T g_st_hdmi_in_timing;

#define TMDS_CLK_VALID(clk)           (clk >= 500)  //5MHz
#define TMDS_CLK_MARGIN(clk, clk_tmp) (xabs(clk, clk_tmp) > (clk / (100 / 5))) //5%

static UINT16 g_u16_input_tmds_clk = 0;

BOOL g_b_hdmi_input_valid = FALSE;

UINT8 g_u8_source_5v_connect;
UINT8 g_u8_sink_hpd_connect[HDMI_TX_CHN_NUM];

static HDMI_CONFIG_T g_st_hdmi_timing;

#if RX_HDCP_SUPPORT_ENABLE
static UINT8 g_u8_rx_hdcp_support = TRUE;       //user_define must enable this function
static UINT8 g_u8_tx_hdcp_support = TRUE;       //user_define must enable this function
#endif

#if HDCP_RPT_SUPPORT_ENABLE
static UINT8 g_u8_hdcp_repeater_support = TRUE; //user_define must enable this function
#endif

//for debug mode
static UINT8 g_u8_tx_chn_enable_flag = SYS_HDMI_TX_CHN_EN;//bit0: chn0 enable, bit1: chn1 enable...
static UINT8 g_u8_tx_hpd_test_flag = 0x00;//bit0: chn0 force output, bit1: chn1 force output...
static UINT8 g_u8_rx_hpd_test_flag = TRUE;//FALSE; //fixed set RX HPD true and rx edid use default edid
//static UINT8 g_u8_hdmi_rxpll_error_counter_test_flag = FALSE; //enable hdmi rxpll error counter serivce
//static UINT8 g_u8_hdmi_tx_shell_timing_stable_test_flag = FALSE; //enable hdmi tx shell timing stable service

#define MS933X_APP_LOG1_ENABLE              (1) //app detailed log printf enable

static UINT8 g_u8_hdmi_in_timing_log_enable = MS933X_APP_LOG1_ENABLE; //enable hdmi input timing log printf.


#define RXPLL_ERROR_MAX (0x20)
#define RXPLL_ERROR_MID (0x10)
#define RXPLL_ERROR_MIN (0x02)


#define SYSTEM_ERROR_TIMEOUT_1S (1000 / g_u16Timer) //1000ms
#define SYSTEM_ERROR_TIMEOUT_10S (3000 / g_u16Timer) //3s
static UINT8 g_u8_system_error_service_flag = FALSE;
static UINT8 g_u8_system_error_timer_count_1s = 0;
static UINT8 g_u8_system_error_timer_count_10s = 0;
static UINT8 g_u8_system_error_flag = 0; //bit0: rxpll unlock; bit1: rxpll error; bit2: hdmi shell unstable
static UINT8 g_u8_system_error_action_flag = 0; //record system error, count hpd toggle times


#define CHIP_VALID_CHECK_TIMEOUT (3000 / g_u16Timer) //3000ms
static UINT8 g_u8_chip_valid_check_timer_count = 0;

#define HDMI_SHELL_ERROR_TIMEOUT (500 / g_u16Timer) //500ms
static UINT8 g_u8_hdmi_shell_error_timer_count = 0;

#define HDMI_TX_HPD_DET_TIMEOUT (100 / g_u16Timer) //100ms
#define HDMI_RX_HPD_OFF_TIMEOUT (14) //1400ms
static UINT8 g_u8_hdmi_tx_hpd_detect_count = 0;
static UINT8 g_u8_hdmi_rx_hpd_off_count = HDMI_RX_HPD_OFF_TIMEOUT;

static UINT8 g_u8_tx_ddc_error_flag = 0x00;//bit0: tx0 error, bit1: tx1 error error...

#define RX_HDCP_TIMEOUT (200 / g_u16Timer) //200ms
static UINT8 g_u8_rx_hdcp_timer_count = 0;
static UINT8 g_u8_rx_hdcp_woking_flag = FALSE;
static UINT8 g_u8_rx_hdcp_aksv_be_writed_flag = 0;


#define TX_HDCP_TIMEOUT (3000 / g_u16Timer) //3000ms

#if HDCP_RPT_SUPPORT_ENABLE
#define TX_HDCP_START_TIME ((3000 - 100)  / g_u16Timer) //100ms
#define TX_HDCP_R0_START_TIME ((3000 - 150)  / g_u16Timer) //150ms
#else
#define TX_HDCP_START_TIME ((3000 - 800)  / g_u16Timer) //800ms
#define TX_HDCP_R0_START_TIME ((3000 - 200)  / g_u16Timer) //200ms
#endif

static UINT8 g_u8_tx_hdcp_timer_count_buf[HDMI_TX_CHN_NUM];
static UINT8 g_u8_tx_hdcp_process_flag_buf[HDMI_TX_CHN_NUM];
static UINT8 g_u8_tx_hdcp_init_flag_buf[HDMI_TX_CHN_NUM];
static UINT8 g_u8_tx_hdcp_enable_flag_buf[HDMI_TX_CHN_NUM];
static UINT8  g_u8_tx_hdcp_verify_first_R0_flag_buf[HDMI_TX_CHN_NUM];


#define TX_HDCP_RETRY_START_TIME    ((3000 - 2000)  / g_u16Timer) //2000ms


#define TX_HDCP_PORT_SRC_TIMEOUT (200 / g_u16Timer) //200ms
static UINT8 g_u8_tx_hdcp_port_service_timer_count = 0;

#define HDCP_REPEATER_SRC_TIMEOUT (100 / g_u16Timer) //100ms
static UINT8 g_u8_hdcp_rpt_service_timer_count = 0;

#define HDCP_REPEATER_READY_TIMEOUT (40) //4000ms
static UINT8 g_u8_hdcp_rpt_ready_timer_count = 0;

static UINT8 g_u8_rxpll_configed_status = 0;

#define MDT_CHANGE_TIMEOUT (2 + (50 / g_u16Timer)) //150ms. at leset polling 2times
static UINT8 g_u8_mdt_change_timer_count = 0;


static BOOL g_b_hdmi_rx_audio_cts_change_flag = FALSE;


#define RX_PACKET_TIMEOUT (100 / g_u16Timer) //100ms
static UINT8  g_u8_rx_packet_timer_count = 0;

static BOOL   g_b_rx_gcp_avmute_flag = FALSE;

//static UINT8  g_u8_rx_hpd_flag = 0;
static UINT8  g_u8_sys_edid_flag = 0xff;  //none edid value
static HDMI_EDID_FLAG_T g_st_hdmi_edid_flag[HDMI_TX_CHN_NUM + 1];
static UINT8  g_u8_sys_edid_used_buf[512];
static UINT8  g_u8_sys_edid_buf[512];
static UINT8  g_u8_sys_edid_buf_last_id = 0xff;
static UINT32 g_u32_hdmi_sink_min_timing = 0xFFFFFFFFUL;
static UINT32 g_u32_dvi_sink_min_timing = 0xFFFFFFFFUL;

#define HDMI_TX_DEFAULT_EDID_ID HDMI_TX_CHN_NUM


//
UINT8 g_u8_hdmi_tx_drive_mode = 2;
//
#define INPUT_INVALID_TIMEOUT_1S    (1000 / g_u16Timer)     //1000ms
#define INPUT_INVALID_TIMEOUT       (2000 / g_u16Timer)     //2000ms
static UINT8 g_u8_input_invalid_timer_count = 0;

#define RXPHY_ERROR_TIMEOUT         (3000 / g_u16Timer)     //3000ms
static UINT8 g_u8_rxphy_error_timer_count = 0;

static UINT8 g_u8_ms933xc_version_flag = 0;


/* 4K EDID
static UINT8 __CODE u8_sys_edid_default_buf[256] =
{
    // Explore Semiconductor, Inc. EDID Editor V2
    0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,   // address 0x00
    0x4C, 0x2D, 0xFF, 0x0D, 0x58, 0x4D, 0x51, 0x30,   //
    0x1C, 0x1C, 0x01, 0x03, 0x80, 0x00, 0x00, 0x78,   // address 0x10
    0x2A, 0x5F, 0xB1, 0xA2, 0x57, 0x4F, 0xA2, 0x28,   //
    0x0F, 0x50, 0x54, 0xBF, 0xEF, 0x80, 0x71, 0x4F,   // address 0x20
    0x81, 0x00, 0x81, 0xC0, 0x81, 0x80, 0x95, 0x00,   //
    0xA9, 0xC0, 0xB3, 0x00, 0x01, 0x01, 0x04, 0x74,   // address 0x30
    0x00, 0x30, 0xF2, 0x70, 0x5A, 0x80, 0xB0, 0x58,   //
    0x8A, 0x00, 0x60, 0x59, 0x21, 0x00, 0x00, 0x1E,   // address 0x40
    0x00, 0x00, 0x00, 0xFD, 0x00, 0x18, 0x4B, 0x1E,   //
    0x5A, 0x1E, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20,   // address 0x50
    0x20, 0x20, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x55,   //
    0x32, 0x38, 0x48, 0x37, 0x35, 0x78, 0x0A, 0x20,   // address 0x60
    0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xFF,   //
    0x00, 0x48, 0x54, 0x50, 0x4B, 0x37, 0x30, 0x30,   // address 0x70
    0x30, 0x35, 0x31, 0x0A, 0x20, 0x20, 0x01, 0x57,   //
    0x02, 0x03, 0x26, 0xF0, 0x4B, 0x5F, 0x10, 0x04,   // address 0x80
    0x1F, 0x13, 0x03, 0x12, 0x20, 0x22, 0x5E, 0x5D,   //
    0x23, 0x09, 0x07, 0x07, 0x83, 0x01, 0x00, 0x00,   // address 0x90
    0x6D, 0x03, 0x0C, 0x00, 0x10, 0x00, 0x80, 0x3C,   //
    0x20, 0x10, 0x60, 0x01, 0x02, 0x03, 0x02, 0x3A,   // address 0xA0
    0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C,   //
    0x45, 0x00, 0x60, 0x59, 0x21, 0x00, 0x00, 0x1E,   // address 0xB0
    0x02, 0x3A, 0x80, 0xD0, 0x72, 0x38, 0x2D, 0x40,   //
    0x10, 0x2C, 0x45, 0x80, 0x60, 0x59, 0x21, 0x00,   // address 0xC0
    0x00, 0x1E, 0x01, 0x1D, 0x00, 0x72, 0x51, 0xD0,   //
    0x1E, 0x20, 0x6E, 0x28, 0x55, 0x00, 0x60, 0x59,   // address 0xD0
    0x21, 0x00, 0x00, 0x1E, 0x56, 0x5E, 0x00, 0xA0,   //
    0xA0, 0xA0, 0x29, 0x50, 0x30, 0x20, 0x35, 0x00,   // address 0xE0
    0x60, 0x59, 0x21, 0x00, 0x00, 0x1A, 0x00, 0x00,   //
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   // address 0xF0
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8,   //
};*/

static UINT8 __CODE u8_sys_edid_default_buf[256] =
{
    // Explore Semiconductor, Inc. EDID Editor V2
    0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,   // address 0x00
    0x34, 0x23, 0x01, 0x01, 0x01, 0x02, 0x03, 0x04,   //
    0x01, 0x18, 0x01, 0x03, 0x80, 0x00, 0x00, 0x78,   // address 0x10
    0xEF, 0xEE, 0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26,   //
    0x0F, 0x50, 0x54, 0x2D, 0xCF, 0x00, 0x81, 0x00,   // address 0x20
    0x81, 0xC0, 0x81, 0x80, 0xD1, 0xC0, 0x01, 0x01,   //
    0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1D,   // address 0x30
    0x00, 0x72, 0x51, 0xD0, 0x1E, 0x20, 0x6E, 0x28,   //
    0x55, 0x00, 0xC4, 0x8E, 0x21, 0x00, 0x00, 0x1E,   // address 0x40
    0xF3, 0x39, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40,   //
    0x58, 0x2C, 0x45, 0x00, 0xC4, 0x8E, 0x21, 0x00,   // address 0x50
    0x00, 0x1E, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x32,   //
    0x55, 0x1E, 0x51, 0x11, 0x00, 0x0A, 0x20, 0x20,   // address 0x60
    0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xFC,   //
    0x00, 0x4D, 0x41, 0x43, 0x52, 0x4F, 0x53, 0x49,   // address 0x70
    0x4C, 0x49, 0x43, 0x4F, 0x4E, 0x0A, 0x01, 0x1C,   //
    0x02, 0x03, 0x1D, 0x41, 0x4A, 0x04, 0x1F, 0x02,   // address 0x80
    0x90, 0x06, 0x11, 0x15, 0x14, 0x05, 0x13, 0x23,   //
    0x09, 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x65,   // address 0x90
    0x03, 0x0C, 0x00, 0x10, 0x00, 0x02, 0x3A, 0x80,   //
    0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C, 0x45,   // address 0xA0
    0x00, 0xDD, 0x0C, 0x11, 0x00, 0x00, 0x1E, 0x01,   //
    0x1D, 0x00, 0x72, 0x51, 0xD0, 0x1E, 0x20, 0x6E,   // address 0xB0
    0x28, 0x55, 0x00, 0x10, 0x09, 0x00, 0x00, 0x00,   //
    0x1E, 0x8C, 0x0A, 0xD0, 0x8A, 0x20, 0xE0, 0x2D,   // address 0xC0
    0x10, 0x10, 0x3E, 0x96, 0x00, 0x10, 0x09, 0x00,   //
    0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,   // address 0xD0
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   //
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   // address 0xE0
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   //
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,   // address 0xF0
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6,   //
};

//
static UINT8 g_u8_rx_hdcp_rpt_ready = 0;
#if HDCP_RPT_SUPPORT_ENABLE
static UINT8 g_u8_rx_hdcp_rpt_dev_count = 0;
static UINT8 g_u8_rx_hdcp_rpt_dev_depth = 0;
static UINT8 g_u8_hdcp_rpt_ksv_buf[MS933X_HDCP_RPT_KSV_FIFO_BYTE_MAX];
#endif

static UINT8 g_u8_tx_hdcp_repeater_flag_buf[HDMI_TX_CHN_NUM];

//user define, if use for HDMI CTS hdcp repeater test, pls set to 1
#define HDMI_CTS_HDCP_RPT_ENABLE        (0)
#define HDMI_CTS_HDCP_DEV_COUNT_MAX     (2)

//resolve tx hdcp rpt result status error when input tmds clk large than 200MHz
#define TX_HDCP_RPT_BUG0_FIXED_ENABLE   (1)

#if RX_HDCP_SUPPORT_ENABLE
//Warining: user must use yourself rx and tx hdcp_key on product. below hdcp_key is only for test.
static UINT8 __CODE u8_rx_ksv_buf[5] =
{
    //5 byte ksv
    0xE5,
    0xAA,
    0x2C,
    0x72,
    0x36,
};

static UINT8 __CODE u8_rx_key_buf[280] =
{
    // 280 byte key
    //user need flip license key data byte0~7, byte8~15, byte16~23, ...
    0x89, 0x48, 0xa6, 0x5e, 0xd0, 0x80, 0xac,
    0x87, 0xbc, 0xb9, 0x51, 0xf9, 0x05, 0x1b,
    0xfd, 0x2f, 0xf3, 0x57, 0x44, 0x39, 0x44,
    0x26, 0x1b, 0xb5, 0x9d, 0xeb, 0xa5, 0x3c,
    0xd1, 0x4e, 0x83, 0xef, 0xfc, 0xc3, 0x69,
    0xd4, 0xcf, 0xa1, 0x0a, 0x1d, 0x2d, 0xf0,
    0x38, 0x79, 0x8a, 0x68, 0x2c, 0x5d, 0xfb,
    0x37, 0xf2, 0x7d, 0x26, 0xb5, 0x57, 0xcc,
    0x9e, 0x61, 0x8d, 0x3a, 0x69, 0x14, 0x01,
    0xe5, 0x9a, 0x27, 0xa6, 0x02, 0x8b, 0x0b,
    0xe7, 0xea, 0x30, 0xf0, 0x1a, 0x87, 0x65,
    0x4e, 0x84, 0x8d, 0x60, 0xb9, 0x48, 0x88,
    0x5f, 0xe4, 0xd6, 0x03, 0x85, 0x62, 0x0d,
    0x65, 0x7a, 0xa3, 0x04, 0xec, 0x41, 0xe7,
    0xc3, 0x64, 0xa6, 0x54, 0x2b, 0x34, 0x1b,
    0xa8, 0xc2, 0xf6, 0xeb, 0xe3, 0x41, 0x28,
    0xd0, 0x0c, 0xa1, 0x39, 0x78, 0xd6, 0x7f,
    0x17, 0xae, 0x43, 0x34, 0x4b, 0x7b, 0x6f,
    0xec, 0x4d, 0x42, 0x51, 0xe7, 0x6a, 0x41,
    0x37, 0x21, 0xb7, 0x0b, 0x3d, 0xe3, 0xe7,
    0x56, 0x6b, 0xfc, 0xa4, 0x53, 0x77, 0x0e,
    0x97, 0x6f, 0x21, 0x1f, 0x94, 0x42, 0x83,
    0x81, 0xf4, 0xb3, 0x6e, 0x40, 0x45, 0x45,
    0x93, 0x96, 0x98, 0x3e, 0x75, 0x1a, 0xbb,
    0xec, 0x26, 0x94, 0x50, 0x3a, 0x6c, 0xf5,
    0xaf, 0x08, 0x3c, 0xce, 0x8f, 0xb7, 0x6a,
    0x3a, 0xbd, 0x4f, 0x55, 0x50, 0xcd, 0xd8,
    0x74, 0x80, 0xf6, 0x89, 0xe0, 0xc2, 0x3a,
    0xa5, 0xdb, 0x57, 0x82, 0x3d, 0x25, 0xee,
    0x2f, 0x90, 0x5a, 0x50, 0x2d, 0x56, 0xb2,
    0xee, 0x79, 0xd6, 0x2c, 0x69, 0x66, 0xbf,
    0xab, 0xad, 0x2b, 0x12, 0xb4, 0x9f, 0xbb,
    0xab, 0x0a, 0xdc, 0xb8, 0x0b, 0x8c, 0x03,
    0xbd, 0xb9, 0x8f, 0x5a, 0x41, 0x4b, 0x22,
    0xa8, 0x1a, 0xad, 0x31, 0x24, 0x09, 0x14,
    0x1e, 0x0c, 0x6c, 0x50, 0x59, 0xb8, 0x06,
    0x5d, 0xe6, 0x2f, 0x53, 0xda, 0xf8, 0x41,
    0x50, 0x44, 0x4e, 0x97, 0xe4, 0x8a, 0x0c,
    0x5c, 0x20, 0xeb, 0x4e, 0xaa, 0x85, 0x20,
    0x25, 0xcc, 0x59, 0x99, 0x68, 0x91, 0xf1,
};
#endif
static UINT8 __CODE u8_tx_ksv_buf[5] =
{
    //5 byte ksv
    0x75,
    0xbd,
    0x4e,
    0xc0,
    0x32,
};

static UINT8 __CODE u8_tx_key_buf[280] =
{
    //280 byte key
    0xda, 0x8e, 0x0b, 0x36, 0xd8, 0x9f, 0x1a,
    0x48, 0x6d, 0x69, 0x4b, 0x13, 0x3b, 0x99,
    0x7b, 0xd0, 0xc7, 0x2f, 0x3b, 0xc0, 0xd6,
    0x47, 0xe4, 0xd8, 0x17, 0x57, 0xc8, 0x9c,
    0x7b, 0xaf, 0x3d, 0xb6, 0xc1, 0xfc, 0x6b,
    0xab, 0xa2, 0x06, 0x38, 0x11, 0x6c, 0xcd,
    0x53, 0xf7, 0x0b, 0x45, 0xcc, 0x49, 0xa8,
    0xf4, 0x3a, 0x78, 0xcc, 0xea, 0x96, 0x24,
    0x95, 0x5b, 0xf4, 0xa3, 0xe4, 0x4c, 0xce,
    0x67, 0xa2, 0xac, 0xf8, 0x5d, 0x12, 0xc4,
    0x55, 0x4a, 0xab, 0x66, 0x85, 0x94, 0x29,
    0x47, 0x1f, 0xba, 0x5b, 0x39, 0x6f, 0x64,
    0xf6, 0x81, 0xbb, 0xf4, 0x6e, 0x79, 0x22,
    0xd7, 0xcb, 0xb5, 0xca, 0x67, 0x52, 0xce,
    0xe0, 0x04, 0x30, 0x7c, 0xcc, 0x82, 0xfb,
    0xaf, 0xb1, 0x5a, 0x94, 0x7f, 0xd5, 0x17,
    0x2d, 0xe3, 0xf6, 0xa4, 0x2a, 0x4f, 0xc8,
    0x6c, 0x92, 0xbb, 0xa5, 0x1b, 0x6a, 0x6f,
    0x5a, 0xb3, 0x87, 0xef, 0xc8, 0x45, 0xe9,
    0xd2, 0x8a, 0x2a, 0x32, 0x58, 0xda, 0x2d,
    0x86, 0xd1, 0x36, 0xe0, 0x6a, 0xe6, 0x8b,
    0x00, 0x64, 0x38, 0xf2, 0x68, 0x6a, 0xc9,
    0x8d, 0x55, 0xdb, 0x75, 0xe6, 0x52, 0x47,
    0x71, 0x77, 0xe7, 0x3e, 0xbb, 0xaf, 0x69,
    0x21, 0x4e, 0xff, 0x14, 0xc6, 0x78, 0x17,
    0xf3, 0xcd, 0xb4, 0xa2, 0x5e, 0xb5, 0xa3,
    0x16, 0x65, 0x41, 0xfa, 0xed, 0xae, 0xb1,
    0x77, 0x56, 0xf0, 0x84, 0x05, 0x54, 0x03,
    0x60, 0x58, 0x06, 0x46, 0xd1, 0x69, 0x22,
    0x36, 0x36, 0x1e, 0xb9, 0x57, 0x47, 0x74,
    0x13, 0x93, 0x3e, 0x7a, 0xca, 0x12, 0x75,
    0xe9, 0x3a, 0x8f, 0x78, 0xbd, 0xac, 0x32,
    0x12, 0x57, 0xa5, 0x45, 0xdc, 0x1b, 0x8c,
    0x2d, 0x16, 0x38, 0x4e, 0x7a, 0xf4, 0x88,
    0x1b, 0x07, 0x38, 0xf6, 0xb5, 0x5d, 0x8e,
    0xa9, 0x48, 0xf4, 0x0e, 0x11, 0xd1, 0x62,
    0xff, 0xe7, 0x77, 0x9c, 0x7b, 0xe8, 0x18,
    0x3b, 0x13, 0x16, 0xb2, 0x42, 0xf4, 0x78,
    0xca, 0x0e, 0x09, 0x78, 0xdc, 0x05, 0xca,
    0x2f, 0x78, 0xbf, 0xab, 0x2b, 0x5f, 0x85,
};


typedef enum _E_HDMI_TX_CONFIG_ITEM_
{
    HDMI_TX_CONFIG_AV       = 0x00, //video and audio
    HDMI_TX_CONFIG_AUD      = 0x01, //audio
    HDMI_TX_CONFIG_AUD_FS   = 0x02, //audio fs
    HDMI_TX_CONFIG_AVMUTE   = 0x03  //avmute packet
}HDMI_TX_CONFIG_ITEM_E;

//
BOOL _rx_edid_update(UINT8 *p_u8_edid_buf, BOOL b_rx_hpd_low_delay);
BOOL _rx_hpd_toggle(VOID);
UINT8 _sink_hpd_low_process(UINT8 u8_chn, UINT8 u8_hpd);
void sys_hotplug_init(void);
void _hdmi_tx_gcp_avmute_param_default(void);
void _shutdown_output(UINT8 u8_output_chn);
void sys_shutdown_output(void);
void _config_output(UINT8 u8_output_chn);
void sys_config_output(UINT8 u8_config_item, UINT8 u8_value); //refer to HDMI_TX_CONFIG_ITEM_E
//
static BOOL _tx_sink_exist_unsupport_yuv_check(VOID);

//
void _hdmi_tx_edid_param_default(UINT8 u8_output_chn);
void _hdmi_tx_hdcp_param_default(UINT8 u8_output_chn);
void _hdmi_tx_hdcp_start(UINT8 u8_output_chn);
//


//
VOID _tx_hdcp_rpt_param_repeater_flag_default(UINT8 u8_tx_chn);
VOID _rx_hdcp_rpt_param_ready_reset(VOID);
BOOL _rx_hdcp_rpt_ready_reset(VOID);
BOOL _tx_hdcp_bcaps_repeater_flag_get(VOID);
VOID _tx_hdcp_rpt_param_repeater_flag_set(BOOL b_set);
void _tx_hdcp_rpt_init(UINT8 u8_tx_chn);

//
void sys_ms933x_chip_valid_check(void);
BOOL _tx_ddc_error_get(UINT8 u8_tx_chn);
void _tx_ddc_error_check(UINT8 u8_tx_chn, BOOL b_tx_hpd_lost);
//

//
VOID sys_hdmi_rx_timing_manual_enable(BOOL b_enable);


//
//rx_5v status light
#define RX_LED_light(on)
//tx_hpd status light
#define TX_LED_light(tx_chn, on)    //mculib_led_control((GPIO_PIN_1 << (4 - tx_chn)), on)
//rx timing stable light
#define RX_STB_LED_light(on)       // mculib_led_control(GPIO_PIN_1, on)

//



///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////
void ms933x_app_check_chip_version(void)
{
    if(ms933xdrv_misc_chip_C_version_get())
    {
        g_u8_ms933xc_version_flag = 1;
        LOG("ms933xc chip.");
    }
    else
    {
        g_u8_ms933xc_version_flag = 0;
    }
}

void _param_default(void)
{
    UINT8 i;

    g_u16_input_tmds_clk = 0;
    g_u8_rx_hdcp_timer_count = 0;
    g_u8_rx_hdcp_woking_flag = 0;
    g_u8_rx_hdcp_aksv_be_writed_flag = 0;
    g_b_hdmi_input_valid = 0;
    g_u8_sys_edid_flag = 0xff;
    g_u8_sys_edid_buf_last_id = 0xff;
    g_u32_hdmi_sink_min_timing = 0xFFFFFFFFUL;
    g_u32_dvi_sink_min_timing = 0xFFFFFFFFUL;
    g_u8_source_5v_connect = 0;
    g_u8_hdmi_rx_hpd_off_count = HDMI_RX_HPD_OFF_TIMEOUT;
    g_u8_hdcp_rpt_service_timer_count = 0;
    g_u8_hdcp_rpt_ready_timer_count = 0;
    //
    g_u8_chip_valid_check_timer_count = 0;
    //
    g_u8_hdmi_tx_hpd_detect_count = 0;
    //
    g_u8_system_error_service_flag = FALSE;
    g_u8_system_error_timer_count_1s = 0;
    g_u8_system_error_timer_count_10s = 0;
    g_u8_system_error_flag = 0;
    g_u8_system_error_action_flag = 0;
    //
    g_u8_input_invalid_timer_count = 0;
    g_u8_rxphy_error_timer_count = 0;
    g_u8_hdmi_shell_error_timer_count = 0;
    //
    g_u8_rxpll_configed_status = 0;
    g_u8_mdt_change_timer_count = 0;
    g_u8_rx_packet_timer_count = 0;
    //
    _hdmi_tx_gcp_avmute_param_default();
    //
    #if HDCP_RPT_SUPPORT_ENABLE
    _rx_hdcp_rpt_param_ready_reset();
    #endif
    //
    memset(g_u8_sys_edid_used_buf, 0, 512);

    //buf init
    for (i = 0; i < HDMI_TX_CHN_NUM; i++)
    {
        g_u8_sink_hpd_connect[i] = ((g_u8_tx_hpd_test_flag & g_u8_tx_chn_enable_flag) >> i) & 0x01;

        _hdmi_tx_edid_param_default(i);
        _hdmi_tx_hdcp_param_default(i);
        #if HDCP_RPT_SUPPORT_ENABLE
        _tx_hdcp_rpt_param_repeater_flag_default(i);
        #endif
    }
}

void _tx_common_init(void)
{
    UINT8 i;

    ms933xdrv_hdmi_tx_init();

    for (i = 0; i < HDMI_TX_CHN_NUM; i++)
    {
        if ((g_u8_tx_chn_enable_flag >> i) & 0x01)
        {
            ms933xdrv_hdmi_tx_set_channel(i);

            #if HDMI_TX_TMDS_AUTO_CTRL_ENABLE
            ms933xdrv_hdmi_tx_phy_output_auto_ctrl(0, TRUE);
            #endif

            #if TX_HDCP_SUPPORT_ENABLE
            if (g_u8_tx_hdcp_support)
            {
                ms933xdrv_hdmi_tx_hdcp_key_init((UINT8 *)u8_tx_key_buf);
            }
            #endif
        }
    }
}

void ms933x_init(void)
{
    //IIC_sf_Init();

    mculib_i2c_init();

    //reset chip
    mculib_chip_reset();
    LOG("mculib_chip_reset");

    //param default.
    _param_default();

    if (ms933xdrv_misc_chipisvalid())
    {
        LOG("ms933x chip connect.");
    }
    else
    {
        LOG("ms933x chip disconnect.");
    }

    ms933x_app_check_chip_version();

    ms933xdrv_hdmi_rx_controller_reset(HDMI_RX_CTRL_MAIN);
    ms933xdrv_hdmi_rx_init();

    #if MS933X_HDMI_NET_CABLE_TX_ENABLE
    //internal fosc to 24M, HW 5.1K res. for
    ms933x_HAL_WriteByte(0x61, 0x15);
    #endif

    #if HDMI_RX_CEA_TIMING_USE_MANUAL_ENABLE
    //20190328, MDT stable,
    ms933x_HAL_ModBits_Ex(0x2174, 0xFF000000UL, (0x7FUL) << 24);
    #endif

    //
    ms933xdrv_hdmi_rx_pi_phy_init();

    #if RX_HDCP_SUPPORT_ENABLE
    if (g_u8_rx_hdcp_support)
    {
        ms933xdrv_hdmi_rx_controller_hdcp_encryption_enable(TRUE);
        ms933xdrv_hdmi_rx_controller_hdcp_init((UINT8 *)u8_rx_ksv_buf, (UINT8 *)u8_rx_key_buf);
    }
    else
    {
        ms933xdrv_hdmi_rx_controller_hdcp_encryption_enable(FALSE);
    }
    #endif

    #if HDCP_RPT_SUPPORT_ENABLE
    // rx hdcp rpt init
    if (g_u8_hdcp_repeater_support)
    {
        if (!ms933xdrv_hdmi_rx_core_hdcp_bcaps_rpt_enable(TRUE))
        {
            LOG("hdcp_rpt_enable_failed.");
        }
    }
    else
    {
        ms933xdrv_hdmi_rx_core_hdcp_bcaps_rpt_enable(FALSE);
    }
    ms933xdrv_hdmi_rx_core_hdcp_rpt_reset_enable(TRUE);
    #endif

    _tx_common_init();

    sys_hotplug_init();

    LOG(MS933X_SDK_VERSION);
}

VOID sys_hdmi_rx_tmds_overload_service(VOID)
{
#if 0 //unused
    UINT8 u8Overload;
    u8Overload = ms933xdrv_hdmi_rx_get_tmds_overload();
    if (u8Overload)
    {
        LOG1("input tmds_overload = ", u8Overload);
        ms933xdrv_hdmi_rx_tmds_overload_protect_disable(TRUE);
        //delay for disable efftct.
        mculib_delay_ms(1);
        ms933xdrv_hdmi_rx_tmds_overload_protect_disable(FALSE);
    }
#endif
}

#if HDMI_RX_ERROR_COUNTER_DEBUG_ENABLE
VOID _rxphy_error_service(VOID)
{
    UINT16 u16_error_buf[3];

    ms933xdrv_hdmi_rx_tmds_error_detect(u16_error_buf);

    if (u16_error_buf[0] != 0 || u16_error_buf[1] != 0 || u16_error_buf[2] != 0)
    {
        LOG("");
        LOG1("u16_chn0_error = ", u16_error_buf[0]);
        LOG1("u16_chn1_error = ", u16_error_buf[1]);
        LOG1("u16_chn2_error = ", u16_error_buf[2]);
    }
}
#endif

VOID sys_error_service_reset(VOID)
{
    g_u8_system_error_flag = 0;
    g_u8_system_error_timer_count_10s = 0;
}

VOID _hdmi_tx_shell_error_service(VOID)
{
    UINT8 i;

    for (i = 0; i < HDMI_TX_CHN_NUM; i++)
    {
        if (g_u8_sink_hpd_connect[i])
        {
            //only check one shell stable
            ms933xdrv_hdmi_tx_set_channel(g_u8_ms933xc_version_flag ? 0 : i);
            if (!ms933xdrv_hdmi_tx_shell_timing_stable())
            {
                LOG("hdmi_tx_error.");
            }
            break;
        }
    }
}

VOID sys_error_service(VOID)
{
#if MS933X_SLAVER_I2C_ERROR_SERVICE_ENABLE
    UINT8 u8_value;

    u8_value = mculib_ms993x_i2c_slaver_error_get();
    if (u8_value)
    {
        LOG2("ms933x_slaver_i2c_error = ", u8_value);
        ms933x_init();
        return;
    }
#endif

    sys_ms933x_chip_valid_check();

    if (!TMDS_CLK_VALID(g_u16_input_tmds_clk))
    {
        return;
    }

    #if HDMI_RX_ERROR_COUNTER_DEBUG_ENABLE
    g_u8_rxphy_error_timer_count ++;
    if (g_u8_rxphy_error_timer_count >= RXPHY_ERROR_TIMEOUT)
    {
        g_u8_rxphy_error_timer_count = 0;
        _rxphy_error_service();
    }
    #endif

    if (g_b_hdmi_input_valid)
    {
        g_u8_hdmi_shell_error_timer_count ++;
        if (g_u8_hdmi_shell_error_timer_count >= HDMI_SHELL_ERROR_TIMEOUT)
        {
            g_u8_hdmi_shell_error_timer_count = 0;
            _hdmi_tx_shell_error_service();
        }

        //
        g_u8_system_error_timer_count_10s = 0;
    }
    else
    {
        g_u8_system_error_timer_count_10s ++;
    }

    #if HDMI_RX_TIMING_ERROR_SERVICE_ENABLE
    if (g_u8_system_error_timer_count_10s >= SYSTEM_ERROR_TIMEOUT_10S)
    {
        g_u8_system_error_timer_count_10s = 0;
        //do action
        LOG("sys_error_reset.");
        _rx_hpd_toggle();
    }
    #endif
}

UINT8 _rxpll_errdet_wrong_status(UINT16 u16_error_val)
{
#if 1
    UINT8 u8_flag = 0x00;

    if (!ms933xdrv_rxpll_lock_status())
    {
        //clr error only
        ms933xdrv_errdet_wrong_status(1);
        mculib_delay_ms(2);

        if (!ms933xdrv_rxpll_lock_status())
        {
            u8_flag = 0x01;
        }
        else
        {
            if (ms933xdrv_errdet_wrong_status(RXPLL_ERROR_MIN))
            {
                u8_flag = 0x04;
            }
            else
            {
                //report unlock
                g_u8_system_error_flag |= 0x01;
            }
        }
    }
    else if (ms933xdrv_errdet_wrong_status(u16_error_val))
    {
        //20210302
        //when not in rxpll configed time but input timing still invalid, can goto this error counter process
        if ((g_u8_rxpll_configed_status == 0) && (!g_b_hdmi_input_valid))
        {
            mculib_delay_ms(2);
            if (ms933xdrv_errdet_wrong_status(RXPLL_ERROR_MID))
            {
                u8_flag = 0x02;
            }
            else
            {
                //report error
                g_u8_system_error_flag |= 0x02;
            }
        }
        else
        {
            //report error
            g_u8_system_error_flag |= 0x02;
        }
    }

    return u8_flag;
#else

    UINT8 u8_flag = 0x00;

    #if 1
    if (!ms933xdrv_rxpll_lock_status())
    {
        mculib_delay_ms(2);

        if (!ms933xdrv_rxpll_lock_status())
        {
            u8_flag = 0x01;
        }
        else
        {
            u8_flag = 0x08;
        }
    }
    #else
    if (!ms933xdrv_rxpll_lock_status())
    {
        u8_flag = 0x01;
    }
    #endif
    else if (ms933xdrv_errdet_wrong_status(u16_error_val))
    {
        //report error
        g_u8_system_error_flag |= 0x02;
    }

    return u8_flag;
#endif
}

//b_config_phy_all, TRUE: config rxpll and rxphy EQ; FALSE: config rxpll
UINT8 _hdmi_rx_phy_config(UINT16 *p_u16_tmds_clk, BOOL b_config_phy_all)
{
    UINT8 u8_times;
    UINT8 u8_flag = 0;
    UINT16 u16_clk1;
    UINT16 u16_clk2;

    u16_clk2 = (*p_u16_tmds_clk);

    //if rxpll unlock when rx config, do again
    for (u8_times = 0; u8_times < 3; u8_times ++)
    {
        u8_flag &= 0xFC;
        u8_flag |= ms933xdrv_hdmi_rx_pi_phy_config(u16_clk2, b_config_phy_all ? 0xFF : 0xFE);

        u16_clk1 = ms933xdrv_hdmi_rx_get_tmds_clk();
        b_config_phy_all = TRUE;

        //20200520, if detect input clk invalid, return
        if (!TMDS_CLK_VALID(u16_clk1))
        {
            u8_flag |= 0x08;
            (*p_u16_tmds_clk) = u16_clk1;
            break;
        }

        if (TMDS_CLK_VALID(u16_clk1) && xabs(u16_clk1, u16_clk2) >= 200)
        {
            u16_clk2 = u16_clk1;
            (*p_u16_tmds_clk) = u16_clk1;

            u8_flag |= 0x04;
        }
        else
        {
            if (u8_flag & 0x01)
            {
                break;
            }
        }
    }

    return u8_flag | (u8_times << 4);
}

BOOL _hdmi_rx_phy_errdet(VOID)
{
#if (!HDMI_RX_ERROR_COUNTER_DEBUG_ENABLE)
    UINT16 u16_error_val;

    u16_error_val = (g_u8_system_error_flag & 0x02) ? RXPLL_ERROR_MID : RXPLL_ERROR_MIN;

    if (ms933xdrv_errdet_wrong_status(u16_error_val))
    {
        if (g_u8_system_error_flag & 0x02)
        {
            return TRUE;
        }

        LOG("rx_tmds_error.");
        g_u8_system_error_flag |= 0x02;
    }
    else
    {
        g_u8_system_error_flag &= (~0x02);
    }
#endif

#if MS933X_HDMI_NET_CALBE_RX_ENABLE
    if (g_b_hdmi_input_valid)
    {
        g_u8_input_invalid_timer_count = 0;
    }
    else
    {
        g_u8_input_invalid_timer_count ++;
        if (g_u8_input_invalid_timer_count >= INPUT_INVALID_TIMEOUT)
        {
            return TRUE;
        }
    }
#endif

    return FALSE;
}

VOID sys_hdmi_rx_pll_service(UINT8 u8_hdmi_int)
{
    UINT16 u16_rx_clk;
    UINT16 u16_tmp;
    UINT8  u8_rxphy_error = 0;
    UINT8  u8_rxphy_flag = 0;
    UINT32 u32_int;

    u32_int = ms933xdrv_hdmi_rx_controller_hdmi_interrupt_get_status(CLK_CHANGE_ISTS | PLL_LCK_CHG_ISTS);

    //rx_tmds_clk change int get
    if (u32_int & CLK_CHANGE_ISTS)
    {
        u8_hdmi_int = TRUE;
    }

    //if rx_tmds_clk no change and pre rx_tmds_clk valid, notice rxpll_lock and tmds_error_counter status
    if (!u8_hdmi_int && TMDS_CLK_VALID(g_u16_input_tmds_clk))
    {
        u8_rxphy_error |= (u32_int & PLL_LCK_CHG_ISTS) ? 0x10 : 0x00;
        #if HDMI_RX_TMDS_ERROR_SERVICE_ENABLE
        if (!u8_rxphy_error)
        {
            u8_rxphy_error |= _hdmi_rx_phy_errdet() ? 0x20 : 0x00;
        }
        #endif
    }

    if (u8_hdmi_int || u8_rxphy_error)
    {
        u16_tmp = ms933xdrv_hdmi_rx_get_tmds_clk();
        //if use I2C_bus, don't need to delay.
        //mculib_delay_us(200);
        //double check tmds_clk value. enhance for rx_tmds_clk detection, prevention of accidents
        u16_rx_clk = ms933xdrv_hdmi_rx_get_tmds_clk();

        if (TMDS_CLK_VALID(u16_tmp) || TMDS_CLK_VALID(u16_rx_clk))
        {
            if (TMDS_CLK_MARGIN(u16_rx_clk, u16_tmp))
            {
                if (ms933xdrv_hdmi_rx_controller_hdmi_interrupt_get_status_ext(CLK_CHANGE_ISTS))
                {
                    u16_rx_clk = 1; //magic valid is only for debug
                }
                else
                {
                    u16_rx_clk = 2; //magic valid is only for debug
                    ms933xdrv_hdmi_rx_controller_reset(HDMI_RX_CTRL_MODET);
                }
            }
        }

        //when input timing change or lost, first should shutdown output.
        if (g_b_hdmi_input_valid)
        {
            sys_shutdown_output();
            RX_STB_LED_light(FALSE);
        }

        g_u8_rxpll_configed_status = 0;

        if (TMDS_CLK_VALID(u16_rx_clk))
        {
            #if (!MS933X_HDMI_NET_CALBE_RX_ENABLE)
            u8_rxphy_flag = ms933xdrv_hdmi_rx_pi_phy_config(u16_rx_clk, 0xFF);
            #else
            u8_rxphy_flag = ms933xdrv_hdmi_rx_pi_phy_config_with_28eq(u16_rx_clk, 0xFF);
            #endif

            if ((u8_rxphy_flag & 0x05) == 0x05) //rxpll_lock & rx_clk_stable
            {
                g_u8_rxpll_configed_status = 1; //rxpll_sucess
            }
            else
            {
                if (u8_rxphy_flag & 0x04) //rxpll_ulock & rx_clk_stable
                {
                    ms933xdrv_hdmi_rx_controller_reset(HDMI_RX_CTRL_MODET);
                }

                g_u8_rxpll_configed_status = 2; //rxpll_error
            }
        }
        else
        {
            if (TMDS_CLK_VALID(g_u16_input_tmds_clk)) //pre rx_tmds_clk is valid, but now change to invaid
            {
                //20190116, enhace, reset HDMI before rxpll clk disable.
                ms933xdrv_hdmi_rx_controller_reset(HDMI_RX_CTRL_HDMI);
                ms933xdrv_hdmi_rx_phy_power_down();
                ms933xdrv_hdmi_rx_pi_pll_release(FALSE);
            }
        }

        g_u16_input_tmds_clk = u16_rx_clk;
        LOG2("u16_clk = ", u16_rx_clk);

        if (TMDS_CLK_VALID(u16_rx_clk))
        {
            LOG1("u8_rxphy_flag = ", u8_rxphy_error | u8_rxphy_flag);
        }

        #if HDMI_RX_MDT_INT_ENABLE
        ms933xdrv_hdmi_rx_interrupt_to_pin_ctrl(1, user_mdt_int, (g_u8_rxpll_configed_status == 1) ? TRUE : FALSE);
        #endif

        if (g_b_hdmi_input_valid)
        {
            #if HDMI_RX_PKT_INT_ENABLE
            ms933xdrv_hdmi_rx_interrupt_to_pin_ctrl(0, user_pkt_int, FALSE);
            #endif

            #if HDMI_RX_CEA_TIMING_USE_MANUAL_ENABLE
            //20220527, first disable timing_manual when rx_phy config, then enable in mdt_service.
            sys_hdmi_rx_timing_manual_enable(FALSE);
            #endif
        }

        //reset MDT
        g_b_hdmi_input_valid = 0;
        //enhance, reset service timer
        g_u8_mdt_change_timer_count = 0;
        g_u8_rx_hdcp_timer_count = 0;
        g_u8_rx_hdcp_woking_flag = 0;
        //
        if (u8_hdmi_int)
        {
            sys_error_service_reset();
        }
        //
        g_u8_input_invalid_timer_count = 0;
        g_u8_rxphy_error_timer_count = 0;
    }
}

#define AUDIO_RATE_192K_MIN ((176400UL / 100) + ( (192000UL / 100) - (176400UL / 100) ) / 2)
#define AUDIO_RATE_176K_MIN ((96000UL  / 100) + ( (176400UL / 100) - (96000UL  / 100) ) / 2)
#define AUDIO_RATE_96K_MIN  ((88200UL  / 100) + ( (96000UL  / 100) - (88200UL  / 100) ) / 2)
#define AUDIO_RATE_88K2_MIN ((48000UL  / 100) + ( (88200UL  / 100) - (48000UL  / 100) ) / 2)
#define AUDIO_RATE_48K_MIN  ((44100UL  / 100) + ( (48000UL  / 100) - (44100UL  / 100) ) / 2)
#define AUDIO_RATE_44K1_MIN ((32000UL  / 100) + ( (44100UL  / 100) - (32000UL  / 100) ) / 2)
#define AUDIO_RATE_32K_MIN  ((32000UL  / 100) / 2)

UINT8 _hdmi_rx_audio_fs_type_get(UINT16 u16_fs)
{
    UINT8 u8_audio_sample_rate = HDMI_AUD_RATE_48K;

    if (u16_fs > AUDIO_RATE_192K_MIN)
    {
        u8_audio_sample_rate = HDMI_AUD_RATE_192K;
    }
    else if (u16_fs > AUDIO_RATE_176K_MIN)
    {
        u8_audio_sample_rate = HDMI_AUD_RATE_176K4;
    }
    else if (u16_fs > AUDIO_RATE_96K_MIN)
    {
        u8_audio_sample_rate = HDMI_AUD_RATE_96K;
    }
    else if (u16_fs > AUDIO_RATE_88K2_MIN)
    {
        u8_audio_sample_rate = HDMI_AUD_RATE_88K2;
    }
    else if (u16_fs > AUDIO_RATE_48K_MIN)
    {
        u8_audio_sample_rate = HDMI_AUD_RATE_48K;
    }
    else if (u16_fs > AUDIO_RATE_44K1_MIN)
    {
        u8_audio_sample_rate = HDMI_AUD_RATE_44K1;
    }
    else if (u16_fs > AUDIO_RATE_32K_MIN)
    {
        u8_audio_sample_rate = HDMI_AUD_RATE_32K;
    }

    return u8_audio_sample_rate;
}

void sys_hdmi_rx_audio_cts_change_param_set(BOOL b_change)
{
    g_b_hdmi_rx_audio_cts_change_flag = b_change;
}

BOOL sys_hdmi_rx_audio_cts_change_param_get(void)
{
    return g_b_hdmi_rx_audio_cts_change_flag;
}

//pad_audio I2S & SPDIF output control
void sys_pad_audio_ctrl_service(BOOL b_auto)
{
    BOOL b_flag;
    static BOOL s_b_audio_sample = FALSE; //PCM_flag
    static BOOL s_b_pad_audio_en = FALSE;
    UINT8 u8_audio_mode;

    if (!b_auto)
    {
        s_b_pad_audio_en = FALSE;
        s_b_audio_sample = FALSE;
        ms933xdrv_misc_audio_i2s_mclk_pad_enable(FALSE);
        ms933xdrv_misc_audio_out_pad_enable(FALSE);
        return;
    }

    u8_audio_mode = g_st_hdmi_timing.u8_audio_mode & 0x3f;

    if (u8_audio_mode == HDMI_AUD_CT_REFER_HEADER)
    {
        b_flag = ms933xdrv_hdmi_tx_shell_get_audio_cbyte_status() ? FALSE : TRUE;
    }
    else if (u8_audio_mode == HDMI_AUD_CT_PCM)
    {
        b_flag = TRUE;
    }
    else
    {
        b_flag = FALSE;
    }

    if (s_b_audio_sample != b_flag)
    {
        s_b_audio_sample = b_flag;
        //disable i2s mclk output
        ms933xdrv_misc_audio_i2s_mclk_pad_enable(b_flag);
        LOG2("pad_i2s_en = ", b_flag);
    }

    if (!s_b_pad_audio_en)
    {
        s_b_pad_audio_en = TRUE;
        ms933xdrv_misc_audio_out_pad_enable(TRUE);
        LOG2("pad_spdif_en = ", 1);
    }
}

void sys_hdmi_rx_audio_config(BOOL b_config_all)
{
    UINT16 u16_fs;
    BOOL b_audio_chn_auto_config;

    //20191123, resolve sanxing DVD, speaker_locations is 0x0A, but chn number is 8 chn issue.
    b_audio_chn_auto_config = ms933xdrv_hdmi_rx_controller_audio_channel_config(g_st_hdmi_timing.u8_audio_channels, g_st_hdmi_timing.u8_audio_speaker_locations);

    if (g_u8_hdmi_in_timing_log_enable)
    {
        if (!b_audio_chn_auto_config)
        {
            LOG("hdmi_rx_aud_chn_manual.");
        }
    }

    ms933xdrv_hdmi_rx_audio_fifo_reset(TRUE);

    if (b_config_all)
    {
        u16_fs = ms933xdrv_hdmi_rx_audio_config(RX_AUDIO_DLL_TO_PLL_MODE, g_u16_input_tmds_clk);

        sys_hdmi_rx_audio_cts_change_param_set(FALSE);

        #if 0
        g_st_hdmi_timing.u8_audio_rate = _hdmi_rx_audio_fs_type_get(u16_fs);
        #endif
        LOG2("u16_audio_fs = ", u16_fs);

        #if SYS_AUDIO_PAD_OUTPUT_ENABLE
        //if (u16_fs > 0)
        {
            //176.4K, 192K, use 64fs
            ms933xdrv_misc_audio_i2s_mclk_div((u16_fs > 1360) ? 1 : 0);

            //fixed enable mclk pad.
            sys_pad_audio_ctrl_service(FALSE);

        }
        #endif
    }

    mculib_delay_ms(1);
    ms933xdrv_hdmi_rx_audio_fifo_reset(FALSE);
}

UINT8 sys_hdmi_rx_audio_service(UINT8 u8_int_sts)
{
    UINT8 u8_audio_fifo_status;
    UINT8 u8_audio_status = 0;
    //BOOL b_acr_rcv_flag;
    BOOL b_acr_change_flag;

    //1. acr status process
    //b_acr_rcv_flag = (u8_int_sts & 0x08) ? TRUE : FALSE;
    b_acr_change_flag = (u8_int_sts & 0x10) ? TRUE : FALSE;

    if (b_acr_change_flag)
    {
        sys_hdmi_rx_audio_config(TRUE);
        return 1;
    }

    //2. audio fifo status process
    u8_audio_fifo_status = ms933xdrv_hdmi_rx_get_audio_fifo_status();

    if (u8_audio_fifo_status & AFIF_THS_PASS_STS)
    {
        u8_audio_status = (u8_audio_fifo_status & AFIF_UNDERFL_STS) ? 0x01 : 0x00;
        u8_audio_status |= (u8_audio_fifo_status & AFIF_OVERFL_STS) ? 0x02 : 0x00;

        if (u8_audio_status)
        {
            #if HDMI_RX_AUDIO_CTS_CHNAGE_HANDEL_MODE
            if (sys_hdmi_rx_audio_cts_change_param_get())
            {
                sys_hdmi_rx_audio_config(TRUE);
                return 3;
            }
            else
            #endif
            {
                LOG("audio_fifo_reset.");
                sys_hdmi_rx_audio_config(FALSE);
                return 2;
            }
        }
        return 0;
    }
    else
    {
        return 4;
    }
}

VOID sys_hdmi_rx_video_fifo_reset(VOID)
{
    ms933xdrv_hdmi_rx_video_fifo_reset(TRUE);
    mculib_delay_us(100);
    ms933xdrv_hdmi_rx_video_fifo_reset(FALSE);
}

#if MS933X_APP_LOG1_ENABLE
void printf_input_timing(void)
{
#if 1
    UINT16 u16detHFreq;

    if (!g_u8_hdmi_in_timing_log_enable)
    {
        return;
    }

    #if (!HDMI_RX_TIMING_PARSE_ENABLE)
    if (!ms933xdrv_hdmi_rx_get_input_timing(&g_st_hdmi_in_timing))
    {
        LOG("input_timing_invalid.");
        return;
    }
    #endif

    LOG(" ");

    LOG2("Is Progr      = ", (g_st_hdmi_in_timing.u8_polarity & MSRT_BIT0) ? 1 : 0);
    LOG2("Hsync Pol     = ", (g_st_hdmi_in_timing.u8_polarity & MSRT_BIT1) ? 1 : 0);
    LOG2("Vsync Pol     = ", (g_st_hdmi_in_timing.u8_polarity & MSRT_BIT2) ? 1 : 0);
    LOG2("u16detHTotal  = ", g_st_hdmi_in_timing.u16_htotal);
    LOG2("u16detVTotal  = ", g_st_hdmi_in_timing.u16_vtotal);
    LOG2("u16detHActive = ", g_st_hdmi_in_timing.u16_hactive);
    LOG2("u16detVActive = ", g_st_hdmi_in_timing.u16_vactive);
    LOG2("u16detHst     = ", g_st_hdmi_in_timing.u16_hoffset);
    LOG2("u16detVst     = ", g_st_hdmi_in_timing.u16_voffset);
    LOG2("u16detHW      = ", g_st_hdmi_in_timing.u16_hsyncwidth);
    LOG2("u16detVW      = ", g_st_hdmi_in_timing.u16_vsyncwidth);

    LOG2("u16detPclk    = ", g_st_hdmi_in_timing.u16_pixclk);
    //HSyncFreq / 10
    u16detHFreq = (UINT32)g_st_hdmi_in_timing.u16_vfreq * g_st_hdmi_in_timing.u16_vtotal / 100 / 10;
    if ((g_st_hdmi_in_timing.u8_polarity & MSRT_BIT0) == 0) u16detHFreq >>= 1;
    LOG2("u16detHFreq   = ", u16detHFreq);
    LOG2("u16detVFreq   = ", g_st_hdmi_in_timing.u16_vfreq);
#endif
}

void printf_input_video_config(void)
{
#if 1
    LOG(" ");
    //LOG2("u8_hdmi_flag      = ", g_st_hdmi_timing.u8_hdmi_flag);
    LOG2("u8_vic            = ", g_st_hdmi_timing.u8_vic);
    LOG2("u16_video_clk     = ", g_st_hdmi_timing.u16_video_clk);
    LOG2("u8_clk_rpt        = ", g_st_hdmi_timing.u8_clk_rpt);
    LOG1("u8_scan_info      = ", g_st_hdmi_timing.u8_scan_info);
    LOG1("u8_aspect_ratio   = ", g_st_hdmi_timing.u8_aspect_ratio);
    LOG1("u8_color_space    = ", g_st_hdmi_timing.u8_color_space);
    LOG1("u8_color_depth    = ", g_st_hdmi_timing.u8_color_depth);
    LOG1("u8_colorimetry    = ", g_st_hdmi_timing.u8_colorimetry);
    LOG1("u8_quant_range    = ", g_st_hdmi_timing.u8_quant_range);
    LOG1("u8_it_content     = ", g_st_hdmi_timing.u8_it_content);
    LOG(" ");
#endif
}

void printf_input_vendor_specific_config(void)
{
#if 1
    LOG(" ");
    LOG1("u8_video_format   = ", g_st_hdmi_timing.u8_video_format);
    if (g_st_hdmi_timing.u8_video_format == HDMI_4Kx2K_FORMAT)
    {
        LOG1("u8_4Kx2K_vic      = ", g_st_hdmi_timing.u8_4Kx2K_vic);
    }
    else if (g_st_hdmi_timing.u8_video_format == HDMI_3D_FORMAT)
    {
        LOG1("u8_3D_structure   = ", g_st_hdmi_timing.u8_4Kx2K_vic);
        LOG1("u8_3D_ext_data    = ", g_st_hdmi_timing.u8_3D_structure);
    }
    LOG(" ");
#endif
}

void printf_input_audio_config(void)
{
#if 1
    LOG(" ");
    LOG1("u8_audio_mode     = ", g_st_hdmi_timing.u8_audio_mode);
    LOG1("u8_audio_rate     = ", g_st_hdmi_timing.u8_audio_rate);
    LOG1("u8_audio_bits     = ", g_st_hdmi_timing.u8_audio_bits);
    LOG1("u8_audio_channels = ", g_st_hdmi_timing.u8_audio_channels);
    LOG1("u8_spea_locations = ", g_st_hdmi_timing.u8_audio_speaker_locations);
    LOG(" ");
#endif
}

void printf_input_av_config(UINT8 u8_int_sts)
{
    if (!g_u8_hdmi_in_timing_log_enable)
    {
        return;
    }

    LOG(" ");
    LOG2("u8_hdmi_flag      = ", g_st_hdmi_timing.u8_hdmi_flag);

    if((u8_int_sts & 0x01) == 0x01)
    {
        printf_input_video_config();
    }

    if ((u8_int_sts & 0x04) == 0x04)
    {
        printf_input_vendor_specific_config();
    }

    if((u8_int_sts & 0x02) == 0x02)
    {
        printf_input_audio_config();
    }
}
#endif //MS933X_APP_LOG1_ENABLE


void sys_default_hdmi_video_config(void)
{
    //g_st_hdmi_timing.u8_hdmi_flag = TRUE;
    g_st_hdmi_timing.u8_vic = 0;
    //g_st_hdmi_timing.u16_video_clk = 7425;
    g_st_hdmi_timing.u8_clk_rpt = HDMI_X1CLK;
    g_st_hdmi_timing.u8_scan_info = 0;
    g_st_hdmi_timing.u8_aspect_ratio = 0;
    g_st_hdmi_timing.u8_color_space = HDMI_RGB;
    g_st_hdmi_timing.u8_color_depth = HDMI_COLOR_DEPTH_8BIT;
    g_st_hdmi_timing.u8_colorimetry = 0;
    g_st_hdmi_timing.u8_quant_range = 0;
    g_st_hdmi_timing.u8_it_content = 0;
}

void sys_default_hdmi_vendor_specific_config(void)
{
    g_st_hdmi_timing.u8_video_format = HDMI_NO_ADD_FORMAT;
    g_st_hdmi_timing.u8_4Kx2K_vic = 0;
    g_st_hdmi_timing.u8_3D_structure = 0;
}

void sys_default_hdmi_audio_config(void)
{
    g_st_hdmi_timing.u8_audio_mode = HDMI_AUD_MODE_AUDIO_SAMPLE;
    g_st_hdmi_timing.u8_audio_rate = HDMI_AUD_RATE_48K;
    g_st_hdmi_timing.u8_audio_bits = HDMI_AUD_LENGTH_16BITS;
    g_st_hdmi_timing.u8_audio_channels = HDMI_AUD_2CH;
    g_st_hdmi_timing.u8_audio_speaker_locations = 0;
}

BOOL ms933x_app_hdmi_tx_hpd_det(VOID)
{
    if(g_u8_ms933xc_version_flag)
    {
        return ms933xcdrv_hdmi_tx_shell_hpd();
    }
    else
    {
        return ms933xdrv_hdmi_tx_shell_hpd();
    }
}

//BIT7: change flag, BIT0: valid flag
UINT8 _hotplug_process(UINT8 u8_output_chn)
{
    UINT8 u8_edid_parse_flag = 0;
    UINT8 u8_flag = 0;
    UINT8 u8_sink_hpd_connect;
    UINT16 u16_pixel_clk;
    UINT8 u8_edid_read_retry;

    ms933xdrv_hdmi_tx_set_channel(u8_output_chn);
    u8_sink_hpd_connect = ms933x_app_hdmi_tx_hpd_det() ? 0x01 : 0x00;

    u8_sink_hpd_connect |= (g_u8_tx_hpd_test_flag >> u8_output_chn) & 0x01;
    u8_sink_hpd_connect &= (g_u8_tx_chn_enable_flag >> u8_output_chn);

    TX_LED_light(u8_output_chn, u8_sink_hpd_connect);

    if (g_u8_sink_hpd_connect[u8_output_chn] != u8_sink_hpd_connect)
    {
        u8_flag |= 0x80;
        g_u8_sink_hpd_connect[u8_output_chn] = u8_sink_hpd_connect;

        if (u8_sink_hpd_connect)
        {
            LOG2("sink_hpd_connect_chn = ", u8_output_chn);
            if (!_tx_ddc_error_get(u8_output_chn))
            {
                //20190725, double check for EDID read.
                for (u8_edid_read_retry = 0; u8_edid_read_retry < 3; u8_edid_read_retry ++)
                {
                    if (u8_edid_read_retry != 0)
                    {
                        mculib_delay_ms(u8_edid_read_retry ? 100 : 50);
                        LOG("tx_EDID read again.");
                    }

                    u8_edid_parse_flag = ms933xdrv_hdmi_tx_parse_full_edid(g_u8_sys_edid_buf, &g_st_hdmi_edid_flag[u8_output_chn]);
                    if (u8_edid_parse_flag)
                    {
                        break;
                    }
                    else
                    {
                        _tx_ddc_error_check(u8_output_chn, FALSE);

                        if (!ms933x_app_hdmi_tx_hpd_det())
                        {
                            g_u8_sink_hpd_connect[u8_output_chn] = 0;
                            LOG("tx_hpd_suddendly_lost.");
                            return 0;
                        }
                    }
                }

                g_u8_sys_edid_buf_last_id = u8_output_chn;
            }
            
            if (u8_edid_parse_flag) 
            {
                //if u32_preferred_timing is 4K30, judge Compliance with standards
                if (g_st_hdmi_edid_flag[u8_output_chn].u32_preferred_timing == (3840UL * 2160) && g_st_hdmi_edid_flag[u8_output_chn].u16_preferred_pixel_clk < 45000)
                {
                    u16_pixel_clk = g_st_hdmi_edid_flag[u8_output_chn].u16_preferred_pixel_clk / 100;
                    if (xabs(297, u16_pixel_clk) >= 10)
                    {
                        g_st_hdmi_edid_flag[u8_output_chn].u32_preferred_timing = g_st_hdmi_edid_flag[u8_output_chn].u32_preferred_timing + 297 - u16_pixel_clk;
                        //LOG("4K non-standard.");
                    }
                }

                //20181129, video block timing and HDMI VSDB timing 4K. compare to preferred_timing
                if (g_st_hdmi_edid_flag[u8_output_chn].u32_max_video_block_timing != 0)
                {
                    if (g_st_hdmi_edid_flag[u8_output_chn].u32_preferred_timing < g_st_hdmi_edid_flag[u8_output_chn].u32_max_video_block_timing)
                    {
                        //LOG("fixed to video_block_timing.");
                        g_st_hdmi_edid_flag[u8_output_chn].u32_preferred_timing = g_st_hdmi_edid_flag[u8_output_chn].u32_max_video_block_timing;
                    }
                }
            }
            else
            {
                LOG("tx_EDID read failed.");
            }

            if(g_st_hdmi_edid_flag[u8_output_chn].u8_edid_total_blocks > 2)
            {
                LOG("512 bytes EDID.");
                //_hdmi_tx_edid_param_default(u8_output_chn);
            }


            #if HDMI_CTS_HDCP_RPT_ENABLE
            //sink bcaps hdcp repeater flag
            if (_tx_hdcp_bcaps_repeater_flag_get())
            {
                //LOG("sink_bcaps_rpt_support.");
                //_tx_hdcp_rpt_param_repeater_flag_set(TRUE);
            }
            else
            {
                //_tx_hdcp_rpt_param_repeater_flag_set(FALSE);
            }
            #endif
            
            //if (g_b_hdmi_input_valid)
            //{
            //    _config_output(u8_output_chn);
            //}
        }
        else
        {
            LOG2("sink_hpd_disconnect_chn = ", u8_output_chn);
            //clear edid data
            _hdmi_tx_edid_param_default(u8_output_chn);
            //
            _shutdown_output(u8_output_chn);

            _tx_ddc_error_check(u8_output_chn, TRUE);
        }
    }

    if (u8_sink_hpd_connect)
    {
        u8_flag |= 0x01;
    }

    return u8_flag;
}





void _hdmi_tx_edid_param_default(UINT8 u8_output_chn)
{
    g_st_hdmi_edid_flag[u8_output_chn].u8_hdmi_sink = TRUE; //default HDMI sink
    g_st_hdmi_edid_flag[u8_output_chn].u8_color_space = 0; // only support RGB
    g_st_hdmi_edid_flag[u8_output_chn].u8_edid_total_blocks = 0;
    //
    g_st_hdmi_edid_flag[u8_output_chn].u16_preferred_pixel_clk = 0xFFFF;
    g_st_hdmi_edid_flag[u8_output_chn].u32_preferred_timing = 0xFFFFFFFFUL;
    g_st_hdmi_edid_flag[u8_output_chn].u8_max_tmds_clk = 0;
    g_st_hdmi_edid_flag[u8_output_chn].u32_max_video_block_timing = 0;
    g_st_hdmi_edid_flag[u8_output_chn].u8_hdmi_2_0_flag = 0;
}

UINT8 _mask_hpd_status(UINT8 u8_id)
{
    if (u8_id == 0)
    {
        return 0x08;
    }
    else if (u8_id == 1)
    {
        return 0x04;
    }
    else if (u8_id == 2)
    {
        return 0x02;
    }
    else if (u8_id == 3)
    {
        return 0x01;
    }
    else
    {
        return 0x00;
    }
}

VOID _edid_file_save(BOOL b_source)
{
#if DEBUG_EDID_FILE_SAVE
    // TODO: Add your control notification handler code here
    CString filename;
    FILE* fp = NULL;

    filename = b_source ? "source.bin" : "target.bin";
    size_t origsize = wcslen(filename) + 1;
    size_t convertedChars = 0;
    const size_t newsize = origsize * 2;
    char *nstring = new char[newsize];
    wcstombs_s(&convertedChars, nstring, newsize, filename, _TRUNCATE);
    fopen_s(&fp, nstring, "wb+");

    if (fp)
    {
        fwrite(&g_u8_sys_edid_buf, 1, 512, fp);
        fclose(fp);
    }
#endif
}

BOOL _check_hdmi_sink_exist(VOID)
{
    UINT8 i;
    UINT8 u8_mask;

    for (i = 0; i < HDMI_TX_CHN_NUM; i ++)
    {
        u8_mask = (g_u8_tx_chn_enable_flag >> i) & 0x01;
        if (u8_mask && g_u8_sink_hpd_connect[i])
        {
            return TRUE;
        }
    }

    return FALSE;
}

BOOL _check_hdmi_sink(UINT8 u8_valid_flag)
{
    UINT8 i;

    for (i = 0; i < HDMI_TX_CHN_NUM; i ++)
    {
        if (u8_valid_flag & 0x01)
        {
            if (g_st_hdmi_edid_flag[i].u8_hdmi_sink)
            {
                return TRUE;
            }
        }

        u8_valid_flag >>= 1;
    }

    return FALSE;
}

UINT8 _tx_edid_read_again(UINT8 u8_id)
{
    LOG1("tx EDID read again, channel = ", u8_id);
    ms933xdrv_hdmi_tx_set_channel(u8_id);
    if (!ms933xdrv_hdmi_tx_parse_full_edid(g_u8_sys_edid_buf, &g_st_hdmi_edid_flag[HDMI_TX_DEFAULT_EDID_ID]))
    {
        LOG("tx EDID read unstable.");
        u8_id = HDMI_TX_DEFAULT_EDID_ID;
        memcpy(g_u8_sys_edid_buf, u8_sys_edid_default_buf, 256);
    }

    return u8_id;
}

BOOL _check_tx_hpd_plug_in(UINT8 u8_change_flag, UINT8 u8_valid_flag)
{
    UINT8 i;

    for (i = 0; i < HDMI_TX_CHN_NUM; i++)
    {
        if ((u8_change_flag & 0x01) && (u8_valid_flag & 0x01))
        {
            return TRUE;
        }

        u8_change_flag >>= 1;
        u8_valid_flag >>= 1;
    }

    return FALSE;
}

//suggest user update rx_edid follow below flow.
BOOL _rx_edid_update(UINT8 *p_u8_edid_buf, BOOL b_rx_hpd_low_delay)
{
    BOOL b_rx_hpd_status = ms933xdrv_hdmi_rx_controller_hpd_get();

    //ms933xc av reset
    if (g_b_hdmi_input_valid)
    {
        g_b_hdmi_input_valid = 0;
        sys_shutdown_output();
    }

    if (TMDS_CLK_VALID(g_u16_input_tmds_clk))
    {
        ms933xdrv_hdmi_rx_controller_reset(HDMI_RX_CTRL_HDMI | HDMI_RX_CTRL_MODET);
    }

    //
    ms933xdrv_hdmi_rx_controller_hpd_set(FALSE);

    //config rx_edid
    ms933xdrv_hdmi_rx_full_edid_config(p_u8_edid_buf);

    if (b_rx_hpd_status)
    {
        if (b_rx_hpd_low_delay)
        {
            mculib_delay_ms(200);
        }
        ms933xdrv_hdmi_rx_controller_hpd_set(TRUE);
    }

    return b_rx_hpd_status;
}

//suggest user toggle rx_hpd follow below flow.
//rx hpd high->low->high
BOOL _rx_hpd_toggle(VOID)
{
    BOOL b_rx_hpd_status = ms933xdrv_hdmi_rx_controller_hpd_get();

    //ms933xc av reset
    if (g_b_hdmi_input_valid)
    {
        g_b_hdmi_input_valid = 0;
        sys_shutdown_output();
    }

    if (TMDS_CLK_VALID(g_u16_input_tmds_clk))
    {
        ms933xdrv_hdmi_rx_controller_reset(HDMI_RX_CTRL_HDMI | HDMI_RX_CTRL_MODET);
    }

    if (b_rx_hpd_status)
    {
        ms933xdrv_hdmi_rx_controller_hpd_set(FALSE);
        mculib_delay_ms(200);
        ms933xdrv_hdmi_rx_controller_hpd_set(TRUE);
    }

    return b_rx_hpd_status;
}

#define EDID_CONVERT_DVI_TO_HDMI        (0x01)
#define EDID_CONVERT_AUDIO_2CH          (0x02)
#define EDID_CONVERT_AUDIO_5CH          (0x04)
#define EDID_CONVERT_AUDIO_7CH          (0x08)
#define EDID_CONVERT_DEEP_COLOR_ENABLE  (0x10)
#define EDID_CONVERT_YUV420_CONVERT     (0x20)
#define EDID_CONVERT_HDMI_TO_DVI        (0x40)

VOID edid_block_x_convert1(UINT8 *pu8_buf, HDMI_EDID_FLAG_T st_hdmi_edid_flag, UINT16 u16BlockStart,UINT16 block_covert_sel)
{
    UINT16 i, j;
    UINT16 u16DetailedOffset;
    UINT8 u8TotNum;
    UINT16 u16TPixClk;
    UINT16 u16BlockOffset;
    UINT16 u16ChangeOffset;
    UINT8 u8BlockTag;
    UINT8 u8BlockLength;
    BOOL bHdmi2_0Block;
    UINT8 u8Hdmi2_0Timing[6][3] = {
        { 96, 94, FALSE }, { 97, 95, FALSE }, { 101, 99, FALSE }, { 102, 100, FALSE }, { 106, 104, FALSE }, { 107, 105, FALSE } };
    UINT8 u8Yuv420TimingNum = 0;
        
        
    u16DetailedOffset = u16BlockStart + pu8_buf[u16BlockStart + 0x02];
    u16BlockOffset = u16BlockStart + 0x04;
    u16ChangeOffset = u16BlockOffset;

    while (u16BlockOffset < u16DetailedOffset)
    {
        u8BlockTag = (pu8_buf[u16BlockOffset] & MSRT_BITS7_5) >> 5;
        u8BlockLength = pu8_buf[u16BlockOffset] & MSRT_BITS4_0;

        switch (u8BlockTag)
        {
        case AUDIO_D_BLOCK:
//            i = u16BlockOffset + 1;
//            while(i <= (u16BlockOffset + u8BlockLength))
//            {
//                if (((pu8_buf[i] & 0x78) == 0x58) || ((pu8_buf[i] & 0x78) == 0x60) || ((pu8_buf[i] & 0x78) == 0x78))
//                {
//                    pu8_buf[i] = pu8_buf[i] & 0x78;
//                    pu8_buf[i+1] = 0;
//                    pu8_buf[i+2] = 0;
//                }               
//                i += 3;
//            }
            bHdmi2_0Block = FALSE;
            if((block_covert_sel&EDID_CONVERT_AUDIO_2CH)==EDID_CONVERT_AUDIO_2CH)// 2ch 
            {
                pu8_buf[u16BlockOffset+1]&=(~MSRT_BITS2_0);
                pu8_buf[u16BlockOffset+1]|=0x01;
            }
            if((block_covert_sel&EDID_CONVERT_AUDIO_5CH)==EDID_CONVERT_AUDIO_5CH)//5ch
            {
                pu8_buf[u16BlockOffset+1]&=(~MSRT_BITS2_0);
                pu8_buf[u16BlockOffset+1]|=0x05;
            }
            if((block_covert_sel&EDID_CONVERT_AUDIO_7CH)==EDID_CONVERT_AUDIO_7CH)//7ch
            {
                pu8_buf[u16BlockOffset+1]&=(~MSRT_BITS2_0);
                pu8_buf[u16BlockOffset+1]|=0x07;
            }
            break;
        case VIDEO_D_BLOCK:
            bHdmi2_0Block = FALSE;
            if (!st_hdmi_edid_flag.u8_hdmi_2_0_flag)
            {
                break;
            }
            for (i = u16BlockOffset + 1; i <= u16BlockOffset + u8BlockLength; i++)
            {
                if (((pu8_buf[i] & MSRT_BITS6_0) > 64) && (pu8_buf[i] > 95))
                {
                    for (j = 0; j < sizeof(u8Hdmi2_0Timing) / sizeof(u8Hdmi2_0Timing[0]); j++)
                    {
                        if (pu8_buf[i] == u8Hdmi2_0Timing[j][0])
                        {
                            #ifdef EDID_4K60_TO_4K30_ENABLE
                            pu8_buf[i] = u8Hdmi2_0Timing[j][1];
                            #else
                            bHdmi2_0Block = TRUE;
                            pu8_buf[i] = 0;
                            #endif

                            if (!u8Hdmi2_0Timing[j][2]) u8Yuv420TimingNum++;
                        
                            u8Hdmi2_0Timing[j][2] = TRUE;
                            break;
                        }
                    }
                }
            }
            if (bHdmi2_0Block)
            {
                j = u16ChangeOffset;
                for (i = u16BlockOffset; i <= u16BlockOffset + u8BlockLength; i++)
                {
                    if (pu8_buf[i] != 0)
                    {
                        pu8_buf[u16ChangeOffset++] = pu8_buf[i];
                    }
                }
                pu8_buf[j] = (pu8_buf[j] & MSRT_BITS7_5) | (u16ChangeOffset - j - 1);
            }
            break;
        case SPKR_ALLOC_D_BLOCK:
            bHdmi2_0Block = FALSE;
            break;
        case VENDOR_SPEC_D_BLOCK:
            if ((pu8_buf[u16BlockOffset + 1] == 0x03) && (pu8_buf[u16BlockOffset + 2] == 0x0C) && (pu8_buf[u16BlockOffset + 3] == 0x00))
            {
               // #ifdef EDID_UNSUPPORT_DEEP_COLOR
                if((block_covert_sel&EDID_CONVERT_DEEP_COLOR_ENABLE)==EDID_CONVERT_DEEP_COLOR_ENABLE)
                {
//                    
                    if (u8BlockLength >= 6)
                    {
                        pu8_buf[u16BlockOffset + 6] |= 0x87; //deep color fixed un-support: bit6: 48bit; bit5: 36bit; bit4: 30bit; bit3: yuv444;
                        LOG("DEEP COLOCR OPEN");
                    }
                    
                }
              //  #endif

                //20210811, if sink EDID is HDMI2_0, check hdmi1_4 VSBD max tmds clk whether large than 340M
                //if true, change to 300M.
                if (st_hdmi_edid_flag.u8_hdmi_2_0_flag && u8BlockLength >= 7)
                {
                    if (pu8_buf[u16BlockOffset + 7] >= (340 / 5))
                    {
                        pu8_buf[u16BlockOffset + 7] = (300 / 5);
                    }
                }
                bHdmi2_0Block = FALSE;
            }
            else
            {
                bHdmi2_0Block = TRUE;
            }
            break;
        case VESA_DTC_D_BLOCK:
            bHdmi2_0Block = FALSE;
            break;
        case USE_EXTENDED_TAG:
            switch (pu8_buf[u16BlockOffset + 1])
            {
                case VIDEO_CAPABILITY_D_BLOCK:
                case VENDOR_SPEC_VIDEO_D_BLOCK:
                case COLORIMETRY_D_BLOCK:
                #ifdef EDID_4K60_YUV420_SUPPORT
                case YUV420_VIDEO_D_BLOCK:
                #endif
                //case YUV420_CAPABILITY_D_BLOCK:
                case CEA_MISC_AUDIO_FIELDS:
                case VENDOR_SPEC_AUDIO_D_BLOCK:
                    bHdmi2_0Block = FALSE;
                    break;
                default:
                    bHdmi2_0Block = TRUE;
            }
            break;
        default:
            bHdmi2_0Block = TRUE;
        }
    
        if (st_hdmi_edid_flag.u8_hdmi_2_0_flag && !bHdmi2_0Block)
        {
            if (u16BlockOffset != u16ChangeOffset)
            {
                memcpy(&pu8_buf[u16ChangeOffset], &pu8_buf[u16BlockOffset], u8BlockLength + 1);
            }
            u16ChangeOffset += u8BlockLength + 1;
        }
        u16BlockOffset += u8BlockLength + 1;
    }

    if (st_hdmi_edid_flag.u8_hdmi_2_0_flag)
    {
      //  #ifdef EDID_4K60_YUV420_SUPPORT
        if((block_covert_sel&EDID_CONVERT_YUV420_CONVERT)==EDID_CONVERT_YUV420_CONVERT)
        {
            if (u8Yuv420TimingNum)
            {
                u8BlockTag = USE_EXTENDED_TAG;
                u8BlockLength = u8Yuv420TimingNum + 1;
                pu8_buf[u16ChangeOffset++] = (u8BlockTag << 5) | u8BlockLength;
                pu8_buf[u16ChangeOffset++] = YUV420_VIDEO_D_BLOCK;

                for (i = 0; i < sizeof(u8Hdmi2_0Timing) / sizeof(u8Hdmi2_0Timing[0]); i++)
                {
                    if (u8Hdmi2_0Timing[i][2])
                    {
                        pu8_buf[u16ChangeOffset++] = u8Hdmi2_0Timing[i][0];
                    }
                }
            }
       }
       // #endif
    
        if (u16DetailedOffset != 0x80)
        {
            u8TotNum = 6;
            u8BlockLength = 18;
            for (i = 0; i < u8TotNum; i++)
            {
                if ((pu8_buf[u16DetailedOffset] == 0) || (u16DetailedOffset == 0x1ff))
                {
                    break;
                }
                u16TPixClk = pu8_buf[u16DetailedOffset] + 256 * pu8_buf[u16DetailedOffset + 1];
                if (u16TPixClk >= 34000)
                {
                    u16TPixClk /= 2;
                    pu8_buf[u16DetailedOffset] = u16TPixClk & 0x1ff;
                    pu8_buf[u16DetailedOffset + 1] = u16TPixClk >> 8;
                }
                u16DetailedOffset += u8BlockLength;
            }
            u16DetailedOffset = u16BlockStart + pu8_buf[u16BlockStart + 0x02];
            if (u16ChangeOffset != u16DetailedOffset)
            {
                pu8_buf[u16BlockStart + 0x02] = u16ChangeOffset - u16BlockStart;
                memcpy(&pu8_buf[u16ChangeOffset], &pu8_buf[u16DetailedOffset], i * u8BlockLength);
            }
            u16ChangeOffset += i * u8BlockLength;
        }
    
        memset(&pu8_buf[u16ChangeOffset], 0, (u16BlockStart + 0x80) - u16ChangeOffset);
    }

        //change EDID support color sapce
        if ((pu8_buf[u16BlockStart + 0x03] & MSRT_BITS5_4) != st_hdmi_edid_flag.u8_color_space)
        {
            pu8_buf[u16BlockStart + 0x03] &= ~MSRT_BITS5_4;
            pu8_buf[u16BlockStart + 0x03] |= st_hdmi_edid_flag.u8_color_space & MSRT_BITS5_4;
        }

        pu8_buf[u16BlockStart + 0x7f] = 0;
        for (i = u16BlockStart; i < (u16BlockStart + 0x7f); i++)
        {
            pu8_buf[u16BlockStart + 0x7f] -= pu8_buf[i];
        }       
}

BOOL sys_edid_convert1(UINT8 *pu8_buf, HDMI_EDID_FLAG_T st_hdmi_edid_flag,UINT16 edid_convert_sel)
{
    UINT16 i;
    UINT16 u16DetailedOffset;
    UINT8  u8TotNum;
    UINT16 u16TPixClk;
    UINT8  u8BlockLength;
    UINT8 u8BlockTag;

    //UINT8 u8Hdmi2_0Timing[6][3] = {
    //    { 96, 94, FALSE }, { 97, 95, FALSE }, { 101, 99, FALSE }, { 102, 100, FALSE }, { 106, 104, FALSE }, { 107, 105, FALSE } };
    //UINT8 u8Yuv420TimingNum = 0;

            
        
    //if DVI sink, return
    if (!st_hdmi_edid_flag.u8_hdmi_sink)
    {
       if((edid_convert_sel&EDID_CONVERT_DVI_TO_HDMI)==EDID_CONVERT_DVI_TO_HDMI)
       {
      //  #ifdef EDID_DVI2HDMI
        //change DVI EDID to HDMI EDID
        pu8_buf[0x7e] = 0x01;
        pu8_buf[0x7f] = 0;
        for (i = 0x00; i < 0x7f; i++)
        {
            pu8_buf[0x7f] -= pu8_buf[i];
        }

        memset(&pu8_buf[0x80], 0x00, 0x80);
        pu8_buf[0x80] = 0x02;
        pu8_buf[0x81] = 0x03;
        pu8_buf[0x82] = 0x04;
        pu8_buf[0x83] = 0x40;   //basic audio support
        u8BlockTag = VENDOR_SPEC_D_BLOCK;
        u8BlockLength = 5;
        pu8_buf[0x82] += u8BlockLength + 1;
        pu8_buf[0x84] = (u8BlockTag << 5) | u8BlockLength;
        pu8_buf[0x85] = 0x03;
        pu8_buf[0x86] = 0x0c;
        pu8_buf[0x87] = 0x00;
        pu8_buf[0x88] = 0x00;
        pu8_buf[0x89] = 0x00;

        pu8_buf[0xff] = 0;
        for (i = 0x80; i < 0xff; i++)
        {
            pu8_buf[0xff] -= pu8_buf[i];
        }
      }
        //memcpy(&pu8_buf[0x80], &u8_sys_edid_default_buf[0x80], 128);
     //   #endif

        return TRUE;
    }
    if((edid_convert_sel&EDID_CONVERT_HDMI_TO_DVI)==EDID_CONVERT_HDMI_TO_DVI)
    {
        pu8_buf[0x7e] = 0x00;
        pu8_buf[0x7f] = 0;
        for (i = 0x00; i < 0x7f; i++)
        {
            pu8_buf[0x7f] -= pu8_buf[i];
        }
        return TRUE;
    }
    
    //chenge HDMI2.0 EDID to HDMI1.4 EDID
    if (st_hdmi_edid_flag.u8_hdmi_2_0_flag)
    {
        //block 0
        u16DetailedOffset = 0x36;
        u8TotNum = 4;
        u8BlockLength = 18;
        for (i = 0; i < u8TotNum; i++)
        {
            u16TPixClk = pu8_buf[u16DetailedOffset] + 256 * pu8_buf[u16DetailedOffset + 1];
            if (u16TPixClk >= 34000)
            {
                u16TPixClk /= 2;
                pu8_buf[u16DetailedOffset] = u16TPixClk & 0xff;
                pu8_buf[u16DetailedOffset + 1] = u16TPixClk >> 8;
            }
            else if (pu8_buf[u16DetailedOffset + 0] == 0x00 && 
                     pu8_buf[u16DetailedOffset + 1] == 0x00 && 
                     pu8_buf[u16DetailedOffset + 2] == 0x00 &&
                     pu8_buf[u16DetailedOffset + 3] == 0xFD)
            {
                if (pu8_buf[u16DetailedOffset + 9] >= 34) //340MHz
                {
                    //LOG("edid_block0_max_pclk_300MHz.");
                    pu8_buf[u16DetailedOffset + 9] = 30;
                }
            }
            u16DetailedOffset += u8BlockLength;
        }

        pu8_buf[0x7f] = 0;
        for (i = 0x00; i < 0x7f; i++)
        {
            pu8_buf[0x7f] -= pu8_buf[i];
        }
    }

    if(pu8_buf[0x80] != 0xf0)
    {
        edid_block_x_convert1(pu8_buf, st_hdmi_edid_flag, 0x80,edid_convert_sel);
    }
    else
    {
        if (pu8_buf[0x81] != 0x02 && pu8_buf[0x82] != 0x02) //block2 and block3 all is not CEA_BLOCK
        {
            pu8_buf[0x7e] = 0;
            pu8_buf[0x7f] = 0;
            for (i = 0x00; i < 0x7f; i++)
            {
                pu8_buf[0x7f] -= pu8_buf[i];
            }

            memset(&pu8_buf[0x80], 0, 0x180);
        }
        else if (pu8_buf[0x81] == 0x02 && pu8_buf[0x82] != 0x02) //only block2 is CEA_BLOCK
        {
            pu8_buf[0x7e] = 1;
            pu8_buf[0x7f] = 0;
            for (i = 0x00; i < 0x7f; i++)
            {
                pu8_buf[0x7f] -= pu8_buf[i];
            }

            memcpy(&pu8_buf[0x80], &pu8_buf[0x100], 0x80);
            memset(&pu8_buf[0x100], 0, 0x100);
            edid_block_x_convert1(pu8_buf, st_hdmi_edid_flag, 0x80, edid_convert_sel);
        }
        else if (pu8_buf[0x81] != 0x02 && pu8_buf[0x82] == 0x02) //only block3 is CEA_BLOCK
        {
            pu8_buf[0x7e] = 1;
            pu8_buf[0x7f] = 0;
            for (i = 0x00; i < 0x7f; i++)
            {
                pu8_buf[0x7f] -= pu8_buf[i];
            }

            memcpy(&pu8_buf[0x80], &pu8_buf[0x180], 0x80);
            memset(&pu8_buf[0x100], 0, 0x100);
            edid_block_x_convert1(pu8_buf, st_hdmi_edid_flag, 0x80, edid_convert_sel);
        }
        else //block2 and block3 all is CEA_BLOCK
        {
            edid_block_x_convert1(pu8_buf, st_hdmi_edid_flag, 0x100, edid_convert_sel);
            edid_block_x_convert1(pu8_buf, st_hdmi_edid_flag, 0x180, edid_convert_sel);
        }
    }
           
    return TRUE;
}

UINT8 _hotplug_service(BOOL b_sys_init_flag)
{
    UINT8 u8_edid_change = 0; //bit7: rx HPD toggle flag; bit0: EDID update flag
    UINT8 u8_change_flag = 0;
    UINT8 u8_valid_flag = 0;
    UINT8 u8_data;
    UINT8 u8_id = 0;
    UINT8 b_check = FALSE;
    UINT32 u32_temp;
    UINT32 u32_min_per_timing = 0xFFFFFFFFUL;
    #if 0
    UINT8 u8_used_color_space = 0x30;
    #endif
    UINT8 i;
    UINT8 u8_source_5v_connect;
    UINT8 u8_tx_plug_in_flag = 0;
    UINT8 u8_dvi_mode=0;
    u8_source_5v_connect = ms933xdrv_hdmi_rx_5v_det();
    if (g_u8_source_5v_connect != u8_source_5v_connect)
    {
        LOG1("u8_source_5v_connect = ", u8_source_5v_connect);
        RX_LED_light(u8_source_5v_connect);
        g_u8_source_5v_connect = u8_source_5v_connect;
        if (!g_u8_rx_hpd_test_flag)
        {
            ms933xdrv_hdmi_rx_controller_hpd_set(u8_source_5v_connect && _check_hdmi_sink_exist());

            //if rx 5v lost, clear rx hdcp aksv writed flag
            if (!u8_source_5v_connect)
            {
                g_u8_rx_hdcp_aksv_be_writed_flag = 0;
            }
        }
    }

    for (i = 0; i < HDMI_TX_CHN_NUM; i++)
    {
        u8_data = _hotplug_process(i);
        if (u8_data & 0x01)
        {
            u8_valid_flag |= (1 << i);
        }

        if (u8_data & 0x80)
        {
            u8_change_flag |= (1 << i);
        }

        u32_temp = g_st_hdmi_edid_flag[i].u32_preferred_timing;
        if (u32_temp < u32_min_per_timing)
        {
            u8_id = i;
            u32_min_per_timing = u32_temp;
        }
        #if 0
        if (u8_data & 0x01)
        {
            u8_used_color_space &= g_st_hdmi_edid_flag[i].u8_color_space;
        }
        #endif

        u8_tx_plug_in_flag = u8_change_flag & u8_valid_flag;
    }

    if (g_u8_rx_hpd_test_flag)
    {
        goto _JUMP_EDID_DEFALUT;
    }

    if (u8_change_flag)
    {
        if (u8_valid_flag)
        {
            //if pre hpd false
            if (g_u8_sys_edid_flag == 0xff)
            {
                u8_edid_change = 0x80;
            }

            //invalid edid or no edid, fixed use default EDID
            if (u32_min_per_timing == 0xFFFFFFFFUL)
            {
                g_u32_hdmi_sink_min_timing = 0xFFFFFFFFUL;
                g_u32_dvi_sink_min_timing = 0xFFFFFFFFUL;
                b_check = TRUE;
                u8_id = HDMI_TX_DEFAULT_EDID_ID;
                memcpy(g_u8_sys_edid_buf, u8_sys_edid_default_buf, 256);
            }
            else if (!_check_hdmi_sink(u8_valid_flag)) //all sink is dvi.
            {
                g_u32_hdmi_sink_min_timing = 0xFFFFFFFFUL;

                if (u32_min_per_timing < g_u32_dvi_sink_min_timing)
                {
                    g_u32_dvi_sink_min_timing = u32_min_per_timing;
                    b_check = TRUE;

                    //if selected EDID(g_u8_sys_edid_buf) is not the last be readed
                    if (g_u8_sys_edid_buf_last_id != u8_id)
                    {
                        u8_id = _tx_edid_read_again(u8_id);
                    }
                }
            }
            else if (u32_min_per_timing < g_u32_hdmi_sink_min_timing)
            {
                g_u32_dvi_sink_min_timing = 0xFFFFFFFFUL;
                g_u32_hdmi_sink_min_timing = u32_min_per_timing;
                b_check = TRUE;

                //if min_timing is dvi sink and hdmi sink exist, fixed use default EDID
                if (!g_st_hdmi_edid_flag[u8_id].u8_hdmi_sink)
                {
                    u8_id = HDMI_TX_DEFAULT_EDID_ID;
                    memcpy(g_u8_sys_edid_buf, u8_sys_edid_default_buf, 256);
                }
                //if selected EDID(g_u8_sys_edid_buf) is not the last be readed
                else if (g_u8_sys_edid_buf_last_id != u8_id)
                {
                    u8_id = _tx_edid_read_again(u8_id);
                }
            }

            if (b_check)
            {
                g_u8_sys_edid_buf_last_id = u8_id;
                g_u8_sys_edid_flag = u8_id;

                if (memcmp(g_u8_sys_edid_used_buf, g_u8_sys_edid_buf, 512) != 0)
                {
                    u8_edid_change = 0x81;
                    memcpy(g_u8_sys_edid_used_buf, g_u8_sys_edid_buf, 512);
                }
            }
            
            if (u8_edid_change)
            {
                LOG1("u8_edid_change = ", u8_edid_change);

                if (u8_edid_change & 0x01)
                {
                    LOG1("hdmi_rx_edid_id = ", u8_id);

                    g_u8_rx_hdcp_aksv_be_writed_flag = 0;

                    _edid_file_save(1);

                    g_st_hdmi_edid_flag[HDMI_TX_DEFAULT_EDID_ID] = g_st_hdmi_edid_flag[u8_id];
                    //20220620, chip new version support CSC function
                    if (ms933xdrv_misc_chip_new_version_get())
                    {
                        g_st_hdmi_edid_flag[HDMI_TX_DEFAULT_EDID_ID].u8_color_space = MSRT_BITS5_4; //support YUV444/YUV422
                    }
                    else
                    {
                        g_st_hdmi_edid_flag[HDMI_TX_DEFAULT_EDID_ID].u8_color_space = 0; //only support RGB
                    }
                    if (u8_id != HDMI_TX_DEFAULT_EDID_ID && _check_hdmi_sink(u8_valid_flag)) //if not the default EDID and have hdmi sink
                    {

//                        for(int i =0;i<255;i++)
//                        {
//                           LOG1("i = ",i);
//                            LOG1("g_u8_sys_edid_buf[I]=  ",g_u8_sys_edid_buf[i]);
//                        }
                        if(u8_dvi_mode==1)
                        {
                             sys_edid_convert1(g_u8_sys_edid_buf, g_st_hdmi_edid_flag[HDMI_TX_DEFAULT_EDID_ID],0x31);
                        }
                        else
                        {
                            sys_edid_convert1(g_u8_sys_edid_buf, g_st_hdmi_edid_flag[HDMI_TX_DEFAULT_EDID_ID],0x30);
                        }
//                           for(int i =0;i<255;i++)
//                        {
//                           LOG1("i = ",i);
//                            LOG1("g_u8_sys_edid_buf[I]=  ",g_u8_sys_edid_buf[i]);
//                        }
                    }

                    //when system init, rx_hpd low delay not needed
                    _rx_edid_update(g_u8_sys_edid_buf, !b_sys_init_flag);

                    _edid_file_save(0);
                    memcpy(g_u8_sys_edid_buf, g_u8_sys_edid_used_buf, 512);
                }

                //rx_5v valid but rx_hpd not be set
                if (g_u8_source_5v_connect && !ms933xdrv_hdmi_rx_controller_hpd_get())
                {
                    ms933xdrv_hdmi_rx_controller_hpd_set(TRUE);
                }
            }
        }
        else
        {
            #if HDMI_RX_HPD_DELAY_OFF_ENABLE
            LOG("hdmi tx sink lost.");
            #endif
            g_u8_sys_edid_flag = 0xff;
            g_u32_hdmi_sink_min_timing = 0xFFFFFFFFUL;
            g_u32_dvi_sink_min_timing = 0xFFFFFFFFUL;

            #if (HDMI_RX_HPD_DELAY_OFF_ENABLE)
            g_u8_hdmi_rx_hpd_off_count = 0;
            #else
            g_u8_hdmi_rx_hpd_off_count = HDMI_RX_HPD_OFF_TIMEOUT - 1;
            #endif
        }
    }

    #if HDCP_RPT_SUPPORT_ENABLE
    if (g_u8_hdcp_repeater_support)
    {
        if (u8_tx_plug_in_flag && g_u8_source_5v_connect && g_b_hdmi_input_valid && (g_u8_rx_hdcp_woking_flag | g_u8_rx_hdcp_aksv_be_writed_flag))
        {
            g_u8_rx_hdcp_aksv_be_writed_flag = 0;
            LOG("hdmi_rx_hpd toggle.");
            _rx_hpd_toggle();
        }
    }
    #endif

    if (g_b_hdmi_input_valid && g_u8_ms933xc_version_flag && u8_tx_plug_in_flag)
    {
        if ((_tx_sink_exist_unsupport_yuv_check() && !ms933xcdrv_hdmi_tx_csc_setting_get()) ||
            (!_tx_sink_exist_unsupport_yuv_check() && ms933xcdrv_hdmi_tx_csc_setting_get()))
        {
            LOG("hdmi_rx_hpd toggle.");
            _rx_hpd_toggle();
        }
    }

_JUMP_EDID_DEFALUT:
    
    if (g_b_hdmi_input_valid)
    {
        //config each plug in tx_channel
        for (i = 0; i < HDMI_TX_CHN_NUM; i++)
        {
            //check tx plug in channel
            if ((u8_tx_plug_in_flag >> i) & 0x01)
            {
                _config_output(i);
            }
        }
    }
          
    return u8_edid_change;
}

VOID sys_hotplug_service(void)
{
    g_u8_hdmi_tx_hpd_detect_count ++;
    if (g_u8_hdmi_tx_hpd_detect_count < HDMI_TX_HPD_DET_TIMEOUT)
    {
        return;
    }
    g_u8_hdmi_tx_hpd_detect_count = 0;

    _hotplug_service(FALSE);

    //rx hpd off service
    if (g_u8_sys_edid_flag == 0xff)
    {
        if (g_u8_hdmi_rx_hpd_off_count < HDMI_RX_HPD_OFF_TIMEOUT)
        {
            g_u8_hdmi_rx_hpd_off_count ++;
            if (g_u8_hdmi_rx_hpd_off_count == HDMI_RX_HPD_OFF_TIMEOUT)
            {
                //rx hpd already be false, dont't need do next.
                if (ms933xdrv_hdmi_rx_controller_hpd_get())
                {
                    ms933xdrv_hdmi_rx_controller_hpd_set(FALSE);
                    LOG("hdmi rx hpd off.");
                }
            }
        }
    }
}


void sys_hotplug_init(void)
{
    //remove, chip_default
    //ms933xdrv_hdmi_rx_controller_hpd_set(FALSE);

    _hotplug_service(TRUE);

    if (g_u8_rx_hpd_test_flag)
    {
        LOG("rx_hpd force on.");
        //delay for hpd, not necessary
        //mculib_delay_ms(200);
        ms933xdrv_hdmi_rx_full_edid_config((UINT8 *)u8_sys_edid_default_buf);
        ms933xdrv_hdmi_rx_controller_hpd_set(TRUE);
    }
}

//csc yuv to rgb

static BOOL _tx_sink_unsupport_yuv_check(UINT8 u8_output_chn)
{
    //UINT8 i;
    UINT8 u8_mask;
    UINT8 u8_in_color;

    u8_in_color = g_st_hdmi_timing.u8_color_space;

    if (u8_in_color == HDMI_RGB || u8_in_color == HDMI_YUV420)
    {
        return FALSE;
    }

    u8_mask = (u8_in_color == HDMI_YCBCR444) ? MSRT_BIT5 : MSRT_BIT4;

    //unsupport judge
    if (!(g_st_hdmi_edid_flag[u8_output_chn].u8_color_space & u8_mask))
    {
        return TRUE;
    }

    return FALSE;
}

static BOOL _tx_sink_exist_unsupport_yuv_check(VOID)
{
    UINT8 i;

    for (i = 0; i < HDMI_TX_CHN_NUM; i++)
    {
        if (g_u8_sink_hpd_connect[i])
        {
            //unsupport judge
            if (_tx_sink_unsupport_yuv_check(i))
            {
                return TRUE;
            }
        }
    }

    return FALSE;
}

//judge whether input yuv444 or yuv222 need to convert rgb
static BOOL _csc_process(UINT8 u8_output_chn)
{
    if (!ms933xdrv_misc_chip_new_version_get())
    {
        return FALSE;
    }

    if (_tx_sink_unsupport_yuv_check(u8_output_chn) || (g_u8_ms933xc_version_flag && _tx_sink_exist_unsupport_yuv_check()))
    {
        ms933xdrv_hdmi_tx_csc((g_st_hdmi_timing.u8_colorimetry << 4) | g_st_hdmi_timing.u8_color_space, HDMI_RGB);
        return TRUE;
    }
    else
    {
        //bypass
        ms933xdrv_hdmi_tx_csc(0, 0);
        return FALSE;
    }
}


static UINT8 g_u8_rx_spd_code = 0xff;

void _packet_fifo_init(VOID)
{
#if HDMI_SPD_INFO_CTRL_ENABLE
    g_u8_rx_spd_code = 0xff;

    ms933xdrv_hdmi_rx_core_packet_fifo_init(8);
#endif
}

void _get_packet_fifo_data(VOID)
{
#if HDMI_SPD_INFO_CTRL_ENABLE
    UINT8 u8_data;

    g_u8_rx_spd_code = 0xff;
    if (ms933xdrv_hdmi_rx_core_packet_fifo_get(&u8_data))
    {
        g_u8_rx_spd_code = u8_data;
    }

    LOG1("u8_rx_spd_code = ", g_u8_rx_spd_code);
#endif
}

UINT8 _get_packet_fifo_spd_code(VOID)
{
    return g_u8_rx_spd_code;
}

void _config_output_spd_info(UINT8 u8_output_chn)
{
#if HDMI_SPD_INFO_CTRL_ENABLE
    UINT8 u8_spd_code = _get_packet_fifo_spd_code();

    ms933xdrv_hdmi_tx_set_channel(u8_output_chn);

    ms933xdrv_hdmi_tx_shell_set_spd_infoframe(&u8_spd_code, 1, (u8_spd_code == 0xff) ? FALSE : TRUE);
#endif
}

#if MS933X_HDMI_NET_CABLE_TX_ENABLE
void sys_hdmi_tx_drive_mode_config(UINT8 u8_mode)
{
    switch (u8_mode)
    {
    //关闭6mA
    //drive 适中
    //打开去加重
    case 0:
        ms933x_HAL_WriteByte(0x920, 0x1e);
        ms933x_HAL_WriteByte(0x921, 0xe0);
        ms933x_HAL_WriteByte(0x922, 0x03);
        ms933x_HAL_WriteByte(0x923, 0x07);
        ms933x_HAL_WriteByte(0x924, 0x44);
        ms933x_HAL_WriteByte(0x925, 0x07);
        ms933x_HAL_WriteByte(0x926, 0x1d);
        ms933x_HAL_WriteByte(0x927, 0x0d);
        ms933x_HAL_WriteByte(0x928, 0xc8);
        ms933x_HAL_WriteByte(0x929, 0x08);
        break;

    //打开6mA
    //drive 最大
    //关闭去加重
    case 1:
        ms933x_HAL_WriteByte(0x920, 0x1e);
        ms933x_HAL_WriteByte(0x921, 0xe0);
        ms933x_HAL_WriteByte(0x922, 0x03);
        ms933x_HAL_WriteByte(0x923, 0x17);
        ms933x_HAL_WriteByte(0x924, 0x77);
        ms933x_HAL_WriteByte(0x925, 0x07);
        ms933x_HAL_WriteByte(0x926, 0xff);
        ms933x_HAL_WriteByte(0x927, 0x0f);
        ms933x_HAL_WriteByte(0x928, 0x00);
        ms933x_HAL_WriteByte(0x929, 0x00);
        break;

    //打开6mA
    //drive 最大
    //打开去加重
    case 2:
        ms933x_HAL_WriteByte(0x920, 0x1e);
        ms933x_HAL_WriteByte(0x921, 0xe0);
        ms933x_HAL_WriteByte(0x922, 0x03);
        ms933x_HAL_WriteByte(0x923, 0x17);
        ms933x_HAL_WriteByte(0x924, 0x77);
        ms933x_HAL_WriteByte(0x925, 0x07);
        ms933x_HAL_WriteByte(0x926, 0xff);
        ms933x_HAL_WriteByte(0x927, 0x0f);
        ms933x_HAL_WriteByte(0x928, 0xff);
        ms933x_HAL_WriteByte(0x929, 0x0f);
        break;

    //关闭6mA
    //drive 最大
    //关闭去加重
    case 3:
        ms933x_HAL_WriteByte(0x920, 0x1e);
        ms933x_HAL_WriteByte(0x921, 0xe0);
        ms933x_HAL_WriteByte(0x922, 0x03);
        ms933x_HAL_WriteByte(0x923, 0x07);
        ms933x_HAL_WriteByte(0x924, 0x77);
        ms933x_HAL_WriteByte(0x925, 0x07);
        ms933x_HAL_WriteByte(0x926, 0xff);
        ms933x_HAL_WriteByte(0x927, 0x0f);
        ms933x_HAL_WriteByte(0x928, 0x00);
        ms933x_HAL_WriteByte(0x929, 0x00);
        break;
    }
}
#endif //MS933X_HDMI_NET_CABLE_TX_ENABLE

void _tx_drive_for_short_cable(UINT8 u8_output_chn)
{
    ms933xdrv_hdmi_tx_set_channel(u8_output_chn);
    //
    ms933xdrv_hdmi_tx_phy_clk_drive_config(0, 0);
    ms933xdrv_hdmi_tx_phy_data_drive_config(0, 0, 0);
}

void _tx_drive_for_long_cable(UINT8 u8_output_chn)
{
    ms933xdrv_hdmi_tx_set_channel(u8_output_chn);
    //
    //20191219, hdmi tx drive update for 60m HDMI cable.
    ms933xdrv_hdmi_tx_phy_data_drive_enhance(TRUE);
    ms933xdrv_hdmi_tx_phy_data_R200_enable(FALSE);
    ms933xdrv_hdmi_tx_phy_clk_drive_config(4, 15);
    ms933xdrv_hdmi_tx_phy_data_drive_config(4, 15, 0);
}

void _config_output(UINT8 u8_output_chn)
{
    HDMI_CONFIG_T st_hdmi_tx_config;

    st_hdmi_tx_config = g_st_hdmi_timing;

    st_hdmi_tx_config.u8_hdmi_flag &=g_st_hdmi_edid_flag[u8_output_chn].u8_hdmi_sink;
    LOG1("st_hdmi_tx_config.u8_hdmi_flag  = ",st_hdmi_tx_config.u8_hdmi_flag);
    ms933xdrv_hdmi_tx_set_channel(u8_output_chn);
    ms933xdrv_hdmi_tx_phy_output_enable(FALSE);
    ms933xdrv_hdmi_tx_hdcp_enable(FALSE);
    ms933xdrv_hdmi_tx_shell_set_gcp_packet_avmute(FALSE);

    #if HDMI_VIDEO_CSC_AUTO_ENABLE
    if (_csc_process(u8_output_chn))
    {
        st_hdmi_tx_config.u8_color_space = HDMI_RGB;
        st_hdmi_tx_config.u8_colorimetry = 0;
        st_hdmi_tx_config.u8_quant_range = 0;
    }
    #endif

    ms933xdrv_hdmi_tx_config(&st_hdmi_tx_config);

    _config_output_spd_info(u8_output_chn);

    ms933xdrv_hdmi_tx_shell_video_mute_enable(FALSE);
    ms933xdrv_hdmi_tx_shell_audio_mute_enable(FALSE);

    #if MS933X_HDMI_NET_CABLE_TX_ENABLE
    //_tx_drive_for_long_cable(u8_output_chn);
    g_u8_hdmi_tx_drive_mode = 2;
    sys_hdmi_tx_drive_mode_config(g_u8_hdmi_tx_drive_mode);
    #endif
    ms933xdrv_hdmi_tx_phy_output_enable(TRUE);
    //
    if (!g_u8_ms933xc_version_flag)
    {
        _hdmi_tx_hdcp_start(u8_output_chn);
    }
    _hdmi_tx_gcp_avmute_param_default();
}

void _config_output_audio(UINT8 u8_output_chn)
{
    ms933xdrv_hdmi_tx_set_channel(u8_output_chn);

    ms933xdrv_hdmi_tx_audio_config(&g_st_hdmi_timing);
}

void _config_output_audio_fs(UINT8 u8_output_chn)
{
    ms933xdrv_hdmi_tx_set_channel(u8_output_chn);

    ms933xdrv_hdmi_tx_audio_fs_update(g_st_hdmi_timing.u8_audio_rate);
}

void _config_output_avmute(UINT8 u8_output_chn, BOOL b_avmute)
{
    ms933xdrv_hdmi_tx_set_channel(u8_output_chn);

    ms933xdrv_hdmi_tx_shell_set_gcp_packet_avmute(b_avmute);
}

void sys_config_output(UINT8 u8_config_item, UINT8 u8_value)
{
    UINT8 i;

    for (i = 0; i < HDMI_TX_CHN_NUM; i++)
    {
        if (g_u8_sink_hpd_connect[i])
        {
            if (u8_config_item == HDMI_TX_CONFIG_AV)
            {
                _config_output(i);
            }
            else if (u8_config_item == HDMI_TX_CONFIG_AUD)
            {
                if (g_u8_ms933xc_version_flag)
                {
                    _config_output_audio(0);
                    break;
                }
                else
                {
                    _config_output_audio(i);
                }
            }
            else if (u8_config_item == HDMI_TX_CONFIG_AUD_FS)
            {
                #if 0 //20190805, do update cts value. because input detect value maybe 不准确
                if (g_u8_ms933xc_version_flag)
                {
                    _config_output_audio_fs(0);
                    break;
                }
                else
                {
                    _config_output_audio_fs(i);
                }
                #endif
            }
            else if (u8_config_item == HDMI_TX_CONFIG_AVMUTE)
            {
                if (g_u8_ms933xc_version_flag)
                {
                    _config_output_avmute(0, u8_value);
                    break;
                }
                else
                {
                    _config_output_avmute(i, u8_value);
                }
            }
            
        }
    }
}

void _shutdown_output(UINT8 u8_output_chn)
{
    ms933xdrv_hdmi_tx_set_channel(u8_output_chn);
    ms933xdrv_hdmi_tx_phy_output_enable(FALSE);
    ms933xdrv_hdmi_tx_phy_power_down();
    //
    ms933xdrv_hdmi_tx_hdcp_enable(FALSE);
    _hdmi_tx_hdcp_param_default(u8_output_chn);
}

void sys_shutdown_output(void)
{
    UINT8 i;

    for (i = 0; i < HDMI_TX_CHN_NUM; i++)
    {
        if (g_u8_sink_hpd_connect[i])
        {
            _shutdown_output(i);
        }
    }

    if (g_u8_ms933xc_version_flag)
    {
        ms933xcdrv_hdmi_tx_core_power_down();
    }

    #if HDCP_RPT_SUPPORT_ENABLE
    _rx_hdcp_rpt_ready_reset();
    #endif

    #if SYS_AUDIO_PAD_OUTPUT_ENABLE
    sys_pad_audio_ctrl_service(FALSE);
    #endif
}

//BIT7: AVI change flag; BIT6: AIF change flag; BIT5: VSI change flag; BIT4: acr cts change flag;
//BIT0, AVI inforframe receive flag; BIT1: Audio inforframe receive flag;
//BIT2: VSI inforframe receive flag; BIT3: ACR packet receive flag;
UINT8 _get_infoframe_status(VOID)
{
    UINT8 u8_int_sts = 0;
    UINT32 u32_pdec_int_sts;

    u32_pdec_int_sts = ms933xdrv_hdmi_rx_controller_pdec_interrupt_get_status(PEDC_USED_ISTS);
    if (u32_pdec_int_sts & AVI_CKS_CHG_ISTS)
    {
        u8_int_sts |= 0x80;
    }

    if (u32_pdec_int_sts & (AIF_CKS_CHG_ISTS | AUD_TYPE_CHG_ISTS))
    {
        u8_int_sts |= 0x40;
    }

    if (u32_pdec_int_sts & VSI_CKS_CHG_ISTS)
    {
        u8_int_sts |= 0x20;
    }

    #if (!HDMI_RX_AUDIO_CTS_CHNAGE_HANDEL_MODE)
    if (u32_pdec_int_sts & (ACR_CTS_CHG_ISTS | ACR_N_CHG_ISTS))
    {
        u8_int_sts |= 0x10;
    }
    #else
    if (u32_pdec_int_sts & ACR_N_CHG_ISTS)
    {
        u8_int_sts |= 0x10;
    }

    if (u32_pdec_int_sts & ACR_CTS_CHG_ISTS)
    {
        sys_hdmi_rx_audio_cts_change_param_set(TRUE);
    }
    #endif
    if (u32_pdec_int_sts & AVI_RCV_ISTS)
    {
        u8_int_sts |= 0x01;
    }

    if (u32_pdec_int_sts & AIF_RCV_ISTS)
    {
        u8_int_sts |= 0x02;
    }

    if (u32_pdec_int_sts & VSI_RCV_ISTS)
    {
        u8_int_sts |= 0x04;
    }

    if (u32_pdec_int_sts & ACR_RCV_ISTS)
    {
        u8_int_sts |= 0x08;
    }

    return u8_int_sts;
}

BOOL sys_hdmi_av_config(UINT8 u8_int_sts, BOOL b_config)
{
    HDMI_CONFIG_T st_hdmi_timing;
    BOOL b_config_all;

    ms933xdrv_hdmi_rx_controller_get_input_config(&st_hdmi_timing);

    //20190704, enhance tmds clk fixed use common detect result. To prevent accidental
    st_hdmi_timing.u16_video_clk = g_u16_input_tmds_clk;

    //if (!b_config && memcmp(&st_hdmi_timing, &g_st_hdmi_timing, sizeof(HDMI_CONFIG_T)) == 0)
    if(!b_config)
    {
        if((st_hdmi_timing.u8_clk_rpt==g_st_hdmi_timing.u8_clk_rpt)&&(st_hdmi_timing.u8_color_space==g_st_hdmi_timing.u8_color_space)&&\
           (st_hdmi_timing.u8_quant_range==g_st_hdmi_timing.u8_quant_range)&&(st_hdmi_timing.u8_colorimetry==g_st_hdmi_timing.u8_colorimetry))
        {
            LOG("infoframe ignore.");
            return FALSE;
        }
    }

    g_st_hdmi_timing = st_hdmi_timing;

    //20190723, fixed bug for design, if dvi input no packet info
    if (!g_st_hdmi_timing.u8_hdmi_flag)
    {
        u8_int_sts = 0x00;
    }

    //do hdmi rx task
    b_config_all = b_config;

    if (u8_int_sts & 0xA0)
    {
        b_config_all = TRUE;
    }

    if((u8_int_sts & 0x01) == 0x00)
    {
        sys_default_hdmi_video_config();
    }

    if ((u8_int_sts & 0x04) == 0x00)
    {
        sys_default_hdmi_vendor_specific_config();
    }

    if((u8_int_sts & 0x02) == 0x00)
    {
        sys_default_hdmi_audio_config();
    }

    //if because packet updated and need update video and audio. first shutdown output.
    //Also do not expect shutdown output agagin, because this action maybe done before here.
    if (!b_config && b_config_all)
    {
        sys_shutdown_output();
    }

    if (b_config_all)
    {
        ms933xdrv_hdmi_rx_controller_pixel_clk_config(g_st_hdmi_timing.u8_color_depth, g_st_hdmi_timing.u8_clk_rpt);
        //20181221, config rx auto avmute color.
        ms933xdrv_hdmi_rx_controller_set_avmute_black_color(g_st_hdmi_timing.u8_color_space);

        //20190515, reset video fifo after pixel config done.
        sys_hdmi_rx_video_fifo_reset();
    }

    //audio config
    sys_hdmi_rx_audio_config(TRUE);

    //hdmi tx config
    //do

    if (b_config_all)
    {
        sys_config_output(HDMI_TX_CONFIG_AV, 0);
    }
    else
    {
        sys_config_output(HDMI_TX_CONFIG_AUD, 0);
    }

    return TRUE;
}

void _hdmi_tx_gcp_avmute_param_default(void)
{
    g_b_rx_gcp_avmute_flag = FALSE;
}

BOOL sys_hdmi_gcp_packet_avmute_service(void)
{
    BOOL b_avmute;

    b_avmute = ms933xdrv_hdmi_rx_controller_get_gcp_avmute();

    if (g_b_rx_gcp_avmute_flag != b_avmute)
    {
        g_b_rx_gcp_avmute_flag = b_avmute;
        LOG1("b_avmute = ", b_avmute);
        sys_config_output(HDMI_TX_CONFIG_AVMUTE, b_avmute);
        return b_avmute;
    }

    return FALSE;
}

void sys_hdmi_rx_packet_service(void)
{
    BOOL b_config = FALSE;
    UINT8 u8_int_sts = 0;

    ////if DVI input, no packet
    if (!g_b_hdmi_input_valid || !g_st_hdmi_timing.u8_hdmi_flag)
    {
        g_u8_rx_packet_timer_count = 0;
        return;
    }

    g_u8_rx_packet_timer_count ++;
    if (g_u8_rx_packet_timer_count < RX_PACKET_TIMEOUT)
    {
        return;
    }
    g_u8_rx_packet_timer_count = 0;

    u8_int_sts = sys_hdmi_gcp_packet_avmute_service();

    //20191115
    //if get avmute status change to mute enable, this time do not process infoframe_status and hdmi_rx_audio_service
    if (u8_int_sts)
    {
        return;
    }

    u8_int_sts = _get_infoframe_status();

    if (u8_int_sts & 0xE0)
    {
        LOG1("packet_int_sts = ", u8_int_sts);

        b_config = sys_hdmi_av_config(u8_int_sts, FALSE);
        if (b_config)
        {
            #if MS933X_APP_LOG1_ENABLE
            printf_input_av_config(u8_int_sts);
            #endif
            return;
        }
    }

    u8_int_sts = sys_hdmi_rx_audio_service(u8_int_sts);

    #if SYS_AUDIO_PAD_OUTPUT_ENABLE
    sys_pad_audio_ctrl_service(u8_int_sts ? FALSE : TRUE);
    #endif

}

void sys_hdmi_rx_hdcp_service(void)
{
    UINT8 u8_rx_woking_flag;

    if (!TMDS_CLK_VALID(g_u16_input_tmds_clk))
    {
        g_u8_rx_hdcp_timer_count = 0;
        return;
    }

    g_u8_rx_hdcp_timer_count++;
    if (g_u8_rx_hdcp_timer_count < RX_HDCP_TIMEOUT)
    {
        return;
    }
    g_u8_rx_hdcp_timer_count = 0;

    u8_rx_woking_flag = ms933xdrv_hdmi_rx_controller_hdcp_get_status();

    #if HDCP_RPT_SUPPORT_ENABLE
    //20210124, if support HDCP repeater, must use ksv be wirted flag
    if (g_u8_hdcp_repeater_support)
    {
        if (ms933xdrv_hdmi_rx_controller_hdmi_interrupt_get_status(AKSV_RCV_ISTS))
        {
            g_u8_rx_hdcp_aksv_be_writed_flag = 1;

            if (!u8_rx_woking_flag) LOG("rx hdcp aksv be writed.");
        }
    }
    #endif

    if (g_u8_rx_hdcp_woking_flag != u8_rx_woking_flag)
    {
        g_u8_rx_hdcp_woking_flag = u8_rx_woking_flag;
        if (g_u8_rx_hdcp_woking_flag)
        {
            LOG("rx hdcp woking.");
        }
        else
        {
            LOG("rx hdcp stop.");
        }
    }

}

void _hdmi_tx_hdcp_param_default(UINT8 u8_output_chn)
{
    g_u8_tx_hdcp_process_flag_buf[u8_output_chn] = 0;
    g_u8_tx_hdcp_init_flag_buf[u8_output_chn] = 0;
    g_u8_tx_hdcp_enable_flag_buf[u8_output_chn] = 0;
    g_u8_tx_hdcp_timer_count_buf[u8_output_chn] = 0;
    g_u8_tx_hdcp_verify_first_R0_flag_buf[u8_output_chn] = 0;
}

void _hdmi_tx_hdcp_start(UINT8 u8_output_chn)
{
    g_u8_tx_hdcp_process_flag_buf[u8_output_chn] = 1;
    g_u8_tx_hdcp_init_flag_buf[u8_output_chn] = 1;
    g_u8_tx_hdcp_enable_flag_buf[u8_output_chn] = 0;
    g_u8_tx_hdcp_verify_first_R0_flag_buf[u8_output_chn] = 0;
    //
    g_u8_tx_hdcp_timer_count_buf[u8_output_chn] = TX_HDCP_START_TIME;
}

void _hdmi_tx_hdcp_restart(UINT8 u8_output_chn)
{
    g_u8_tx_hdcp_process_flag_buf[u8_output_chn] = 1;
    g_u8_tx_hdcp_init_flag_buf[u8_output_chn] = 1;
    g_u8_tx_hdcp_enable_flag_buf[u8_output_chn] = 0;
    g_u8_tx_hdcp_verify_first_R0_flag_buf[u8_output_chn] = 0;
    //
    g_u8_tx_hdcp_timer_count_buf[u8_output_chn] = TX_HDCP_RETRY_START_TIME;
}

void _hdmi_tx_hdcp_service(UINT8 u8_output_chn)
{
    HDMI_HDCP_RI st_val;

    ms933xdrv_hdmi_tx_set_channel(u8_output_chn);

    if (g_u8_tx_hdcp_init_flag_buf[u8_output_chn])
    {
        g_u8_tx_hdcp_init_flag_buf[u8_output_chn] = FALSE;

        _tx_hdcp_rpt_init(u8_output_chn);
        if (ms933xdrv_hdmi_tx_hdcp_init((UINT8 *)u8_tx_key_buf, (UINT8 *)u8_tx_ksv_buf))
        {
            LOG2("tx_hdcp_init_ok_chn = ", u8_output_chn);

            //20210128, delay unused now, hdcp first R0 verfiy in next polling
            #if 0
            //delay for R0 calc, spec 100ms.
            //if use i2c bus, time cost on iic access. so here not delay.
            mculib_delay_ms(100);
            #endif

            //
            g_u8_tx_hdcp_verify_first_R0_flag_buf[u8_output_chn] = 1;
            g_u8_tx_hdcp_timer_count_buf[u8_output_chn] = TX_HDCP_R0_START_TIME;

            #if HDMI_CTS_HDCP_RPT_ENABLE
            g_u8_hdmi_tx_hpd_detect_count = HDMI_TX_HPD_DET_TIMEOUT;
            #endif
        }
        else
        {
            #if HDMI_TX_HDCP_RETRY_ENABLE
            _hdmi_tx_hdcp_restart(u8_output_chn);
            ms933xdrv_hdmi_tx_hdcp_enable(FALSE);
            #endif

            LOG2("tx_hdcp_init_falied_chn = ", u8_output_chn);
        }

        return;
    }

    if (g_u8_tx_hdcp_verify_first_R0_flag_buf[u8_output_chn])
    {
        g_u8_tx_hdcp_verify_first_R0_flag_buf[u8_output_chn] = 0;

        if (ms933xdrv_hdmi_tx_hdcp_get_status(&st_val))
        {
            ms933xdrv_hdmi_tx_hdcp_enable(TRUE);
            g_u8_tx_hdcp_enable_flag_buf[u8_output_chn] = TRUE;

            //when hdcp init fisrt step done, I want to immediately goto repeater service
            g_u8_hdcp_rpt_service_timer_count = HDCP_REPEATER_SRC_TIMEOUT;
            g_u8_hdcp_rpt_ready_timer_count = 0;
            //LOG1("TX_Ri0 = ", st_val.TX_Ri0);
            //LOG1("TX_Ri1 = ", st_val.TX_Ri1);
            //LOG1("RX_Ri0 = ", st_val.RX_Ri0);
            //LOG1("RX_Ri1 = ", st_val.RX_Ri1);

            #if HDMI_CTS_HDCP_RPT_ENABLE
            g_u8_hdmi_tx_hpd_detect_count = HDMI_TX_HPD_DET_TIMEOUT;
            #endif
        }
        else
        {
            #if HDMI_TX_HDCP_RETRY_ENABLE
            _hdmi_tx_hdcp_restart(u8_output_chn);
            #endif

            ms933xdrv_hdmi_tx_hdcp_enable(FALSE);
            LOG2("tx_hdcp_r0_failed_chn = ", u8_output_chn);
        }

        return;
    }

    if (!g_u8_tx_hdcp_enable_flag_buf[u8_output_chn])
    {
        return;
    }

    if (ms933xdrv_hdmi_tx_hdcp_get_status(&st_val))
    {
        //LOG2("tx_hdcp_link_ok_chn = ", u8_output_chn);
    }
    else
    {
        ms933xdrv_hdmi_tx_hdcp_enable(FALSE);

        LOG2("tx_hdcp_link_error_chn = ", u8_output_chn);

        #if HDMI_TX_HDCP_RETRY_ENABLE
        _hdmi_tx_hdcp_restart(u8_output_chn);

        _rx_hdcp_rpt_ready_reset();

        #else
        g_u8_tx_hdcp_enable_flag_buf[u8_output_chn] = FALSE;
        #endif
    }
}

void sys_hdmi_tx_hdcp_service(void)
{
    UINT8 i;
    UINT8 u8_rx_hdcp_working;

    for (i = 0; i < HDMI_TX_CHN_NUM; i++)
    {
        #if HDCP_RPT_SUPPORT_ENABLE
        //if support hdmi hdcp repeater
        if (g_u8_hdcp_repeater_support)
        {
            u8_rx_hdcp_working = (g_u8_rx_hdcp_woking_flag | g_u8_rx_hdcp_aksv_be_writed_flag) ? 0x01 : 0x00;
        }
        else
        #endif
        {
            u8_rx_hdcp_working = g_u8_rx_hdcp_woking_flag;
        }

        //if rx hdcp no working and tx hdcp not be enable and tx hdcp not goto verify first R0, do not go tx hdcp process.
        if (!u8_rx_hdcp_working && !g_u8_tx_hdcp_enable_flag_buf[i] && !g_u8_tx_hdcp_verify_first_R0_flag_buf[i])
        {
            g_u8_tx_hdcp_timer_count_buf[i] = TX_HDCP_START_TIME;
            continue;
        }

        if (!g_u8_tx_hdcp_process_flag_buf[i])
        {
            continue;
        }

        g_u8_tx_hdcp_timer_count_buf[i] ++;

        if (g_u8_tx_hdcp_timer_count_buf[i] < TX_HDCP_TIMEOUT)
        {
            continue;
        }

        g_u8_tx_hdcp_timer_count_buf[i] = 0;

        if (_tx_ddc_error_get(i))
        {
            return;
        }

        _hdmi_tx_hdcp_service(i);

        _tx_ddc_error_check(i, FALSE);
    }
}

VOID _rx_hdcp_rpt_param_ready_reset(VOID)
{
    g_u8_rx_hdcp_rpt_ready = 0;
}

BOOL _rx_hdcp_rpt_ready_reset(VOID)
{
    #if HDCP_RPT_SUPPORT_ENABLE

    if (g_u8_rx_hdcp_rpt_ready)
    {
        g_u8_rx_hdcp_rpt_ready = 0;
        ms933xdrv_hdmi_rx_core_hdcp_rpt_reset_enable(TRUE);
        return TRUE;
    }
    #endif

    return FALSE;
}

BOOL _tx_hdcp_bcaps_repeater_flag_get(VOID)
{
    UINT8 u8_val;

    if (!ms933xdrv_hdmi_tx_hdcp_get_bcaps_from_rx(&u8_val))
    {
        return FALSE;
    }

    if (u8_val & 0x40)
    {
        return TRUE;
    }

    return FALSE;
}

BOOL _tx_hdcp_bcaps_repeater_ready_get(BOOL b_time_out)
{
    UINT8 u8_val;
    UINT8 u8_count;
    UINT8 u8_depth;

    if (!ms933xdrv_hdmi_tx_hdcp_get_bcaps_from_rx(&u8_val))
    {
        return FALSE;
    }

    if ((u8_val & 0x60) == 0x60)
    {
        return TRUE;
    }

    if (b_time_out)
    {
        //double check repeater flag, if invalid, it is a error.
        if ((u8_val & 0x40) != 0x40)
        {
            return FALSE;
        }

        //if HDCP_MAX_DEVS_EXCEEDED or HDCP_MAX_CASCADE_EXCEEDED bit is 1, also means sink ready
        ms933xdrv_hdmi_tx_hdcp_get_bstatus_from_rx(&u8_count, &u8_depth);

        if ((u8_count & HDCP_MAX_DEVS_EXCEEDED_BIT_MASK) ||
            (u8_depth & HDCP_MAX_CASCADE_EXCEEDED_BIT_MASK))
        {
            return TRUE;
        }
    }

    return FALSE;
}

VOID _tx_hdcp_rpt_param_repeater_flag_set(BOOL b_set)
{
    UINT8 u8_tx_chn;

    u8_tx_chn = ms933xdrv_hdmi_tx_get_channel();

    g_u8_tx_hdcp_repeater_flag_buf[u8_tx_chn] = b_set ? 1 : 0;
}

BOOL _tx_hdcp_rpt_param_repeater_flag_get(UINT8 u8_tx_chn)
{
    return g_u8_tx_hdcp_repeater_flag_buf[u8_tx_chn] ? TRUE : FALSE;
}

VOID _tx_hdcp_rpt_param_repeater_flag_default(UINT8 u8_tx_chn)
{
    g_u8_tx_hdcp_repeater_flag_buf[u8_tx_chn] = 0;
}

void _tx_hdcp_rpt_init(UINT8 u8_tx_chn)
{
    #if HDCP_RPT_SUPPORT_ENABLE

    if (!g_u8_hdcp_repeater_support)
    {
        #if HDMI_CTS_HDCP_RPT_ENABLE
        _tx_hdcp_bcaps_repeater_flag_get();
        #endif
        return;
    }

    //sink bcaps hdcp repeater flag
    if (_tx_hdcp_bcaps_repeater_flag_get())
    {
        LOG("sink_bcaps_rpt_support.");
        _tx_hdcp_rpt_param_repeater_flag_set(TRUE);
        ms933xdrv_hdmi_tx_hdcp_rpt_enable(TRUE);
    }
    else
    {
        _tx_hdcp_rpt_param_repeater_flag_set(FALSE);
    }

    #else

    #if HDMI_CTS_HDCP_RPT_ENABLE
    //HDCP CTS SPEC, must read bcaps
    _tx_hdcp_bcaps_repeater_flag_get();
    #endif

    #endif
}

BOOL _tx_hdcp_param_encoding_enable_flag_verify(VOID)
{
    UINT8 i;
    BOOL b_exist_hpd = FALSE;

    for (i = 0; i < HDMI_TX_CHN_NUM; i++)
    {
        if (g_u8_sink_hpd_connect[i])
        {
            if (!g_u8_tx_hdcp_enable_flag_buf[i])
            {
                return FALSE;
            }

            b_exist_hpd = TRUE;
        }
    }

    return b_exist_hpd;
}

BOOL _tx_hdcp_ksv_collect(VOID)
{
    return FALSE;
}

BOOL _tx_hdcp_rpt_check_all_repeater_sink_ready(BOOL b_time_out)
{
    UINT8 i;

    for (i = 0; i < HDMI_TX_CHN_NUM; i++)
    {
        if (g_u8_sink_hpd_connect[i])
        {
            if (_tx_hdcp_rpt_param_repeater_flag_get(i))
            {
                ms933xdrv_hdmi_tx_set_channel(i);
                if (!_tx_hdcp_bcaps_repeater_ready_get(b_time_out))
                {
                    return FALSE;
                }
            }
        }
    }

    return TRUE;
}

//return error code
UINT8 _tx_hdcp_rpt_process(VOID)
{
#if HDCP_RPT_SUPPORT_ENABLE
    UINT8 i;
    UINT8 u8_rx_dev_count = 0;
    UINT8 u8_rx_dev_depth = 0;
    UINT8 u8_dev_count;
    UINT8 u8_dev_depth;
    UINT8 u8_tx_rpt_status;
    UINT8 *p_u8_ksv = g_u8_hdcp_rpt_ksv_buf;

    for (i = 0; i < HDMI_TX_CHN_NUM; i++)
    {
        if (g_u8_sink_hpd_connect[i])
        {
            ms933xdrv_hdmi_tx_set_channel(i);

            if (_tx_hdcp_rpt_param_repeater_flag_get(i))
            {
                u8_tx_rpt_status = ms933xdrv_hdmi_tx_hdcp_repeat_init(&u8_dev_count, &u8_dev_depth, p_u8_ksv);

                #if TX_HDCP_RPT_BUG0_FIXED_ENABLE
                if ((u8_tx_rpt_status == 0x04) && (g_u16_input_tmds_clk > 20000))
                {
                    u8_tx_rpt_status = 0x00;
                }
                #endif

                if (u8_tx_rpt_status)
                {
                    LOG1("u8_tx_hdcp_rpt_error = ", u8_tx_rpt_status);
                    LOG1("sink_hdcp_bstatus = ", ((UINT16)u8_dev_depth << 8) | u8_dev_count);

                    u8_dev_depth &= 0x0f;

                    if ((u8_dev_count & HDCP_MAX_DEVS_EXCEEDED_BIT_MASK) ||
                        (u8_dev_depth & HDCP_MAX_CASCADE_EXCEEDED_BIT_MASK))
                    {
                        if (u8_dev_count & HDCP_MAX_DEVS_EXCEEDED_BIT_MASK)
                        {
                            u8_dev_count = HDCP_MAX_DEVS_EXCEEDED_BIT_MASK | 0x01;

                            if ((u8_dev_depth & HDCP_MAX_CASCADE_EXCEEDED_BIT_MASK) == 0x00)
                            {
                                u8_dev_depth = 0x01;
                            }
                        }

                        if (u8_dev_depth & HDCP_MAX_CASCADE_EXCEEDED_BIT_MASK)
                        {
                            u8_dev_depth = HDCP_MAX_CASCADE_EXCEEDED_BIT_MASK | 0x01;

                            if ((u8_dev_count & HDCP_MAX_DEVS_EXCEEDED_BIT_MASK) == 0x00)
                            {
                                u8_dev_count = 0x01;
                            }
                        }

                        g_u8_rx_hdcp_rpt_dev_count = u8_dev_count;
                        g_u8_rx_hdcp_rpt_dev_depth = u8_dev_depth;
                        return 0;
                    }
                    else if (u8_dev_depth >= HDCP_RPT_RPT_DEV_DEPTH_MAX) //hdmi cts, depth is first judge than count
                    {
                        g_u8_rx_hdcp_rpt_dev_count = 0x01;
                        g_u8_rx_hdcp_rpt_dev_depth = HDCP_MAX_CASCADE_EXCEEDED_BIT_MASK | 0x01;
                        return 0;
                    }
                    else if (u8_dev_count >= MS933X_HDCP_RPT_COUNT_MAX)
                    {
                        g_u8_rx_hdcp_rpt_dev_count = HDCP_MAX_DEVS_EXCEEDED_BIT_MASK | 0x01;
                        g_u8_rx_hdcp_rpt_dev_depth = 0x01;
                        return 0;
                    }
                    else
                    {
                        ms933xdrv_hdmi_tx_hdcp_enable(FALSE);
                        _hdmi_tx_hdcp_restart(i);
                        LOG1("tx_hdcp_restart_chn = ", i);
                        return 0x01;
                    }
                }

                #if HDMI_CTS_HDCP_RPT_ENABLE
                if (u8_dev_count >= HDMI_CTS_HDCP_DEV_COUNT_MAX)
                {
                    LOG1("sink_hdcp_bstatus = ", ((UINT16)u8_dev_depth << 8) | u8_dev_count);
                    g_u8_rx_hdcp_rpt_dev_count = HDCP_MAX_DEVS_EXCEEDED_BIT_MASK | 0x01;
                    g_u8_rx_hdcp_rpt_dev_depth = 0x01;
                    return 0;
                }
                #endif

                if (!ms933xdrv_hdmi_tx_hdcp_get_bksv_from_rx(&p_u8_ksv[u8_dev_count * HDCP_KSV_BYTE_SIZE]))
                {
                    return 0x02;
                }

                u8_dev_count += 1;

                u8_dev_depth &= 0x07;
                u8_dev_depth += 1;
            }
            else
            {
                if (!ms933xdrv_hdmi_tx_hdcp_get_bksv_from_rx(p_u8_ksv))
                {
                    return 0x03;
                }
                u8_dev_count = 1;
                u8_dev_depth = 1;
            }

            u8_rx_dev_count += u8_dev_count;
            if (u8_rx_dev_count > MS933X_HDCP_RPT_COUNT_MAX)
            {
                LOG2("sink_hdcp_dev_count_too_large = ", u8_rx_dev_count);
                g_u8_rx_hdcp_rpt_dev_count = HDCP_MAX_DEVS_EXCEEDED_BIT_MASK | 0x01;
                g_u8_rx_hdcp_rpt_dev_depth = 0x01;
                return 0;
            }

            p_u8_ksv += u8_rx_dev_count * HDCP_KSV_BYTE_SIZE;

            if (u8_dev_depth > u8_rx_dev_depth)
            {
                u8_rx_dev_depth = u8_dev_depth;
            }

            #if 0 //this case impossible
            if (u8_rx_dev_depth > HDCP_RPT_RPT_DEV_DEPTH_MAX)
            {
                LOG2("sink_hdcp_dev_depth_too_large = ", u8_rx_dev_depth);
                g_u8_rx_hdcp_rpt_dev_count = 0x01;
                g_u8_rx_hdcp_rpt_dev_depth = HDCP_MAX_CASCADE_EXCEEDED_BIT_MASK | 0x01;
                return 0x00;
            }
            #endif
        }
    }

    g_u8_rx_hdcp_rpt_dev_count = u8_rx_dev_count;
    g_u8_rx_hdcp_rpt_dev_depth = u8_rx_dev_depth;

#endif //HDCP_RPT_SUPPORT_ENABLE

    return 0;
}

BOOL _rx_hdcp_rpt_ksv_list_write(VOID)
{
#if HDCP_RPT_SUPPORT_ENABLE
    UINT8 u8_i;

    LOG1("rx_hdcp_rpt_dev_count = ", g_u8_rx_hdcp_rpt_dev_count);
    LOG1("rx_hdcp_rpt_dev_depth = ", g_u8_rx_hdcp_rpt_dev_depth);

    if ( ( (g_u8_rx_hdcp_rpt_dev_count & HDCP_MAX_DEVS_EXCEEDED_BIT_MASK   ) == 0x00 ) &&
         ( (g_u8_rx_hdcp_rpt_dev_depth & HDCP_MAX_CASCADE_EXCEEDED_BIT_MASK) == 0x00 ) )
    {
        LOG("");
        LOG("rx_ksv_list:");
        for (u8_i = 0; u8_i < g_u8_rx_hdcp_rpt_dev_count; u8_i ++)
        {
            LOG("");
            LOG1("rx_ksv_fifo = ", g_u8_hdcp_rpt_ksv_buf[u8_i * HDCP_KSV_BYTE_SIZE + 0]);
            LOG1("rx_ksv_fifo = ", g_u8_hdcp_rpt_ksv_buf[u8_i * HDCP_KSV_BYTE_SIZE + 1]);
            LOG1("rx_ksv_fifo = ", g_u8_hdcp_rpt_ksv_buf[u8_i * HDCP_KSV_BYTE_SIZE + 2]);
            LOG1("rx_ksv_fifo = ", g_u8_hdcp_rpt_ksv_buf[u8_i * HDCP_KSV_BYTE_SIZE + 3]);
            LOG1("rx_ksv_fifo = ", g_u8_hdcp_rpt_ksv_buf[u8_i * HDCP_KSV_BYTE_SIZE + 4]);
            LOG("");
        }
    }

    if (ms933xdrv_hdmi_rx_core_hdcp_rpt_ksv_init(g_u8_rx_hdcp_rpt_dev_count, g_u8_rx_hdcp_rpt_dev_depth, g_u8_hdcp_rpt_ksv_buf))
    {
        LOG("rx_hdcp_rpt_ready ok.");
        return TRUE;
    }
    else
    {
        LOG("rx_hdcp_rpt_ready failed.");
        return FALSE;
    }

#else //HDCP_RPT_SUPPORT_ENABLE

    return FALSE;

#endif

}

void sys_hdmi_hdcp_repeater_service(void)
{
    UINT8 u8_error_code;
    UINT8 u8_ready_timeout = FALSE;

    if (!g_b_hdmi_input_valid)
    {
        g_u8_hdcp_rpt_service_timer_count = 0;
        return;
    }

    if (g_u8_rx_hdcp_rpt_ready)
    {
        return;
    }

    g_u8_hdcp_rpt_service_timer_count ++;
    if (g_u8_hdcp_rpt_service_timer_count < HDCP_REPEATER_SRC_TIMEOUT)
    {
        return;
    }
    g_u8_hdcp_rpt_service_timer_count = 0;

    if (!_tx_hdcp_param_encoding_enable_flag_verify())
    {
        return;
    }

    if (g_u8_hdcp_rpt_service_timer_count < HDCP_REPEATER_READY_TIMEOUT)
    {
        g_u8_hdcp_rpt_ready_timer_count ++;
    }
    else
    {
        u8_ready_timeout = TRUE;
    }

    if (!_tx_hdcp_rpt_check_all_repeater_sink_ready(u8_ready_timeout))
    {
        return;
    }

    u8_error_code = _tx_hdcp_rpt_process();
    if (u8_error_code)
    {
        LOG1("tx_hdcp_rpt_proc_error = ", u8_error_code);
        return;
    }

    LOG("sink_ksv_collect done.");
    g_u8_rx_hdcp_rpt_ready = 1;

    _rx_hdcp_rpt_ksv_list_write();
}

void sys_tx_hdcp_port_service(void)
{
    //UINT8 i;

    if (!TMDS_CLK_VALID(g_u16_input_tmds_clk) && !g_u8_sink_hpd_connect[0])
    {
        g_u8_tx_hdcp_port_service_timer_count = 0;
        return;
    }

    if (TMDS_CLK_VALID(g_u16_input_tmds_clk) && g_u8_sink_hpd_connect[0])
    {
        g_u8_tx_hdcp_port_service_timer_count = 0;
        return;
    }

    g_u8_tx_hdcp_port_service_timer_count++;
    if (g_u8_tx_hdcp_port_service_timer_count < TX_HDCP_PORT_SRC_TIMEOUT)
    {
        return;
    }
    g_u8_tx_hdcp_port_service_timer_count = 0;

    ms933xdrv_hdmi_tx_set_channel(0);
    _tx_hdcp_bcaps_repeater_flag_get();
    LOG("tx_hdcp_port_accessed.");
}

void _tx_ddc_error_check(UINT8 u8_tx_chn, BOOL b_tx_hpd_lost)
{
    #if MS933X_TX_DDC_ERROR_SERVICE_ENABLE
    if (b_tx_hpd_lost)
    {
        if ((g_u8_tx_ddc_error_flag & (1 << u8_tx_chn)) && ms933xdrv_misc_chipisvalid())
        {
            g_u8_tx_ddc_error_flag &= ~(1 << u8_tx_chn);
        }
    }
    else
    {
        if (!ms933xdrv_misc_chipisvalid())
        {
            g_u8_tx_ddc_error_flag |= (1 << u8_tx_chn);
            g_u8_chip_valid_check_timer_count = CHIP_VALID_CHECK_TIMEOUT;
        }
    }
    #endif
}

BOOL _tx_ddc_error_get(UINT8 u8_tx_chn)
{
    #if MS933X_TX_DDC_ERROR_SERVICE_ENABLE
    if (g_u8_tx_ddc_error_flag & (1 << u8_tx_chn))
    {
        return TRUE;
    }

    if (g_u8_tx_ddc_error_flag && !ms933xdrv_misc_chipisvalid())
    {
        return TRUE;
    }
    #endif

    return FALSE;
}

void sys_ms933x_chip_valid_check(void)
{
    g_u8_chip_valid_check_timer_count ++;
    if (g_u8_chip_valid_check_timer_count < CHIP_VALID_CHECK_TIMEOUT)
    {
        return;
    }
    g_u8_chip_valid_check_timer_count = 0;

    if (!ms933xdrv_misc_chipisvalid())
    {
        LOG("ms933x chip invalid.");
        ms933x_init();
    }
}

#if MS933X_HDMI_NET_CALBE_RX_ENABLE

typedef struct _T_MANUAL_TIMING_T_
{
    UINT8  u8_polarity;
    UINT16 u16_h_active;
    UINT16 u16_h_blank;
    UINT16 u16_h_sw;
    UINT16 u16_h_front;
    UINT16 u16_v_active;
    UINT16 u16_v_blank;
    UINT16 u16_v_sw;
    UINT16 u16_v_front;
} MANUAL_TIMING_T;

extern BOOL ms933xdrv_hdmi_rx_controller_mdt_syncvalid(VOID);
extern e_RxMdtPol ms933xdrv_mdt_get_sync_polarity(VOID);

extern UINT16 ms933xdrv_mdt_get_htotal(VOID);
extern UINT16 ms933xdrv_mdt_get_vtotal(VOID);
extern UINT16 ms933xdrv_mdt_get_hactive(VOID);
extern UINT16 ms933xdrv_mdt_get_vactive(VOID);
extern UINT32 ms933xdrv_mdt_get_hfreq(VOID);

BOOL _hdmi_rx_get_input_timing(MANUAL_TIMING_T *ptTiming)
{
    BOOL bValid = FALSE;
    UINT32 u32_val;
    UINT16 u16_v_blank;
    UINT16 u16_v_front;
    UINT16 u16_mdt_int;
    BOOL b_sync_valid;

    UINT16 u16_h_hotal_ex;
    UINT16 u16_v_total_ex;
    UINT16 u16_h_active_ex;
    UINT16 u16_v_vative_ex;
    UINT16 u16_v_freq_ex;

    if (g_u8_input_invalid_timer_count >= INPUT_INVALID_TIMEOUT_1S)
    {
        b_sync_valid = ((ms933x_HAL_ReadDWord_Ex(0x2180) & 0x07) == 0x07) ? TRUE : FALSE;
    }
    else
    {
        b_sync_valid = ((ms933x_HAL_ReadDWord_Ex(0x2180) & 0x7f07) == 0x7f07) ? TRUE : FALSE;
    }

    if (b_sync_valid)
    {
        ptTiming->u8_polarity = ms933xdrv_mdt_get_sync_polarity();

        u32_val = ms933x_HAL_ReadDWord_Ex(0x2198);
        ptTiming->u16_h_active = u32_val;
        ptTiming->u16_h_blank = u32_val >> 16;

        //
        u32_val = ms933x_HAL_ReadDWord_Ex(0x219c);
        ptTiming->u16_h_front = u32_val;
        ptTiming->u16_h_sw = u32_val >> 16;

        //
        u32_val = ms933x_HAL_ReadDWord_Ex(0x218c);
        ptTiming->u16_v_active = u32_val;
        u16_v_blank = u32_val >> 16;

        if (!(ptTiming->u8_polarity & 0x01) && (u16_v_blank % 2))
        {
            u16_v_blank -= 1;
        }

        ptTiming->u16_v_blank = u16_v_blank;

        //
        u32_val = ms933x_HAL_ReadDWord_Ex(0x2190);
        u16_v_front = u32_val;
        ptTiming->u16_v_sw = u32_val >> 16;

        if (!(ptTiming->u8_polarity & 0x01) && (u16_v_front % 2))
        {
            u16_v_front -= 1;
        }
        ptTiming->u16_v_front = u16_v_front;

        u16_h_hotal_ex = ms933xdrv_mdt_get_htotal();
        u16_v_total_ex = ms933xdrv_mdt_get_vtotal();
        u16_h_active_ex = ms933xdrv_mdt_get_hactive();
        u16_v_vative_ex = ms933xdrv_mdt_get_vactive();

        if (u16_v_total_ex > 0)
        {
            u16_v_freq_ex = 100 * ms933xdrv_mdt_get_hfreq() / u16_v_total_ex;
        }
        else
        {
            u16_v_freq_ex = 0;
        }

        if (g_u8_input_invalid_timer_count >= INPUT_INVALID_TIMEOUT_1S)
        {
            u16_mdt_int = 0;
        }
        else
        {
            //I think timing unstable
            u16_mdt_int = ms933xdrv_hdmi_rx_get_mdt_interrupt_status_ext(MDT_USED_ISTS);
        }

        #if 0
        LOG1("u16_h_hotal_ex  = ", u16_h_hotal_ex);
        LOG1("u16_v_total_ex  = ", u16_v_total_ex);
        LOG1("u16_h_active_ex = ", u16_h_active_ex);
        LOG1("u16_v_vative_ex = ", u16_v_vative_ex);
        LOG2("u16_v_freq_ex   = ", u16_v_freq_ex);
        LOG2("u16_h_active   = ", ptTiming->u16_h_active);
        LOG2("u16_v_active   = ", ptTiming->u16_v_active);
        #endif

        if ( u16_h_hotal_ex < 50 ||
             u16_v_total_ex < 50 ||
             u16_h_active_ex < 50 ||
             u16_v_vative_ex < 50 ||
             u16_h_hotal_ex < u16_h_active_ex ||
             u16_v_total_ex < u16_v_vative_ex ||
             u16_v_freq_ex < 500 ||
             u16_v_freq_ex > 30000 ||
             ptTiming->u16_h_active < 50 ||
             ptTiming->u16_v_active < 50 ||
             u16_mdt_int)
        {
            LOG("mdt error.");
            return FALSE;
        }

        bValid = TRUE;
    }

    return bValid;
}

VOID sys_hdmi_rx_timing_config(MANUAL_TIMING_T *ptTiming)
{
    #if 0
    UINT8  u8_polarity      = 0x03;
    UINT16 u16_h_active     = 0x780;
    UINT16 u16_h_blank      = 0x118;
    UINT16 u16_h_sw         = 0x2c;
    UINT16 u16_h_front      = 0x58;
    UINT16 u16_v_active     = 0x438;
    UINT16 u16_v_blank      = 0x2d;
    UINT16 u16_v_sw         = 0x5;
    UINT16 u16_v_front      = 0x4;
    UINT16 u16_v_total      = 0x465;
    #endif

    BOOL b_ceavid_vbos = 0;

    #if 0
    LOG1("u8_polarity  = ", ptTiming->u8_polarity);
    LOG1("u16_h_active = ", ptTiming->u16_h_active);
    LOG1("u16_h_blank  = ", ptTiming->u16_h_blank);
    LOG1("u16_h_sw     = ", ptTiming->u16_h_sw);
    LOG1("u16_h_front  = ", ptTiming->u16_h_front);
    LOG1("u16_v_active = ", ptTiming->u16_v_active);
    LOG1("u16_v_blank  = ", ptTiming->u16_v_blank);
    LOG1("u16_v_sw     = ", ptTiming->u16_v_sw);
    LOG1("u16_v_front  = ", ptTiming->u16_v_front);
    #endif

    if (!(ptTiming->u8_polarity & 0x01))
    {
        b_ceavid_vbos = 1;
        #if 0
        if (ptTiming->u16_v_total % 2)
        {
            if (ptTiming->u16_v_total == 625)    //1920x1080i (1250 Total) @ 50 Hz (Format 39)
            {
                b_ceavid_vbos = 0;
            }
        }
        #endif
    }

    ms933x_HAL_ToggleBits_Ex(0x2400, MSRT_BIT4, (ptTiming->u8_polarity & 0x01) ? 0 : 1);
    ms933x_HAL_ToggleBits_Ex(0x2400, MSRT_BIT3, (ptTiming->u8_polarity & 0x04) ? 1 : 0);
    ms933x_HAL_ToggleBits_Ex(0x2400, MSRT_BIT2, (ptTiming->u8_polarity & 0x02) ? 1 : 0);

    ms933x_HAL_ToggleBits_Ex(0x2400, MSRT_BIT5, b_ceavid_vbos);

    ms933x_HAL_WriteDWord_Ex(0x2408, ((UINT32)ptTiming->u16_h_blank << 16) + ptTiming->u16_h_active);
    ms933x_HAL_WriteDWord_Ex(0x240c, ((UINT32)ptTiming->u16_h_front << 16) + ptTiming->u16_h_sw);

    ms933x_HAL_WriteDWord_Ex(0x2410, ((UINT32)ptTiming->u16_v_blank << 16) + ptTiming->u16_v_active);
    ms933x_HAL_WriteDWord_Ex(0x2414, ((UINT32)ptTiming->u16_v_front << 16) + ptTiming->u16_v_sw);
}

static BOOL _rx_timing_diff(MANUAL_TIMING_T *pt_timing, MANUAL_TIMING_T *pt_timing1)
{
    if (pt_timing->u8_polarity    != pt_timing1->u8_polarity   ||
        pt_timing->u16_h_active   != pt_timing1->u16_h_active  ||
        pt_timing->u16_h_blank    != pt_timing1->u16_h_blank   ||
        pt_timing->u16_h_sw       != pt_timing1->u16_h_sw      ||
        pt_timing->u16_h_front    != pt_timing1->u16_h_front   ||
        pt_timing->u16_v_active   != pt_timing1->u16_v_active  ||
        pt_timing->u16_v_blank    != pt_timing1->u16_v_blank   ||
        pt_timing->u16_v_sw       != pt_timing1->u16_v_sw      ||
        pt_timing->u16_v_front    != pt_timing1->u16_v_front)
    {
        return TRUE;
    }

    return FALSE;
}

BOOL sys_hdmi_rx_timing_process(VOID)
{
    UINT8 i;

    MANUAL_TIMING_T st_timing;
    MANUAL_TIMING_T st_timing1;

    if (!_hdmi_rx_get_input_timing(&st_timing))
    {
        return FALSE;
    }
    else
    {
        //if interlace mode use auto timing mode
        if (!(st_timing.u8_polarity & 0x01))
        {
            sys_hdmi_rx_timing_manual_enable(FALSE);
            mculib_delay_ms(50);
            return TRUE;
        }
    }

    if (!_hdmi_rx_get_input_timing(&st_timing1))
    {
        return FALSE;
    }

    if (_rx_timing_diff(&st_timing, &st_timing1))
    {
        LOG("mdt error1.");
        return FALSE;
    }

    if (!_hdmi_rx_get_input_timing(&st_timing1))
    {
        return FALSE;
    }

    if (_rx_timing_diff(&st_timing, &st_timing1))
    {
        LOG("mdt error2.");
        return FALSE;
    }

    sys_hdmi_rx_timing_manual_enable(FALSE);
    sys_hdmi_rx_timing_config(&st_timing);
    sys_hdmi_rx_timing_manual_enable(TRUE);

    mculib_delay_ms(50);

    return TRUE;
}


VOID sys_hdmi_rx_timing_manual_enable(BOOL b_enable)
{
    ms933x_HAL_ToggleBits_Ex(0x2400, MSRT_BIT1, b_enable);
}
#endif //MS933X_HDMI_NET_CALBE_RX_ENABLE


void sys_mdt_service(void)
{
    UINT16 u16_mdt_ists;
    UINT8 u8_int_sts = 0;

    if (!TMDS_CLK_VALID(g_u16_input_tmds_clk))
    {
        return;
    }

    //rxpll_error, return
    if (g_u8_rxpll_configed_status == 2)
    {
        g_u8_rxpll_configed_status = 0;
        return;
    }

    u16_mdt_ists = ms933xdrv_hdmi_rx_get_mdt_interrupt_status(MDT_USED_ISTS);

    #if HDMI_RX_CEA_TIMING_USE_MANUAL_ENABLE
    if (g_b_hdmi_input_valid)
    {
        if (u16_mdt_ists)
        {
            LOG1("u16_mdt_ists = ", u16_mdt_ists);
        }
        return;
    }

    if (g_u8_input_invalid_timer_count >= INPUT_INVALID_TIMEOUT_1S)
    {
        u16_mdt_ists = 0;
    }
    #endif

    //rxpll_sucess or mdt_int
    if ((g_u8_rxpll_configed_status == 1) || u16_mdt_ists)
    {
        g_u8_rxpll_configed_status = 0;
        g_u8_mdt_change_timer_count = 0;

        if (g_b_hdmi_input_valid)
        {
            g_b_hdmi_input_valid = FALSE;
            sys_shutdown_output();

            #if HDMI_RX_PKT_INT_ENABLE
            ms933xdrv_hdmi_rx_interrupt_to_pin_ctrl(0, user_pkt_int, FALSE);
            #endif

            RX_STB_LED_light(FALSE);

            LOG("g_b_input_valid = 0");
        }

        //LOG1("u16_mdt_ists = ", u16_mdt_ists);

        //config audio pll for audio reset.
        ms933xdrv_hdmi_rx_audio_fifo_reset(TRUE);
        ms933xdrv_hdmi_rx_audio_config(RX_AUDIO_PLL_FREERUN_MODE, g_u16_input_tmds_clk);

        //20180622, clr packet status.
        //20200520, add reset audio
        //20200520, reset audio must by audio clk and video vsync
        ms933xdrv_hdmi_rx_controller_reset(HDMI_RX_CTRL_PDEC | HDMI_RX_CTRL_AUD);
        //clr pdec interrupt status
        ms933xdrv_hdmi_rx_controller_pdec_interrupt_get_status(PEDC_USED_ISTS);
        _packet_fifo_init();

        return;
    }

    if (!g_b_hdmi_input_valid)
    {
        #if (!HDMI_RX_CEA_TIMING_USE_MANUAL_ENABLE)
        if (ms933xdrv_hdmi_rx_controller_mdt_syncvalid())
        #endif
        {
            g_u8_mdt_change_timer_count ++;

            if (g_u8_mdt_change_timer_count >= MDT_CHANGE_TIMEOUT)
            {
                g_u8_mdt_change_timer_count = 0;

                #if HDMI_RX_CEA_TIMING_USE_MANUAL_ENABLE
                g_b_hdmi_input_valid = sys_hdmi_rx_timing_process();
                #else
                //
                #if HDMI_RX_TIMING_PARSE_ENABLE
                g_b_hdmi_input_valid = ms933xdrv_hdmi_rx_get_input_timing(&g_st_hdmi_in_timing);
                #else
                g_b_hdmi_input_valid = 1; //normal use this case.
                #endif
                //
                #endif

                if (g_b_hdmi_input_valid)
                {
                    RX_STB_LED_light(TRUE);

                    LOG("g_b_input_valid = 1");
                    u8_int_sts = _get_infoframe_status();
                    _get_packet_fifo_data();
                    sys_hdmi_av_config(u8_int_sts, TRUE);
                    //
                    #if MS933X_APP_LOG1_ENABLE
                    printf_input_timing();
                    printf_input_av_config(u8_int_sts);
                    #endif

                    #if HDMI_RX_PKT_INT_ENABLE
                    ms933xdrv_hdmi_rx_interrupt_to_pin_ctrl(0, user_pkt_int, TRUE);
                    #endif
                }
            }
        }
        #if (!HDMI_RX_CEA_TIMING_USE_MANUAL_ENABLE)
        else
        {
            g_u8_mdt_change_timer_count = 0;
        }
        #endif

        //enhance, reset service timer
        g_u8_rx_packet_timer_count = 0;
        g_u8_hdmi_shell_error_timer_count = 0;
    }
}

void ms933x_interrupt_service(void)
{
    if (!mculib_chip_read_interrupt_pin())
    {
        #if (HDMI_RX_CLK_INT_ENABLE && (!(HDMI_RX_MDT_INT_ENABLE || HDMI_RX_PKT_INT_ENABLE)))

        sys_hdmi_rx_pll_service(0); //register_int get in service
        //LOG("rx_clk_int.");

        #else

        #if HDMI_RX_CLK_INT_ENABLE
        if (ms933xdrv_hdmi_rx_controller_hdmi_interrupt_get_status(CLK_CHANGE_ISTS))
        {
            sys_hdmi_rx_pll_service(1);
            //LOG("rx_clk_int.");
        }
        #endif

        #if HDMI_RX_MDT_INT_ENABLE
        if (ms933xdrv_hdmi_rx_get_mdt_interrupt_status(user_mdt_int))
        {
            //user to do
            //LOG("rx_mdt_int.");
        }
        #endif

        #if HDMI_RX_PKT_INT_ENABLE
        if (ms933xdrv_hdmi_rx_controller_pdec_interrupt_get_status(user_pkt_int))
        {
            //user to do
            //LOG("rx_pkt_int.");
        }
        #endif

        #endif
    }
}
//void sys_led_process(void)
//{
//    if (g_b_hdmi_input_valid)
//    {
//        mculib_hdmi_rx_led_control(1);
//
//        mculib_hdmi_tx_led_control(0, g_u8_sink_hpd_connect[0]);
//        mculib_hdmi_tx_led_control(1, g_u8_sink_hpd_connect[1]);
//        mculib_hdmi_tx_led_control(2, g_u8_sink_hpd_connect[2]);
//        mculib_hdmi_tx_led_control(3, g_u8_sink_hpd_connect[3]);
//    }
//    else
//    {
//         mculib_hdmi_rx_led_control(0);
//        mculib_hdmi_tx_led_control(0, 0);
//        mculib_hdmi_tx_led_control(1, 0);
//        mculib_hdmi_tx_led_control(2, 0);
//        mculib_hdmi_tx_led_control(3, 0);
//    }
//}

void ms933x_media_service(void)
{
    sys_hotplug_service();

    sys_hdmi_rx_pll_service(0);

    sys_mdt_service();
    //sys_led_process();

    sys_hdmi_rx_packet_service();

    #if RX_HDCP_SUPPORT_ENABLE
    if (g_u8_rx_hdcp_support)
    {
        sys_hdmi_rx_hdcp_service();
    }
    #endif

    #if TX_HDCP_SUPPORT_ENABLE
    if (g_u8_tx_hdcp_support)
    {
        sys_hdmi_tx_hdcp_service();
    }
    #endif

    #if HDCP_RPT_SUPPORT_ENABLE

    if (g_u8_hdcp_repeater_support)
    {
        sys_hdmi_hdcp_repeater_service();
    }

    #if HDMI_CTS_HDCP_RPT_ENABLE
    sys_tx_hdcp_port_service();
    #endif

    #endif

    sys_error_service();

    printf_input_timing();
}

#if MS933X_HDMI_NET_CABLE_TX_ENABLE
VOID ms933x_hdmi_tx_drive_key_service(VOID)
{
    UINT8 u8key = 0xff; //mculib_key_detect();

    switch (u8key)
    {
    case 1:
        if (!g_b_hdmi_input_valid) return;

        g_u8_hdmi_tx_drive_mode ++;
        g_u8_hdmi_tx_drive_mode %= 4;
        LOG2("g_u8_tx_mode = ", g_u8_hdmi_tx_drive_mode);

        ms933xdrv_hdmi_tx_set_channel(0);
        ms933xdrv_hdmi_tx_phy_output_enable(FALSE);
        mculib_delay_ms(50);

        sys_hdmi_tx_drive_mode_config(g_u8_hdmi_tx_drive_mode);
        ms933xdrv_hdmi_tx_phy_output_enable(TRUE);
        break;
    }
}
#endif



