Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/herbert/crypto-2.6
[cascardo/linux.git] / drivers / gpu / drm / i915 / intel_hdmi.c
index 1ab6f68..a884470 100644 (file)
@@ -638,7 +638,7 @@ static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder)
                reg = HSW_TVIDEO_DIP_GCP(crtc->config->cpu_transcoder);
        else if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
                reg = VLV_TVIDEO_DIP_GCP(crtc->pipe);
-       else if (HAS_PCH_SPLIT(dev_priv->dev))
+       else if (HAS_PCH_SPLIT(dev_priv))
                reg = TVIDEO_DIP_GCP(crtc->pipe);
        else
                return false;
@@ -836,6 +836,22 @@ static void hsw_set_infoframes(struct drm_encoder *encoder,
        intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode);
 }
 
+void intel_dp_dual_mode_set_tmds_output(struct intel_hdmi *hdmi, bool enable)
+{
+       struct drm_i915_private *dev_priv = to_i915(intel_hdmi_to_dev(hdmi));
+       struct i2c_adapter *adapter =
+               intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
+
+       if (hdmi->dp_dual_mode.type < DRM_DP_DUAL_MODE_TYPE2_DVI)
+               return;
+
+       DRM_DEBUG_KMS("%s DP dual mode adaptor TMDS output\n",
+                     enable ? "Enabling" : "Disabling");
+
+       drm_dp_dual_mode_set_tmds_output(hdmi->dp_dual_mode.type,
+                                        adapter, enable);
+}
+
 static void intel_hdmi_prepare(struct intel_encoder *encoder)
 {
        struct drm_device *dev = encoder->base.dev;
@@ -845,6 +861,8 @@ static void intel_hdmi_prepare(struct intel_encoder *encoder)
        const struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
        u32 hdmi_val;
 
+       intel_dp_dual_mode_set_tmds_output(intel_hdmi, true);
+
        hdmi_val = SDVO_ENCODING_HDMI;
        if (!HAS_PCH_SPLIT(dev) && crtc->config->limited_color_range)
                hdmi_val |= HDMI_COLOR_RANGE_16_235;
@@ -952,10 +970,9 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
        if (pipe_config->pixel_multiplier)
                dotclock /= pipe_config->pixel_multiplier;
 
-       if (HAS_PCH_SPLIT(dev_priv->dev))
-               ironlake_check_encoder_dotclock(pipe_config, dotclock);
-
        pipe_config->base.adjusted_mode.crtc_clock = dotclock;
+
+       pipe_config->lane_count = 4;
 }
 
 static void intel_enable_hdmi_audio(struct intel_encoder *encoder)
@@ -1143,6 +1160,8 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
        }
 
        intel_hdmi->set_infoframes(&encoder->base, false, NULL);
+
+       intel_dp_dual_mode_set_tmds_output(intel_hdmi, false);
 }
 
 static void g4x_disable_hdmi(struct intel_encoder *encoder)
@@ -1168,27 +1187,42 @@ static void pch_post_disable_hdmi(struct intel_encoder *encoder)
        intel_disable_hdmi(encoder);
 }
 
-static int hdmi_port_clock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit)
+static int intel_hdmi_source_max_tmds_clock(struct drm_i915_private *dev_priv)
 {
-       struct drm_device *dev = intel_hdmi_to_dev(hdmi);
-
-       if ((respect_dvi_limit && !hdmi->has_hdmi_sink) || IS_G4X(dev))
+       if (IS_G4X(dev_priv))
                return 165000;
-       else if (IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8)
+       else if (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8)
                return 300000;
        else
                return 225000;
 }
 
+static int hdmi_port_clock_limit(struct intel_hdmi *hdmi,
+                                bool respect_downstream_limits)
+{
+       struct drm_device *dev = intel_hdmi_to_dev(hdmi);
+       int max_tmds_clock = intel_hdmi_source_max_tmds_clock(to_i915(dev));
+
+       if (respect_downstream_limits) {
+               if (hdmi->dp_dual_mode.max_tmds_clock)
+                       max_tmds_clock = min(max_tmds_clock,
+                                            hdmi->dp_dual_mode.max_tmds_clock);
+               if (!hdmi->has_hdmi_sink)
+                       max_tmds_clock = min(max_tmds_clock, 165000);
+       }
+
+       return max_tmds_clock;
+}
+
 static enum drm_mode_status
 hdmi_port_clock_valid(struct intel_hdmi *hdmi,
-                     int clock, bool respect_dvi_limit)
+                     int clock, bool respect_downstream_limits)
 {
        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))
