[Intel-gfx] [PATCH 2/2] SDVO: handle multifunction encoder

Zhenyu Wang zhenyu.z.wang at intel.com
Mon Jan 5 09:35:34 CET 2009


For SDVO encoder that advertise multiple functions,
we have to get current attached display to determine
output type.
---
 src/i830_sdvo.c |  237 +++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 162 insertions(+), 75 deletions(-)

diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index 219eb6a..b96454f 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -66,6 +66,11 @@ struct i830_sdvo_priv {
      */
     struct i830_sdvo_caps caps;
 
+    /**
+     * SDVO devices currently attached by i830_sdvo_get_attached_display()
+     */
+    uint16_t attached_output;
+
     /** Pixel clock limitations reported by the SDVO device, in kHz */
     int pixel_clock_min, pixel_clock_max;
 
@@ -113,6 +118,8 @@ struct i830_sdvo_priv {
     /** @} */
 };
 
+static Bool i830_sdvo_output_setup(xf86OutputPtr , uint16_t );
+
 /**
  * Writes the SDVOB or SDVOC with the given value, but always writes both
  * SDVOB and SDVOC to work around apparent hardware issues (according to
@@ -1455,12 +1462,52 @@ i830_sdvo_digital_output(xf86OutputPtr output)
     I830OutputPrivatePtr intel_output = output->driver_private;
     struct i830_sdvo_priv *dev_priv = intel_output->dev_priv;
 
-    if (dev_priv->caps.output_flags & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1))
+    if (dev_priv->attached_output & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1))
 	return TRUE;
     else
 	return FALSE;
 }
 
+static Bool
+i830_sdvo_get_attached_display (xf86OutputPtr output, uint16_t* response)
+{
+    uint8_t status;
+
+    i830_sdvo_write_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
+
+    status = i830_sdvo_read_response(output, response, 2);
+    if (status != SDVO_CMD_STATUS_SUCCESS)
+	return FALSE;
+    else
+	return TRUE;
+}
+
+
+static Bool
+i830_sdvo_multifunc_encoder(xf86OutputPtr output)
+{
+    I830OutputPrivatePtr  intel_output = output->driver_private;
+    struct i830_sdvo_priv *dev_priv = intel_output->dev_priv;
+    int count = 0;
+
+    if (dev_priv->caps.output_flags & (SDVO_OUTPUT_TMDS0 |
+		SDVO_OUTPUT_TMDS1))
+	count++;
+    if (dev_priv->caps.output_flags & (SDVO_OUTPUT_RGB0 |
+		SDVO_OUTPUT_RGB1))
+	count++;
+    if (dev_priv->caps.output_flags & (SDVO_OUTPUT_CVBS0 |
+		SDVO_OUTPUT_SVID0 | SDVO_OUTPUT_YPRPB0 |
+		SDVO_OUTPUT_SCART0 | SDVO_OUTPUT_CVBS1 |
+		SDVO_OUTPUT_SVID1 | SDVO_OUTPUT_YPRPB1 |
+		SDVO_OUTPUT_SCART1))
+	count++;
+    if (dev_priv->caps.output_flags & (SDVO_OUTPUT_LVDS0 |
+		SDVO_OUTPUT_LVDS1))
+	count++;
+    return (count > 1);
+}
+
 /**
  * Asks the SDVO device if any displays are currently connected.
  *
@@ -1474,19 +1521,25 @@ static xf86OutputStatus
 i830_sdvo_detect(xf86OutputPtr output)
 {
     I830OutputPrivatePtr intel_output = output->driver_private;
+    struct i830_sdvo_priv *dev_priv = intel_output->dev_priv;
     xf86MonPtr edid_mon;
-    uint8_t response[2];
-    uint8_t status;
-
-    i830_sdvo_write_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
-    status = i830_sdvo_read_response(output, &response, 2);
+    uint16_t response;
 
-    if (status != SDVO_CMD_STATUS_SUCCESS)
+    if (i830_sdvo_get_attached_display(output, &response)
+	    == FALSE)
 	return XF86OutputStatusUnknown;
 
-    if (response[0] == 0 && response[1] == 0)
+    if (response == 0)
 	return XF86OutputStatusDisconnected;
 
+    if (dev_priv->attached_output != response) {
+	dev_priv->attached_output = response;
+	if (i830_sdvo_multifunc_encoder(output) &&
+		i830_sdvo_output_setup(output, dev_priv->attached_output)
+		== FALSE)
+	    return XF86OutputStatusUnknown;
+    }
+
     if (i830_sdvo_digital_output(output)) {
 	/* EDID is required and type should be digital, otherwise
 	   we don't assume it's connected. */
@@ -1773,6 +1826,94 @@ i830_sdvo_get_digital_encoding_mode(xf86OutputPtr output)
     return TRUE;
 }
 
