diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_bios.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_bios.c | 142 | 
1 files changed, 83 insertions, 59 deletions
| diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 927442a11925..61abef8a8119 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -74,7 +74,7 @@ get_blocksize(void *p)  static void  fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, -			struct lvds_dvo_timing *dvo_timing) +			const struct lvds_dvo_timing *dvo_timing)  {  	panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) |  		dvo_timing->hactive_lo; @@ -115,20 +115,75 @@ fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode,  	drm_mode_set_name(panel_fixed_mode);  } +static bool +lvds_dvo_timing_equal_size(const struct lvds_dvo_timing *a, +			   const struct lvds_dvo_timing *b) +{ +	if (a->hactive_hi != b->hactive_hi || +	    a->hactive_lo != b->hactive_lo) +		return false; + +	if (a->hsync_off_hi != b->hsync_off_hi || +	    a->hsync_off_lo != b->hsync_off_lo) +		return false; + +	if (a->hsync_pulse_width != b->hsync_pulse_width) +		return false; + +	if (a->hblank_hi != b->hblank_hi || +	    a->hblank_lo != b->hblank_lo) +		return false; + +	if (a->vactive_hi != b->vactive_hi || +	    a->vactive_lo != b->vactive_lo) +		return false; + +	if (a->vsync_off != b->vsync_off) +		return false; + +	if (a->vsync_pulse_width != b->vsync_pulse_width) +		return false; + +	if (a->vblank_hi != b->vblank_hi || +	    a->vblank_lo != b->vblank_lo) +		return false; + +	return true; +} + +static const struct lvds_dvo_timing * +get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data, +		    const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs, +		    int index) +{ +	/* +	 * the size of fp_timing varies on the different platform. +	 * So calculate the DVO timing relative offset in LVDS data +	 * entry to get the DVO timing entry +	 */ + +	int lfp_data_size = +		lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset - +		lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset; +	int dvo_timing_offset = +		lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset - +		lvds_lfp_data_ptrs->ptr[0].fp_timing_offset; +	char *entry = (char *)lvds_lfp_data->data + lfp_data_size * index; + +	return (struct lvds_dvo_timing *)(entry + dvo_timing_offset); +} +  /* Try to find integrated panel data */  static void  parse_lfp_panel_data(struct drm_i915_private *dev_priv,  			    struct bdb_header *bdb)  { -	struct bdb_lvds_options *lvds_options; -	struct bdb_lvds_lfp_data *lvds_lfp_data; -	struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; -	struct bdb_lvds_lfp_data_entry *entry; -	struct lvds_dvo_timing *dvo_timing; +	const struct bdb_lvds_options *lvds_options; +	const struct bdb_lvds_lfp_data *lvds_lfp_data; +	const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs; +	const struct lvds_dvo_timing *panel_dvo_timing;  	struct drm_display_mode *panel_fixed_mode; -	int lfp_data_size, dvo_timing_offset; -	int i, temp_downclock; -	struct drm_display_mode *temp_mode; +	int i, downclock;  	lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);  	if (!lvds_options) @@ -150,75 +205,44 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,  	dev_priv->lvds_vbt = 1; -	lfp_data_size = lvds_lfp_data_ptrs->ptr[1].dvo_timing_offset - -		lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset; -	entry = (struct bdb_lvds_lfp_data_entry *) -		((uint8_t *)lvds_lfp_data->data + (lfp_data_size * -						   lvds_options->panel_type)); -	dvo_timing_offset = lvds_lfp_data_ptrs->ptr[0].dvo_timing_offset - -		lvds_lfp_data_ptrs->ptr[0].fp_timing_offset; - -	/* -	 * the size of fp_timing varies on the different platform. -	 * So calculate the DVO timing relative offset in LVDS data -	 * entry to get the DVO timing entry -	 */ -	dvo_timing = (struct lvds_dvo_timing *) -			((unsigned char *)entry + dvo_timing_offset); +	panel_dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, +					       lvds_lfp_data_ptrs, +					       lvds_options->panel_type);  	panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL);  	if (!panel_fixed_mode)  		return; -	fill_detail_timing_data(panel_fixed_mode, dvo_timing); +	fill_detail_timing_data(panel_fixed_mode, panel_dvo_timing);  	dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode;  	DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n");  	drm_mode_debug_printmodeline(panel_fixed_mode); -	temp_mode = kzalloc(sizeof(*temp_mode), GFP_KERNEL); -	temp_downclock = panel_fixed_mode->clock;  	/* -	 * enumerate the LVDS panel timing info entry in VBT to check whether -	 * the LVDS downclock is found. +	 * Iterate over the LVDS panel timing info to find the lowest clock +	 * for the native resolution.  	 */ +	downclock = panel_dvo_timing->clock;  	for (i = 0; i < 16; i++) { -		entry = (struct bdb_lvds_lfp_data_entry *) -			((uint8_t *)lvds_lfp_data->data + (lfp_data_size * i)); -		dvo_timing = (struct lvds_dvo_timing *) -			((unsigned char *)entry + dvo_timing_offset); - -		fill_detail_timing_data(temp_mode, dvo_timing); - -		if (temp_mode->hdisplay == panel_fixed_mode->hdisplay && -		temp_mode->hsync_start == panel_fixed_mode->hsync_start && -		temp_mode->hsync_end == panel_fixed_mode->hsync_end && -		temp_mode->htotal == panel_fixed_mode->htotal && -		temp_mode->vdisplay == panel_fixed_mode->vdisplay && -		temp_mode->vsync_start == panel_fixed_mode->vsync_start && -		temp_mode->vsync_end == panel_fixed_mode->vsync_end && -		temp_mode->vtotal == panel_fixed_mode->vtotal && -		temp_mode->clock < temp_downclock) { -			/* -			 * downclock is already found. But we expect -			 * to find the lower downclock. -			 */ -			temp_downclock = temp_mode->clock; -		} -		/* clear it to zero */ -		memset(temp_mode, 0, sizeof(*temp_mode)); +		const struct lvds_dvo_timing *dvo_timing; + +		dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, +						 lvds_lfp_data_ptrs, +						 i); +		if (lvds_dvo_timing_equal_size(dvo_timing, panel_dvo_timing) && +		    dvo_timing->clock < downclock) +			downclock = dvo_timing->clock;  	} -	kfree(temp_mode); -	if (temp_downclock < panel_fixed_mode->clock && -	    i915_lvds_downclock) { + +	if (downclock < panel_dvo_timing->clock && i915_lvds_downclock) {  		dev_priv->lvds_downclock_avail = 1; -		dev_priv->lvds_downclock = temp_downclock; +		dev_priv->lvds_downclock = downclock * 10;  		DRM_DEBUG_KMS("LVDS downclock is found in VBT. "  			      "Normal Clock %dKHz, downclock %dKHz\n", -			      temp_downclock, panel_fixed_mode->clock); +			      panel_fixed_mode->clock, 10*downclock);  	} -	return;  }  /* Try to find sdvo panel data */ | 
