xf86-video-intel: src/i830_sdvo.c src/i830_sdvo_regs.h

Zhenyu Wang zhen at kemper.freedesktop.org
Tue Jul 7 22:20:51 PDT 2009


 src/i830_sdvo.c      |   93 ++++++++++++++++++++++++++++++++++++++++++++-------
 src/i830_sdvo_regs.h |    2 +
 2 files changed, 83 insertions(+), 12 deletions(-)

New commits:
commit 216d939858abc924f2e32c95518f937f29ea018e
Author: ling.ma at intel.com <ling.ma at intel.com>
Date:   Tue Jul 7 14:26:02 2009 +0800

    enable sdvo lvds scaling function
    
    Currently we implemented basic sdvo lvds function,
    But except for sdvo lvds fixed mode, we can not switch
    to other modes, otherwise display get black. The patch
    intends to work for all modes whose HDisplay and VDisplay
    are lower than fixed mode.
    
    Signed-off-by: Ma Ling <ling.ma at intel.com>

diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index acfe599..8f3193b 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -95,6 +95,11 @@ struct i830_sdvo_priv {
      * This is set if we detect output of sdvo device as LVDS.
      */
     Bool is_lvds;
+    DisplayModePtr sdvo_lvds_fixed_mode;
+    /**
+     *This is set if output is LVDS or TV.
+     */
+    uint8_t sdvo_flags;
 
     /**
      * Returned SDTV resolutions allowed for the current format, if the
@@ -614,6 +619,8 @@ static Bool
 i830_sdvo_create_preferred_input_timing(xf86OutputPtr output, uint16_t clock,
 					uint16_t width, uint16_t height)
 {
+    I830OutputPrivatePtr    intel_output = output->driver_private;
+    struct i830_sdvo_priv   *dev_priv = intel_output->dev_priv;
     struct i830_sdvo_preferred_input_timing_args args;
     uint8_t status;
 
@@ -622,7 +629,11 @@ i830_sdvo_create_preferred_input_timing(xf86OutputPtr output, uint16_t clock,
     args.width = width;
     args.height = height;
     args.interlace = 0;
-    args.scaled = 0;
+    if (dev_priv->is_lvds &&
+        (dev_priv->sdvo_lvds_fixed_mode->HDisplay != width ||
+        (dev_priv->sdvo_lvds_fixed_mode->VDisplay != height)))
+        args.scaled = 1;
+
     i830_sdvo_write_cmd(output, SDVO_CMD_CREATE_PREFERRED_INPUT_TIMING,
 			&args, sizeof(args));
     status = i830_sdvo_read_response(output, NULL, 0);
@@ -1012,12 +1023,7 @@ 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) {
-	/* 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);
-    } else {
+    if (dev_priv->is_tv) {
 	struct i830_sdvo_dtd output_dtd;
 	Bool success;
 
@@ -1048,6 +1054,7 @@ i830_sdvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
 	    i830_sdvo_get_preferred_input_timing(output, &input_dtd);
 
 	    i830_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
+	    dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags;
 
 	    xf86SetModeCrtc(adjusted_mode, 0);
 
@@ -1063,7 +1070,47 @@ i830_sdvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
 	} else {
 	    return FALSE;
 	}
-    }
+    } else if (dev_priv->is_lvds) {
+        struct i830_sdvo_dtd output_dtd;
+        Bool success;
+
+        /* Set output timings */
+        i830_sdvo_get_dtd_from_mode(&output_dtd,
+                                    dev_priv->sdvo_lvds_fixed_mode);
+        i830_sdvo_set_target_output(output, dev_priv->controlled_output);
+        i830_sdvo_set_output_timing(output, &output_dtd);
+
+        /* Set the input timing to the screen. Assume always input 0. */
+        i830_sdvo_set_target_input(output, TRUE, FALSE);
+
+
+        success = i830_sdvo_create_preferred_input_timing(output,
+                                                          mode->Clock / 10,
+                                                          mode->HDisplay,
+                                                          mode->VDisplay);
+        if (success) {
+            struct i830_sdvo_dtd input_dtd;
+
+            i830_sdvo_get_preferred_input_timing(output, &input_dtd);
+
+            i830_sdvo_get_mode_from_dtd(adjusted_mode, &input_dtd);
+            dev_priv->sdvo_flags = input_dtd.part2.sdvo_flags;
+
+            xf86SetModeCrtc(adjusted_mode, 0);
+
+            /* adjust origin mode's clock for current input,
+              for correct pixel mulitiplier setting. */
+            mode->Clock = adjusted_mode->Clock;
+
+            /* Clock range is required to be in 100-200Mhz */
+            adjusted_mode->Clock *= i830_sdvo_get_pixel_multiplier(mode);
+        } else
+            return FALSE;
+    } else
+	/* 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);
 
     return TRUE;
 }
@@ -1107,9 +1154,10 @@ i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode,
 
     /* We have tried to get input timing in mode_fixup, and filled into
        adjusted_mode */
