Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit db545019 authored by David Müller (ELSOFT AG)'s avatar David Müller (ELSOFT AG) Committed by Eric Anholt
Browse files

drm/i915: Improve CRTDDC mapping by using VBT info



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: default avatarDavid Müller <d.mueller@elsoft.ch>
Reviewed-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
Tested on: 855 (David), and 945GM, 965GM, GM45, and G45 (anholt)
parent a09ba7fa
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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 */
+48 −3
Original line number Diff line number Diff line
@@ -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)
@@ -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)
@@ -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) {
@@ -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);
@@ -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);
+6 −1
Original line number Diff line number Diff line
@@ -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);
@@ -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 "