void hdmirx_set_hpd(int port, unsigned char val)
{
#ifdef USE_GPIO_FOR_HPD
    int bitpos = 1;
    switch(port){
        case 0:
            bitpos=1;
            break;
        case 1:
            bitpos=5;
            break;
        case 2:
            bitpos=9;
            break;
        case 3:
            bitpos=13;
            break;
    }
    if(val){
        WRITE_CBUS_REG(PREG_PAD_GPIO5_O, READ_CBUS_REG(PREG_PAD_GPIO5_O) & (~(1<<bitpos)));
    }
    else{
        WRITE_CBUS_REG(PREG_PAD_GPIO5_O, READ_CBUS_REG(PREG_PAD_GPIO5_O) | (1<<bitpos));
    }
#else
    if(val){
        hdmirx_wr_top( HDMIRX_TOP_HPD_PWR5V,  hdmirx_rd_top(HDMIRX_TOP_HPD_PWR5V)|(1<<rx.port));
    }
    else{
        hdmirx_wr_top( HDMIRX_TOP_HPD_PWR5V,  hdmirx_rd_top(HDMIRX_TOP_HPD_PWR5V)&(~(1<<rx.port)));
    }
#endif
    hdmirx_print("%s(%d,%d)\n", __func__, port, val);
    
}
void hdmirx_hw_config(void)
{
	hdmirx_print("%s %d\n", __func__, rx.port);
	WRITE_CBUS_REG(RESET0_REGISTER, 0x8); //reset HDMIRX module
	mdelay(10);
	clk_init();
	hdmirx_wr_top(HDMIRX_TOP_INTR_MASKN, 0); //disable top interrupt gate
	control_reset(0);
	hdmirx_wr_top( HDMIRX_TOP_PORT_SEL,   (1<<rx.port));  //EDID port select
	hdmirx_interrupts_cfg(false); //disable dwc interrupt
	if(hdcp_enable){
		hdmi_rx_ctrl_hdcp_config(&rx.hdcp);
	} else {
		hdmirx_wr_bits_dwc( RA_HDCP_CTRL, HDCP_ENABLE, 0);
	}

	/*phy config*/
	//hdmirx_phy_restart();
	//hdmi_rx_phy_fast_switching(1);
	phy_init(rx.port, 0); //port, dcm
	/**/

	/* control config */
	control_init(rx.port);
	audio_init();
	packet_init();
	hdmirx_audio_fifo_rst();
	hdmirx_packet_fifo_rst();
	/**/
	control_reset(1);

	/*enable irq */
    hdmirx_wr_top(HDMIRX_TOP_INTR_STAT_CLR, ~0);
    hdmirx_wr_top(HDMIRX_TOP_INTR_MASKN, 0x00001fff);
    hdmirx_interrupts_hpd(true);
	/**/

#ifndef USE_GPIO_FOR_HPD
	hdmi_rx_ctrl_hpd(true);
	hdmirx_wr_top( HDMIRX_TOP_HPD_PWR5V, (1<<5)|(1<<4)); //invert HDP output
#endif

	/* wait at least 4 video frames (at 24Hz) : 167ms for the mode detection
	recover the video mode */
	mdelay(200);

	/* Check If HDCP engine is in Idle state, if not wait for authentication time.
	200ms is enough if no Ri errors */
    if (hdmirx_rd_dwc(0xe0) != 0)
    {
        mdelay(200);
    }
#if CEC_FUNC_ENABLE
	cec_init();
#endif
}
static void control_reset(unsigned char seq)
{
    unsigned long   data32;

    if(seq==0){
    //DWC reset default to be active, until reg HDMIRX_TOP_SW_RESET[0] is set to 0.
    //hdmirx_rd_check_reg(HDMIRX_DEV_ID_TOP, HDMIRX_TOP_SW_RESET, 0x1, 0x0);
    

    // Release IP reset
    hdmirx_wr_top( HDMIRX_TOP_SW_RESET, 0x0);

    
    // Enable functional modules
    data32  = 0;
    data32 |= 1 << 5;   // [5]      cec_enable
    data32 |= 1 << 4;   // [4]      aud_enable
    data32 |= 1 << 3;   // [3]      bus_enable
    data32 |= 1 << 2;   // [2]      hdmi_enable
    data32 |= 1 << 1;   // [1]      modet_enable
    data32 |= 1 << 0;   // [0]      cfg_enable
    hdmirx_wr_dwc(RA_DMI_DISABLE_IF, data32);    // DEFAULT: {31'd0, 1'b0}

    mdelay(1);
    // Reset functional modules
    hdmirx_wr_dwc(RA_DMI_SW_RST,     0x0000007F);

    mdelay(1);

    //hdmirx_rd_check_reg(HDMIRX_DEV_ID_DWC, HDMIRX_DWC_DMI_SW_RST,   0, 0);

    // RX Reset
    }
    else{
    data32  = 0;
    data32 |= 0 << 5;   // [5]      cec_enable
    data32 |= 0 << 4;   // [4]      aud_enable
    data32 |= 0 << 3;   // [3]      bus_enable
    data32 |= 0 << 2;   // [2]      hdmi_enable
    data32 |= 0 << 1;   // [1]      modet_enable
    data32 |= 1 << 0;   // [0]      cfg_enable
    hdmirx_wr_dwc(RA_DMI_DISABLE_IF, data32);    // DEFAULT: {31'd0, 1'b0}

    mdelay(1);

    //--------------------------------------------------------------------------
    // Bring up RX
    //--------------------------------------------------------------------------
    data32  = 0;
    data32 |= 1 << 5;   // [5]      cec_enable
    data32 |= 1 << 4;   // [4]      aud_enable
    data32 |= 1 << 3;   // [3]      bus_enable
    data32 |= 1 << 2;   // [2]      hdmi_enable
    data32 |= 1 << 1;   // [1]      modet_enable
    data32 |= 1 << 0;   // [0]      cfg_enable
    hdmirx_wr_dwc(RA_DMI_DISABLE_IF, data32);    // DEFAULT: {31'd0, 1'b0}

    mdelay(1);
    }
}
void hdmirx_config_video(struct hdmi_rx_ctrl_video *video_params)
{
	int data32=0;
    data32 |= 0 << 23; //video_params.pixel_repetition << 23;  // [23]     hscale_half: 1=Horizontally scale down by half
    data32 |= 0                             << 22;  // [22]     force_vid_rate: 1=Force video output sample rate
    data32 |= 0                             << 19;  // [21:19]  force_vid_rate_chroma_cfg : 0=Bypass, not rate change. Applicable only if force_vid_rate=1
    data32 |= 0                             << 16;  // [18:16]  force_vid_rate_luma_cfg   : 0=Bypass, not rate change. Applicable only if force_vid_rate=1
    data32 |= 0x7fff                        << 0;   // [14: 0]  hsizem1
    hdmirx_wr_top( HDMIRX_TOP_VID_CNTL,   data32);
}    
void clk_init(void)
{
    unsigned int data32;


    /* DWC clock enable */

    Wr_reg_bits(HHI_GCLK_MPEG0, 1, 21, 1);  // Turn on clk_hdmirx_pclk, also = sysclk

    // Enable APB3 fail on error
    *((volatile unsigned long *) P_HDMIRX_CTRL_PORT)          |= (1 << 15);   // APB3 to HDMIRX-TOP err_en
    *((volatile unsigned long *) (P_HDMIRX_CTRL_PORT+0x10))   |= (1 << 15);   // APB3 to HDMIRX-DWC err_en

    //turn on clocks: md, cfg...

    data32  = 0;
    data32 |= 0 << 25;  // [26:25] HDMIRX mode detection clock mux select: osc_clk
    data32 |= 1 << 24;  // [24]    HDMIRX mode detection clock enable
    data32 |= 0 << 16;  // [22:16] HDMIRX mode detection clock divider
    data32 |= 3 << 9;   // [10: 9] HDMIRX config clock mux select: fclk_div5=400MHz
    data32 |= 1 << 8;   // [    8] HDMIRX config clock enable
    data32 |= 3 << 0;   // [ 6: 0] HDMIRX config clock divider: 400/4=100MHz
    WRITE_MPEG_REG(HHI_HDMIRX_CLK_CNTL,     data32);

    data32  = 0;
    data32 |= 2             << 25;  // [26:25] HDMIRX ACR ref clock mux select: fclk_div5
    data32 |= rx.ctrl.acr_mode      << 24;  // [24]    HDMIRX ACR ref clock enable
    data32 |= 0             << 16;  // [22:16] HDMIRX ACR ref clock divider
    data32 |= 2             << 9;   // [10: 9] HDMIRX audmeas clock mux select: fclk_div5
    data32 |= 1             << 8;   // [    8] HDMIRX audmeas clock enable
    data32 |= 1             << 0;   // [ 6: 0] HDMIRX audmeas clock divider: 400/2 = 200MHz
    WRITE_MPEG_REG(HHI_HDMIRX_AUD_CLK_CNTL, data32);

    data32  = 0;
    data32 |= 1 << 17;  // [17]     audfifo_rd_en
    data32 |= 1 << 16;  // [16]     pktfifo_rd_en
    data32 |= 1 << 2;   // [2]      hdmirx_cecclk_en
    data32 |= 0 << 1;   // [1]      bus_clk_inv
    data32 |= 0 << 0;   // [0]      hdmi_clk_inv
    hdmirx_wr_top( HDMIRX_TOP_CLK_CNTL, data32);    // DEFAULT: {32'h0}
  

}
int hdmirx_config_audio(void)
{
#define AUD_CLK_DELTA   2000
#define RX_8_CHANNEL        1        // 0=I2S 2-channel; 1=I2S 4 x 2-channel.
int err = 0;
unsigned long data32 = 0;
#if 1
    data32  = 0;
    data32 |= 0         << 9;   // [9]      force_afif_status:1=Use cntl_audfifo_status_cfg as fifo status; 0=Use detected afif_status.
    data32 |= 1         << 8;   // [8]      afif_status_auto:1=Enable audio FIFO status auto-exit EMPTY/FULL, if FIFO level is back to LipSync; 0=Once enters EMPTY/FULL, never exits.
    data32 |= 1         << 6;   // [ 7: 6]  Audio FIFO nominal level :0=s_total/4;1=s_total/8;2=s_total/16;3=s_total/32.
    data32 |= 3         << 4;   // [ 5: 4]  Audio FIFO critical level:0=s_total/4;1=s_total/8;2=s_total/16;3=s_total/32.
    data32 |= 0         << 3;   // [3]      afif_status_clr:1=Clear audio FIFO status to IDLE.
    data32 |= rx.ctrl.acr_mode  << 2;   // [2]      dig_acr_en
    data32 |= 0         << 1;   // [1]      audmeas_clk_sel: 0=select aud_pll_clk; 1=select aud_acr_clk.
    data32 |= rx.ctrl.acr_mode  << 0;   // [0]      aud_clk_sel: 0=select aud_pll_clk; 1=select aud_acr_clk.
    hdmirx_wr_top( HDMIRX_TOP_ACR_CNTL_STAT, data32);

    //hdmirx_wr_dwc( RA_AUDPLL_GEN_CTS, manual_acr_cts);
    //hdmirx_wr_dwc( RA_AUDPLL_GEN_N,   manual_acr_n);
#if 0
    // Force N&CTS to start with, will switch to received values later on, for simulation speed up.
    data32  = 0;
    data32 |= 1 << 4;   // [4]      cts_n_ref: 0=used decoded; 1=use manual N&CTS.
    hdmirx_wr_dwc( RA_AUD_CLK_CTRL,   data32);
#endif
    data32  = 0;
    data32 |= 0 << 28;  // [28]     pll_lock_filter_byp
    data32 |= 0 << 24;  // [27:24]  pll_lock_toggle_div
    hdmirx_wr_dwc( RA_AUD_PLL_CTRL,   data32);    // DEFAULT: {1'b0, 3'd0, 4'd6, 4'd3, 4'd8, 1'b0, 1'b0, 1'b1, 1'b0, 12'd0}


    data32  = 0;
    data32 |= 80    << 18;  // [26:18]  afif_th_start
    data32 |= 8     << 9;   // [17:9]   afif_th_max
    data32 |= 8     << 0;   // [8:0]    afif_th_min
    hdmirx_wr_dwc( RA_AUD_FIFO_TH,    data32);

    data32  = 0;
    data32 |= 1     << 16;  // [16]     afif_subpackets: 0=store all sp; 1=store only the ones' spX=1.
    data32 |= 0     << 0;   // [0]      afif_init
    hdmirx_wr_dwc( RA_AUD_FIFO_CTRL,  data32); // DEFAULT: {13'd0, 2'd0, 1'b1, 15'd0, 1'b0}

    data32  = 0;
    data32 |= (RX_8_CHANNEL? 0x7 :0x0)  << 8;   // [10:8]   ch_map[7:5]
    data32 |= 1                         << 7;   // [7]      ch_map_manual
    data32 |= (RX_8_CHANNEL? 0x1f:0x3)  << 2;   // [6:2]    ch_map[4:0]
    data32 |= 1                         << 0;   // [1:0]    aud_layout_ctrl:0/1=auto layout; 2=layout 0; 3=layout 1.
    hdmirx_wr_dwc( RA_AUD_CHEXTRA_CTRL,    data32); // DEFAULT: {24'd0, 1'b0, 5'd0, 2'd0}
#endif 
/* amlogic HDMIRX audio module enable*/
	WRITE_MPEG_REG(HHI_AUDCLK_PLL_CNTL,  0x60010000); 
	WRITE_MPEG_REG(HHI_AUDCLK_PLL_CNTL2, 0x814d3928);
	WRITE_MPEG_REG(HHI_AUDCLK_PLL_CNTL3, 0x6b425012);
	WRITE_MPEG_REG(HHI_AUDCLK_PLL_CNTL4, 0x101);
	WRITE_MPEG_REG(HHI_AUDCLK_PLL_CNTL5, 0x8550d20);
	if(rx.aud_info.audio_recovery_clock > (96000 + AUD_CLK_DELTA)){
		if(rx.ctrl.tmds_clk2 <= 36000000) {
			printk("tmds_clk2 <= 36000000\n");
			WRITE_MPEG_REG(HHI_AUDCLK_PLL_CNTL6, 0x55013000);
		} else if (rx.ctrl.tmds_clk2 <= 53000000) {
			printk("tmds_clk2 <= 53000000\n");
			WRITE_MPEG_REG(HHI_AUDCLK_PLL_CNTL6, 0x55053000);
		} else {
			printk("tmds_clk2 > 53000000\n");
			WRITE_MPEG_REG(HHI_AUDCLK_PLL_CNTL6, 0x55153000);
		}
	} else {
		printk("audio_recovery_clock > 98000\n");
		WRITE_MPEG_REG(HHI_AUDCLK_PLL_CNTL6, 0x55153000);
	}
	WRITE_MPEG_REG(HHI_AUDCLK_PLL_CNTL, 0x00010000);  //reset

/**/
#if 0
    WRITE_MPEG_REG(AUDIN_SOURCE_SEL,    (0  <<12)   | // [14:12]cntl_hdmirx_chsts_sel: 0=Report chan1 status; 1=Report chan2 status; ...; 7=Report chan8 status.
                            (0xf<<8)    | // [11:8] cntl_hdmirx_chsts_en
                            (1  <<4)    | // [5:4]  spdif_src_sel: 1=Select HDMIRX SPDIF output as AUDIN source
                            (2 << 0));    // [1:0]  i2sin_src_sel: 2=Select HDMIRX I2S output as AUDIN source
#endif
return err;
}
static void control_init_more(void)
{
#define VSYNC_POLARITY      1                       // TX VSYNC polarity: 0=low active; 1=high active.
   unsigned long   data32;

    data32  = 0;
    data32 |= 0                         << 13;  // [   13]  checksum_init_mode
    data32 |= EDID_AUTO_CHECKSUM_ENABLE << 12;  // [   12]  auto_checksum_enable
    data32 |= EDID_AUTO_CEC_ENABLE      << 11;  // [   11]  auto_cec_enable
    data32 |= 0                         << 10;  // [   10]  scl_stretch_trigger_config
    data32 |= 0                         << 9;   // [    9]  force_scl_stretch_trigger
    data32 |= 1                         << 8;   // [    8]  scl_stretch_enable
    data32 |= EDID_CLK_DIVIDE_M1 << 0;   // [ 7: 0]  clk_divide_m1
    hdmirx_wr_top(HDMIRX_TOP_EDID_GEN_CNTL,  data32);

#if 0    
    data32  = 0;
    data32 |= VSYNC_POLARITY    << 3;   // [4:3]    vs_pol_adj_mode:0=invert input VS; 1=no invert; 2=auto convert to high active; 3=no invert.
    data32 |= 2                 << 1;   // [2:1]    hs_pol_adj_mode:0=invert input VS; 1=no invert; 2=auto convert to high active; 3=no invert.
    hdmirx_wr_dwc( RA_HDMI_SYNC_CTRL,     data32); // DEFAULT: {27'd0, 2'd0, 2'd0, 1'b0}
#endif

#define interlace_mode 1    
    data32  = 0;
    data32 |= 1                 << 4;   // [4]      v_offs_lin_mode
    data32 |= 1                 << 1;   // [1]      v_edge
    data32 |= interlace_mode    << 0;   // [0]      v_mode
    hdmirx_wr_dwc( RA_MD_VCTRL,   data32); // DEFAULT: {27'd0, 1'b0, 2'd0, 1'b1, 1'b0}

    data32  = 0;
    data32 |= 0     << 20;  // [20]     rg_block_off:1=Enable HS/VS/CTRL filtering during active video
    data32 |= 1     << 19;  // [19]     block_off:1=Enable HS/VS/CTRL passing during active video
    data32 |= 5     << 16;  // [18:16]  valid_mode
    data32 |= 0     << 12;  // [13:12]  ctrl_filt_sens
    data32 |= 3     << 10;  // [11:10]  vs_filt_sens
    data32 |= 0     << 8;   // [9:8]    hs_filt_sens
    data32 |= 2     << 6;   // [7:6]    de_measure_mode
    data32 |= 0     << 5;   // [5]      de_regen
    data32 |= 3     << 3;   // [4:3]    de_filter_sens 
    hdmirx_wr_dwc( RA_HDMI_ERRORA_PROTECT, data32); // DEFAULT: {11'd0, 1'b0, 1'b0, 3'd0, 2'd0, 2'd0, 2'd0, 2'd0, 2'd0, 1'b0, 2'd0, 3'd0}

    data32  = 0;
    data32 |= 0     << 8;   // [10:8]   hact_pix_ith
    data32 |= 0     << 5;   // [5]      hact_pix_src
    data32 |= 1     << 4;   // [4]      htot_pix_src
    hdmirx_wr_dwc( RA_MD_HCTRL1,  data32); // DEFAULT: {21'd0, 3'd1, 2'd0, 1'b0, 1'b1, 4'd0}

    data32  = 0;
    data32 |= 1     << 12;  // [14:12]  hs_clk_ith
    data32 |= 7     << 8;   // [10:8]   htot32_clk_ith
    data32 |= 1     << 5;   // [5]      vs_act_time
    data32 |= 3     << 3;   // [4:3]    hs_act_time
    data32 |= 0     << 0;   // [1:0]    h_start_pos
    hdmirx_wr_dwc( RA_MD_HCTRL2,  data32); // DEFAULT: {17'd0, 3'd2, 1'b0, 3'd1, 2'd0, 1'b0, 2'd0, 1'b0, 2'd2}

    data32  = 0;
    data32 |= 1 << 10;  // [11:10]  vofs_lin_ith
    data32 |= 3 << 8;   // [9:8]    vact_lin_ith 
    data32 |= 0 << 6;   // [7:6]    vtot_lin_ith
    data32 |= 7 << 3;   // [5:3]    vs_clk_ith
    data32 |= 2 << 0;   // [2:0]    vtot_clk_ith
    hdmirx_wr_dwc( RA_MD_VTH,     data32); // DEFAULT: {20'd0, 2'd2, 2'd0, 2'd0, 3'd2, 3'd2}

    data32  = 0;
    data32 |= 1 << 2;   // [2]      fafielddet_en
    data32 |= 0 << 0;   // [1:0]    field_pol_mode
    hdmirx_wr_dwc( RA_MD_IL_POL,  data32); // DEFAULT: {29'd0, 1'b0, 2'd0}

    data32  = 0;
    data32 |= 0                 << 1;   // [4:1]    man_vid_derepeat
    data32 |= 1                 << 0;   // [0]      auto_derepeat
    hdmirx_wr_dwc( RA_HDMI_RESMPL_CTRL,   data32); // DEFAULT: {27'd0, 4'd0, 1'b1}
}