mirror of https://gitee.com/openkylin/linux.git
drm/i915: Read the response after issuing DDC bus switch command
For some SDVO cards based on conexant chip, we can't read the EDID if we don't read the response after issuing SDVO DDC bus switch command. From the SDVO spec once when another I2C transaction is finished after completing the I2C transaction of issuing the bus switch command, it will be switched back to the SDVO internal state again. So we can't initiate a new I2C transaction to read the response after issuing the DDC bus switch command. Instead we should issue DDC bus switch command and read the response in the same I2C transaction. https://bugs.freedesktop.org/show_bug.cgi?id=23842 https://bugs.freedesktop.org/show_bug.cgi?id=24458 https://bugs.freedesktop.org/show_bug.cgi?id=24522 https://bugs.freedesktop.org/show_bug.cgi?id=24282 Signed-off-by: Zhao Yakui <yakui.zhao@intel.com> Tested-by: Sebastien Caty <sebastien.caty@mrnf.gouv.qc.ca> Signed-off-by: Eric Anholt <eric@anholt.net>
This commit is contained in:
parent
6207937d4f
commit
6a304caf0b
|
@ -462,14 +462,63 @@ static int intel_sdvo_get_pixel_multiplier(struct drm_display_mode *mode)
|
|||
}
|
||||
|
||||
/**
|
||||
* Don't check status code from this as it switches the bus back to the
|
||||
* SDVO chips which defeats the purpose of doing a bus switch in the first
|
||||
* place.
|
||||
* Try to read the response after issuie the DDC switch command. But it
|
||||
* is noted that we must do the action of reading response and issuing DDC
|
||||
* switch command in one I2C transaction. Otherwise when we try to start
|
||||
* another I2C transaction after issuing the DDC bus switch, it will be
|
||||
* switched to the internal SDVO register.
|
||||
*/
|
||||
static void intel_sdvo_set_control_bus_switch(struct intel_output *intel_output,
|
||||
u8 target)
|
||||
{
|
||||
intel_sdvo_write_cmd(intel_output, SDVO_CMD_SET_CONTROL_BUS_SWITCH, &target, 1);
|
||||
struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
|
||||
u8 out_buf[2], cmd_buf[2], ret_value[2], ret;
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = sdvo_priv->slave_addr >> 1,
|
||||
.flags = 0,
|
||||
.len = 2,
|
||||
.buf = out_buf,
|
||||
},
|
||||
/* the following two are to read the response */
|
||||
{
|
||||
.addr = sdvo_priv->slave_addr >> 1,
|
||||
.flags = 0,
|
||||
.len = 1,
|
||||
.buf = cmd_buf,
|
||||
},
|
||||
{
|
||||
.addr = sdvo_priv->slave_addr >> 1,
|
||||
.flags = I2C_M_RD,
|
||||
.len = 1,
|
||||
.buf = ret_value,
|
||||
},
|
||||
};
|
||||
|
||||
intel_sdvo_debug_write(intel_output, SDVO_CMD_SET_CONTROL_BUS_SWITCH,
|
||||
&target, 1);
|
||||
/* write the DDC switch command argument */
|
||||
intel_sdvo_write_byte(intel_output, SDVO_I2C_ARG_0, target);
|
||||
|
||||
out_buf[0] = SDVO_I2C_OPCODE;
|
||||
out_buf[1] = SDVO_CMD_SET_CONTROL_BUS_SWITCH;
|
||||
cmd_buf[0] = SDVO_I2C_CMD_STATUS;
|
||||
cmd_buf[1] = 0;
|
||||
ret_value[0] = 0;
|
||||
ret_value[1] = 0;
|
||||
|
||||
ret = i2c_transfer(intel_output->i2c_bus, msgs, 3);
|
||||
if (ret != 3) {
|
||||
/* failure in I2C transfer */
|
||||
DRM_DEBUG_KMS("I2c transfer returned %d\n", ret);
|
||||
return;
|
||||
}
|
||||
if (ret_value[0] != SDVO_CMD_STATUS_SUCCESS) {
|
||||
DRM_DEBUG_KMS("DDC switch command returns response %d\n",
|
||||
ret_value[0]);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static bool intel_sdvo_set_target_input(struct intel_output *intel_output, bool target_0, bool target_1)
|
||||
|
|
Loading…
Reference in New Issue