Subject: [RFC][Patch 1/3] DRM/I915: parse child device from VBT From: Zhao Yakui Parse the child device from VBT. Signed-Off-by: Zhao Yakui --- drivers/gpu/drm/i915/i915_dma.c | 11 ++++++ drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/intel_bios.c | 65 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) Index: linux-2.6/drivers/gpu/drm/i915/i915_drv.h =================================================================== --- linux-2.6.orig/drivers/gpu/drm/i915/i915_drv.h 2009-07-20 15:00:01.000000000 +0800 +++ linux-2.6/drivers/gpu/drm/i915/i915_drv.h 2009-07-20 17:24:22.000000000 +0800 @@ -437,6 +437,8 @@ struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT]; } mm; struct sdvo_device_mapping sdvo_mappings[2]; + int child_dev_num; + struct child_device_config *child_dev; } drm_i915_private_t; /** driver private structure attached to each drm_gem_object */ Index: linux-2.6/drivers/gpu/drm/i915/intel_bios.c =================================================================== --- linux-2.6.orig/drivers/gpu/drm/i915/intel_bios.c 2009-07-13 08:49:30.000000000 +0800 +++ linux-2.6/drivers/gpu/drm/i915/intel_bios.c 2009-07-20 16:52:51.000000000 +0800 @@ -295,6 +295,70 @@ } return; } +static void +parse_device_mapping_from_vbt(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, *block_ptr; + + p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); + if (!p_defs) { + DRM_DEBUG("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("different child size is found. Invalid.\n"); + return; + } + /* get the block size of general definitions */ + block_ptr = (u16 *)((char *)p_defs - 2); + block_size = *block_ptr; + /* 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("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("Can't allocate memory space for child device\n"); + } + 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; + printk(KERN_DEBUG "initial %p, result %p, size %d\n", + dev_priv->child_dev, child_dev_ptr, sizeof(*p_child) * 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 @@ -345,6 +409,7 @@ parse_lfp_panel_data(dev_priv, bdb); parse_sdvo_panel_data(dev_priv, bdb); parse_sdvo_device_mapping(dev_priv, bdb); + parse_device_mapping_from_vbt(dev_priv, bdb); pci_unmap_rom(pdev, bios); return 0; Index: linux-2.6/drivers/gpu/drm/i915/i915_dma.c =================================================================== --- linux-2.6.orig/drivers/gpu/drm/i915/i915_dma.c 2009-07-20 15:26:30.000000000 +0800 +++ linux-2.6/drivers/gpu/drm/i915/i915_dma.c 2009-07-20 15:29:54.000000000 +0800 @@ -1242,6 +1242,8 @@ } if (drm_core_check_feature(dev, DRIVER_MODESET)) { + dev_priv->child_dev = NULL; + dev_priv->child_dev_num = 0; ret = i915_load_modeset_init(dev, prealloc_size, agp_size); if (ret < 0) { DRM_ERROR("failed to init modeset\n"); @@ -1299,6 +1301,15 @@ mutex_unlock(&dev->struct_mutex); drm_mm_takedown(&dev_priv->vram); i915_gem_lastclose(dev); + /* + * free the memory space allocated for the child device + * config parsed from VBT + */ + if (dev_priv->child_dev_num && dev_priv->child_dev) { + kfree(dev_priv->child_dev); + dev_priv->child_dev = NULL; + dev_priv->child_dev_num = 0; + } } kfree(dev->dev_private);