+       if (clock > hdmi_port_clock_limit(hdmi, respect_downstream_limits))
                return MODE_CLOCK_HIGH;
 
        /* BXT DPLL can't generate 223-240 MHz */
@@ -1312,7 +1346,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
         * within limits.
         */
        if (pipe_config->pipe_bpp > 8*3 && pipe_config->has_hdmi_sink &&
-           hdmi_port_clock_valid(intel_hdmi, clock_12bpc, false) == MODE_OK &&
+           hdmi_port_clock_valid(intel_hdmi, clock_12bpc, true) == MODE_OK &&
            hdmi_12bpc_possible(pipe_config)) {
                DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
                desired_bpp = 12*3;
@@ -1340,6 +1374,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
        /* Set user selected PAR to incoming mode's member */
        adjusted_mode->picture_aspect_ratio = intel_hdmi->aspect_ratio;
 
+       pipe_config->lane_count = 4;
+
        return true;
 }
 
@@ -1352,10 +1388,57 @@ intel_hdmi_unset_edid(struct drm_connector *connector)
        intel_hdmi->has_audio = false;
        intel_hdmi->rgb_quant_range_selectable = false;
 
+       intel_hdmi->dp_dual_mode.type = DRM_DP_DUAL_MODE_NONE;
+       intel_hdmi->dp_dual_mode.max_tmds_clock = 0;
+
        kfree(to_intel_connector(connector)->detect_edid);
        to_intel_connector(connector)->detect_edid = NULL;
 }
 
+static void
+intel_hdmi_dp_dual_mode_detect(struct drm_connector *connector, bool has_edid)
+{
+       struct drm_i915_private *dev_priv = to_i915(connector->dev);
+       struct intel_hdmi *hdmi = intel_attached_hdmi(connector);
+       enum port port = hdmi_to_dig_port(hdmi)->port;
+       struct i2c_adapter *adapter =
+               intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
+       enum drm_dp_dual_mode_type type = drm_dp_dual_mode_detect(adapter);
+
+       /*
+        * Type 1 DVI adaptors are not required to implement any
+        * registers, so we can't always detect their presence.
+        * Ideally we should be able to check the state of the
+        * CONFIG1 pin, but no such luck on our hardware.
+        *
+        * The only method left to us is to check the VBT to see
+        * if the port is a dual mode capable DP port. But let's
+        * only do that when we sucesfully read the EDID, to avoid
+        * confusing log messages about DP dual mode adaptors when
+        * there's nothing connected to the port.
+        */
+       if (type == DRM_DP_DUAL_MODE_UNKNOWN) {
+               if (has_edid &&
+                   intel_bios_is_port_dp_dual_mode(dev_priv, port)) {
+                       DRM_DEBUG_KMS("Assuming DP dual mode adaptor presence based on VBT\n");
+                       type = DRM_DP_DUAL_MODE_TYPE1_DVI;
+               } else {
+                       type = DRM_DP_DUAL_MODE_NONE;
+               }
+       }
+
+       if (type == DRM_DP_DUAL_MODE_NONE)
+               return;
+
+       hdmi->dp_dual_mode.type = type;
+       hdmi->dp_dual_mode.max_tmds_clock =
+               drm_dp_dual_mode_max_tmds_clock(type, adapter);
+
+       DRM_DEBUG_KMS("DP dual mode adaptor (%s) detected (max TMDS clock: %d kHz)\n",
+                     drm_dp_get_dual_mode_type_name(type),
+                     hdmi->dp_dual_mode.max_tmds_clock);
+}
+
 static bool
 intel_hdmi_set_edid(struct drm_connector *connector, bool force)
 {
@@ -1371,6 +1454,8 @@ intel_hdmi_set_edid(struct drm_connector *connector, bool force)
                                    intel_gmbus_get_adapter(dev_priv,
                                    intel_hdmi->ddc_bus));
 
+               intel_hdmi_dp_dual_mode_detect(connector, edid != NULL);
+
                intel_display_power_put(dev_priv, POWER_DOMAIN_GMBUS);
        }
 
@@ -2057,6 +2142,9 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
        enum port port = intel_dig_port->port;
        uint8_t alternate_ddc_pin;
 
+       DRM_DEBUG_KMS("Adding HDMI connector on port %c\n",
+                     port_name(port));
+
        if (WARN(intel_dig_port->max_lanes < 4,
                 "Not enough lanes (%d) for HDMI on port %c\n",
                 intel_dig_port->max_lanes, port_name(port)))