[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