From: Nickey Yang Date: Tue, 21 Feb 2017 06:34:52 +0000 (+0800) Subject: drm: bridge/dw_hdmi: Add scdc operations for HDMI2.0 X-Git-Tag: firefly_0821_release~503 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=ed58c4b7ebba72530ca1193366256f1d62a658ac;p=firefly-linux-kernel-4.4.55.git drm: bridge/dw_hdmi: Add scdc operations for HDMI2.0 This patch do the following operation with scdc: 1、TMDS Configuration set TMDS_Bit_Clock_Ratio bit when supports TMDS Bit Rates above 3.4 Gbps (details see HDMI2.0 Specification Section 6.1.3.2) 2、Scrambling Control set Scrambling_Enable bit when it needs. (details see HDMI2.0 Specification Section 6.1.3.1) Change-Id: Ibd4428bdf752d767caf9dd4e03f3c8d240f18f6b Signed-off-by: Nickey Yang --- diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c index 40e183d88068..50001c6fba6f 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/dw-hdmi.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #ifdef CONFIG_SWITCH #include @@ -1065,7 +1066,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, unsigned char res, int cscon) { unsigned res_idx; - u8 val, msec; + u8 val, msec, tmds_cfg; const struct dw_hdmi_plat_data *pdata = hdmi->plat_data; const struct dw_hdmi_mpll_config *mpll_config = pdata->mpll_cfg; const struct dw_hdmi_curr_ctrl *curr_ctrl = pdata->cur_ctr; @@ -1127,6 +1128,16 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, /* gen2 pddq */ dw_hdmi_phy_gen2_pddq(hdmi, 1); + /* Control for TMDS Bit Period/TMDS Clock-Period Ratio */ + if (hdmi->connector.scdc_present) { + drm_scdc_readb(hdmi->ddc, SCDC_TMDS_CONFIG, &tmds_cfg); + if (mpll_config->mpixelclock > 340000000) + tmds_cfg |= 2; + else + tmds_cfg &= 0x1; + drm_scdc_writeb(hdmi->ddc, SCDC_TMDS_CONFIG, tmds_cfg); + } + /* PHY reset */ hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ); hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ); @@ -1156,8 +1167,14 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, dw_hdmi_phy_enable_powerdown(hdmi, false); - /* toggle TMDS enable */ + /* toggle TMDS disable */ dw_hdmi_phy_enable_tmds(hdmi, 0); + + /* Wait for resuming transmission of TMDS clock and data */ + if (mpll_config->mpixelclock > 340000000) + msleep(100); + + /* toggle TMDS enable */ dw_hdmi_phy_enable_tmds(hdmi, 1); /* gen2 tx power on */ @@ -1167,7 +1184,7 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep, if (is_rockchip(hdmi->dev_type)) dw_hdmi_phy_enable_spare(hdmi, 1); - /*Wait for PHY PLL lock */ + /* Wait for PHY PLL lock */ msec = 5; do { val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK; @@ -1332,7 +1349,7 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode) static void hdmi_av_composer(struct dw_hdmi *hdmi, const struct drm_display_mode *mode) { - u8 inv_val; + u8 inv_val, bytes; struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode; int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len; unsigned int vdisplay; @@ -1341,8 +1358,13 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock); - /* Set up HDMI_FC_INVIDCONF */ - inv_val = (hdmi->hdmi_data.hdcp_enable ? + /* Set up HDMI_FC_INVIDCONF + * fc_invidconf.HDCP_keepout must be set (1'b1) + * when activate the scrambler feature. + */ + inv_val = (hdmi->hdmi_data.hdcp_enable || + vmode->mpixelclock > 340000000 || + hdmi->connector.lte_340mcsc_scramble ? HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE : HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE); @@ -1391,6 +1413,26 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, vsync_len /= 2; } + /* Scrambling Control */ + if (hdmi->connector.scdc_present) { + if (vmode->mpixelclock > 340000000 || + hdmi->connector.lte_340mcsc_scramble) { + drm_scdc_readb(&hdmi->i2c->adap, SCDC_SINK_VERSION, + &bytes); + drm_scdc_writeb(&hdmi->i2c->adap, SCDC_SOURCE_VERSION, + bytes); + drm_scdc_writeb(&hdmi->i2c->adap, SCDC_TMDS_CONFIG, 1); + hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, + HDMI_MC_SWRSTZ); + hdmi_writeb(hdmi, 1, HDMI_FC_SCRAMBLER_CTRL); + } else { + hdmi_writeb(hdmi, 0, HDMI_FC_SCRAMBLER_CTRL); + hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, + HDMI_MC_SWRSTZ); + drm_scdc_writeb(&hdmi->i2c->adap, SCDC_TMDS_CONFIG, 0); + } + } + /* Set up horizontal active pixel width */ hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1); hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0); diff --git a/drivers/gpu/drm/bridge/dw-hdmi.h b/drivers/gpu/drm/bridge/dw-hdmi.h index 92c41d776891..593ad89ec2bb 100644 --- a/drivers/gpu/drm/bridge/dw-hdmi.h +++ b/drivers/gpu/drm/bridge/dw-hdmi.h @@ -255,6 +255,7 @@ #define HDMI_FC_MASK2 0x10DA #define HDMI_FC_POL2 0x10DB #define HDMI_FC_PRCONF 0x10E0 +#define HDMI_FC_SCRAMBLER_CTRL 0x10E1 #define HDMI_FC_GMD_STAT 0x1100 #define HDMI_FC_GMD_EN 0x1101