-    if (dev_priv->is_tv)
+    if (dev_priv->is_tv || dev_priv->is_lvds) {
 	i830_sdvo_get_dtd_from_mode(&input_dtd, adjusted_mode);
-    else
+        input_dtd.part2.sdvo_flags = dev_priv->sdvo_flags;
+    } else
 	i830_sdvo_get_dtd_from_mode(&input_dtd, mode);
 
     /* If it's a TV, we already set the output timing in mode_fixup.
@@ -1122,7 +1170,7 @@ i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode,
     if (dev_priv->is_tv)
 	i830_sdvo_set_tv_format(output);
 
-    if (!dev_priv->is_tv) {
+    if (!dev_priv->is_tv && !dev_priv->is_lvds) {
 	/* Set the output timing to the screen */
 	i830_sdvo_set_output_timing(output, &input_dtd);
     }
@@ -1185,6 +1233,8 @@ i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode,
     } else {
 	sdvox |= (sdvo_pixel_multiply - 1) << SDVO_PORT_MULTIPLY_SHIFT;
     }
+    if (dev_priv->sdvo_flags & SDVO_STALL_FLAG)
+        sdvox |= SDVO_STALL_SELECT;
 
     i830_sdvo_write_sdvox(output, sdvox);
 
@@ -1343,6 +1393,16 @@ i830_sdvo_mode_valid(xf86OutputPtr output, DisplayModePtr pMode)
 
     if (dev_priv->pixel_clock_max < pMode->Clock)
 	return MODE_CLOCK_HIGH;
+    if (dev_priv->is_lvds) {
+        if (dev_priv->sdvo_lvds_fixed_mode == NULL)
+            return MODE_PANEL;
+
+        if (pMode->HDisplay > dev_priv->sdvo_lvds_fixed_mode->HDisplay)
+            return MODE_PANEL;
+
+        if (pMode->VDisplay > dev_priv->sdvo_lvds_fixed_mode->VDisplay)
+            return MODE_PANEL;
+    }
 
     return MODE_OK;
 }
@@ -1556,6 +1616,8 @@ i830_sdvo_check_hdmi_encode (xf86OutputPtr output)
 /* This function will try to fetch native modes for sdvo lvds output*/
 static DisplayModePtr i830_sdvo_lvds_fetch_modes(xf86OutputPtr  output)
 {
+    I830OutputPrivatePtr intel_output =output->driver_private;
+    struct i830_sdvo_priv *dev_priv = intel_output->dev_priv;
     I830Ptr                 pI830 = I830PTR(output->scrn);
     DisplayModePtr          modes;
 
@@ -1573,8 +1635,11 @@ static DisplayModePtr i830_sdvo_lvds_fetch_modes(xf86OutputPtr  output)
 
 end:
     /* Guarantee the the first preferred mode is chosen by xserver */
-    if (modes != NULL)
+    if (modes != NULL) {
+        dev_priv->sdvo_lvds_fixed_mode = xf86DuplicateMode(modes);
         modes->type |= (M_T_DRIVER | M_T_PREFERRED);
+        xf86SetModeCrtc(dev_priv->sdvo_lvds_fixed_mode, 0);
+    }
     return modes;
 }
 
@@ -1958,6 +2023,10 @@ i830_sdvo_destroy (xf86OutputPtr output)
 		xfree(randr_output->name);
 	}
 
+	if (dev_priv->sdvo_lvds_fixed_mode)
+		xf86DeleteMode(&dev_priv->sdvo_lvds_fixed_mode,
+			dev_priv->sdvo_lvds_fixed_mode);
+
 	xfree (intel_output);
     }
 }
diff --git a/src/i830_sdvo_regs.h b/src/i830_sdvo_regs.h
index ab38355..9fb99b6 100644
--- a/src/i830_sdvo_regs.h
+++ b/src/i830_sdvo_regs.h
@@ -722,3 +722,5 @@ struct i830_sdvo_encode{
     uint8_t dvi_rev;
     uint8_t hdmi_rev;
 } __attribute__ ((packed));
+
+#define SDVO_STALL_FLAG (1 << 7)


More information about the xorg-commit mailing list