summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorling.ma@intel.com <ling.ma@intel.com>2009-07-07 14:26:02 +0800
committerZhenyu Wang <zhenyu.z.wang@intel.com>2009-07-08 09:22:40 +0800
commit216d939858abc924f2e32c95518f937f29ea018e (patch)
tree20f582abbf2413ab40968af6f028e4c3fd539633
parent0402f4f331148084552bd3963dbcb3fb900be8ea (diff)
downloadxorg-driver-xf86-video-intel-216d939858abc924f2e32c95518f937f29ea018e.tar.gz
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@intel.com>
-rw-r--r--src/i830_sdvo.c93
-rw-r--r--src/i830_sdvo_regs.h2
2 files changed, 83 insertions, 12 deletions
diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index acfe5999..8f3193b1 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 ab383550..9fb99b61 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)