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, ®_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, ®_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; }
static void rk3288_hdmi_av_mute(struct hdmi *hdmi_drv, int enable) { struct rk3288_hdmi_device *hdmi_dev = container_of(hdmi_drv, struct rk3288_hdmi_device, driver); hdmi_msk_reg(hdmi_dev, FC_GCP, m_FC_SET_AVMUTE, v_FC_SET_AVMUTE(enable)); #if 0 /* audio mute priority: AVMUTE, sample flat, validity */ /* AVMUTE also mutes video */ value = enable ? 0xF : 0; hdmi_msk_reg(hdmi_dev, FC_AUDSCONF, m_AUD_PACK_SAMPFIT, v_AUD_PACK_SAMPFIT(value)); #endif }
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; }
void rk616_hdcp_disable(void) { // Diable HDCP Interrupt hdmi_writel(HDCP_INT_MASK1, 0x00); // Stop and Reset HDCP hdmi_msk_reg(HDCP_CTRL1, m_ENCRYPT_ENABLE | m_AUTH_STOP | m_HDCP_RESET, v_ENCRYPT_ENABLE(0) | v_AUTH_STOP(1) | v_HDCP_RESET(1) ); }
int rk616_hdcp_stop_authentication(void) { hdmi_msk_reg(SYS_CTRL, m_REG_CLK_SOURCE, v_REG_CLK_SOURCE_SYS); hdmi_writel(DDC_CLK_L, 0x1c); hdmi_writel(DDC_CLK_H, 0x00); hdmi_writel(HDCP_CTRL2, 0x08); hdmi_writel(HDCP_INT_MASK2, 0x06); hdmi_writel(HDCP_CTRL1, 0x02); return 0; //hdmi_writel(HDCP_CTRL1, 0x0a); }
static int rk3288_hdmi_video_forceOutput(struct hdmi *hdmi_drv, char enable) { struct rk3288_hdmi_device *hdmi_dev = container_of(hdmi_drv, struct rk3288_hdmi_device, driver); hdmi_msk_reg(hdmi_dev, FC_DBGFORCE, m_FC_FORCEAUDIO, v_FC_FORCEAUDIO(0)); if(enable) { /*Force output Blue*/ hdmi_writel(hdmi_dev, FC_DBGTMDS2, 0x00); /*R*/ hdmi_writel(hdmi_dev, FC_DBGTMDS1, 0x00); /*G*/ hdmi_writel(hdmi_dev, FC_DBGTMDS0, 0xff); /*B*/ hdmi_msk_reg(hdmi_dev, FC_DBGFORCE, m_FC_FORCEVIDEO, v_FC_FORCEVIDEO(1)); } else { hdmi_msk_reg(hdmi_dev, FC_DBGFORCE, m_FC_FORCEVIDEO, v_FC_FORCEVIDEO(0)); hdmi_writel(hdmi_dev, FC_DBGTMDS2, 0x00); /*R*/ hdmi_writel(hdmi_dev, FC_DBGTMDS1, 0x00); /*G*/ hdmi_writel(hdmi_dev, FC_DBGTMDS0, 0x00); /*B*/ } return 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, ®_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); }
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, ®_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, ®_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; } } }
static void rk3288_hdmi_set_pwr_mode(struct hdmi *hdmi_drv, int mode) { struct rk3288_hdmi_device *hdmi_dev = container_of(hdmi_drv, struct rk3288_hdmi_device, driver); if(hdmi_drv->pwr_mode == mode) return; dev_printk(KERN_INFO, hdmi_drv->dev, "%s change pwr_mode %d --> %d\n", __FUNCTION__, hdmi_drv->pwr_mode, mode); switch(mode) { case NORMAL: hdmi_writel(hdmi_dev, MC_CLKDIS, 0x00); break; case LOWER_PWR: //hdmi_msk_reg(hdmi_dev, MC_CLKDIS, m_AUDCLK_DISABLE | m_PREPCLK_DISABLE | m_TMDSCLK_DISABLE | m_PIXELCLK_DISABLE, //v_AUDCLK_DISABLE(1) | v_PREPCLK_DISABLE(1) | v_TMDSCLK_DISABLE(1) | v_PIXELCLK_DISABLE(1)); hdmi_msk_reg(hdmi_dev, PHY_CONF0, m_TMDS_EN | m_TXPWRON_SIG | m_ENHPD_RXSENSE_SIG, v_TMDS_EN(0) | v_TXPWRON_SIG(0) | v_ENHPD_RXSENSE_SIG(1)); break; default: hdmi_dbg(hdmi_drv->dev, "unkown hdmi pwr mode %d\n",mode); } hdmi_drv->pwr_mode = mode; }
//i2c master reset void rk3288_hdmi_i2cm_reset(struct rk3288_hdmi_device *hdmi_dev) { hdmi_msk_reg(hdmi_dev, I2CM_SOFTRSTZ, m_I2CM_SOFTRST, v_I2CM_SOFTRST(0)); udelay(100); }
int rk3288_hdmi_video_sampler(struct hdmi *hdmi_drv, struct hdmi_video_para *vpara) { int map_code = 0; struct rk3288_hdmi_device *hdmi_dev = container_of(hdmi_drv, struct rk3288_hdmi_device, driver); if (vpara->input_color == VIDEO_INPUT_COLOR_RGB || vpara->input_color == VIDEO_INPUT_COLOR_YCBCR444 || vpara->input_color == VIDEO_INPUT_COLOR_YCBCR420) { switch (vpara->color_depth) { case HDMI_COLOR_DEPTH_8BIT: map_code = VIDEO_RGB444_8BIT; break; case HDMI_COLOR_DEPTH_10BIT: map_code = VIDEO_RGB444_10BIT; break; case HDMI_COLOR_DEPTH_12BIT: map_code = VIDEO_RGB444_12BIT; break; case HDMI_COLOR_DEPTH_16BIT: map_code = VIDEO_RGB444_16BIT; break; default: map_code = VIDEO_RGB444_8BIT; break; } map_code += (vpara->input_color == VIDEO_INPUT_COLOR_YCBCR444) ? 8 : 0; } else if (vpara->input_color == VIDEO_INPUT_COLOR_YCBCR422) { /* YCC422 mapping is discontinued - only map 1 is supported */ switch (vpara->color_depth) { case HDMI_COLOR_DEPTH_8BIT: map_code = VIDEO_YCBCR422_8BIT; break; case HDMI_COLOR_DEPTH_10BIT: map_code = VIDEO_YCBCR422_10BIT; break; case HDMI_COLOR_DEPTH_12BIT: map_code = VIDEO_YCBCR422_12BIT; break; default: map_code = VIDEO_YCBCR422_8BIT; break; } } else { hdmi_err(hdmi_drv->dev, "invalid input color type: %d", vpara->input_color); return -1; } //Set Data enable signal from external and set video sample input mapping hdmi_msk_reg(hdmi_dev, TX_INVID0, m_INTERNAL_DE_GEN | m_VIDEO_MAPPING, v_INTERNAL_DE_GEN(0) | v_VIDEO_MAPPING(map_code)); #if defined(HDMI_VIDEO_STUFFING) hdmi_writel(hdmi_dev, TX_GYDATA0, 0x00); hdmi_writel(hdmi_dev, TX_GYDATA1, 0x00); hdmi_msk_reg(hdmi_dev, TX_INSTUFFING, m_GYDATA_STUFF, v_GYDATA_STUFF(1)); hdmi_writel(hdmi_dev, TX_RCRDATA0, 0x00); hdmi_writel(hdmi_dev, TX_RCRDATA1, 0x00); hdmi_msk_reg(hdmi_dev, TX_INSTUFFING, m_RCRDATA_STUFF, v_RCRDATA_STUFF(1)); hdmi_writel(hdmi_dev, TX_BCBDATA0, 0x00); hdmi_writel(hdmi_dev, TX_BCBDATA1, 0x00); hdmi_msk_reg(hdmi_dev, TX_INSTUFFING, m_BCBDATA_STUFF, v_BCBDATA_STUFF(1)); #endif return 0; }
static int rk3288_hdmi_video_packetizer(struct hdmi *hdmi_drv, struct hdmi_video_para *vpara) { unsigned char color_depth = 0; unsigned char output_select = 0; unsigned char remap_size = 0; struct rk3288_hdmi_device *hdmi_dev = container_of(hdmi_drv, struct rk3288_hdmi_device, driver); if (vpara->output_color == VIDEO_OUTPUT_RGB444 || vpara->output_color == VIDEO_OUTPUT_YCBCR444 || vpara->output_color == VIDEO_OUTPUT_YCBCR420) { switch (vpara->color_depth) { case HDMI_COLOR_DEPTH_8BIT: color_depth = COLOR_DEPTH_24BIT; output_select = OUT_FROM_8BIT_BYPASS; break; case HDMI_COLOR_DEPTH_10BIT: color_depth = COLOR_DEPTH_30BIT; output_select = OUT_FROM_PIXEL_PACKING; break; case HDMI_COLOR_DEPTH_12BIT: color_depth = COLOR_DEPTH_36BIT; output_select = OUT_FROM_PIXEL_PACKING; break; case HDMI_COLOR_DEPTH_16BIT: color_depth = COLOR_DEPTH_48BIT; output_select = OUT_FROM_PIXEL_PACKING; break; default: color_depth = COLOR_DEPTH_24BIT; output_select = OUT_FROM_8BIT_BYPASS; break; } /*Config Color Depth*/ hdmi_msk_reg(hdmi_dev, VP_PR_CD, m_COLOR_DEPTH, v_COLOR_DEPTH(color_depth)); } else if (vpara->output_color == VIDEO_OUTPUT_YCBCR422) { switch (vpara->color_depth) { case HDMI_COLOR_DEPTH_8BIT: remap_size = YCC422_16BIT; break; case HDMI_COLOR_DEPTH_10BIT: remap_size = YCC422_20BIT; break; case HDMI_COLOR_DEPTH_12BIT: remap_size = YCC422_24BIT; break; default: remap_size = YCC422_16BIT; break; } output_select = OUT_FROM_YCC422_REMAP; /*Config remap size for the different color Depth*/ hdmi_msk_reg(hdmi_dev, VP_REMAP, m_YCC422_SIZE, v_YCC422_SIZE(remap_size)); } else { hdmi_err(hdmi_drv->dev, "invalid output color type: %d", vpara->output_color); return -1; } /*Config pixel repettion*/ hdmi_msk_reg(hdmi_dev, VP_PR_CD, m_DESIRED_PR_FACTOR, v_DESIRED_PR_FACTOR(vpara->pixel_repet)); if (vpara->pixel_repet > 0) hdmi_msk_reg(hdmi_dev, VP_CONF, m_PIXEL_REPET_EN | m_BYPASS_SEL, v_PIXEL_REPET_EN(1) | v_BYPASS_SEL(0)); else hdmi_msk_reg(hdmi_dev, VP_CONF, m_PIXEL_REPET_EN | m_BYPASS_SEL, v_PIXEL_REPET_EN(0) | v_BYPASS_SEL(1)); /*config output select*/ if (output_select == OUT_FROM_PIXEL_PACKING) { /* pixel packing */ hdmi_msk_reg(hdmi_dev, VP_CONF, m_BYPASS_EN | m_PIXEL_PACK_EN | m_YCC422_EN | m_OUTPUT_SEL, v_BYPASS_EN(0) | v_PIXEL_PACK_EN(1) | v_YCC422_EN(0) | v_OUTPUT_SEL(output_select)); } else if (output_select == OUT_FROM_YCC422_REMAP) { /* YCC422 */ hdmi_msk_reg(hdmi_dev, VP_CONF, m_BYPASS_EN | m_PIXEL_PACK_EN | m_YCC422_EN | m_OUTPUT_SEL, v_BYPASS_EN(0) | v_PIXEL_PACK_EN(0) | v_YCC422_EN(1) | v_OUTPUT_SEL(output_select)); } else if (output_select == OUT_FROM_8BIT_BYPASS || output_select == 3) { /* bypass */ hdmi_msk_reg(hdmi_dev, VP_CONF, m_BYPASS_EN | m_PIXEL_PACK_EN | m_YCC422_EN | m_OUTPUT_SEL, v_BYPASS_EN(1) | v_PIXEL_PACK_EN(0) | v_YCC422_EN(0) | v_OUTPUT_SEL(output_select)); } #if defined(HDMI_VIDEO_STUFFING) /* YCC422 and pixel packing stuffing*/ hdmi_msk_reg(hdmi_dev, VP_STUFF, m_PR_STUFFING, v_PR_STUFFING(1)); hdmi_msk_reg(hdmi_dev, VP_STUFF, m_YCC422_STUFFING | m_PP_STUFFING, v_YCC422_STUFFING(1) | v_PP_STUFFING(1)); #endif return 0; }
static int rk3288_hdmi_video_frameComposer(struct hdmi *hdmi_drv, struct hdmi_video_para *vpara) //TODO Daisen wait to add support 3D { int h_act = 0, v_act = 0; int h_syncdelay = 0, v_syncdelay = 0; int h_sync = 0, v_sync = 0; int h_blank = 0, v_blank = 0; int vsync_pol = hdmi_drv->lcdc->cur_screen->pin_vsync; int hsync_pol = hdmi_drv->lcdc->cur_screen->pin_hsync; int de_pol = (hdmi_drv->lcdc->cur_screen->pin_den == 0) ? 1 : 0; struct fb_videomode *mode = NULL; struct rk3288_hdmi_device *hdmi_dev = container_of(hdmi_drv, struct rk3288_hdmi_device, driver); mode = (struct fb_videomode *)hdmi_vic_to_videomode(vpara->vic); if(mode == NULL) { hdmi_err(hdmi_drv->dev, "[%s] not found vic %d\n", __FUNCTION__, vpara->vic); return -ENOENT; } hdmi_drv->pixclock = mode->pixclock; switch(vpara->color_depth) { case HDMI_COLOR_DEPTH_8BIT: hdmi_drv->tmdsclk = mode->pixclock; break; case HDMI_COLOR_DEPTH_10BIT: hdmi_drv->tmdsclk = mode->pixclock * 10 / 8; break; case HDMI_COLOR_DEPTH_12BIT: hdmi_drv->tmdsclk = mode->pixclock * 12 / 8; break; case HDMI_COLOR_DEPTH_16BIT: hdmi_drv->tmdsclk = mode->pixclock * 2; break; default: hdmi_drv->tmdsclk = mode->pixclock; break; } rk3288_hdmi_config_phy(hdmi_drv, vpara->pixel_repet, vpara->color_depth); hdmi_msk_reg(hdmi_dev, A_HDCPCFG0, m_ENCRYPT_BYPASS | m_HDMI_DVI, v_ENCRYPT_BYPASS(1) | v_HDMI_DVI(vpara->output_mode)); //cfg to bypass hdcp data encrypt hdmi_msk_reg(hdmi_dev, FC_INVIDCONF, m_FC_VSYNC_POL | m_FC_HSYNC_POL | m_FC_DE_POL | m_FC_HDMI_DVI | m_FC_INTERLACE_MODE, v_FC_VSYNC_POL(vsync_pol) | v_FC_HSYNC_POL(hsync_pol) | v_FC_DE_POL(de_pol) | v_FC_HDMI_DVI(vpara->output_mode) | v_FC_INTERLACE_MODE(mode->vmode)); hdmi_msk_reg(hdmi_dev, FC_INVIDCONF, m_FC_VBLANK, v_FC_VBLANK(mode->vmode)); h_act = mode->xres; hdmi_writel(hdmi_dev, FC_INHACTIV1, v_FC_HACTIVE1(h_act >> 8)); hdmi_writel(hdmi_dev, FC_INHACTIV0, (h_act & 0xff)); v_act = mode->yres; hdmi_writel(hdmi_dev, FC_INVACTIV1, v_FC_VACTIVE1(v_act >> 8)); hdmi_writel(hdmi_dev, FC_INVACTIV0, (v_act & 0xff)); h_blank = mode->hsync_len + mode->left_margin + mode->right_margin; hdmi_writel(hdmi_dev, FC_INHBLANK1, v_FC_HBLANK1(h_blank >> 8)); hdmi_writel(hdmi_dev, FC_INHBLANK0, (h_blank & 0xff)); v_blank = mode->vsync_len + mode->upper_margin + mode->lower_margin; hdmi_writel(hdmi_dev, FC_INVBLANK, (v_blank & 0xff)); h_syncdelay = mode->right_margin; hdmi_writel(hdmi_dev, FC_HSYNCINDELAY1, v_FC_HSYNCINDEAY1(h_syncdelay >> 8)); hdmi_writel(hdmi_dev, FC_HSYNCINDELAY0, (h_syncdelay & 0xff)); v_syncdelay = mode->lower_margin; hdmi_writel(hdmi_dev, FC_VSYNCINDELAY, (v_syncdelay & 0xff)); h_sync = mode->hsync_len; hdmi_writel(hdmi_dev, FC_HSYNCINWIDTH1, v_FC_HSYNCWIDTH1(h_sync >> 8)); hdmi_writel(hdmi_dev, FC_HSYNCINWIDTH0, (h_sync & 0xff)); v_sync = mode->vsync_len; hdmi_writel(hdmi_dev, FC_VSYNCINWIDTH, (v_sync & 0xff)); /*Set the control period minimum duration(min. of 12 pixel clock cycles, refer to HDMI 1.4b specification)*/ hdmi_writel(hdmi_dev, FC_CTRLDUR, 12); hdmi_writel(hdmi_dev, FC_EXCTRLDUR, 32); #if 0 if(hdmi_drv->tmdsclk > 340000000) { //used for HDMI 2.0 TX //TODO Daisen wait to modify HDCP KEEPOUT hdmi_msk_reg(hdmi_dev, FC_INVIDCONF, m_FC_HDCP_KEEPOUT, v_FC_HDCP_KEEPOUT(1)); hdmi_msk_reg(hdmi_dev, FC_SCRAMBLER_CTRL, m_FC_SCRAMBLE_EN, v_FC_SCRAMBLE_EN(1)); } /* spacing < 256^2 * config / tmdsClock, spacing <= 50ms * worst case: tmdsClock == 25MHz => config <= 19 */ hdmi_writel(hdmi_dev, FC_EXCTRLSPAC, 1); /*Set PreambleFilter*/ for (i = 0; i < 3; i++) { value = (i + 1) * 11; if (i == 0) /*channel 0*/ hdmi_writel(hdmi_dev, FC_CH0PREAM, value); else if (i == 1) /*channel 1*/ hdmi_writel(hdmi_dev, FC_CH1PREAM, value & 0x3f); else if (i == 2) /*channel 2*/ hdmi_writel(hdmi_dev, FC_CH2PREAM, value & 0x3f); } #endif /*Set PixelRepetition:No pixel repetition*/ hdmi_writel(hdmi_dev, FC_PRCONF, v_FC_PR_FACTOR(vpara->pixel_repet + 1)); return 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; }