summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/i915/intel_hdmi.c
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2015-05-05 17:06:20 +0300
committerDaniel Vetter <daniel.vetter@ffwll.ch>2015-06-15 11:27:59 +0200
commit6d67415f40b1f166212f37ecc9c23b9f380dfebc (patch)
treede375437bc6232f273781acda97d7d251c230817 /drivers/gpu/drm/i915/intel_hdmi.c
parentd1b1589c4800678a8a2beba83845366b2dff5d70 (diff)
drm/i915: Send GCP infoframes for deep color HDMI sinks
GCP infoframes are required to inform the HDMI sink about the color depth. Send the GCP infoframe whenever the sink supports any deep color modes since such sinks must anyway be capable of receiving them. For sinks that don't support deep color let's skip the GCP in case it might confuse the sink, although HDMI 1.4 spec does say all sinks must be capable of reciving them. In theory we could skip the GCP infoframe for deep color sinks in 8bpc mode as well since sinks must fall back to 8bpc whenever GCP isn't received for some time. BSpec says we should disable GCP after disabling the port, so do that as well. v2: s/intel_set_gcp_infoframe/intel_hdmi_set_gcp_infoframe/ Rebased due to crtc->config changes Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> [danvet: Resolve conflict with lack of chv phy patches and fixup typo Chandra spotted.] Reviewed-by: Chandra Konduru <Chandra.konduru@intel.com> Reviewed-by: Ander Conselvan de Oliveira <conselvan2@gmail.com> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Diffstat (limited to 'drivers/gpu/drm/i915/intel_hdmi.c')
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 9ee6176a5f27..a422d83b6efb 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -541,6 +541,66 @@ static void g4x_set_infoframes(struct drm_encoder *encoder,
intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
}
+static bool hdmi_sink_is_deep_color(struct drm_encoder *encoder)
+{
+ struct drm_device *dev = encoder->dev;
+ struct drm_connector *connector;
+
+ WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
+
+ /*
+ * HDMI cloning is only supported on g4x which doesn't
+ * support deep color or GCP infoframes anyway so no
+ * need to worry about multiple HDMI sinks here.
+ */
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+ if (connector->encoder == encoder)
+ return connector->display_info.bpc > 8;
+
+ return false;
+}
+
+static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder)
+{
+ struct drm_i915_private *dev_priv = encoder->dev->dev_private;
+ struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
+ u32 reg, val = 0;
+
+ if (HAS_DDI(dev_priv))
+ reg = HSW_TVIDEO_DIP_GCP(crtc->config->cpu_transcoder);
+ else if (IS_VALLEYVIEW(dev_priv))
+ reg = VLV_TVIDEO_DIP_GCP(crtc->pipe);
+ else if (HAS_PCH_SPLIT(dev_priv->dev))
+ reg = TVIDEO_DIP_GCP(crtc->pipe);
+ else
+ return false;
+
+ /* Indicate color depth whenever the sink supports deep color */
+ if (hdmi_sink_is_deep_color(encoder))
+ val |= GCP_COLOR_INDICATION;
+
+ I915_WRITE(reg, val);
+
+ return val != 0;
+}
+
+static void intel_disable_gcp_infoframe(struct intel_crtc *crtc)
+{
+ struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+ u32 reg;
+
+ if (HAS_DDI(dev_priv))
+ reg = HSW_TVIDEO_DIP_CTL(crtc->config->cpu_transcoder);
+ else if (IS_VALLEYVIEW(dev_priv))
+ reg = VLV_TVIDEO_DIP_CTL(crtc->pipe);
+ else if (HAS_PCH_SPLIT(dev_priv->dev))
+ reg = TVIDEO_DIP_CTL(crtc->pipe);
+ else
+ return;
+
+ I915_WRITE(reg, I915_READ(reg) & ~VIDEO_DIP_ENABLE_GCP);
+}
+
static void ibx_set_infoframes(struct drm_encoder *encoder,
bool enable,
struct drm_display_mode *adjusted_mode)
@@ -581,6 +641,9 @@ static void ibx_set_infoframes(struct drm_encoder *encoder,
val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
VIDEO_DIP_ENABLE_GCP);
+ if (intel_hdmi_set_gcp_infoframe(encoder))
+ val |= VIDEO_DIP_ENABLE_GCP;
+
I915_WRITE(reg, val);
POSTING_READ(reg);
@@ -618,6 +681,9 @@ static void cpt_set_infoframes(struct drm_encoder *encoder,
val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT |
VIDEO_DIP_ENABLE_GCP);
+ if (intel_hdmi_set_gcp_infoframe(encoder))
+ val |= VIDEO_DIP_ENABLE_GCP;
+
I915_WRITE(reg, val);
POSTING_READ(reg);
@@ -666,6 +732,9 @@ static void vlv_set_infoframes(struct drm_encoder *encoder,
val &= ~(VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_ENABLE_VENDOR |
VIDEO_DIP_ENABLE_GAMUT | VIDEO_DIP_ENABLE_GCP);
+ if (intel_hdmi_set_gcp_infoframe(encoder))
+ val |= VIDEO_DIP_ENABLE_GCP;
+
I915_WRITE(reg, val);
POSTING_READ(reg);
@@ -695,6 +764,9 @@ static void hsw_set_infoframes(struct drm_encoder *encoder,
val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_GCP_HSW |
VIDEO_DIP_ENABLE_VS_HSW | VIDEO_DIP_ENABLE_GMP_HSW);
+ if (intel_hdmi_set_gcp_infoframe(encoder))
+ val |= VIDEO_DIP_ENABLE_GCP_HSW;
+
I915_WRITE(reg, val);
POSTING_READ(reg);
@@ -960,6 +1032,8 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
I915_WRITE(intel_hdmi->hdmi_reg, temp);
POSTING_READ(intel_hdmi->hdmi_reg);
}
+
+ intel_disable_gcp_infoframe(to_intel_crtc(encoder->base.crtc));
}
static void g4x_disable_hdmi(struct intel_encoder *encoder)