[Intel-gfx] [PATCH 3/4 V2] drm/i915: Construct all possible sdvo outputs for sdvo encoder

ling.ma at intel.com ling.ma at intel.com
Mon Jul 13 11:57:56 CEST 2009


SDVO encoders will advertise multiple functions,
We will be aware of the real one until sdvo output detection
completes, sometime we have to change connector and encoder
type, it looks strange for users. So we construct all possible
sdvo outputs at initialization time, and mark real output owner
after detection finised. Sinc then any operation to sdvo device
will be monitored by sdvo output owner

Signed-off-by: Ma Ling <ling.ma at intel.com>
---
 drivers/gpu/drm/i915/intel_sdvo.c |  155 +++++++++++++++++++++++++-----------
 1 files changed, 107 insertions(+), 48 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 4f0c309..5f3ab36 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -37,11 +37,21 @@
 
 #undef SDVO_DEBUG
 #define I915_SDVO	"i915_sdvo"
-struct intel_sdvo_priv {
-	u8 slave_addr;
+#define ANYOUTPUT	0
 
+struct output_device {
 	/* Register for the SDVO device: SDVOB or SDVOC */
 	int output_device;
+	uint16_t output_owner;
+};
+
+struct output_device  SDVOB_PORT;
+struct output_device  SDVOC_PORT;
+
+struct intel_sdvo_priv {
+	u8 slave_addr;
+
+	struct output_device  *sdvodevice;
 
 	/* Active outputs controlled by this SDVO output */
 	uint16_t controlled_output;
@@ -127,7 +137,7 @@ static void intel_sdvo_write_sdvox(struct intel_output *intel_output, u32 val)
 	u32 bval = val, cval = val;
 	int i;
 
-	if (sdvo_priv->output_device == SDVOB) {
+	if (sdvo_priv->sdvodevice->output_device == SDVOB) {
 		cval = I915_READ(SDVOC);
 	} else {
 		bval = I915_READ(SDVOB);
@@ -278,8 +288,10 @@ static const struct _sdvo_cmd_name {
     SDVO_CMD_NAME_ENTRY(SDVO_CMD_GET_HBUF_DATA),
 };
 
-#define SDVO_NAME(dev_priv) ((dev_priv)->output_device == SDVOB ? "SDVOB" : "SDVOC")
-#define SDVO_PRIV(output)   ((struct intel_sdvo_priv *) (output)->dev_priv)
+#define SDVO_NAME(dev_priv) \
+((dev_priv)->sdvodevice->output_device == SDVOB ? "SDVOB" : "SDVOC")
+#define SDVO_PRIV(output) \
+((struct intel_sdvo_priv *) (output)->dev_priv)
 
 #ifdef SDVO_DEBUG
 static void intel_sdvo_debug_write(struct intel_output *intel_output, u8 cmd,
@@ -1153,8 +1165,8 @@ static void intel_sdvo_mode_set(struct drm_encoder *encoder,
 			SDVO_VSYNC_ACTIVE_HIGH |
 			SDVO_HSYNC_ACTIVE_HIGH;
 	} else {
-		sdvox |= I915_READ(sdvo_priv->output_device);
-		switch (sdvo_priv->output_device) {
+		sdvox |= I915_READ(sdvo_priv->sdvodevice->output_device);
+		switch (sdvo_priv->sdvodevice->output_device) {
 		case SDVOB:
 			sdvox &= SDVOB_PRESERVE_MASK;
 			break;
@@ -1189,13 +1201,22 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
 	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
 	u32 temp;
 
+	/*
+	* Only real output owner have right to control
+	* corresponding output device.
+	*/
+
+	if (sdvo_priv->sdvodevice->output_owner != ANYOUTPUT &&
+	    sdvo_priv->sdvodevice->output_owner != sdvo_priv->controlled_output)
+		return;
+
 	if (mode != DRM_MODE_DPMS_ON) {
 		intel_sdvo_set_active_outputs(intel_output, 0);
 		if (0)
 			intel_sdvo_set_encoder_power_state(intel_output, mode);
 
 		if (mode == DRM_MODE_DPMS_OFF) {
-			temp = I915_READ(sdvo_priv->output_device);
+			temp = I915_READ(sdvo_priv->sdvodevice->output_device);
 			if ((temp & SDVO_ENABLE) != 0) {
 				intel_sdvo_write_sdvox(intel_output, temp & ~SDVO_ENABLE);
 			}
@@ -1205,7 +1226,7 @@ static void intel_sdvo_dpms(struct drm_encoder *encoder, int mode)
 		int i;
 		u8 status;
 
-		temp = I915_READ(sdvo_priv->output_device);
+		temp = I915_READ(sdvo_priv->sdvodevice->output_device);
 		if ((temp & SDVO_ENABLE) == 0)
 			intel_sdvo_write_sdvox(intel_output, temp | SDVO_ENABLE);
 		for (i = 0; i < 2; i++)
@@ -1268,7 +1289,7 @@ static void intel_sdvo_save(struct drm_connector *connector)
 		/* XXX: Save TV format/enhancements. */
 	}
 
-	sdvo_priv->save_SDVOX = I915_READ(sdvo_priv->output_device);
+	sdvo_priv->save_SDVOX = I915_READ(sdvo_priv->sdvodevice->output_device);
 }
 
 static void intel_sdvo_restore(struct drm_connector *connector)
@@ -1379,10 +1400,10 @@ struct drm_connector* intel_sdvo_find(struct drm_device *dev, int sdvoB)
 
 		sdvo = iout->dev_priv;
 
-		if (sdvo->output_device == SDVOB && sdvoB)
+		if (sdvo->sdvodevice->output_device == SDVOB && sdvoB)
 			return connector;
 
-		if (sdvo->output_device == SDVOC && !sdvoB)
+		if (sdvo->sdvodevice->output_device == SDVOC && !sdvoB)
 			return connector;
 
 	}
@@ -1453,20 +1474,24 @@ intel_sdvo_hdmi_sink_detect(struct drm_connector *connector)
 
 static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connector)
 {
-	u8 response[2];
+	u16 response;
 	u8 status;
 	struct intel_output *intel_output = to_intel_output(connector);
+	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
 
 	intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
 	status = intel_sdvo_read_response(intel_output, &response, 2);
 
-	DRM_DEBUG("SDVO response %d %d\n", response[0], response[1]);
+	DRM_DEBUG("SDVO response %d %d\n", response & 0xff, response >> 8);
 
 	if (status != SDVO_CMD_STATUS_SUCCESS)
 		return connector_status_unknown;
 
-	if ((response[0] != 0) || (response[1] != 0)) {
+	if (response & sdvo_priv->controlled_output) {
 		intel_sdvo_hdmi_sink_detect(connector);
+		/* We found the real output controler on this port */
+		sdvo_priv->sdvodevice->output_owner =
+			sdvo_priv->controlled_output;
 		return connector_status_connected;
 	} else
 		return connector_status_disconnected;
@@ -1866,7 +1891,9 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, int output_device)
 		return 0x72;
 }
 
-bool intel_sdvo_init(struct drm_device *dev, int output_device)
+#define MAX_SDVO_OUTPUTS_BITS 0xFFFF
+static int intel_sdvo_outputs_init(struct drm_device *dev, int output_device,
+				   int sdvo_output_id, int sdvo_output_flags)
 {
 	struct drm_connector *connector;
 	struct intel_output *intel_output;
@@ -1876,24 +1903,35 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
 	u8 ch[0x40];
 	int i;
 	int encoder_type;
+	uint16_t maked_output_flags;
 
 	intel_output = kcalloc(sizeof(struct intel_output)+sizeof(struct intel_sdvo_priv), 1, GFP_KERNEL);
 	if (!intel_output) {
-		return false;
+		return -1;
 	}
 
 	sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1);
-	sdvo_priv->output_device = output_device;
 
 	intel_output->dev_priv = sdvo_priv;
 	intel_output->type = INTEL_OUTPUT_SDVO;
 
 	/* setup the DDC bus. */
-	if (output_device == SDVOB)
-		intel_output->i2c_bus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB");
-	else
-		intel_output->i2c_bus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC");
+	if (output_device == SDVOB) {
+		sdvo_priv->sdvodevice = &SDVOB_PORT;
+		sdvo_priv->sdvodevice->output_device = output_device;
+		sprintf(ch, "SDVOCTRL_E for SDVOB_%d", sdvo_output_id);
+		intel_output->i2c_bus = intel_i2c_create(dev,
+					GPIOE, (const char *)ch);
+	} else {
+		sdvo_priv->sdvodevice = &SDVOC_PORT;
+		sdvo_priv->sdvodevice->output_device = output_device;
+		sprintf(ch, "SDVOCTRL_E for SDVOC_%d", sdvo_output_id);
+		intel_output->i2c_bus = intel_i2c_create(dev,
+					GPIOE, (const char *)ch);
+	}
 
+	/* We do not know the real sdvo encoder function on this port */
+	sdvo_priv->sdvodevice->output_owner = ANYOUTPUT;
 	if (!intel_output->i2c_bus)
 		goto err_inteloutput;
 
@@ -1913,10 +1951,15 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
 	}
 
 	/* setup the DDC bus. */
-	if (output_device == SDVOB)
-		intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS");
-	else
-		intel_output->ddc_bus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS");
+	if (output_device == SDVOB) {
+		sprintf(ch, "SDVOB DDC BUS_%d", sdvo_output_id);
+		intel_output->ddc_bus = intel_i2c_create(dev,
+					GPIOE, (const char *)ch);
+	} else {
+		sprintf(ch, "SDVOC DDC BUS_%d", sdvo_output_id);
+		intel_output->ddc_bus = intel_i2c_create(dev,
+					GPIOE, (const char *)ch);
+	}
 
 	if (intel_output->ddc_bus == NULL)
 		goto err_i2c;
@@ -1928,8 +1971,11 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
 	sdvo_priv->is_lvds = false;
 	intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps);
 
-	if (sdvo_priv->caps.output_flags &
-	    (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) {
+	if (sdvo_output_flags == MAX_SDVO_OUTPUTS_BITS)
+		sdvo_output_flags = sdvo_priv->caps.output_flags;
+
+	maked_output_flags = sdvo_output_flags & sdvo_priv->caps.output_flags;
+	if (maked_output_flags & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1)) {
 		if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
 			sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS0;
 		else
@@ -1948,43 +1994,36 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
 						   SDVO_COLORIMETRY_RGB256);
 			connector_type = DRM_MODE_CONNECTOR_HDMIA;
 		}
-	}
-	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_SVID0)
-	{
+	} else if (maked_output_flags & SDVO_OUTPUT_SVID0) {
+
 		sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0;
 		encoder_type = DRM_MODE_ENCODER_TVDAC;
 		connector_type = DRM_MODE_CONNECTOR_SVIDEO;
 		sdvo_priv->is_tv = true;
 		intel_output->needs_tv_clock = true;
-	}
-	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0)
-	{
+	} else if (maked_output_flags & SDVO_OUTPUT_RGB0) {
+
 		sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0;
 		encoder_type = DRM_MODE_ENCODER_DAC;
 		connector_type = DRM_MODE_CONNECTOR_VGA;
-	}
-	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1)
-	{
+	} else if (maked_output_flags & SDVO_OUTPUT_RGB1) {
+
 		sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1;
 		encoder_type = DRM_MODE_ENCODER_DAC;
 		connector_type = DRM_MODE_CONNECTOR_VGA;
-	}
-	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS0)
-	{
+	} else if (maked_output_flags & SDVO_OUTPUT_LVDS0) {
+
 		sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0;
 		encoder_type = DRM_MODE_ENCODER_LVDS;
 		connector_type = DRM_MODE_CONNECTOR_LVDS;
 		sdvo_priv->is_lvds = true;
-	}
-	else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS1)
-	{
+	} else if (maked_output_flags & SDVO_OUTPUT_LVDS1) {
+
 		sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1;
 		encoder_type = DRM_MODE_ENCODER_LVDS;
 		connector_type = DRM_MODE_CONNECTOR_LVDS;
 		sdvo_priv->is_lvds = true;
-	}
-	else
-	{
+	} else {
 		unsigned char bytes[2];
 
 		sdvo_priv->controlled_output = 0;
@@ -2039,7 +2078,7 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device)
 			sdvo_priv->caps.output_flags &
 			(SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N');
 
-	return true;
+	return sdvo_output_flags & (~sdvo_priv->controlled_output);
 
 err_i2c:
 	if (intel_output->ddc_bus != NULL)
@@ -2049,5 +2088,25 @@ err_i2c:
 err_inteloutput:
 	kfree(intel_output);
 
-	return false;
+	return -1;
+}
+
+bool intel_sdvo_init(struct drm_device *dev, int output_device)
+{
+	int sdvo_output_id;
+	int sdvo_output_flags = MAX_SDVO_OUTPUTS_BITS;
+	bool ret = false;
+	sdvo_output_id = 1;
+
+	do {
+		sdvo_output_flags =
+			intel_sdvo_outputs_init(dev, output_device,
+						sdvo_output_id++,
+						sdvo_output_flags);
+		if (sdvo_output_flags >= 0)
+			ret = true;
+	} while (sdvo_output_flags > 0);
+
+	return ret;
 }
+
-- 
1.5.4.4




More information about the Intel-gfx mailing list