]> Pileus Git - ~andy/linux/blobdiff - drivers/gpu/drm/i915/intel_sdvo.c
Merge tag 'drm-intel-next-2013-06-18' of git://people.freedesktop.org/~danvet/drm...
[~andy/linux] / drivers / gpu / drm / i915 / intel_sdvo.c
index 4d4a3f0cadfba0754efc9a547d6424ea9a1a4242..2628d56224499307cffa4e409a646122a9578db0 100644 (file)
@@ -80,7 +80,7 @@ struct intel_sdvo {
 
        /*
         * Capabilities of the SDVO device returned by
-        * i830_sdvo_get_capabilities()
+        * intel_sdvo_get_capabilities()
         */
        struct intel_sdvo_caps caps;
 
@@ -1219,6 +1219,7 @@ static void intel_sdvo_mode_set(struct intel_encoder *intel_encoder)
 
        switch (intel_crtc->config.pixel_multiplier) {
        default:
+               WARN(1, "unknown pixel mutlipler specified\n");
        case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
        case 2: rate = SDVO_CLOCK_RATE_MULT_2X; break;
        case 4: rate = SDVO_CLOCK_RATE_MULT_4X; break;
@@ -1276,7 +1277,7 @@ static bool intel_sdvo_connector_get_hw_state(struct intel_connector *connector)
        struct intel_sdvo_connector *intel_sdvo_connector =
                to_intel_sdvo_connector(&connector->base);
        struct intel_sdvo *intel_sdvo = intel_attached_sdvo(&connector->base);
-       u16 active_outputs;
+       u16 active_outputs = 0;
 
        intel_sdvo_get_active_outputs(intel_sdvo, &active_outputs);
 
@@ -1292,7 +1293,7 @@ static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder,
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
-       u16 active_outputs;
+       u16 active_outputs = 0;
        u32 tmp;
 
        tmp = I915_READ(intel_sdvo->sdvo_reg);
@@ -1312,28 +1313,69 @@ static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder,
 static void intel_sdvo_get_config(struct intel_encoder *encoder,
                                  struct intel_crtc_config *pipe_config)
 {
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_sdvo *intel_sdvo = to_intel_sdvo(&encoder->base);
        struct intel_sdvo_dtd dtd;
-       u32 flags = 0;
+       int encoder_pixel_multiplier = 0;
+       u32 flags = 0, sdvox;
+       u8 val;
        bool ret;
 
        ret = intel_sdvo_get_input_timing(intel_sdvo, &dtd);
        if (!ret) {
+               /* Some sdvo encoders are not spec compliant and don't
+                * implement the mandatory get_timings function. */
                DRM_DEBUG_DRIVER("failed to retrieve SDVO DTD\n");
-               return;
+               pipe_config->quirks |= PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS;
+       } else {
+               if (dtd.part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE)
+                       flags |= DRM_MODE_FLAG_PHSYNC;
+               else
+                       flags |= DRM_MODE_FLAG_NHSYNC;
+
+               if (dtd.part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE)
+                       flags |= DRM_MODE_FLAG_PVSYNC;
+               else
+                       flags |= DRM_MODE_FLAG_NVSYNC;
        }
 
-       if (dtd.part2.dtd_flags & DTD_FLAG_HSYNC_POSITIVE)
-               flags |= DRM_MODE_FLAG_PHSYNC;
-       else
-               flags |= DRM_MODE_FLAG_NHSYNC;
+       pipe_config->adjusted_mode.flags |= flags;
 
-       if (dtd.part2.dtd_flags & DTD_FLAG_VSYNC_POSITIVE)
-               flags |= DRM_MODE_FLAG_PVSYNC;
-       else
-               flags |= DRM_MODE_FLAG_NVSYNC;
+       /*
+        * pixel multiplier readout is tricky: Only on i915g/gm it is stored in
+        * the sdvo port register, on all other platforms it is part of the dpll
+        * state. Since the general pipe state readout happens before the
+        * encoder->get_config we so already have a valid pixel multplier on all
+        * other platfroms.
+        */
+       if (IS_I915G(dev) || IS_I915GM(dev)) {
+               sdvox = I915_READ(intel_sdvo->sdvo_reg);
+               pipe_config->pixel_multiplier =
+                       ((sdvox & SDVO_PORT_MULTIPLY_MASK)
+                        >> SDVO_PORT_MULTIPLY_SHIFT) + 1;
+       }
 
-       pipe_config->adjusted_mode.flags |= flags;
+       /* Cross check the port pixel multiplier with the sdvo encoder state. */
+       intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_CLOCK_RATE_MULT, &val, 1);
+       switch (val) {
+       case SDVO_CLOCK_RATE_MULT_1X:
+               encoder_pixel_multiplier = 1;
+               break;
+       case SDVO_CLOCK_RATE_MULT_2X:
+               encoder_pixel_multiplier = 2;
+               break;
+       case SDVO_CLOCK_RATE_MULT_4X:
+               encoder_pixel_multiplier = 4;
+               break;
+       }
+
+       if(HAS_PCH_SPLIT(dev))
+               return; /* no pixel multiplier readout support yet */
+
+       WARN(encoder_pixel_multiplier != pipe_config->pixel_multiplier,
+            "SDVO pixel multiplier mismatch, port: %i, encoder: %i\n",
+            pipe_config->pixel_multiplier, encoder_pixel_multiplier);
 }
 
 static void intel_disable_sdvo(struct intel_encoder *encoder)
@@ -1416,6 +1458,7 @@ static void intel_enable_sdvo(struct intel_encoder *encoder)
        intel_sdvo_set_active_outputs(intel_sdvo, intel_sdvo->attached_output);
 }
 
