[Intel-gfx] [intel-gfx][PATCH] i830_sdvo.c.v01:set sdvo-lvds modes from EDID and default modes.

Ma Ling ling.ma at intel.com
Fri Jan 23 09:02:38 CET 2009


Hi All,

Currently our SDVO driver only support basic SDVO-LVDS resolution (1024x768), 
this patch intends to support all default modes from EDID and default modes by scaling mode.
It is not final released version, in following work, I will append advanced functions 
such as backlight, and power controller options.

Any comments are welcome!
(I will be on holiday from 24 Jan to 31 Jan, please expect slow-email response.)

Thanks
Ma Ling

---
 src/i830_display.c |   14 ++++-
 src/i830_sdvo.c    |  167 +++++++++++++++++++++++++++++++++++++++++++++++----
 src/i830_sdvo.h    |    2 +-
 3 files changed, 165 insertions(+), 18 deletions(-)

diff --git a/src/i830_display.c b/src/i830_display.c
index 7a8e96d..8fe8d1a 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -1221,6 +1221,7 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
     xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
     I830Ptr pI830 = I830PTR(pScrn);
     I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+    xf86OutputPtr  output;
     I830OutputPrivatePtr intel_output;
     int pipe = intel_crtc->pipe;
     int plane = intel_crtc->plane;
@@ -1249,7 +1250,7 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
      * our pipe, used in DPLL setup.
      */
     for (i = 0; i < xf86_config->num_output; i++) {
-	xf86OutputPtr  output = xf86_config->output[i];
+	output = xf86_config->output[i];
 	intel_output = output->driver_private;
 
 	if (output->crtc != crtc)
@@ -1322,7 +1323,8 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
 	    if ((IS_I945G(pI830) || IS_I945GM(pI830) || IS_G33CLASS(pI830)) &&
 		!is_tv)
 	    {
-		int sdvo_pixel_multiply = adjusted_mode->Clock / mode->Clock;
+		int sdvo_pixel_multiply =
+		    i830_sdvo_get_pixel_multiplier(output, mode);
 		dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
 	    }
 	}
