]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/i915/intel_bios.c
drm/i915: fix gpio register detection logic for BIOS without VBT
[karo-tx-linux.git] / drivers / gpu / drm / i915 / intel_bios.c
index 1e28c1652fd03f48633b3eb2674460b760487530..800d13bd9e6abf98a5978889db9162d656cf8348 100644 (file)
@@ -114,6 +114,8 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
        struct lvds_dvo_timing *dvo_timing;
        struct drm_display_mode *panel_fixed_mode;
        int lfp_data_size, dvo_timing_offset;
+       int i, temp_downclock;
+       struct drm_display_mode *temp_mode;
 
        /* Defaults if we can't find VBT info */
        dev_priv->lvds_dither = 0;
@@ -159,9 +161,49 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
 
        dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode;
 
-       DRM_DEBUG("Found panel mode in BIOS VBT tables:\n");
+       DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n");
        drm_mode_debug_printmodeline(panel_fixed_mode);
 
+       temp_mode = kzalloc(sizeof(*temp_mode), GFP_KERNEL);
+       temp_downclock = panel_fixed_mode->clock;
+       /*
+        * enumerate the LVDS panel timing info entry in VBT to check whether
+        * the LVDS downclock is found.
+        */
+       for (i = 0; i < 16; i++) {
+               entry = (struct bdb_lvds_lfp_data_entry *)
+                       ((uint8_t *)lvds_lfp_data->data + (lfp_data_size * i));
+               dvo_timing = (struct lvds_dvo_timing *)
+                       ((unsigned char *)entry + dvo_timing_offset);
+
+               fill_detail_timing_data(temp_mode, dvo_timing);
+
+               if (temp_mode->hdisplay == panel_fixed_mode->hdisplay &&
+               temp_mode->hsync_start == panel_fixed_mode->hsync_start &&
+               temp_mode->hsync_end == panel_fixed_mode->hsync_end &&
+               temp_mode->htotal == panel_fixed_mode->htotal &&
+               temp_mode->vdisplay == panel_fixed_mode->vdisplay &&
+               temp_mode->vsync_start == panel_fixed_mode->vsync_start &&
+               temp_mode->vsync_end == panel_fixed_mode->vsync_end &&
+               temp_mode->vtotal == panel_fixed_mode->vtotal &&
+               temp_mode->clock < temp_downclock) {
+                       /*
+                        * downclock is already found. But we expect
+                        * to find the lower downclock.
+                        */
+                       temp_downclock = temp_mode->clock;
+               }
+               /* clear it to zero */
+               memset(temp_mode, 0, sizeof(*temp_mode));
+       }
+       kfree(temp_mode);
+       if (temp_downclock < panel_fixed_mode->clock) {
+               dev_priv->lvds_downclock_avail = 1;
+               dev_priv->lvds_downclock = temp_downclock;
+               DRM_DEBUG_KMS("LVDS downclock is found in VBT. ",
+                               "Normal Clock %dKHz, downclock %dKHz\n",
+                               temp_downclock, panel_fixed_mode->clock);
+       }
        return;
 }
 
@@ -217,6 +259,9 @@ parse_general_features(struct drm_i915_private *dev_priv,
                        if (IS_I85X(dev_priv->dev))
                                dev_priv->lvds_ssc_freq =
                                        general->ssc_freq ? 66 : 48;
+                       else if (IS_IGDNG(dev_priv->dev))
+                               dev_priv->lvds_ssc_freq =
+                                       general->ssc_freq ? 100 : 120;
                        else
                                dev_priv->lvds_ssc_freq =
                                        general->ssc_freq ? 100 : 96;
@@ -238,22 +283,18 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
                GPIOF,
        };
 
