예제 #1
0
void rk616_hdcp_interrupt(char *status1, char *status2)
{
	int interrupt1 = 0;
	int interrupt2 = 0;
	int temp =0;
	hdmi_readl(HDCP_INT_STATUS1,&interrupt1);
	hdmi_readl(HDCP_INT_STATUS2,&interrupt2);
	if(interrupt1) {
		hdmi_writel(HDCP_INT_STATUS1, interrupt1);
		if(interrupt1 & m_INT_HDCP_ERR){
			hdmi_readl(HDCP_ERROR,&temp);
			printk(KERN_INFO "HDCP: Error reg 0x65 = 0x%02x\n", temp);
                        rk616_hdcp_error(temp); 
	                hdmi_writel(HDCP_ERROR, 0x00);
		}
	}
	if(interrupt2)
		hdmi_writel(HDCP_INT_STATUS2, interrupt2);
	
	*status1 = interrupt1;
	*status2 = interrupt2;

        hdmi_readl(HDCP_ERROR, &temp);
        DBG("HDCP: Error reg 0x65 = 0x%02x\n", temp);
}
예제 #2
0
void bsp_hdmi_set_video_en(unsigned char enable)
{
	if(enable)
		hdmi_writel(0x10020,hdmi_readl(0x10020)|(0xf<<12));
	else
		hdmi_writel(0x10020,hdmi_readl(0x10020)&(~(0xf<<12)));
}
예제 #3
0
void rk616_set_colorbar(int enable)
{
        static int display_mask = 0;
        int reg_value;
        if (enable) {
                if (!display_mask) {
                        if (hdmi->tmdsclk <= (HDMI_SYS_FREG_CLK << 2)) {
	                        hdmi_readl(SYS_CTRL, &reg_value);
                                hdmi_msk_reg(SYS_CTRL, m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_SYS);  
        	                hdmi_writel(HDMI_COLORBAR, 0x00);
                                hdmi_writel(SYS_CTRL, reg_value);
                        } else {
        	                hdmi_writel(HDMI_COLORBAR, 0x00);
                        }

                        display_mask = 1;
                }
        } else {
                if (display_mask) {

                        if (hdmi->tmdsclk <= (HDMI_SYS_FREG_CLK << 2)) {
	                        hdmi_readl(SYS_CTRL, &reg_value);
                                hdmi_msk_reg(SYS_CTRL, m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_SYS);  
                                hdmi_writel(HDMI_COLORBAR, 0x10);
                                hdmi_writel(SYS_CTRL, reg_value);
                        } else {
                                hdmi_writel(HDMI_COLORBAR, 0x10);
                        }

                        display_mask = 0;
                }
        }
}
int rk3036_hdcp_start_authentication(void)
{
	int temp;
	int retry = 0;
	int tmds_clk;

	tmds_clk = hdmi_dev->driver.tmdsclk;
	if (hdcp->keys == NULL) {
		HDCP_WARN("HDCP: key is not loaded\n");
		return HDCP_KEY_ERR;
	}
	if (rk3036_hdcp_key_check(hdcp->keys) == HDCP_KEY_INVALID) {
		HDCP_WARN("loaded HDCP key is incorrect\n");
		return HDCP_KEY_ERR;
	}
	if (tmds_clk > (HDMI_SYS_FREG_CLK << 2)) {
		/*Select TMDS CLK to configure regs*/
		hdmi_msk_reg(hdmi_dev, SYS_CTRL,
			     m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_TMDS);
	} else {
		hdmi_msk_reg(hdmi_dev, SYS_CTRL,
			     m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_SYS);
	}
	hdmi_writel(hdmi_dev, HDCP_TIMER_100MS, 0x28);
	hdmi_readl(hdmi_dev, HDCP_KEY_STATUS, &temp);
	while ((temp & m_KEY_READY) == 0) {
		if (retry > 1000) {
			HDCP_WARN("HDCP: loaded key error\n");
			return HDCP_KEY_ERR;
		}
		rk3036_hdcp_load_key2mem(hdcp->keys);
		msleep(1);
		hdmi_readl(hdmi_dev, HDCP_KEY_STATUS, &temp);
		retry++;
	}
	/*Config DDC bus clock: ddc_clk = reg_clk/4*(reg 0x4c 0x4b)*/
	retry = hdmi_dev->hclk_rate/(HDCP_DDC_CLK << 2);
	hdmi_writel(hdmi_dev, DDC_CLK_L, retry & 0xFF);
	hdmi_writel(hdmi_dev, DDC_CLK_H, (retry >> 8) & 0xFF);
	hdmi_writel(hdmi_dev, HDCP_CTRL2, 0x67);
	/*Enable interrupt*/
	hdmi_writel(hdmi_dev, HDCP_INT_MASK1,
		    m_INT_HDCP_ERR | m_INT_BKSV_READY | m_INT_BKSV_UPDATE |
		    m_INT_AUTH_SUCCESS | m_INT_AUTH_READY);
	hdmi_writel(hdmi_dev, HDCP_INT_MASK2, 0x00);
	/*Start authentication*/
	hdmi_msk_reg(hdmi_dev, HDCP_CTRL1,
		     m_AUTH_START | m_ENCRYPT_ENABLE | m_ADVANED_ENABLE |
		     m_AUTH_STOP | m_HDCP_RESET,
		     v_AUTH_START(1) | v_ENCRYPT_ENABLE(1) |
		     v_ADVANED_ENABLE(0) | v_AUTH_STOP(0) | v_HDCP_RESET(0));

	if (tmds_clk <= (HDMI_SYS_FREG_CLK << 2)) {
		hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_REG_CLK_SOURCE,
			     v_REG_CLK_SOURCE_TMDS);
	}
	return HDCP_OK;
}
예제 #5
0
int	rk616_hdcp_start_authentication(void)
{
	int temp;
	int retry = 0;

	if(hdcp->keys == NULL) {
		printk(KERN_ERR "HDCP: key is not loaded\n");
		return HDCP_KEY_ERR;
	}
	
	if(rk616_hdcp_key_check(hdcp->keys) == HDCP_KEY_INVALID){
		printk(KERN_ERR "loaded HDCP key is incorrect\n");
		return HDCP_KEY_ERR;
	}	

        if (hdmi->tmdsclk > (HDMI_SYS_FREG_CLK << 2)) {
        	// Select TMDS CLK to configure regs
	        hdmi_msk_reg(SYS_CTRL, m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_TMDS);
        }

	hdmi_readl(HDCP_KEY_STATUS,&temp);
	while( ( temp & m_KEY_READY) == 0 ) {
		if(retry > 1000) {
			printk(KERN_ERR "HDCP: loaded key error\n");
			return HDCP_KEY_ERR;
		}
		rk616_hdcp_load_key2mem(hdcp->keys);
		msleep(1);
		hdmi_readl(HDCP_KEY_STATUS,&temp);
                retry++;
	}
        
        // Config DDC bus clock: ddc_clk = reg_clk/4*(reg 0x4c 0x4b)
        retry = hdmi->tmdsclk/(HDCP_DDC_CLK << 2);
        hdmi_writel(DDC_CLK_L, retry & 0xFF);
        hdmi_writel(DDC_CLK_H, (retry >> 8) & 0xFF);
 
	hdmi_writel(HDCP_CTRL2, 0x77);
	
	//Enable interrupt
	hdmi_writel(HDCP_INT_MASK1, m_INT_HDCP_ERR | m_INT_BKSV_READY | m_INT_BKSV_UPDATE | m_INT_AUTH_SUCCESS | m_INT_AUTH_READY);
	 hdmi_writel(HDCP_INT_MASK2, 0x00);

	//Start authentication
	hdmi_msk_reg(HDCP_CTRL1, m_AUTH_START | m_ENCRYPT_ENABLE | m_ADVANED_ENABLE, v_AUTH_START(1) | v_ENCRYPT_ENABLE(1) | v_ADVANED_ENABLE(0));
	

        if (hdmi->tmdsclk <= (HDMI_SYS_FREG_CLK << 2)) {
                hdmi_msk_reg(SYS_CTRL, m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_TMDS);
        }
	return HDCP_OK;
}
int is_1b_03_test(void)
{
	int reg_value;
	int reg_val_1;

	hdmi_readl(hdmi_dev, 0x58, &reg_value);
	hdmi_readl(hdmi_dev, 0xc3, &reg_val_1);

	if (reg_value != 0) {
		if ((reg_val_1 & 0x40) == 0)
			return 1;
	}
	return 0;
}
예제 #7
0
static int rk3288_hdmi_read_phy(struct rk3288_hdmi_device *hdmi_dev, int reg_addr)
{
	int trytime = 2, i = 0, op_status = 0;
	int val = 0;

	mutex_lock(&hdmi_dev->int_mutex);
	hdmi_dev->phy_i2cm_int = 0;
	mutex_unlock(&hdmi_dev->int_mutex);

	while(trytime--) {
		hdmi_writel(hdmi_dev, PHY_I2CM_ADDRESS, reg_addr);
		hdmi_writel(hdmi_dev, PHY_I2CM_DATAI_1, 0x00);
		hdmi_writel(hdmi_dev, PHY_I2CM_DATAI_0, 0x00);
		hdmi_writel(hdmi_dev, PHY_I2CM_OPERATION, m_PHY_I2CM_READ);
#if 0
		i = 100;
		while(i--) {
			mutex_lock(&hdmi_dev->int_mutex);
			//op_status = hdmi_readl(hdmi_dev, PHY_I2CM_INT);
			op_status = hdmi_dev->phy_i2cm_int;
			hdmi_dev->phy_i2cm_int = 0;
			mutex_unlock(&hdmi_dev->int_mutex);
			if(op_status & (m_I2CMPHY_DONE | m_I2CMPHY_ERR)) {
				break;
			}
			msleep(10);
		}

		if(op_status & m_I2CMPHY_DONE) {
			*val = (hdmi_readl(hdmi_dev, PHY_I2CM_DATAI_1) >> 8) & 0xff;
			*val += (hdmi_readl(hdmi_dev, PHY_I2CM_DATAI_0) & 0xff);
			return 0;
		}
		else {
예제 #8
0
int rk3288_hdmi_detect_hotplug(struct hdmi *hdmi_drv)
{
	struct rk3288_hdmi_device *hdmi_dev = container_of(hdmi_drv, struct rk3288_hdmi_device, driver);
	u32 value = hdmi_readl(hdmi_dev, PHY_STAT0);

	hdmi_dbg(hdmi_drv->dev, "[%s] reg%x value %02x\n", __FUNCTION__, PHY_STAT0, value);

	if((value & m_PHY_HPD) || ((value & 0xf0) == 0xf0))
		return HDMI_HPD_ACTIVED;
	else
		return HDMI_HPD_REMOVED;
}
void rk3036_hdcp_interrupt(char *status1, char *status2)
{
	int interrupt1 = 0;
	int interrupt2 = 0;
	int temp = 0;
	int tmds_clk;

	tmds_clk = hdmi_dev->driver.tmdsclk;
	hdmi_readl(hdmi_dev, HDCP_INT_STATUS1, &interrupt1);
	hdmi_readl(hdmi_dev, HDCP_INT_STATUS2, &interrupt2);

	if (tmds_clk <= (HDMI_SYS_FREG_CLK << 2))
		hdmi_msk_reg(hdmi_dev, SYS_CTRL,
			     m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_SYS);

	if (interrupt1) {
		hdmi_writel(hdmi_dev, HDCP_INT_STATUS1, interrupt1);
		if (interrupt1 & m_INT_HDCP_ERR) {
			hdmi_readl(hdmi_dev, HDCP_ERROR, &temp);
			HDCP_WARN("HDCP: Error reg 0x65 = 0x%02x\n", temp);
			rk3036_hdcp_error(temp);
			hdmi_writel(hdmi_dev, HDCP_ERROR, temp);
		}
	}
	if (interrupt2)
		hdmi_writel(hdmi_dev, HDCP_INT_STATUS2, interrupt2);

	*status1 = interrupt1;
	*status2 = interrupt2;

	if (tmds_clk <= (HDMI_SYS_FREG_CLK << 2))
		hdmi_msk_reg(hdmi_dev, SYS_CTRL, m_REG_CLK_SOURCE,
			     v_REG_CLK_SOURCE_TMDS);
/*
	hdmi_readl(HDCP_ERROR, &temp);
	DBG("HDCP: Error reg 0x65 = 0x%02x\n", temp);
*/
}
void rk3036_set_colorbar(int enable)
{
	static int display_mask;
	int reg_value;
	int tmds_clk;

	tmds_clk = hdmi_dev->driver.tmdsclk;
	if (enable) {
		if (!display_mask) {
			if (tmds_clk <= (HDMI_SYS_FREG_CLK << 2)) {
				hdmi_readl(hdmi_dev, SYS_CTRL, &reg_value);
				hdmi_msk_reg(hdmi_dev, SYS_CTRL,
					     m_REG_CLK_SOURCE,
					     v_REG_CLK_SOURCE_SYS);
				hdmi_writel(hdmi_dev, HDMI_COLORBAR, 0x00);
				hdmi_writel(hdmi_dev, SYS_CTRL, reg_value);
			} else {
				hdmi_writel(hdmi_dev, HDMI_COLORBAR, 0x00);
			}
			display_mask = 1;
		}
	} else {
		if (display_mask) {
			if (tmds_clk <= (HDMI_SYS_FREG_CLK << 2)) {
				hdmi_readl(hdmi_dev, SYS_CTRL, &reg_value);
				hdmi_msk_reg(hdmi_dev, SYS_CTRL,
					     m_REG_CLK_SOURCE,
					     v_REG_CLK_SOURCE_SYS);
				hdmi_writel(hdmi_dev, HDMI_COLORBAR, 0x10);
				hdmi_writel(hdmi_dev, SYS_CTRL, reg_value);
			} else {
				hdmi_writel(hdmi_dev, HDMI_COLORBAR, 0x10);
			}
			display_mask = 0;
		}
	}
}
예제 #11
0
unsigned int bsp_hdmi_get_hpd()
{
	unsigned int ret = 0;

	hdmi_write(0x10010,0x45);
	hdmi_write(0x10011,0x45);
	hdmi_write(0x10012,0x52);
	hdmi_write(0x10013,0x54);

	if(hdmi_readl(0x10038)&0x80000)
		ret = 1;
	else
		ret = 0;

	hdmi_write(0x10010,0x52);
	hdmi_write(0x10011,0x54);
	hdmi_write(0x10012,0x41);
	hdmi_write(0x10013,0x57);

	return ret;
}
예제 #12
0
static int rk616_hdmi_reg_show(struct seq_file *s, void *v)
{
	int i = 0;
	u32 val = 0;
	seq_printf(s, "\n>>>rk616_ctl reg");
	for (i = 0; i < 16; i++) {
		seq_printf(s, " %2x", i);
	}
	seq_printf(s, "\n-----------------------------------------------------------------");
	
	for(i=0; i<= PHY_PRE_DIV_RATIO; i++) {
                hdmi_readl(i, &val);
		if(i%16==0)
			seq_printf(s,"\n>>>rk616_ctl %2x:", i);
		seq_printf(s," %02x",val);

	}
	seq_printf(s, "\n-----------------------------------------------------------------\n");
	
	return 0;
}
예제 #13
0
int	rk616_hdcp_check_bksv(void)
{
	int i, j;
	int temp = 0, bksv[5];
	char *invalidkey;
	
	for(i = 0; i < 5; i++) {
		hdmi_readl(HDCP_KSV_BYTE0 + (4 - i), &temp);
		bksv[i] = temp & 0xFF;
	}
	DBG("bksv is 0x%02x%02x%02x%02x%02x", bksv[0], bksv[1], bksv[2], bksv[3], bksv[4]);
	
	temp = 0; 	
	for (i = 0; i < 5; i++)
	{
    	for (j = 0; j < 8; j++)
    	{
    		if (bksv[i] & 0x01)
    		{
        		temp++;
    		}
    		bksv[i] >>= 1;
    	}
 	}
 	if (temp != 20)
    	return HDCP_KSV_ERR;
	
	for(i = 0; i < hdcp->invalidkey; i++)
	{
		invalidkey = hdcp->invalidkeys + i *5;
		if(memcmp(bksv, invalidkey, 5) == 0) {
			printk(KERN_ERR "HDCP: BKSV was revocated!!!\n");
			hdmi_msk_reg(HDCP_CTRL1, m_BKSV_INVALID | m_ENCRYPT_ENABLE, v_BKSV_INVALID(1) | v_ENCRYPT_ENABLE(1));
			return HDCP_KSV_ERR;
		}
	}
	hdmi_msk_reg(HDCP_CTRL1, m_BKSV_VALID | m_ENCRYPT_ENABLE, v_BKSV_VALID(1) | v_ENCRYPT_ENABLE(1));
	return HDCP_OK;
}
void rk3036_hdcp_disable(void)
{
	int reg_value;
	int tmds_clk;

	tmds_clk = hdmi_dev->driver.tmdsclk;
	if (tmds_clk <= (HDMI_SYS_FREG_CLK << 2)) {
		hdmi_readl(hdmi_dev, SYS_CTRL, &reg_value);
		hdmi_msk_reg(hdmi_dev, SYS_CTRL,
			     m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_SYS);
	}

	/* Diable HDCP Interrupt*/
	hdmi_writel(hdmi_dev, HDCP_INT_MASK1, 0x00);
	/* Stop and Reset HDCP*/
	hdmi_msk_reg(hdmi_dev, HDCP_CTRL1,
		     m_AUTH_START | m_AUTH_STOP | m_HDCP_RESET,
		     v_AUTH_START(0) | v_AUTH_STOP(1) | v_HDCP_RESET(1));

	if (tmds_clk <= (HDMI_SYS_FREG_CLK << 2))
		hdmi_writel(hdmi_dev, SYS_CTRL, reg_value);
}
예제 #15
0
static int hdmi_phy_set(struct video_para *video)
{
	unsigned int id;
	unsigned int tmp;

	id = get_vid(video->vic);
	hdmi_writel(0x10020,hdmi_readl(0x10020)&(~0xf000));
	switch(ptbl[id].para[1])
	{
		case 1:
			hdmi_writel(0x1002c,0x39dc5fc0);
			hdmi_writel(0x10030,0x800843c0);
			hdmi_udelay(10000);
			hdmi_writel(0x10034,0x00000001);
			hdmi_writel(0x1002c,hdmi_readl(0x1002c)|0x02000000);
			hdmi_udelay(100000);
			tmp = hdmi_readl(0x10038);
			hdmi_writel(0x1002c,hdmi_readl(0x1002c)|0xC0000000);
			hdmi_writel(0x1002c,hdmi_readl(0x1002c)|((tmp&0x1f800)>>11));
			hdmi_writel(0x10020,0x00FFFF7F);
			hdmi_writel(0x10024,0x80639000);
			hdmi_writel(0x10028,0x0F8246B5);
			break;
		case 2:
			hdmi_writel(0x1002c,0x39dc5040);
			hdmi_writel(0x10030,0x80084381);
			hdmi_udelay(10000);
			hdmi_writel(0x10034,0x00000001);
			hdmi_writel(0x1002c,0x3bdc5040);
			hdmi_udelay(100000);
			tmp = hdmi_readl(0x10038);
			hdmi_writel(0x1002c,0xfbdc5040);
			hdmi_writel(0x1002c,hdmi_readl(0x1002c)|((tmp&0x1f800)>>11));
			hdmi_writel(0x10020,0x00FFFF7F);
			hdmi_writel(0x10024,0x80639000);
			hdmi_writel(0x10028,0x0F81C485);
			break;
		case 4:
			hdmi_writel(0x1002c,0x39dc5040);
			hdmi_writel(0x10030,0x80084343);
			hdmi_udelay(100000);
			hdmi_writel(0x10034,0x00000001);
			hdmi_writel(0x1002c,0x3bdc5040);
			hdmi_udelay(50000);
			tmp = hdmi_readl(0x10038);
			hdmi_writel(0x1002c,0xfbdc5040);
			hdmi_writel(0x1002c,hdmi_readl(0x1002c)|((tmp&0x1f800)>>11));
			hdmi_writel(0x10020,0x00FFFF7F);
			hdmi_writel(0x10024,0x80639000);
			hdmi_writel(0x10028,0x0F81C405);
			break;
		case 11:
			hdmi_writel(0x1002c,0x39dc5040);
			hdmi_writel(0x10030,0x8008430a);
			hdmi_udelay(10000);
			hdmi_writel(0x10034,0x00000001);
			hdmi_writel(0x1002c,0x3bdc5040);
			hdmi_udelay(100000);
			tmp = hdmi_readl(0x10038);
			hdmi_writel(0x1002c,0xfbdc5040);
			hdmi_writel(0x1002c,hdmi_readl(0x1002c)|((tmp&0x1f800)>>11));
			hdmi_writel(0x10020,0x00FFFF7F);
			hdmi_writel(0x10024,0x80639000);
			hdmi_writel(0x10028,0x0F81C405);
			break;
		default:
			return -1;
	}
	return 0;
}
예제 #16
0
static void hdmi_phy_init(struct video_para *video)
{
	unsigned int to_cnt;
	unsigned int tmp;

	hdmi_writel(0x10020,0);
	hdmi_writel(0x10020,(1<<0));
	hdmi_udelay(5);
	hdmi_writel(0x10020,hdmi_readl(0x10020)|(1<<16));
	hdmi_writel(0x10020,hdmi_readl(0x10020)|(1<<1));
	hdmi_udelay(10);
	hdmi_writel(0x10020,hdmi_readl(0x10020)|(1<<2));
	hdmi_udelay(5);
	hdmi_writel(0x10020,hdmi_readl(0x10020)|(1<<3));
	hdmi_udelay(40);
	hdmi_writel(0x10020,hdmi_readl(0x10020)|(1<<19));
	hdmi_udelay(100);
	hdmi_writel(0x10020,hdmi_readl(0x10020)|(1<<18));
	hdmi_writel(0x10020,hdmi_readl(0x10020)|(7<<4));
	to_cnt = 10;
	while(1)
	{
		if( (hdmi_readl(0x10038)&0x80) == 0x80 )
			break;
		hdmi_udelay(200);

		to_cnt--;
		if(to_cnt == 0) {
			__wrn("%s, timeout\n", __func__);
			break;
		}
	}
	hdmi_writel(0x10020,hdmi_readl(0x10020)|(0xf<<8));
//	hdmi_writel(0x10020,hdmi_readl(0x10020)&(~(1<<19)));
	hdmi_writel(0x10020,hdmi_readl(0x10020)|(1<<7));
//	hdmi_writel(0x10020,hdmi_readl(0x10020)|(0xf<<12));

	hdmi_writel(0x1002c,0x39dc5040);
	hdmi_writel(0x10030,0x80084343);
	hdmi_udelay(10000);
	hdmi_writel(0x10034,0x00000001);
	hdmi_writel(0x1002c,0x3bdc5040);
	hdmi_udelay(100000);
	tmp = hdmi_readl(0x10038);
	hdmi_writel(0x1002c,0xfbdc5040);
	hdmi_writel(0x1002c,hdmi_readl(0x1002c)|((tmp&0x1f800)>>11));
	hdmi_writel(0x10020,0x00FF0F7F);
	hdmi_writel(0x10024,0x80629000);
	hdmi_writel(0x10028,0x0f820505);
}
예제 #17
0
int rk3288_hdmi_read_edid(struct hdmi *hdmi_drv, int block, unsigned char *buff)
{
	int i = 0, n = 0, index = 0, ret = -1, trytime = 2;
	int offset = (block % 2) * 0x80;
	//int interrupt = 0;
	//unsigned long flags;
	struct rk3288_hdmi_device *hdmi_dev = container_of(hdmi_drv, struct rk3288_hdmi_device, driver);

	hdmi_dbg(hdmi_drv->dev, "[%s] block %d\n", __FUNCTION__, block);
	//spin_lock_irqsave(&hdmi_drv->irq_lock, flags);
	hdmi_dev->i2cm_int = 0;
	//spin_unlock_irqrestore(&hdmi_drv->irq_lock, flags);

	//Set DDC I2C CLK which devided from DDC_CLK to 100KHz.
	hdmi_writel(hdmi_dev, I2CM_SS_SCL_HCNT_0_ADDR, 0x7a);
	hdmi_writel(hdmi_dev, I2CM_SS_SCL_LCNT_0_ADDR, 0x8d);
	hdmi_msk_reg(hdmi_dev, I2CM_DIV, m_I2CM_FAST_STD_MODE, v_I2CM_FAST_STD_MODE(STANDARD_MODE));	//Set Standard Mode

	//Enable I2C interrupt for reading edid
	hdmi_writel(hdmi_dev, IH_MUTE_I2CM_STAT0, v_SCDC_READREQ_MUTE(0) | v_I2CM_DONE_MUTE(0) | v_I2CM_ERR_MUTE(0));
	hdmi_msk_reg(hdmi_dev, I2CM_INT, m_I2CM_DONE_MASK, v_I2CM_DONE_MASK(0));
	hdmi_msk_reg(hdmi_dev, I2CM_CTLINT, m_I2CM_NACK_MASK | m_I2CM_ARB_MASK, v_I2CM_NACK_MASK(0) | v_I2CM_ARB_MASK(0));

	hdmi_writel(hdmi_dev, I2CM_SLAVE, DDC_I2C_EDID_ADDR);
	hdmi_writel(hdmi_dev, I2CM_SEGADDR, DDC_I2C_SEG_ADDR);
	hdmi_writel(hdmi_dev, I2CM_SEGPTR, block / 2);
	while(trytime--) {
		for(n = 0; n < HDMI_EDID_BLOCK_SIZE / 8; n++) {
			hdmi_writel(hdmi_dev, I2CM_ADDRESS, offset + 8 * n);
			//enable extend sequential read operation
			if(block == 0)
				hdmi_msk_reg(hdmi_dev, I2CM_OPERATION, m_I2CM_RD8, v_I2CM_RD8(1));
			else
				hdmi_msk_reg(hdmi_dev, I2CM_OPERATION, m_I2CM_RD8_EXT, v_I2CM_RD8_EXT(1));
#if 0
			i = 200;
			while(i--)
			{
				//spin_lock_irqsave(&hdmi_drv->irq_lock, flags);
				interrupt = hdmi_dev->i2cm_int;
				hdmi_dev->i2cm_int = 0;
				//spin_unlock_irqrestore(&hdmi_drv->irq_lock, flags);
				if(interrupt & (m_SCDC_READREQ | m_I2CM_DONE | m_I2CM_ERROR))
					break;
				msleep(5);
			}

			if((i == 0) || (interrupt & m_I2CM_ERROR)) {
				hdmi_err(hdmi_drv->dev, "[%s] edid read error\n", __FUNCTION__);
				rk3288_hdmi_i2cm_reset(hdmi_dev);
				break;
			}
#endif
			//if(interrupt & m_I2CM_DONE)
			{
				msleep(1);
				for(index = 0; index < 8; index++) {
					buff[8 * n + index] = hdmi_readl(hdmi_dev, I2CM_READ_BUFF0 + index);
				}

				if(n == HDMI_EDID_BLOCK_SIZE / 8 - 1) {
					ret = 0;
					hdmi_dbg(hdmi_drv->dev, "[%s] edid read sucess\n", __FUNCTION__);

				#ifdef HDMI_DEBUG
					for(i = 0; i < 128; i++) {
						printk("%02x ,", buff[i]);
						if( (i + 1) % 16 == 0)
							printk("\n");
					}
				#endif
					goto exit;
				}
			}
		}

		hdmi_err(hdmi_drv->dev, "[%s] edid try times %d\n", __FUNCTION__, trytime);
		msleep(100);
	}

exit:
	//Disable I2C interrupt
	hdmi_msk_reg(hdmi_dev, IH_MUTE_I2CM_STAT0, m_I2CM_DONE_MUTE | m_I2CM_ERR_MUTE, v_I2CM_DONE_MUTE(1) | v_I2CM_ERR_MUTE(1));
	hdmi_msk_reg(hdmi_dev, I2CM_INT, m_I2CM_DONE_MASK, v_I2CM_DONE_MASK(1));
	hdmi_msk_reg(hdmi_dev, I2CM_CTLINT, m_I2CM_NACK_MASK | m_I2CM_ARB_MASK, v_I2CM_NACK_MASK(1) | v_I2CM_ARB_MASK(1));
	return ret;
}