@@ -1503,7 +1505,13 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
     usleep(150);
     
     if (IS_I965G(pI830)) {
-	int sdvo_pixel_multiply = adjusted_mode->Clock / mode->Clock;
+
+	int sdvo_pixel_multiply;
+	if (is_sdvo == TRUE)
+	    sdvo_pixel_multiply = i830_sdvo_get_pixel_multiplier(output, mode);
+	else
+	    sdvo_pixel_multiply =  adjusted_mode->Clock / mode->Clock;
+
 	OUTREG(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
 	       ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
     } else {
diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index 0750166..d01c115 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -84,6 +84,11 @@ struct i830_sdvo_priv {
     Bool is_hdmi;
 
     /**
+     * This is set if we detect output of sdvo device as LVDS.
+     */
+    Bool is_lvds;
+
+    /**
      * Returned SDTV resolutions allowed for the current format, if the
      * device reported it.
      */
@@ -367,12 +372,21 @@ i830_sdvo_read_response(xf86OutputPtr output, void *response, int response_len)
     return status;
 }
 
-int
-i830_sdvo_get_pixel_multiplier(DisplayModePtr pMode)
+int i830_sdvo_get_pixel_multiplier(xf86OutputPtr output,
+			           DisplayModePtr pMode)
 {
-    if (pMode->Clock >= 100000)
+    I830OutputPrivatePtr    intel_output = output->driver_private;
+    struct i830_sdvo_priv   *dev_priv = intel_output->dev_priv;
+    uint32_t clock;
+
+    if (dev_priv->is_lvds == TRUE) {
+	clock = I830PTR(output->scrn)->lvds_fixed_mode->Clock;
+    } else
+	clock = pMode->Clock;
+
+    if (clock >= 100000)
 	return 1;
-    else if (pMode->Clock >= 50000)
+    else if (clock >= 50000)
 	return 2;
     else
 	return 4;
@@ -953,6 +967,51 @@ static void i830_sdvo_set_avi_infoframe(xf86OutputPtr output,
 			SDVO_HBUF_TX_VSYNC);
 }
 
+static void sdvo_lvds_fixup(xf86OutputPtr output,
+			    DisplayModePtr adjusted_mode,
+			    DisplayModePtr mode)
+{
+    I830Ptr pI830 = I830PTR(output->scrn);
+    int left_border = 0, right_border = 0,
+        top_border = 0, bottom_border = 0;
+
+    adjusted_mode->HDisplay = pI830->lvds_fixed_mode->HDisplay;
+    adjusted_mode->HSyncStart = pI830->lvds_fixed_mode->HSyncStart;
+    adjusted_mode->HSyncEnd = pI830->lvds_fixed_mode->HSyncEnd;
+    adjusted_mode->HTotal = pI830->lvds_fixed_mode->HTotal;
+    adjusted_mode->VDisplay = pI830->lvds_fixed_mode->VDisplay;
+    adjusted_mode->VSyncStart = pI830->lvds_fixed_mode->VSyncStart;
+    adjusted_mode->VSyncEnd = pI830->lvds_fixed_mode->VSyncEnd;
+    adjusted_mode->VTotal = pI830->lvds_fixed_mode->VTotal;
+    adjusted_mode->Clock = pI830->lvds_fixed_mode->Clock;
+    adjusted_mode->Clock *=
+	i830_sdvo_get_pixel_multiplier(output, mode);
+    xf86SetModeCrtc(adjusted_mode, INTERLACE_HALVE_V);
+
+    /* Currently only support fitting mode as Center*/
+    left_border = (adjusted_mode->HDisplay - mode->HDisplay) / 2;
+    right_border = left_border;
+    if (mode->HDisplay & 1)
+	right_border++;
+    top_border = (adjusted_mode->VDisplay - mode->VDisplay) / 2;
+    bottom_border = top_border;
+    if (mode->VDisplay & 1)
+	bottom_border++;
+
+    adjusted_mode->CrtcHDisplay = mode->HDisplay;
+    adjusted_mode->CrtcHBlankStart = mode->HDisplay + right_border - 1;
+    adjusted_mode->CrtcHBlankEnd = adjusted_mode->CrtcHTotal -
+	left_border - 1;
+    adjusted_mode->CrtcHSyncStart = adjusted_mode->CrtcHBlankStart;
+    adjusted_mode->CrtcHSyncEnd = adjusted_mode->CrtcHBlankEnd;
+    adjusted_mode->CrtcVDisplay = mode->VDisplay;
+    adjusted_mode->CrtcVBlankStart = mode->VDisplay + bottom_border - 1;
+    adjusted_mode->CrtcVBlankEnd = adjusted_mode->CrtcVTotal -
+	top_border - 1;
+    adjusted_mode->CrtcVSyncStart = adjusted_mode->CrtcVBlankStart;
+    adjusted_mode->CrtcVSyncEnd = adjusted_mode->CrtcVBlankEnd;
+}
+
 static Bool
 i830_sdvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
 		     DisplayModePtr adjusted_mode)
@@ -960,11 +1019,17 @@ i830_sdvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
     I830OutputPrivatePtr    intel_output = output->driver_private;
     struct i830_sdvo_priv   *dev_priv = intel_output->dev_priv;
 
-    if (!dev_priv->is_tv) {
+    if (!dev_priv->is_tv && !dev_priv->is_lvds) {
 	/* Make the CRTC code factor in the SDVO pixel multiplier.  The SDVO
 	 * device will be told of the multiplier during mode_set.
 	 */
-	adjusted_mode->Clock *= i830_sdvo_get_pixel_multiplier(mode);
+	adjusted_mode->Clock *=
+	    i830_sdvo_get_pixel_multiplier(output, mode);
+    } else if(dev_priv->is_lvds == TRUE) {
+	/* scale mode as adjusted mode based on
+	 * fixed mode from init function.
+	 */
+	sdvo_lvds_fixup(output, adjusted_mode, mode);
     } else {
 	struct i830_sdvo_dtd output_dtd;
 	Bool success;
@@ -1077,7 +1142,7 @@ i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode,
     i830_sdvo_set_input_timing(output, &input_dtd);
 #endif
 
-    switch (i830_sdvo_get_pixel_multiplier(mode)) {
+    switch (i830_sdvo_get_pixel_multiplier(output, mode)) {
     case 1:
 	i830_sdvo_set_clock_rate_mult(output, SDVO_CLOCK_RATE_MULT_1X);
 	break;
@@ -1109,7 +1174,7 @@ i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode,
     if (intel_crtc->pipe == 1)
 	sdvox |= SDVO_PIPE_B_SELECT;
 
-    sdvo_pixel_multiply = i830_sdvo_get_pixel_multiplier(mode);
+    sdvo_pixel_multiply = i830_sdvo_get_pixel_multiplier(output, mode);
     if (IS_I965G(pI830)) {
 	/* done in crtc_mode_set as the dpll_md reg must be written early */
     } else if (IS_I945G(pI830) || IS_I945GM(pI830) || IS_G33CLASS(pI830)) {
@@ -1749,6 +1814,71 @@ i830_sdvo_get_digital_encoding_mode(xf86OutputPtr output)
     return TRUE;
 }
 
+/* This function will try to fetch lvds fixed mode from sdvo device*/
+static Bool fetch_lvds_fixed_mode(xf86OutputPtr  output)
+{
+    I830Ptr		    pI830 = I830PTR(output->scrn);
+    DisplayModePtr	    modes, scan;
+    xf86CrtcPtr		    crtc;
+    uint32_t		    lvds;
+    uint32_t		    pipe;
+    Bool		    ret = TRUE;
+
+    /* Attempt to get the fixed panel mode from DDC.
+     * Assume that the preferred,mode is the right one.
+     * Mode list is arranged in priority order,
+     * so first ones are preferred.
+     */
+    modes = i830_ddc_get_modes(output);
+    for (scan = modes; scan != NULL; scan = scan->next) {
+	if (scan->type & M_T_PREFERRED) {
+	    /* Pull our chosen mode out
+	     * and make it the fixed mode.
+	     */
+	    if (modes == scan)
+		modes = modes->next;
+	    if (scan->prev != NULL)
+		scan->prev = scan->next;
+	    if (scan->next != NULL)
+		scan->next = scan->prev;
+
+	    pI830->lvds_fixed_mode = scan;
+	    goto end;
+	}
+    }
+
+    /* Get the LVDS fixed mode out of the BIOS.  We should support LVDS with
+     * the BIOS being unavailable or broken, but lack the configuration options
+     * for now.
+     */
+    if (pI830->lvds_fixed_mode)
+	goto end;
+
+    /* If we *still* don't have a mode, try checking if the panel is already
+     * turned on.  If so, assume that whatever is currently programmed is the
+     * correct mode.
+     */
+    lvds = INREG(LVDS);
+    pipe = (lvds & LVDS_PIPEB_SELECT) ? 1 : 0;
+    crtc = XF86_CRTC_CONFIG_PTR(output->scrn)->crtc[pipe];
+
+    if ((lvds & LVDS_PORT_EN) &&
+	(pI830->lvds_fixed_mode = i830_crtc_mode_get(output->scrn, crtc))) {
+	pI830->lvds_fixed_mode->type |= M_T_PREFERRED;
+	goto end;
+    }
+
+    /* failed to find fixed mode*/
+    ret = FALSE;
+end:
+    /* Delete the mode list we allocated */
+    while (modes != NULL)
+	xf86DeleteMode(&modes, modes);
+
+
+    return ret;
+}
+
 Bool
 i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
 {
@@ -1904,14 +2034,17 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
 	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;
+    }
+    else if (dev_priv->caps.output_flags &
+	    (SDVO_OUTPUT_LVDS0 | SDVO_OUTPUT_LVDS1)) {
+
+	if (dev_priv->caps.output_flags & SDVO_OUTPUT_LVDS0)
+	    dev_priv->controlled_output = SDVO_OUTPUT_LVDS0;
+	else
+	    dev_priv->controlled_output = SDVO_OUTPUT_LVDS1;
         output->subpixel_order = SubPixelHorizontalRGB;
 	name_prefix="LVDS";
+	dev_priv->is_lvds = TRUE;
     }
     else
     {
@@ -1936,6 +2069,12 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device)
 
     i830_sdvo_select_ddc_bus(dev_priv);
 
+    /* failed to fetch lvds fixed modes for sdvo device */
+    if (dev_priv->is_lvds == TRUE && fetch_lvds_fixed_mode(output) == FALSE) {
+	xf86OutputDestroy (output);
+	return FALSE;
+    }
+
     /* Set the input timing to the screen. Assume always input 0. */
     i830_sdvo_set_target_input(output, TRUE, FALSE);
 
diff --git a/src/i830_sdvo.h b/src/i830_sdvo.h
index 798a88d..1ab9d52 100644
--- a/src/i830_sdvo.h
+++ b/src/i830_sdvo.h
@@ -29,7 +29,7 @@ Bool
 i830_sdvo_init(ScrnInfoPtr pScrn, int output_device);
 
 int
-i830_sdvo_get_pixel_multiplier(DisplayModePtr pMode);
+i830_sdvo_get_pixel_multiplier(xf86OutputPtr output, DisplayModePtr pMode);
 
 void
 i830_sdvo_dump(ScrnInfoPtr pScrn);
-- 
1.5.4.4


 
 




More information about the Intel-gfx mailing list