Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/msm/hdmi: Fix HDMI pink strip issue seen on 8x96

A 2 pixel wide pink strip was observed on the left end of some HDMI
monitors configured in a HDMI mode.

It turned out that we were missing out on configuring AVI infoframes, and
unlike APQ8064, the 8x96 HDMI H/W seems to be sensitive to that.

Add configuration of AVI infoframes. While at it, make sure that
hdmi_audio_update is only called when we've detected that the monitor
supports HDMI.

Signed-off-by: Archit Taneja <architt@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>

authored by

Archit Taneja and committed by
Rob Clark
816fa34c b474cbbb

+67 -3
+67 -3
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
··· 86 86 } 87 87 } 88 88 89 + #define AVI_IFRAME_LINE_NUMBER 1 90 + 91 + static void msm_hdmi_config_avi_infoframe(struct hdmi *hdmi) 92 + { 93 + struct drm_crtc *crtc = hdmi->encoder->crtc; 94 + const struct drm_display_mode *mode = &crtc->state->adjusted_mode; 95 + union hdmi_infoframe frame; 96 + u8 buffer[HDMI_INFOFRAME_SIZE(AVI)]; 97 + u32 val; 98 + int len; 99 + 100 + drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode); 101 + 102 + len = hdmi_infoframe_pack(&frame, buffer, sizeof(buffer)); 103 + if (len < 0) { 104 + dev_err(&hdmi->pdev->dev, 105 + "failed to configure avi infoframe\n"); 106 + return; 107 + } 108 + 109 + /* 110 + * the AVI_INFOx registers don't map exactly to how the AVI infoframes 111 + * are packed according to the spec. The checksum from the header is 112 + * written to the LSB byte of AVI_INFO0 and the version is written to 113 + * the third byte from the LSB of AVI_INFO3 114 + */ 115 + hdmi_write(hdmi, REG_HDMI_AVI_INFO(0), 116 + buffer[3] | 117 + buffer[4] << 8 | 118 + buffer[5] << 16 | 119 + buffer[6] << 24); 120 + 121 + hdmi_write(hdmi, REG_HDMI_AVI_INFO(1), 122 + buffer[7] | 123 + buffer[8] << 8 | 124 + buffer[9] << 16 | 125 + buffer[10] << 24); 126 + 127 + hdmi_write(hdmi, REG_HDMI_AVI_INFO(2), 128 + buffer[11] | 129 + buffer[12] << 8 | 130 + buffer[13] << 16 | 131 + buffer[14] << 24); 132 + 133 + hdmi_write(hdmi, REG_HDMI_AVI_INFO(3), 134 + buffer[15] | 135 + buffer[16] << 8 | 136 + buffer[1] << 24); 137 + 138 + hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, 139 + HDMI_INFOFRAME_CTRL0_AVI_SEND | 140 + HDMI_INFOFRAME_CTRL0_AVI_CONT); 141 + 142 + val = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL1); 143 + val &= ~HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE__MASK; 144 + val |= HDMI_INFOFRAME_CTRL1_AVI_INFO_LINE(AVI_IFRAME_LINE_NUMBER); 145 + hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL1, val); 146 + } 147 + 89 148 static void msm_hdmi_bridge_pre_enable(struct drm_bridge *bridge) 90 149 { 91 150 struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge); ··· 157 98 msm_hdmi_phy_resource_enable(phy); 158 99 msm_hdmi_power_on(bridge); 159 100 hdmi->power_on = true; 160 - msm_hdmi_audio_update(hdmi); 101 + if (hdmi->hdmi_mode) { 102 + msm_hdmi_config_avi_infoframe(hdmi); 103 + msm_hdmi_audio_update(hdmi); 104 + } 161 105 } 162 106 163 107 msm_hdmi_phy_powerup(phy, hdmi->pixclock); ··· 196 134 if (hdmi->power_on) { 197 135 power_off(bridge); 198 136 hdmi->power_on = false; 199 - msm_hdmi_audio_update(hdmi); 137 + if (hdmi->hdmi_mode) 138 + msm_hdmi_audio_update(hdmi); 200 139 msm_hdmi_phy_resource_disable(phy); 201 140 } 202 141 } ··· 259 196 DBG("frame_ctrl=%08x", frame_ctrl); 260 197 hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl); 261 198 262 - msm_hdmi_audio_update(hdmi); 199 + if (hdmi->hdmi_mode) 200 + msm_hdmi_audio_update(hdmi); 263 201 } 264 202 265 203 static const struct drm_bridge_funcs msm_hdmi_bridge_funcs = {