-       /* Set sensible defaults in case we can't find the general block
-          or it is the wrong chipset */
-       dev_priv->crt_ddc_bus = -1;
-
        general = find_section(bdb, BDB_GENERAL_DEFINITIONS);
        if (general) {
                u16 block_size = get_blocksize(general);
                if (block_size >= sizeof(*general)) {
                        int bus_pin = general->crt_ddc_gmbus_pin;
-                       DRM_DEBUG("crt_ddc_bus_pin: %d\n", bus_pin);
+                       DRM_DEBUG_KMS("crt_ddc_bus_pin: %d\n", bus_pin);
                        if ((bus_pin >= 1) && (bus_pin <= 6)) {
                                dev_priv->crt_ddc_bus =
                                        crt_bus_map_table[bus_pin-1];
                        }
                } else {
-                       DRM_DEBUG("BDB_GD too small (%d). Invalid.\n",
+                       DRM_DEBUG_KMS("BDB_GD too small (%d). Invalid.\n",
                                  block_size);
                }
        }
@@ -271,7 +312,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
 
        p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
        if (!p_defs) {
-               DRM_DEBUG("No general definition block is found\n");
+               DRM_DEBUG_KMS("No general definition block is found\n");
                return;
        }
        /* judge whether the size of child device meets the requirements.
@@ -281,7 +322,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
         */
        if (p_defs->child_dev_size != sizeof(*p_child)) {
                /* different child dev size . Ignore it */
-               DRM_DEBUG("different child size is found. Invalid.\n");
+               DRM_DEBUG_KMS("different child size is found. Invalid.\n");
                return;
        }
        /* get the block size of general definitions */
@@ -307,11 +348,11 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
                if (p_child->dvo_port != DEVICE_PORT_DVOB &&
                        p_child->dvo_port != DEVICE_PORT_DVOC) {
                        /* skip the incorrect SDVO port */
-                       DRM_DEBUG("Incorrect SDVO port. Skip it \n");
+                       DRM_DEBUG_KMS("Incorrect SDVO port. Skip it \n");
                        continue;
                }
-               DRM_DEBUG("the SDVO device with slave addr %2x is found on "
-                               "%s port\n",
+               DRM_DEBUG_KMS("the SDVO device with slave addr %2x is found on"
+                               " %s port\n",
                                p_child->slave_addr,
                                (p_child->dvo_port == DEVICE_PORT_DVOB) ?
                                        "SDVOB" : "SDVOC");
@@ -322,21 +363,21 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
                        p_mapping->dvo_wiring = p_child->dvo_wiring;
                        p_mapping->initialized = 1;
                } else {
-                       DRM_DEBUG("Maybe one SDVO port is shared by "
+                       DRM_DEBUG_KMS("Maybe one SDVO port is shared by "
                                         "two SDVO device.\n");
                }
                if (p_child->slave2_addr) {
                        /* Maybe this is a SDVO device with multiple inputs */
                        /* And the mapping info is not added */
-                       DRM_DEBUG("there exists the slave2_addr. Maybe this "
-                               "is a SDVO device with multiple inputs.\n");
+                       DRM_DEBUG_KMS("there exists the slave2_addr. Maybe this"
+                               " is a SDVO device with multiple inputs.\n");
                }
                count++;
        }
 
        if (!count) {
                /* No SDVO device info is found */
-               DRM_DEBUG("No SDVO device info is found in VBT\n");
+               DRM_DEBUG_KMS("No SDVO device info is found in VBT\n");
        }
        return;
 }
@@ -348,20 +389,18 @@ parse_driver_features(struct drm_i915_private *dev_priv,
        struct drm_device *dev = dev_priv->dev;
        struct bdb_driver_features *driver;
 
-       /* set default for chips without eDP */
-       if (!SUPPORTS_EDP(dev)) {
-               dev_priv->edp_support = 0;
-               return;
-       }
-
        driver = find_section(bdb, BDB_DRIVER_FEATURES);
        if (!driver)
                return;
 
-       if (driver->lvds_config == BDB_DRIVER_FEATURE_EDP)
+       if (driver && SUPPORTS_EDP(dev) &&
+           driver->lvds_config == BDB_DRIVER_FEATURE_EDP) {
                dev_priv->edp_support = 1;
+       } else {
+               dev_priv->edp_support = 0;
+       }
 
-       if (driver->dual_frequency)
+       if (driver && driver->dual_frequency)
                dev_priv->render_reclock_avail = true;
 }