drm/i915: parse child device from VBT
authorZhao Yakui <yakui.zhao@intel.com>
Tue, 24 Nov 2009 01:48:44 +0000 (09:48 +0800)
committerEric Anholt <eric@anholt.net>
Tue, 1 Dec 2009 00:36:53 +0000 (16:36 -0800)
On some laptops there is no HDMI/DP. But the xrandr still reports
several disconnected HDMI/display ports. In such case the user will be
confused.
 >DVI1 disconnected (normal left inverted right x axis y axis)
 >DP1 disconnected (normal left inverted right x axis y axis)
 >DVI2 disconnected (normal left inverted right x axis y axis)
 >DP2 disconnected (normal left inverted right x axis y axis)
 >DP3 disconnected (normal left inverted right x axis y axis)

This patch set is to use the child device parsed in VBT to decide whether
the HDMI/DP/LVDS/TV should be initialized.

Parse the child device from VBT.

The device class type is also added for LFP, TV, HDMI, DP output.

https://bugs.freedesktop.org/show_bug.cgi?id=22785

Signed-off-by: Zhao Yakui <yakui.zhao@intel.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
Signed-off-by: Eric Anholt <eric@anholt.net>
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_bios.h

index 093146b..a8efe78 100644 (file)
@@ -1526,6 +1526,15 @@ int i915_driver_unload(struct drm_device *dev)
        }
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               /*
+                * free the memory space allocated for the child device
+                * config parsed from VBT
+                */
+               if (dev_priv->child_dev && dev_priv->child_dev_num) {
+                       kfree(dev_priv->child_dev);
+                       dev_priv->child_dev = NULL;
+                       dev_priv->child_dev_num = 0;
+               }
                drm_irq_uninstall(dev);
                vga_client_register(dev->pdev, NULL, NULL, NULL);
        }
index 13ede75..cc91cff 100644 (file)
@@ -545,6 +545,8 @@ typedef struct drm_i915_private {
        struct timer_list idle_timer;
        bool busy;
        u16 orig_clock;
+       int child_dev_num;
+       struct child_device_config *child_dev;
 } drm_i915_private_t;
 
 /** driver private structure attached to each drm_gem_object */
index 800d13b..73ceb36 100644 (file)
@@ -404,6 +404,70 @@ parse_driver_features(struct drm_i915_private *dev_priv,
                dev_priv->render_reclock_avail = true;
 }
 
+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,6 +519,7 @@ 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);
 
        pci_unmap_rom(pdev, bios);
index 0f8e5f6..425ac9d 100644 (file)
@@ -549,4 +549,21 @@ bool intel_init_bios(struct drm_device *dev);
 #define   SWF14_APM_STANDBY    0x1
 #define   SWF14_APM_RESTORE    0x0
 
+/* Add the device class for LFP, TV, HDMI */
+#define         DEVICE_TYPE_INT_LFP    0x1022
+#define         DEVICE_TYPE_INT_TV     0x1009
+#define         DEVICE_TYPE_HDMI       0x60D2
+#define         DEVICE_TYPE_DP         0x68C6
+#define         DEVICE_TYPE_eDP        0x78C6
+
+/* define the DVO port for HDMI output type */
+#define                DVO_B           1
+#define                DVO_C           2
+#define                DVO_D           3
+
+/* define the PORT for DP output type */
+#define                PORT_IDPB       7
+#define                PORT_IDPC       8
+#define                PORT_IDPD       9
+
 #endif /* _I830_BIOS_H_ */