| From 996f9c914d9cb3892c52dd229ebfd42f1766af55 Mon Sep 17 00:00:00 2001 |
| From: Paulo Zanoni <paulo.r.zanoni@intel.com> |
| Date: Wed, 11 Sep 2013 18:02:47 -0300 |
| Subject: drm/i915: VBT's child_device_config changes over time |
| |
| We currently treat the child_device_config as a simple struct, but |
| this is not correct: new BDB versions change the meaning of some |
| offsets, so the struct needs to be adjusted for each version. |
| |
| Since there are too many changes (today we're in version 170!), making |
| a big versioned union would be too complicated, so child_device_config |
| is now a union of 3 things: (i) a "raw" byte array that's safe to use |
| anywhere; (ii) an "old" structure that's the one we've been using and |
| should be safe to keep in the SDVO and TV code; and (iii) a "common" |
| structure that should contain only fields that are common for all the |
| known VBT versions. |
| |
| Signed-off-by: Paulo Zanoni <paulo.r.zanoni@intel.com> |
| Reviewed-by: Rodrigo Vivi <rodrigo.vivi@gmail.com> |
| Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> |
| (cherry picked from commit 768f69c9fe601af39dfeb377f45909896f201444) |
| Signed-off-by: Darren Hart <dvhart@linux.intel.com> |
| --- |
| drivers/gpu/drm/i915/i915_drv.h | 2 +- |
| drivers/gpu/drm/i915/intel_bios.c | 36 ++++++++++++++++++------------------ |
| drivers/gpu/drm/i915/intel_bios.h | 33 +++++++++++++++++++++++++++++++-- |
| drivers/gpu/drm/i915/intel_dp.c | 6 +++--- |
| drivers/gpu/drm/i915/intel_lvds.c | 3 ++- |
| drivers/gpu/drm/i915/intel_tv.c | 8 ++++---- |
| 6 files changed, 59 insertions(+), 29 deletions(-) |
| |
| --- a/drivers/gpu/drm/i915/i915_drv.h |
| +++ b/drivers/gpu/drm/i915/i915_drv.h |
| @@ -1090,7 +1090,7 @@ struct intel_vbt_data { |
| int crt_ddc_pin; |
| |
| int child_dev_num; |
| - struct child_device_config *child_dev; |
| + union child_device_config *child_dev; |
| }; |
| |
| enum intel_ddb_partitioning { |
| --- a/drivers/gpu/drm/i915/intel_bios.c |
| +++ b/drivers/gpu/drm/i915/intel_bios.c |
| @@ -389,7 +389,7 @@ parse_sdvo_device_mapping(struct drm_i91 |
| { |
| struct sdvo_device_mapping *p_mapping; |
| struct bdb_general_definitions *p_defs; |
| - struct child_device_config *p_child; |
| + union child_device_config *p_child; |
| int i, child_device_num, count; |
| u16 block_size; |
| |
| @@ -416,36 +416,36 @@ parse_sdvo_device_mapping(struct drm_i91 |
| count = 0; |
| for (i = 0; i < child_device_num; i++) { |
| p_child = &(p_defs->devices[i]); |
| - if (!p_child->device_type) { |
| + if (!p_child->old.device_type) { |
| /* skip the device block if device type is invalid */ |
| continue; |
| } |
| - if (p_child->slave_addr != SLAVE_ADDR1 && |
| - p_child->slave_addr != SLAVE_ADDR2) { |
| + if (p_child->old.slave_addr != SLAVE_ADDR1 && |
| + p_child->old.slave_addr != SLAVE_ADDR2) { |
| /* |
| * If the slave address is neither 0x70 nor 0x72, |
| * it is not a SDVO device. Skip it. |
| */ |
| continue; |
| } |
| - if (p_child->dvo_port != DEVICE_PORT_DVOB && |
| - p_child->dvo_port != DEVICE_PORT_DVOC) { |
| + if (p_child->old.dvo_port != DEVICE_PORT_DVOB && |
| + p_child->old.dvo_port != DEVICE_PORT_DVOC) { |
| /* skip the incorrect SDVO port */ |
| DRM_DEBUG_KMS("Incorrect SDVO port. Skip it\n"); |
| continue; |
| } |
| DRM_DEBUG_KMS("the SDVO device with slave addr %2x is found on" |
| " %s port\n", |
| - p_child->slave_addr, |
| - (p_child->dvo_port == DEVICE_PORT_DVOB) ? |
| + p_child->old.slave_addr, |
| + (p_child->old.dvo_port == DEVICE_PORT_DVOB) ? |
| "SDVOB" : "SDVOC"); |
| - p_mapping = &(dev_priv->sdvo_mappings[p_child->dvo_port - 1]); |
| + p_mapping = &(dev_priv->sdvo_mappings[p_child->old.dvo_port - 1]); |
| if (!p_mapping->initialized) { |
| - p_mapping->dvo_port = p_child->dvo_port; |
| - p_mapping->slave_addr = p_child->slave_addr; |
| - p_mapping->dvo_wiring = p_child->dvo_wiring; |
| - p_mapping->ddc_pin = p_child->ddc_pin; |
| - p_mapping->i2c_pin = p_child->i2c_pin; |
| + p_mapping->dvo_port = p_child->old.dvo_port; |
| + p_mapping->slave_addr = p_child->old.slave_addr; |
| + p_mapping->dvo_wiring = p_child->old.dvo_wiring; |
| + p_mapping->ddc_pin = p_child->old.ddc_pin; |
| + p_mapping->i2c_pin = p_child->old.i2c_pin; |
| p_mapping->initialized = 1; |
| DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d\n", |
| p_mapping->dvo_port, |
| @@ -457,7 +457,7 @@ parse_sdvo_device_mapping(struct drm_i91 |
| DRM_DEBUG_KMS("Maybe one SDVO port is shared by " |
| "two SDVO device.\n"); |
| } |
| - if (p_child->slave2_addr) { |
| + if (p_child->old.slave2_addr) { |
| /* Maybe this is a SDVO device with multiple inputs */ |
| /* And the mapping info is not added */ |
| DRM_DEBUG_KMS("there exists the slave2_addr. Maybe this" |
| @@ -588,7 +588,7 @@ parse_device_mapping(struct drm_i915_pri |
| struct bdb_header *bdb) |
| { |
| struct bdb_general_definitions *p_defs; |
| - struct child_device_config *p_child, *child_dev_ptr; |
| + union child_device_config *p_child, *child_dev_ptr; |
| int i, child_device_num, count; |
| u16 block_size; |
| |
| @@ -616,7 +616,7 @@ parse_device_mapping(struct drm_i915_pri |
| /* get the number of child device that is present */ |
| for (i = 0; i < child_device_num; i++) { |
| p_child = &(p_defs->devices[i]); |
| - if (!p_child->device_type) { |
| + if (!p_child->common.device_type) { |
| /* skip the device block if device type is invalid */ |
| continue; |
| } |
| @@ -636,7 +636,7 @@ parse_device_mapping(struct drm_i915_pri |
| count = 0; |
| for (i = 0; i < child_device_num; i++) { |
| p_child = &(p_defs->devices[i]); |
| - if (!p_child->device_type) { |
| + if (!p_child->common.device_type) { |
| /* skip the device block if device type is invalid */ |
| continue; |
| } |
| --- a/drivers/gpu/drm/i915/intel_bios.h |
| +++ b/drivers/gpu/drm/i915/intel_bios.h |
| @@ -202,7 +202,10 @@ struct bdb_general_features { |
| #define DEVICE_PORT_DVOB 0x01 |
| #define DEVICE_PORT_DVOC 0x02 |
| |
| -struct child_device_config { |
| +/* We used to keep this struct but without any version control. We should avoid |
| + * using it in the future, but it should be safe to keep using it in the old |
| + * code. */ |
| +struct old_child_dev_config { |
| u16 handle; |
| u16 device_type; |
| u8 device_id[10]; /* ascii string */ |
| @@ -224,6 +227,32 @@ struct child_device_config { |
| u8 dvo_function; |
| } __attribute__((packed)); |
| |
| +/* This one contains field offsets that are known to be common for all BDB |
| + * versions. Notice that the meaning of the contents contents may still change, |
| + * but at least the offsets are consistent. */ |
| +struct common_child_dev_config { |
| + u16 handle; |
| + u16 device_type; |
| + u8 not_common1[12]; |
| + u8 dvo_port; |
| + u8 not_common2[2]; |
| + u8 ddc_pin; |
| + u16 edid_ptr; |
| +} __attribute__((packed)); |
| + |
| +/* This field changes depending on the BDB version, so the most reliable way to |
| + * read it is by checking the BDB version and reading the raw pointer. */ |
| +union child_device_config { |
| + /* This one is safe to be used anywhere, but the code should still check |
| + * the BDB version. */ |
| + u8 raw[33]; |
| + /* This one should only be kept for legacy code. */ |
| + struct old_child_dev_config old; |
| + /* This one should also be safe to use anywhere, even without version |
| + * checks. */ |
| + struct common_child_dev_config common; |
| +}; |
| + |
| struct bdb_general_definitions { |
| /* DDC GPIO */ |
| u8 crt_ddc_gmbus_pin; |
| @@ -249,7 +278,7 @@ struct bdb_general_definitions { |
| * number = (block_size - sizeof(bdb_general_definitions))/ |
| * sizeof(child_device_config); |
| */ |
| - struct child_device_config devices[0]; |
| + union child_device_config devices[0]; |
| } __attribute__((packed)); |
| |
| struct bdb_lvds_options { |
| --- a/drivers/gpu/drm/i915/intel_dp.c |
| +++ b/drivers/gpu/drm/i915/intel_dp.c |
| @@ -3227,7 +3227,7 @@ intel_trans_dp_port_sel(struct drm_crtc |
| bool intel_dpd_is_edp(struct drm_device *dev) |
| { |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| - struct child_device_config *p_child; |
| + union child_device_config *p_child; |
| int i; |
| |
| if (!dev_priv->vbt.child_dev_num) |
| @@ -3236,8 +3236,8 @@ bool intel_dpd_is_edp(struct drm_device |
| for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { |
| p_child = dev_priv->vbt.child_dev + i; |
| |
| - if (p_child->dvo_port == PORT_IDPD && |
| - p_child->device_type == DEVICE_TYPE_eDP) |
| + if (p_child->common.dvo_port == PORT_IDPD && |
| + p_child->common.device_type == DEVICE_TYPE_eDP) |
| return true; |
| } |
| return false; |
| --- a/drivers/gpu/drm/i915/intel_lvds.c |
| +++ b/drivers/gpu/drm/i915/intel_lvds.c |
| @@ -810,7 +810,8 @@ static bool lvds_is_present_in_vbt(struc |
| return true; |
| |
| for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { |
| - struct child_device_config *child = dev_priv->vbt.child_dev + i; |
| + union child_device_config *uchild = dev_priv->vbt.child_dev + i; |
| + struct old_child_dev_config *child = &uchild->old; |
| |
| /* If the device type is not LFP, continue. |
| * We have to check both the new identifiers as well as the |
| --- a/drivers/gpu/drm/i915/intel_tv.c |
| +++ b/drivers/gpu/drm/i915/intel_tv.c |
| @@ -1522,7 +1522,7 @@ static const struct drm_encoder_funcs in |
| static int tv_is_present_in_vbt(struct drm_device *dev) |
| { |
| struct drm_i915_private *dev_priv = dev->dev_private; |
| - struct child_device_config *p_child; |
| + union child_device_config *p_child; |
| int i, ret; |
| |
| if (!dev_priv->vbt.child_dev_num) |
| @@ -1534,13 +1534,13 @@ static int tv_is_present_in_vbt(struct d |
| /* |
| * If the device type is not TV, continue. |
| */ |
| - if (p_child->device_type != DEVICE_TYPE_INT_TV && |
| - p_child->device_type != DEVICE_TYPE_TV) |
| + if (p_child->old.device_type != DEVICE_TYPE_INT_TV && |
| + p_child->old.device_type != DEVICE_TYPE_TV) |
| continue; |
| /* Only when the addin_offset is non-zero, it is regarded |
| * as present. |
| */ |
| - if (p_child->addin_offset) { |
| + if (p_child->old.addin_offset) { |
| ret = 1; |
| break; |
| } |