+/* Special dpms function to support cloning between dvo/sdvo/crt. */
 static void intel_sdvo_dpms(struct drm_connector *connector, int mode)
 {
        struct drm_crtc *crtc;
@@ -1437,6 +1480,8 @@ static void intel_sdvo_dpms(struct drm_connector *connector, int mode)
                return;
        }
 
+       /* We set active outputs manually below in case pipe dpms doesn't change
+        * due to cloning. */
        if (mode != DRM_MODE_DPMS_ON) {
                intel_sdvo_set_active_outputs(intel_sdvo, 0);
                if (0)
@@ -1841,15 +1886,9 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
        struct drm_display_mode *newmode;
 
        /*
-        * Attempt to get the mode list from DDC.
-        * Assume that the preferred modes are
-        * arranged in priority order.
+        * Fetch modes from VBT. For SDVO prefer the VBT mode since some
+        * SDVO->LVDS transcoders can't cope with the EDID mode.
         */
-       intel_ddc_get_modes(connector, intel_sdvo->i2c);
-       if (list_empty(&connector->probed_modes) == false)
-               goto end;
-
-       /* Fetch modes from VBT */
        if (dev_priv->vbt.sdvo_lvds_vbt_mode != NULL) {
                newmode = drm_mode_duplicate(connector->dev,
                                             dev_priv->vbt.sdvo_lvds_vbt_mode);
@@ -1861,7 +1900,13 @@ static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
                }
        }
 
-end:
+       /*
+        * Attempt to get the mode list from DDC.
+        * Assume that the preferred modes are
+        * arranged in priority order.
+        */
+       intel_ddc_get_modes(connector, &intel_sdvo->ddc);
+
        list_for_each_entry(newmode, &connector->probed_modes, head) {
                if (newmode->type & DRM_MODE_TYPE_PREFERRED) {
                        intel_sdvo->sdvo_lvds_fixed_mode =
@@ -2816,7 +2861,6 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_encoder *intel_encoder;
        struct intel_sdvo *intel_sdvo;
-       u32 hotplug_mask;
        int i;
        intel_sdvo = kzalloc(sizeof(struct intel_sdvo), GFP_KERNEL);
        if (!intel_sdvo)
@@ -2845,24 +2889,6 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
                }
        }
 
-       hotplug_mask = 0;
-       if (IS_G4X(dev)) {
-               hotplug_mask = intel_sdvo->is_sdvob ?
-                       SDVOB_HOTPLUG_INT_STATUS_G4X : SDVOC_HOTPLUG_INT_STATUS_G4X;
-       } else if (IS_GEN4(dev)) {
-               hotplug_mask = intel_sdvo->is_sdvob ?
-                       SDVOB_HOTPLUG_INT_STATUS_I965 : SDVOC_HOTPLUG_INT_STATUS_I965;
-       } else {
-               hotplug_mask = intel_sdvo->is_sdvob ?
-                       SDVOB_HOTPLUG_INT_STATUS_I915 : SDVOC_HOTPLUG_INT_STATUS_I915;
-       }
-
-       /* Only enable the hotplug irq if we need it, to work around noisy
-        * hotplug lines.
-        */
-       if (intel_sdvo->hotplug_active)
-               intel_encoder->hpd_pin = HPD_SDVO_B ? HPD_SDVO_B : HPD_SDVO_C;
-
        intel_encoder->compute_config = intel_sdvo_compute_config;
        intel_encoder->disable = intel_disable_sdvo;
        intel_encoder->mode_set = intel_sdvo_mode_set;
@@ -2882,6 +2908,14 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
                goto err_output;
        }
 
+       /* Only enable the hotplug irq if we need it, to work around noisy
+        * hotplug lines.
+        */
+       if (intel_sdvo->hotplug_active) {
+               intel_encoder->hpd_pin =
+                       intel_sdvo->is_sdvob ?  HPD_SDVO_B : HPD_SDVO_C;
+       }
+
        /*
         * Cloning SDVO with anything is often impossible, since the SDVO
         * encoder can request a special input timing mode. And even if that's