[Intel-gfx] [PATCH 1/2] drm/i915: try to read the response after issue SDVO DDC bus switch

yakui.zhao at intel.com yakui.zhao at intel.com
Fri Dec 18 10:33:10 CET 2009


From: Zhao Yakui <yakui.zhao at intel.com>

When the external monitor is connected throught SDVO DVI-D, we must issue the
DDC switch command and read the EDID of external monitor. But on one SDVO
card based on conextant chip, we can't read the EDID after issuing the DDC
switch command. Then it causes that we can't detect the external monitor even
when it is really connected.

After some investigation we find that this issue is caused by that we don't
read the response after issuing the DDC switch command.

https://bugs.freedesktop.org/show_bug.cgi?id=23842

Signed-off-by: Zhao Yakui <yakui.zhao at intel.com>
Tested-by: Sebastien Caty <sebastien.caty at mrnf.gouv.qc.ca>
---
The DDC swith on SDVO card is divided into two steps:
   a. send the DDC switch argument. It means which DDC bus should be selected
behind the SDVO card.
   b. send the DDC switch command.
   Then we will start to read the EDID. And after one I2C transaction is
finished, it will switch to SDVO internal register again. It means that we
must issue another DDC switch command if we try to read the EDID again.

In the vbios code it will read the response after issuing the DDC switch command,
which is missing in our driver. It is noted that the DDC switch command and 
reading response are finished in one I2C transaction.(When the I2c stop is issued,
it is regarded as that I2C transaction is finished.)Then I try to read the response
after issuing the DDC switch command. And it is very surprising that we can get
the EDID of external monitor on this SDVO card. 

But we can't use the function of intel_sdvo_read_response directly to read
the response after issuing the DDC switch command. In our code it will issue
i2c stop after issuing the DDC switch command. If we use the intel_sdvo_read_response
to read the response, it means that we will restart another i2c transaction.Then
it will switch to SDVO internal register and we can't read the EDID.

 drivers/gpu/drm/i915/intel_sdvo.c |   57 ++++++++++++++++++++++++++++++++++--
 1 files changed, 53 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index de5144c..f899afd 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -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)
-- 
1.5.4.5




More information about the Intel-gfx mailing list