+static Bool
+i830_sdvo_output_setup(xf86OutputPtr output, uint16_t flag)
+{
+    I830OutputPrivatePtr  intel_output = output->driver_private;
+    struct i830_sdvo_priv *dev_priv = intel_output->dev_priv;
+    char                 name[60];
+    char                 *name_prefix;
+    char                 *name_suffix;
+
+    if (dev_priv->output_device == SDVOB)
+	name_suffix="-1";
+    else
+	name_suffix="-2";
+
+    if (flag & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1))
+    {
+	if (flag & SDVO_OUTPUT_TMDS0)
+	    dev_priv->controlled_output = SDVO_OUTPUT_TMDS0;
+	else
+	    dev_priv->controlled_output = SDVO_OUTPUT_TMDS1;
+	output->subpixel_order = SubPixelHorizontalRGB;
+	name_prefix="TMDS";
+
+	if (i830_sdvo_get_supp_encode(output, &dev_priv->encode) &&
+		i830_sdvo_get_digital_encoding_mode(output) &&
+		dev_priv->is_hdmi) {
+	    /* enable hdmi encoding mode if supported */
+	    i830_sdvo_set_encode(output, SDVO_ENCODE_HDMI);
+	    i830_sdvo_set_colorimetry(output, SDVO_COLORIMETRY_RGB256);
+	    name_prefix = "HDMI";
+	}
+    }
+    else if (flag & SDVO_OUTPUT_RGB0)
+    {
+	dev_priv->controlled_output = SDVO_OUTPUT_RGB0;
+	output->subpixel_order = SubPixelHorizontalRGB;
+	name_prefix="VGA";
+    }
+    else if (flag & SDVO_OUTPUT_RGB1)
+    {
+	dev_priv->controlled_output = SDVO_OUTPUT_RGB1;
+	output->subpixel_order = SubPixelHorizontalRGB;
+	name_prefix="VGA";
+    }
+    else if (dev_priv->caps.output_flags & SDVO_OUTPUT_LVDS0)
+    {
+	dev_priv->controlled_output = SDVO_OUTPUT_LVDS0;
+	output->subpixel_order = SubPixelHorizontalRGB;
+	name_prefix="LVDS";
+    }
+    else if (dev_priv->caps.output_flags & SDVO_OUTPUT_LVDS1)
+    {
+	dev_priv->controlled_output = SDVO_OUTPUT_LVDS1;
+	output->subpixel_order = SubPixelHorizontalRGB;
+	name_prefix="LVDS";
+    }
+    else if (flag & SDVO_OUTPUT_SVID0)
+    {
+	dev_priv->controlled_output = SDVO_OUTPUT_SVID0;
+	output->subpixel_order = SubPixelHorizontalRGB; /* XXX */
+	name_prefix="TV";
+	dev_priv->is_tv = TRUE;
+	intel_output->needs_tv_clock = TRUE;
+    }
+    else
+    {
+	unsigned char   bytes[2];
+
+	dev_priv->controlled_output = 0;
+	memcpy (bytes, &flag, 2);
+	xf86DrvMsg(intel_output->pI2CBus->scrnIndex, X_WARNING,
+		"%s: Unknown SDVO output type (0x%02x%02x)\n",
+		SDVO_NAME(dev_priv),
+		bytes[0], bytes[1]);
+	name_prefix="Unknown";
+    }
+
+    strcpy (name, name_prefix);
+    strcat (name, name_suffix);
+    if (!xf86OutputRename (output, name)) {
+	return FALSE;
+    }
+
+    i830_sdvo_select_ddc_bus(dev_priv);
+
+    return TRUE;
+}
+
 Bool
 i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
 {
@@ -1782,11 +1923,9 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
     int			    i;
     unsigned char	    ch[0x40];
     I2CBusPtr		    i2cbus = NULL, ddcbus;
-    char		    name[60];
-    char		    *name_prefix;
-    char		    *name_suffix;
 
-    output = xf86OutputCreate (pScrn, &i830_sdvo_output_funcs,NULL);
+    output = xf86OutputCreate (pScrn, &i830_sdvo_output_funcs,
+	    (output_device == SDVOB) ? "SDVOB" : "SDVOC");
     if (!output)
 	return FALSE;
     intel_output = xnfcalloc (sizeof (I830OutputPrivateRec) +
@@ -1824,11 +1963,9 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
     if (output_device == SDVOB) {
 	dev_priv->d.DevName = "SDVO Controller B";
 	dev_priv->d.SlaveAddr = 0x70;
-	name_suffix="-1";
     } else {
 	dev_priv->d.DevName = "SDVO Controller C";
 	dev_priv->d.SlaveAddr = 0x72;
-	name_suffix="-2";
     }
     dev_priv->d.pI2CBus = i2cbus;
     dev_priv->d.DriverPrivate.ptr = output;
@@ -1889,76 +2026,26 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
     intel_output->pDDCBus = ddcbus;
     intel_output->dev_priv = dev_priv;
 
-    i830_sdvo_get_capabilities(output, &dev_priv->caps);
-
-    if (dev_priv->caps.output_flags & (SDVO_OUTPUT_TMDS0 | SDVO_OUTPUT_TMDS1))
+    if (i830_sdvo_get_capabilities(output, &dev_priv->caps) == FALSE ||
+	    dev_priv->caps.output_flags == 0)
     {
-	if (dev_priv->caps.output_flags & SDVO_OUTPUT_TMDS0)
-	    dev_priv->controlled_output = SDVO_OUTPUT_TMDS0;
-	else
-	    dev_priv->controlled_output = SDVO_OUTPUT_TMDS1;
-        output->subpixel_order = SubPixelHorizontalRGB;
-	name_prefix="TMDS";
-
-	if (i830_sdvo_get_supp_encode(output, &dev_priv->encode) &&
-		i830_sdvo_get_digital_encoding_mode(output) &&
-		dev_priv->is_hdmi) {
-	    /* enable hdmi encoding mode if supported */
-	    i830_sdvo_set_encode(output, SDVO_ENCODE_HDMI);
-	    i830_sdvo_set_colorimetry(output, SDVO_COLORIMETRY_RGB256);
-	    name_prefix = "HDMI";
-	}
-    }
-    else if (dev_priv->caps.output_flags & SDVO_OUTPUT_SVID0)
-    {
-	dev_priv->controlled_output = SDVO_OUTPUT_SVID0;
-        output->subpixel_order = SubPixelHorizontalRGB; /* XXX */
-	name_prefix="TV";
-	dev_priv->is_tv = TRUE;
-	intel_output->needs_tv_clock = TRUE;
-    }
-    else if (dev_priv->caps.output_flags & SDVO_OUTPUT_RGB0)
-    {
-	dev_priv->controlled_output = SDVO_OUTPUT_RGB0;
-        output->subpixel_order = SubPixelHorizontalRGB;
-	name_prefix="VGA";
-    }
-    else if (dev_priv->caps.output_flags & SDVO_OUTPUT_RGB1)
-    {
-	dev_priv->controlled_output = SDVO_OUTPUT_RGB1;
-        output->subpixel_order = SubPixelHorizontalRGB;
-	name_prefix="VGA";
-    } else if (dev_priv->caps.output_flags & SDVO_OUTPUT_LVDS0) {
-	dev_priv->controlled_output = SDVO_OUTPUT_LVDS0;
-        output->subpixel_order = SubPixelHorizontalRGB;
-	name_prefix="LVDS";
-    } else if (dev_priv->caps.output_flags & SDVO_OUTPUT_LVDS1) {
-	dev_priv->controlled_output = SDVO_OUTPUT_LVDS1;
-        output->subpixel_order = SubPixelHorizontalRGB;
-	name_prefix="LVDS";
-    }
-    else
-    {
-	unsigned char	bytes[2];
-
-	dev_priv->controlled_output = 0;
-	memcpy (bytes, &dev_priv->caps.output_flags, 2);
 	xf86DrvMsg(intel_output->pI2CBus->scrnIndex, X_WARNING,
-		   "%s: Unknown SDVO output type (0x%02x%02x)\n",
-		   SDVO_NAME(dev_priv),
-		   bytes[0], bytes[1]);
-	name_prefix="Unknown";
+		   "%s: can't get encoder capability\n",
+		   SDVO_NAME(dev_priv));
+	xf86OutputDestroy (output);
+	return FALSE;
     }
 
-    strcpy (name, name_prefix);
-    strcat (name, name_suffix);
-    if (!xf86OutputRename (output, name))
+    /* if capability flags has no multiple function outputs,
+       setup output, else leave to ->detect time */
+    if (!i830_sdvo_multifunc_encoder(output) &&
+	    i830_sdvo_output_setup(output, dev_priv->caps.output_flags)
+	    == FALSE)
     {
 	xf86OutputDestroy (output);
 	return FALSE;
     }
 
-    i830_sdvo_select_ddc_bus(dev_priv);
 
     /* Set the input timing to the screen. Assume always input 0. */
     i830_sdvo_set_target_input(output, TRUE, FALSE);
-- 
1.5.6.5




More information about the Intel-gfx mailing list