drm/i915: Deobfuscate the render p-state obfuscation
[safe/jmp/linux-2.6] / drivers / gpu / drm / i915 / intel_bios.c
index 800d13b..15fbc1b 100644 (file)
@@ -33,6 +33,8 @@
 #define        SLAVE_ADDR1     0x70
 #define        SLAVE_ADDR2     0x72
 
+static int panel_type;
+
 static void *
 find_section(struct bdb_header *bdb, int section_id)
 {
@@ -128,6 +130,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
        dev_priv->lvds_dither = lvds_options->pixel_dither;
        if (lvds_options->panel_type == 0xff)
                return;
+       panel_type = lvds_options->panel_type;
 
        lvds_lfp_data = find_section(bdb, BDB_LVDS_LFP_DATA);
        if (!lvds_lfp_data)
@@ -197,7 +200,8 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
                memset(temp_mode, 0, sizeof(*temp_mode));
        }
        kfree(temp_mode);
-       if (temp_downclock < panel_fixed_mode->clock) {
+       if (temp_downclock < panel_fixed_mode->clock &&
+           i915_lvds_downclock) {
                dev_priv->lvds_downclock_avail = 1;
                dev_priv->lvds_downclock = temp_downclock;
                DRM_DEBUG_KMS("LVDS downclock is found in VBT. ",
@@ -259,7 +263,7 @@ 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))
+                       else if (IS_IRONLAKE(dev_priv->dev))
                                dev_priv->lvds_ssc_freq =
                                        general->ssc_freq ? 100 : 120;
                        else
@@ -404,6 +408,98 @@ parse_driver_features(struct drm_i915_private *dev_priv,
                dev_priv->render_reclock_avail = true;
 }
 
+static void
+parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
+{
+       struct bdb_edp *edp;
+
+       edp = find_section(bdb, BDB_EDP);
+       if (!edp) {
+               if (SUPPORTS_EDP(dev_priv->dev) && dev_priv->edp_support) {
+                       DRM_DEBUG_KMS("No eDP BDB found but eDP panel supported,\
+                                      assume 18bpp panel color depth.\n");
+                       dev_priv->edp_bpp = 18;
+               }
+               return;
+       }
+
+       switch ((edp->color_depth >> (panel_type * 2)) & 3) {
+       case EDP_18BPP:
+               dev_priv->edp_bpp = 18;
+               break;
+       case EDP_24BPP:
+               dev_priv->edp_bpp = 24;
+               break;
+       case EDP_30BPP:
+               dev_priv->edp_bpp = 30;
+               break;
+       }
+}
+
+static void
+parse_device_mapping(struct drm_i915_private *dev_priv,
+                      struct bdb_header *bdb)
+{
+       struct bdb_general_definitions *p_defs;
+       struct child_device_config *p_child, *child_dev_ptr;
+       int i, child_device_num, count;
+       u16     block_size;
+
+       p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
+       if (!p_defs) {
+               DRM_DEBUG_KMS("No general definition block is found\n");
+               return;
+       }
+       /* judge whether the size of child device meets the requirements.
+        * If the child device size obtained from general definition block
+        * is different with sizeof(struct child_device_config), skip the
+        * parsing of sdvo device info
+        */
+       if (p_defs->child_dev_size != sizeof(*p_child)) {
+               /* different child dev size . Ignore it */
+               DRM_DEBUG_KMS("different child size is found. Invalid.\n");
+               return;
+       }
+       /* get the block size of general definitions */
+       block_size = get_blocksize(p_defs);
+       /* get the number of child device */
+       child_device_num = (block_size - sizeof(*p_defs)) /
+                               sizeof(*p_child);
+       count = 0;
+       /* get the number of child device that is present */
+       for (i = 0; i < child_device_num; i++) {
+               p_child = &(p_defs->devices[i]);
+               if (!p_child->device_type) {
+                       /* skip the device block if device type is invalid */
+                       continue;
+               }
+               count++;
+       }
+       if (!count) {
+               DRM_DEBUG_KMS("no child dev is parsed from VBT \n");
+               return;
+       }
+       dev_priv->child_dev = kzalloc(sizeof(*p_child) * count, GFP_KERNEL);
+       if (!dev_priv->child_dev) {
+               DRM_DEBUG_KMS("No memory space for child device\n");
+               return;
+       }
+
+       dev_priv->child_dev_num = count;
+       count = 0;
+       for (i = 0; i < child_device_num; i++) {
+               p_child = &(p_defs->devices[i]);
+               if (!p_child->device_type) {
+                       /* skip the device block if device type is invalid */
+                       continue;
+               }
+               child_dev_ptr = dev_priv->child_dev + count;
+               count++;
+               memcpy((void *)child_dev_ptr, (void *)p_child,
+                                       sizeof(*p_child));
+       }
+       return;
+}
 /**
  * intel_init_bios - initialize VBIOS settings & find VBT
  * @dev: DRM device
@@ -455,7 +551,9 @@ intel_init_bios(struct drm_device *dev)
        parse_lfp_panel_data(dev_priv, bdb);
        parse_sdvo_panel_data(dev_priv, bdb);
        parse_sdvo_device_mapping(dev_priv, bdb);
+       parse_device_mapping(dev_priv, bdb);
        parse_driver_features(dev_priv, bdb);
+       parse_edp(dev_priv, bdb);
 
        pci_unmap_rom(pdev, bios);