Skip to content

Commit

Permalink
drm/i915: VBT's child_device_config changes over time
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Paulo Zanoni authored and Daniel Vetter committed Oct 1, 2013
1 parent f740334 commit 768f69c
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 29 deletions.
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
36 changes: 18 additions & 18 deletions drivers/gpu/drm/i915/intel_bios.c
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
{
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;

Expand All @@ -416,36 +416,36 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
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,
Expand All @@ -457,7 +457,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv,
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"
Expand Down Expand Up @@ -588,7 +588,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
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;

Expand Down Expand Up @@ -616,7 +616,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
/* 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;
}
Expand All @@ -636,7 +636,7 @@ parse_device_mapping(struct drm_i915_private *dev_priv,
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;
}
Expand Down
33 changes: 31 additions & 2 deletions drivers/gpu/drm/i915/intel_bios.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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;
Expand All @@ -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 {
Expand Down
6 changes: 3 additions & 3 deletions drivers/gpu/drm/i915/intel_dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -3203,7 +3203,7 @@ intel_trans_dp_port_sel(struct drm_crtc *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)
Expand All @@ -3212,8 +3212,8 @@ bool intel_dpd_is_edp(struct drm_device *dev)
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;
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/i915/intel_lvds.c
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,8 @@ static bool lvds_is_present_in_vbt(struct drm_device *dev,
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
Expand Down
8 changes: 4 additions & 4 deletions drivers/gpu/drm/i915/intel_tv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1518,7 +1518,7 @@ static const struct drm_encoder_funcs intel_tv_enc_funcs = {
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)
Expand All @@ -1530,13 +1530,13 @@ static int tv_is_present_in_vbt(struct drm_device *dev)
/*
* 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;
}
Expand Down

0 comments on commit 768f69c

Please sign in to comment.