Skip to content

Commit

Permalink
drm/i915: Improve CRTDDC mapping by using VBT info
Browse files Browse the repository at this point in the history
Use VBT information to determine which DDC bus to use for CRTDCC.
Fall back to GPIOA if VBT info is not available.

Signed-off-by: David Müller <d.mueller@elsoft.ch>
Reviewed-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: Eric Anholt <eric@anholt.net>
Tested on: 855 (David), and 945GM, 965GM, GM45, and G45 (anholt)
  • Loading branch information
David Müller (ELSOFT AG) authored and Eric Anholt committed Aug 30, 2009
1 parent a09ba7f commit db54501
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 4 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ typedef struct drm_i915_private {
unsigned int edp_support:1;
int lvds_ssc_freq;

int crt_ddc_bus; /* -1 = unknown, else GPIO to use for CRT DDC */
struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */
int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
int num_fence_regs; /* 8 on pre-965, 16 otherwise */
Expand Down
51 changes: 48 additions & 3 deletions drivers/gpu/drm/i915/intel_bios.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ find_section(struct bdb_header *bdb, int section_id)
return NULL;
}

static u16
get_blocksize(void *p)
{
u16 *block_ptr, block_size;

block_ptr = (u16 *)((char *)p - 2);
block_size = *block_ptr;
return block_size;
}

static void
fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,
struct lvds_dvo_timing *dvo_timing)
Expand Down Expand Up @@ -214,6 +224,41 @@ parse_general_features(struct drm_i915_private *dev_priv,
}
}

static void
parse_general_definitions(struct drm_i915_private *dev_priv,
struct bdb_header *bdb)
{
struct bdb_general_definitions *general;
const int crt_bus_map_table[] = {
GPIOB,
GPIOA,
GPIOC,
GPIOD,
GPIOE,
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);
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",
block_size);
}
}
}

static void
parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
struct bdb_header *bdb)
Expand All @@ -222,7 +267,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
struct bdb_general_definitions *p_defs;
struct child_device_config *p_child;
int i, child_device_num, count;
u16 block_size, *block_ptr;
u16 block_size;

p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
if (!p_defs) {
Expand All @@ -240,8 +285,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
return;
}
/* get the block size of general definitions */
block_ptr = (u16 *)((char *)p_defs - 2);
block_size = *block_ptr;
block_size = get_blocksize(p_defs);
/* get the number of child device */
child_device_num = (block_size - sizeof(*p_defs)) /
sizeof(*p_child);
Expand Down Expand Up @@ -362,6 +406,7 @@ intel_init_bios(struct drm_device *dev)

/* Grab useful general definitions */
parse_general_features(dev_priv, bdb);
parse_general_definitions(dev_priv, bdb);
parse_lfp_panel_data(dev_priv, bdb);
parse_sdvo_panel_data(dev_priv, bdb);
parse_sdvo_device_mapping(dev_priv, bdb);
Expand Down
7 changes: 6 additions & 1 deletion drivers/gpu/drm/i915/intel_crt.c
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@ void intel_crt_init(struct drm_device *dev)
{
struct drm_connector *connector;
struct intel_output *intel_output;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 i2c_reg;

intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
Expand All @@ -527,8 +528,12 @@ void intel_crt_init(struct drm_device *dev)
/* Set up the DDC bus. */
if (IS_IGDNG(dev))
i2c_reg = PCH_GPIOA;
else
else {
i2c_reg = GPIOA;
/* Use VBT information for CRT DDC if available */
if (dev_priv->crt_ddc_bus != -1)
i2c_reg = dev_priv->crt_ddc_bus;
}
intel_output->ddc_bus = intel_i2c_create(dev, i2c_reg, "CRTDDC_A");
if (!intel_output->ddc_bus) {
dev_printk(KERN_ERR, &dev->pdev->dev, "DDC bus registration "
Expand Down

0 comments on commit db54501

Please sign in to comment.