Merge tag 'drm-intel-fixes-2015-07-15' into drm-intel-next-queued
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / i915 / intel_hdmi.c
index 69244ed2c35225188b64d15d46263decb18a7469..70bad5bf1d48b9cc1c72afa360475487bf9b152e 100644 (file)
@@ -1151,7 +1151,7 @@ static void pch_post_disable_hdmi(struct intel_encoder *encoder)
        intel_disable_hdmi(encoder);
 }
 
-static int hdmi_portclock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit)
+static int hdmi_port_clock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit)
 {
        struct drm_device *dev = intel_hdmi_to_dev(hdmi);
 
@@ -1163,25 +1163,52 @@ static int hdmi_portclock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit)
                return 225000;
 }
 
+static enum drm_mode_status
+hdmi_port_clock_valid(struct intel_hdmi *hdmi,
+                     int clock, bool respect_dvi_limit)
+{
+       struct drm_device *dev = intel_hdmi_to_dev(hdmi);
+
+       if (clock < 25000)
+               return MODE_CLOCK_LOW;
+       if (clock > hdmi_port_clock_limit(hdmi, respect_dvi_limit))
+               return MODE_CLOCK_HIGH;
+
+       /* BXT DPLL can't generate 223-240 MHz */
+       if (IS_BROXTON(dev) && clock > 223333 && clock < 240000)
+               return MODE_CLOCK_RANGE;
+
+       /* CHV DPLL can't generate 216-240 MHz */
+       if (IS_CHERRYVIEW(dev) && clock > 216000 && clock < 240000)
+               return MODE_CLOCK_RANGE;
+
+       return MODE_OK;
+}
+
 static enum drm_mode_status
 intel_hdmi_mode_valid(struct drm_connector *connector,
                      struct drm_display_mode *mode)
 {
-       int clock = mode->clock;
+       struct intel_hdmi *hdmi = intel_attached_hdmi(connector);
+       struct drm_device *dev = intel_hdmi_to_dev(hdmi);
+       enum drm_mode_status status;
+       int clock;
+
+       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
+               return MODE_NO_DBLESCAN;
 
+       clock = mode->clock;
        if (mode->flags & DRM_MODE_FLAG_DBLCLK)
                clock *= 2;
 
-       if (clock > hdmi_portclock_limit(intel_attached_hdmi(connector),
-                                        true))
-               return MODE_CLOCK_HIGH;
-       if (clock < 25000)
-               return MODE_CLOCK_LOW;
+       /* check if we can do 8bpc */
+       status = hdmi_port_clock_valid(hdmi, clock, true);
 
-       if (mode->flags & DRM_MODE_FLAG_DBLSCAN)
-               return MODE_NO_DBLESCAN;
+       /* if we can't do 8bpc we may still be able to do 12bpc */
+       if (!HAS_GMCH_DISPLAY(dev) && status != MODE_OK)
+               status = hdmi_port_clock_valid(hdmi, clock * 3 / 2, true);
 
-       return MODE_OK;
+       return status;
 }
 
 static bool hdmi_12bpc_possible(struct intel_crtc_state *crtc_state)
@@ -1222,8 +1249,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
        struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
        struct drm_device *dev = encoder->base.dev;
        struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
-       int clock_12bpc = pipe_config->base.adjusted_mode.crtc_clock * 3 / 2;
-       int portclock_limit = hdmi_portclock_limit(intel_hdmi, false);
+       int clock_8bpc = pipe_config->base.adjusted_mode.crtc_clock;
+       int clock_12bpc = clock_8bpc * 3 / 2;
        int desired_bpp;
 
        pipe_config->has_hdmi_sink = intel_hdmi->has_hdmi_sink;
@@ -1242,6 +1269,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
 
        if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) {
                pipe_config->pixel_multiplier = 2;
+               clock_8bpc *= 2;
                clock_12bpc *= 2;
        }
 
@@ -1261,9 +1289,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
         * within limits.
         */
        if (pipe_config->pipe_bpp > 8*3 && pipe_config->has_hdmi_sink &&
-           clock_12bpc <= portclock_limit &&
-           hdmi_12bpc_possible(pipe_config) &&
-           0 /* FIXME 12bpc support totally broken */) {
+           hdmi_port_clock_valid(intel_hdmi, clock_12bpc, false) == MODE_OK &&
+           hdmi_12bpc_possible(pipe_config)) {
                DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
                desired_bpp = 12*3;
 
@@ -1272,6 +1299,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
        } else {
                DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n");
                desired_bpp = 8*3;
+
+               pipe_config->port_clock = clock_8bpc;
        }
 
        if (!pipe_config->bw_constrained) {
@@ -1279,8 +1308,9 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
                pipe_config->pipe_bpp = desired_bpp;
        }
 
-       if (adjusted_mode->crtc_clock > portclock_limit) {
-               DRM_DEBUG_KMS("too high HDMI clock, rejecting mode\n");
+       if (hdmi_port_clock_valid(intel_hdmi, pipe_config->port_clock,
+                                 false) != MODE_OK) {
+               DRM_DEBUG_KMS("unsupported HDMI clock, rejecting mode\n");
                return false;
        }