Commit 90e4f159 authored by Ville Syrjälä's avatar Ville Syrjälä Committed by Daniel Vetter

drm/i915: Fix the VBT child device parsing for BSW

Recent BSW VBT has a VBT child device size 37 bytes instead of the 33
bytes our code assumes. This means we fail to parse the VBT and thus
fail to detect eDP ports properly and just register them as DP ports
instead.

Fix it up by using the reported child device size from the VBT instead
of assuming it matches out struct defintions.

The latest spec I have shows that the child device size should be 36
bytes for rev >= 195, however on my BSW the size is actually 37 bytes.
And our current struct definition is 33 bytes.

Feels like the entire VBT parses would need to be rewritten to handle
changes in the layout better, but for now I've decided to do just the
bare minimum to get my eDP port back.

Cc: Vijay Purushothaman <vijay.a.purushothaman@linux.intel.com>
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: default avatarDamien Lespiau <damien.lespiau@intel.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent a4e0bedc
...@@ -447,6 +447,12 @@ parse_general_definitions(struct drm_i915_private *dev_priv, ...@@ -447,6 +447,12 @@ parse_general_definitions(struct drm_i915_private *dev_priv,
} }
} }
static union child_device_config *
child_device_ptr(struct bdb_general_definitions *p_defs, int i)
{
return (void *) &p_defs->devices[i * p_defs->child_dev_size];
}
static void static void
parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
struct bdb_header *bdb) struct bdb_header *bdb)
...@@ -476,10 +482,10 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, ...@@ -476,10 +482,10 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
block_size = get_blocksize(p_defs); block_size = get_blocksize(p_defs);
/* get the number of child device */ /* get the number of child device */
child_device_num = (block_size - sizeof(*p_defs)) / child_device_num = (block_size - sizeof(*p_defs)) /
sizeof(*p_child); p_defs->child_dev_size;
count = 0; count = 0;
for (i = 0; i < child_device_num; i++) { for (i = 0; i < child_device_num; i++) {
p_child = &(p_defs->devices[i]); p_child = child_device_ptr(p_defs, i);
if (!p_child->old.device_type) { if (!p_child->old.device_type) {
/* skip the device block if device type is invalid */ /* skip the device block if device type is invalid */
continue; continue;
...@@ -1067,25 +1073,19 @@ parse_device_mapping(struct drm_i915_private *dev_priv, ...@@ -1067,25 +1073,19 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n"); DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n");
return; return;
} }
/* judge whether the size of child device meets the requirements. if (p_defs->child_dev_size < sizeof(*p_child)) {
* If the child device size obtained from general definition block DRM_ERROR("General definiton block child device size is too small.\n");
* 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_KMS("different child size is found. Invalid.\n");
return; return;
} }
/* get the block size of general definitions */ /* get the block size of general definitions */
block_size = get_blocksize(p_defs); block_size = get_blocksize(p_defs);
/* get the number of child device */ /* get the number of child device */
child_device_num = (block_size - sizeof(*p_defs)) / child_device_num = (block_size - sizeof(*p_defs)) /
sizeof(*p_child); p_defs->child_dev_size;
count = 0; count = 0;
/* get the number of child device that is present */ /* get the number of child device that is present */
for (i = 0; i < child_device_num; i++) { for (i = 0; i < child_device_num; i++) {
p_child = &(p_defs->devices[i]); p_child = child_device_ptr(p_defs, i);
if (!p_child->common.device_type) { if (!p_child->common.device_type) {
/* skip the device block if device type is invalid */ /* skip the device block if device type is invalid */
continue; continue;
...@@ -1105,7 +1105,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv, ...@@ -1105,7 +1105,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
dev_priv->vbt.child_dev_num = count; dev_priv->vbt.child_dev_num = count;
count = 0; count = 0;
for (i = 0; i < child_device_num; i++) { for (i = 0; i < child_device_num; i++) {
p_child = &(p_defs->devices[i]); p_child = child_device_ptr(p_defs, i);
if (!p_child->common.device_type) { if (!p_child->common.device_type) {
/* skip the device block if device type is invalid */ /* skip the device block if device type is invalid */
continue; continue;
......
...@@ -277,9 +277,9 @@ struct bdb_general_definitions { ...@@ -277,9 +277,9 @@ struct bdb_general_definitions {
* And the device num is related with the size of general definition * And the device num is related with the size of general definition
* block. It is obtained by using the following formula: * block. It is obtained by using the following formula:
* number = (block_size - sizeof(bdb_general_definitions))/ * number = (block_size - sizeof(bdb_general_definitions))/
* sizeof(child_device_config); * defs->child_dev_size;
*/ */
union child_device_config devices[0]; uint8_t devices[0];
} __packed; } __packed;
/* Mask for DRRS / Panel Channel / SSC / BLT control bits extraction */ /* Mask for DRRS / Panel Channel / SSC / BLT control bits extraction */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment