summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_bios.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/intel_bios.c')
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c133
1 files changed, 64 insertions, 69 deletions
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index 198fc3c3291b..8e46149bafdd 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -122,42 +122,6 @@ 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,
@@ -213,7 +177,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
const struct lvds_dvo_timing *panel_dvo_timing;
const struct lvds_fp_timing *fp_timing;
struct drm_display_mode *panel_fixed_mode;
- int i, downclock, drrs_mode;
+ int drrs_mode;
lvds_options = find_section(bdb, BDB_LVDS_OPTIONS);
if (!lvds_options)
@@ -272,30 +236,6 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n");
drm_mode_debug_printmodeline(panel_fixed_mode);
- /*
- * 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++) {
- 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;
- }
-
- if (downclock < panel_dvo_timing->clock && i915.lvds_downclock) {
- dev_priv->lvds_downclock_avail = 1;
- dev_priv->lvds_downclock = downclock * 10;
- DRM_DEBUG_KMS("LVDS downclock is found in VBT. "
- "Normal Clock %dKHz, downclock %dKHz\n",
- panel_fixed_mode->clock, 10*downclock);
- }
-
fp_timing = get_lvds_fp_timing(bdb, lvds_lfp_data,
lvds_lfp_data_ptrs,
lvds_options->panel_type);
@@ -946,6 +886,17 @@ err:
memset(dev_priv->vbt.dsi.sequence, 0, sizeof(dev_priv->vbt.dsi.sequence));
}
+static u8 translate_iboost(u8 val)
+{
+ static const u8 mapping[] = { 1, 3, 7 }; /* See VBT spec */
+
+ if (val >= ARRAY_SIZE(mapping)) {
+ DRM_DEBUG_KMS("Unsupported I_boost value found in VBT (%d), display may not work properly\n", val);
+ return 0;
+ }
+ return mapping[val];
+}
+
static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
const struct bdb_header *bdb)
{
@@ -1028,13 +979,28 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
}
if (is_dp) {
- if (aux_channel == 0x40 && port != PORT_A)
+ if (port == PORT_E) {
+ info->alternate_aux_channel = aux_channel;
+ /* if DDIE share aux channel with other port, then
+ * DP couldn't exist on the shared port. Otherwise
+ * they share the same aux channel and system
+ * couldn't communicate with them seperately. */
+ if (aux_channel == DP_AUX_A)
+ dev_priv->vbt.ddi_port_info[PORT_A].supports_dp = 0;
+ else if (aux_channel == DP_AUX_B)
+ dev_priv->vbt.ddi_port_info[PORT_B].supports_dp = 0;
+ else if (aux_channel == DP_AUX_C)
+ dev_priv->vbt.ddi_port_info[PORT_C].supports_dp = 0;
+ else if (aux_channel == DP_AUX_D)
+ dev_priv->vbt.ddi_port_info[PORT_D].supports_dp = 0;
+ }
+ else if (aux_channel == DP_AUX_A && port != PORT_A)
DRM_DEBUG_KMS("Unexpected AUX channel for port A\n");
- if (aux_channel == 0x10 && port != PORT_B)
+ else if (aux_channel == DP_AUX_B && port != PORT_B)
DRM_DEBUG_KMS("Unexpected AUX channel for port B\n");
- if (aux_channel == 0x20 && port != PORT_C)
+ else if (aux_channel == DP_AUX_C && port != PORT_C)
DRM_DEBUG_KMS("Unexpected AUX channel for port C\n");
- if (aux_channel == 0x30 && port != PORT_D)
+ else if (aux_channel == DP_AUX_D && port != PORT_D)
DRM_DEBUG_KMS("Unexpected AUX channel for port D\n");
}
@@ -1046,6 +1012,16 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
hdmi_level_shift);
info->hdmi_level_shift = hdmi_level_shift;
}
+
+ /* Parse the I_boost config for SKL and above */
+ if (bdb->version >= 196 && (child->common.flags_1 & IBOOST_ENABLE)) {
+ info->dp_boost_level = translate_iboost(child->common.iboost_level & 0xF);
+ DRM_DEBUG_KMS("VBT (e)DP boost level for port %c: %d\n",
+ port_name(port), info->dp_boost_level);
+ info->hdmi_boost_level = translate_iboost(child->common.iboost_level >> 4);
+ DRM_DEBUG_KMS("VBT HDMI boost level for port %c: %d\n",
+ port_name(port), info->hdmi_boost_level);
+ }
}
static void parse_ddi_ports(struct drm_i915_private *dev_priv,
@@ -1075,15 +1051,34 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
const union child_device_config *p_child;
union child_device_config *child_dev_ptr;
int i, child_device_num, count;
- u16 block_size;
+ u8 expected_size;
+ u16 block_size;
p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
if (!p_defs) {
DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n");
return;
}
- if (p_defs->child_dev_size < sizeof(*p_child)) {
- DRM_ERROR("General definiton block child device size is too small.\n");
+ if (bdb->version < 195) {
+ expected_size = 33;
+ } else if (bdb->version == 195) {
+ expected_size = 37;
+ } else if (bdb->version <= 197) {
+ expected_size = 38;
+ } else {
+ expected_size = 38;
+ DRM_DEBUG_DRIVER("Expected child_device_config size for BDB version %u not known; assuming %u\n",
+ expected_size, bdb->version);
+ }
+
+ if (expected_size > sizeof(*p_child)) {
+ DRM_ERROR("child_device_config cannot fit in p_child\n");
+ return;
+ }
+
+ if (p_defs->child_dev_size != expected_size) {
+ DRM_ERROR("Size mismatch; child_device_config size=%u (expected %u); bdb->version: %u\n",
+ p_defs->child_dev_size, expected_size, bdb->version);
return;
}
/* get the block size of general definitions */
@@ -1130,7 +1125,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
child_dev_ptr = dev_priv->vbt.child_dev + count;
count++;
- memcpy(child_dev_ptr, p_child, sizeof(*p_child));
+ memcpy(child_dev_ptr, p_child, p_defs->child_dev_size);
}
return;
}
OpenPOWER on IntegriCloud