xf86-video-intel: Branch 'modesetting' - 6 commits - src/i830_display.c src/i830_driver.c src/i830.h src/i830_modes.c src/i830_sdvo.h src/i830_xf86Modes.c src/i830_xf86Modes.h src/Makefile.am

Eric Anholt anholt at kemper.freedesktop.org
Mon Jun 26 13:56:03 EEST 2006


 src/Makefile.am      |    5 
 src/i830.h           |    1 
 src/i830_display.c   |  130 ++++++++++++++++--
 src/i830_driver.c    |    5 
 src/i830_modes.c     |  356 ++++++++++++++++++++++++---------------------------
 src/i830_sdvo.h      |    3 
 src/i830_xf86Modes.c |  348 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/i830_xf86Modes.h |   40 +++++
 8 files changed, 684 insertions(+), 204 deletions(-)

New commits:
diff-tree f113e9002cf53510e30984f816d44b06f1e71216 (from 0e5cda3796ba0164496f0814eb57d1dfa7ab9257)
Author: Eric Anholt <anholt at FreeBSD.org>
Date:   Mon Jun 26 12:54:30 2006 +0200

    Fix the plane/pipe disabling and turn off missing outputs when no longer DDCed.

diff --git a/src/i830_display.c b/src/i830_display.c
index 4719cef..05b7655 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -633,8 +633,6 @@ i830DisableUnusedFunctions(ScrnInfoPtr p
     I830Ptr pI830 = I830PTR(pScrn);
     int outputsA, outputsB;
 
-    return;
-
     outputsA = pI830->operatingDevices & 0xff;
     outputsB = (pI830->operatingDevices >> 8) & 0xff;
 
@@ -644,7 +642,7 @@ i830DisableUnusedFunctions(ScrnInfoPtr p
     if ((outputsA & PIPE_CRT_ACTIVE) == 0 &&
 	(outputsB & PIPE_CRT_ACTIVE) == 0)
     {
-	CARD32 adpa = INREG(adpa);
+	CARD32 adpa = INREG(ADPA);
 
 	if (adpa & ADPA_DAC_ENABLE) {
 	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling CRT output\n");
@@ -704,6 +702,8 @@ i830DisableUnusedFunctions(ScrnInfoPtr p
 	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling DPLL A\n");
 	    OUTREG(DPLL_A, dpll & ~DPLL_VCO_ENABLE);
 	}
+
+	memset(&pI830->pipeCurMode[0], 0, sizeof(pI830->pipeCurMode[0]));
     }
 
     if (!pI830->planeEnabled[1]) {
@@ -729,6 +729,8 @@ i830DisableUnusedFunctions(ScrnInfoPtr p
 	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling DPLL B\n");
 	    OUTREG(DPLL_B, dpll & ~DPLL_VCO_ENABLE);
 	}
+
+	memset(&pI830->pipeCurMode[1], 0, sizeof(pI830->pipeCurMode[1]));
     }
 }
 
diff --git a/src/i830_modes.c b/src/i830_modes.c
index fe28c7a..a43fa61 100644
--- a/src/i830_modes.c
+++ b/src/i830_modes.c
@@ -603,7 +603,9 @@ I830ReprobePipeModeList(ScrnInfoPtr pScr
     int i;
     int outputs;
     DisplayModePtr pMode;
+    Bool had_modes;
 
+    had_modes = (pI830->pipeModes[pipe] != NULL);
     while (pI830->pipeModes[pipe] != NULL)
 	xf86DeleteMode(&pI830->pipeModes[pipe], pI830->pipeModes[pipe]);
 
@@ -650,6 +652,14 @@ I830ReprobePipeModeList(ScrnInfoPtr pScr
 	{
 	    I830xf86SetModeCrtc(pMode, INTERLACE_HALVE_V);
 	}
+	if (had_modes && pI830->pipeModes[pipe] == NULL) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		       "Failed to DDC pipe %d, disabling output\n", pipe);
+	    if (pipe == 0)
+		pI830->operatingDevices &= ~0x00ff;
+	    else
+		pI830->operatingDevices &= ~0xff00;
+	}
     } else {
 	ErrorF("don't know how to get modes for this device.\n");
     }
diff-tree 0e5cda3796ba0164496f0814eb57d1dfa7ab9257 (from 51d14f803aae6d0a738520c3cad110289ee444db)
Author: Eric Anholt <anholt at FreeBSD.org>
Date:   Mon Jun 26 10:30:46 2006 +0200

    Fix FP scaling by using the desired mode to get at the real [HV]Display.

diff --git a/src/i830_display.c b/src/i830_display.c
index a96e6ee..4719cef 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -262,6 +262,7 @@ i830PipeSetMode(ScrnInfoPtr pScrn, Displ
     Bool ok, is_sdvo;
     int refclk, pixel_clock, sdvo_pixel_multiply;
     int outputs;
+    DisplayModePtr pMasterMode = pMode;
 
     assert(pMode->VRefresh != 0.0);
     /* If we've got a list of modes probed for the device, find the best match
@@ -341,8 +342,8 @@ i830PipeSetMode(ScrnInfoPtr pScrn, Displ
     vtot = (pMode->CrtcVDisplay - 1) | ((pMode->CrtcVTotal - 1) << 16);
     vblank = (pMode->CrtcVBlankStart - 1) | ((pMode->CrtcVBlankEnd - 1) << 16);
     vsync = (pMode->CrtcVSyncStart - 1) | ((pMode->CrtcVSyncEnd - 1) << 16);
-    pipesrc = ((pMode->HDisplay - 1) << 16) | (pMode->VDisplay - 1);
-    dspsize = ((pMode->VDisplay - 1) << 16) | (pMode->HDisplay - 1);
+    pipesrc = ((pMasterMode->HDisplay - 1) << 16) | (pMasterMode->VDisplay - 1);
+    dspsize = ((pMasterMode->VDisplay - 1) << 16) | (pMasterMode->HDisplay - 1);
     pixel_clock = pMode->Clock;
     if (outputs & PIPE_LCD_ACTIVE && pI830->panel_fixed_hactive != 0)
     {
@@ -369,17 +370,6 @@ i830PipeSetMode(ScrnInfoPtr pScrn, Displ
 	vsync = (pI830->panel_fixed_vactive + pI830->panel_fixed_vsyncoff - 1) |
 		((pI830->panel_fixed_vactive + pI830->panel_fixed_vsyncoff +
 		  pI830->panel_fixed_vsyncwidth - 1) << 16);
-	/* Hack until we get better clone-mode modesetting.  If the mode to be
-	 * programmed is larger than the size of the panel, only display the
-	 * size of the panel.
-	 */
-	if (pMode->HDisplay > pI830->panel_fixed_hactive || 
-	    pMode->VDisplay > pI830->panel_fixed_vactive) {
-	    dspsize = ((pI830->panel_fixed_vactive - 1) << 16) |
-		      (pI830->panel_fixed_hactive - 1);
-	    pipesrc = ((pI830->panel_fixed_hactive - 1) << 16) |
-		      (pI830->panel_fixed_vactive - 1);
-	}
 	pixel_clock = pI830->panel_fixed_clock;
     }
 
diff-tree 51d14f803aae6d0a738520c3cad110289ee444db (from d2c18d8d79596513149273e4a0d322f04bf27e80)
Author: Eric Anholt <anholt at FreeBSD.org>
Date:   Mon Jun 26 10:21:23 2006 +0200

    Add a function to turn off unused outputs, DPLLs, planes, and pipes.

diff --git a/src/i830_display.c b/src/i830_display.c
index 1546c37..a96e6ee 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -637,6 +637,111 @@ i830PipeSetMode(ScrnInfoPtr pScrn, Displ
     return TRUE;
 }
 
+static void
+i830DisableUnusedFunctions(ScrnInfoPtr pScrn)
+{
+    I830Ptr pI830 = I830PTR(pScrn);
+    int outputsA, outputsB;
+
+    return;
+
+    outputsA = pI830->operatingDevices & 0xff;
+    outputsB = (pI830->operatingDevices >> 8) & 0xff;
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling unused functions\n");
+
+    /* First, disable the unused outputs */
+    if ((outputsA & PIPE_CRT_ACTIVE) == 0 &&
+	(outputsB & PIPE_CRT_ACTIVE) == 0)
+    {
+	CARD32 adpa = INREG(adpa);
+
+	if (adpa & ADPA_DAC_ENABLE) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling CRT output\n");
+	    OUTREG(ADPA, adpa & ~ADPA_DAC_ENABLE);
+	}
+    }
+
+    if ((outputsB & PIPE_LCD_ACTIVE) == 0) {
+	CARD32 pp_status = INREG(PP_STATUS);
+
+	if (pp_status & PP_ON) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling LVDS output\n");
+	    i830SetLVDSPanelPower(pScrn, FALSE);
+	}
+    }
+
+    if (IS_I9XX(pI830) && ((outputsA & PIPE_DFP_ACTIVE) == 0 &&
+	(outputsB & PIPE_DFP_ACTIVE) == 0))
+    {
+	CARD32 sdvob = INREG(SDVOB);
+	CARD32 sdvoc = INREG(SDVOC);
+
+	if (sdvob & SDVO_ENABLE) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling SDVOB output\n");
+	    OUTREG(SDVOB, sdvob & ~SDVO_ENABLE);
+	}
+	if (sdvoc & SDVO_ENABLE) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling SDVOC output\n");
+	    OUTREG(SDVOC, sdvoc & ~SDVO_ENABLE);
+	}
+    }
+
+    /* Now, any unused plane, pipe, and DPLL (FIXME: except for DVO, i915
+     * internal TV) should have no outputs trying to pull data out of it, so
+     * we're ready to turn those off.
+     */
+    if (!pI830->planeEnabled[0]) {
+	CARD32 dspcntr, pipeconf, dpll;
+
+	dspcntr = INREG(DSPACNTR);
+	if (dspcntr & DISPLAY_PLANE_ENABLE) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling plane A\n");
+	    OUTREG(DSPACNTR, dspcntr & ~DISPLAY_PLANE_ENABLE);
+
+	    /* Wait for vblank for the disable to take effect */
+	    i830WaitForVblank(pScrn);
+	}
+
+	pipeconf = INREG(PIPEACONF);
+	if (pipeconf & PIPEACONF_ENABLE) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling pipe A\n");
+	   OUTREG(PIPEACONF, pipeconf & ~PIPEACONF_ENABLE);
+	}
+
+	dpll = INREG(DPLL_A);
+	if (dpll & DPLL_VCO_ENABLE) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling DPLL A\n");
+	    OUTREG(DPLL_A, dpll & ~DPLL_VCO_ENABLE);
+	}
+    }
+
+    if (!pI830->planeEnabled[1]) {
+	CARD32 dspcntr, pipeconf, dpll;
+
+	dspcntr = INREG(DSPBCNTR);
+	if (dspcntr & DISPLAY_PLANE_ENABLE) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling plane B\n");
+	    OUTREG(DSPBCNTR, dspcntr & ~DISPLAY_PLANE_ENABLE);
+
+	    /* Wait for vblank for the disable to take effect */
+	    i830WaitForVblank(pScrn);
+	}
+
+	pipeconf = INREG(PIPEBCONF);
+	if (pipeconf & PIPEBCONF_ENABLE) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling pipe B\n");
+	   OUTREG(PIPEBCONF, pipeconf & ~PIPEBCONF_ENABLE);
+	}
+
+	dpll = INREG(DPLL_B);
+	if (dpll & DPLL_VCO_ENABLE) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Disabling DPLL B\n");
+	    OUTREG(DPLL_B, dpll & ~DPLL_VCO_ENABLE);
+	}
+    }
+}
+
 /**
  * This function sets the given mode on the active pipes.
  */
@@ -693,6 +798,8 @@ i830SetMode(ScrnInfoPtr pScrn, DisplayMo
 	       (int)(pMode->HDisplay * pMode->VDisplay *
 		     pMode->VRefresh / 1000000));
 
+    i830DisableUnusedFunctions(pScrn);
+
     planeA = INREG(DSPACNTR);
     planeB = INREG(DSPBCNTR);
 
diff-tree d2c18d8d79596513149273e4a0d322f04bf27e80 (from 6d1d105d68d9c25890c3fd2ebad1367529c2a991)
Author: Eric Anholt <anholt at FreeBSD.org>
Date:   Mon Jun 26 10:15:11 2006 +0200

    Fix DDC probing after last (untested) commit.

diff --git a/src/i830_modes.c b/src/i830_modes.c
index e1e5fd5..fe28c7a 100644
--- a/src/i830_modes.c
+++ b/src/i830_modes.c
@@ -182,41 +182,43 @@ I830DuplicateMode(DisplayModePtr pMode)
  * Highest resolution first.
  */
 void
-I830xf86SortModes(DisplayModePtr *new, DisplayModePtr *first,
+I830xf86SortModes(DisplayModePtr new, DisplayModePtr *first,
 	      DisplayModePtr *last)
 {
     DisplayModePtr  p;
 
     p = *last;
     while (p) {
-	if ((((*new)->HDisplay < p->HDisplay) &&
-	     ((*new)->VDisplay < p->VDisplay)) ||
-	    (((*new)->HDisplay == p->HDisplay) &&
-	     ((*new)->VDisplay == p->VDisplay) &&
-	     ((*new)->Clock < p->Clock))) {
-
-	    if (p->next) p->next->prev = *new;
-	    (*new)->prev = p;
-	    (*new)->next = p->next;
-	    p->next = *new;
-	    if (!((*new)->next)) *last = *new;
+	if (((new->HDisplay < p->HDisplay) &&
+	     (new->VDisplay < p->VDisplay)) ||
+	    ((new->HDisplay == p->HDisplay) &&
+	     (new->VDisplay == p->VDisplay) &&
+	     (new->Clock < p->Clock))) {
+
+	    if (p->next) 
+		p->next->prev = new;
+	    new->prev = p;
+	    new->next = p->next;
+	    p->next = new;
+	    if (!(new->next))
+		*last = new;
 	    break;
 	}
 	if (!p->prev) {
-	    (*new)->prev = NULL;
-	    (*new)->next = p;
-	    p->prev = *new;
-	    *first = *new;
+	    new->prev = NULL;
+	    new->next = p;
+	    p->prev = new;
+	    *first = new;
 	    break;
 	}
 	p = p->prev;
     }
 
     if (!*first) {
-	*first = *new;
-	(*new)->prev = NULL;
-	(*new)->next = NULL;
-	*last = *new;
+	*first = new;
+	new->prev = NULL;
+	new->next = NULL;
+	*last = new;
     }
 }
 
@@ -230,7 +232,7 @@ I830GetVESAEstablishedMode(ScrnInfoPtr p
 {
     DisplayModePtr pMode;
 
-    for (pMode = I830xf86DefaultModes; pMode->name != NULL; pMode = pMode->next)
+    for (pMode = I830xf86DefaultModes; pMode->name != NULL; pMode++)
     {
 	if (pMode->HDisplay == est_timings[i].hsize &&
 	    pMode->VDisplay == est_timings[i].vsize &&
@@ -301,7 +303,7 @@ DisplayModePtr I830GetDDCModes(ScrnInfoP
 		       new->HTotal, new->HSyncStart, new->HSyncEnd,
 		       new->VTotal, new->VSyncStart, new->VSyncEnd);
 
-	    I830xf86SortModes(&new, &first, &last);
+	    I830xf86SortModes(new, &first, &last);
 	}
     }
 
@@ -315,7 +317,11 @@ DisplayModePtr I830GetDDCModes(ScrnInfoP
 	new->status = MODE_OK;
 	new->type |= M_T_DEFAULT;
 
-	I830xf86SortModes(&new, &first, &last);
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		   "Valid Mode from standard timing table: %s\n",
+		   new->name);
+
+	I830xf86SortModes(new, &first, &last);
 #else
 	for (p = pScrn->monitor->Modes; p && p->next; p = p->next->next) {
 
@@ -342,7 +348,7 @@ DisplayModePtr I830GetDDCModes(ScrnInfoP
 			       "Valid Mode from standard timing table: %s\n",
 			       new->name);
 
-		    I830xf86SortModes(&new, &first, &last);
+		    I830xf86SortModes(new, &first, &last);
 		    break;
 		}
 	    }
@@ -354,11 +360,11 @@ DisplayModePtr I830GetDDCModes(ScrnInfoP
     tmp = (ddc->timings1.t1 << 8) | ddc->timings1.t2;
     for (j = 0; j < 16; j++) {
 	if (tmp & (1 << j)) {
-	    DisplayModePtr pNew;
-
-	    pNew = I830GetVESAEstablishedMode(pScrn, j);
-	    assert(pNew != NULL); /* We'd better have all the est. modes. */
-
+	    new = I830GetVESAEstablishedMode(pScrn, j);
+	    if (new == NULL) {
+		ErrorF("Couldn't get established mode %d\n", j);
+		continue;
+	    }
 	    new->status = MODE_OK;
 	    new->type = M_T_DEFAULT;
 
@@ -367,7 +373,7 @@ DisplayModePtr I830GetDDCModes(ScrnInfoP
 	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Valid Mode from established "
 		       "timing table: %s\n", new->name);
 
-	    I830xf86SortModes(&new, &first, &last);
+	    I830xf86SortModes(new, &first, &last);
 	}
     }
 
@@ -643,7 +649,6 @@ I830ReprobePipeModeList(ScrnInfoPtr pScr
 	for (pMode = pI830->pipeModes[pipe]; pMode != NULL; pMode = pMode->next)
 	{
 	    I830xf86SetModeCrtc(pMode, INTERLACE_HALVE_V);
-	    pMode->VRefresh = I830ModeVRefresh(pMode);
 	}
     } else {
 	ErrorF("don't know how to get modes for this device.\n");
@@ -714,7 +719,7 @@ I830ValidateXF86ModeList(ScrnInfoPtr pSc
     I830Ptr pI830 = I830PTR(pScrn);
     ClockRangePtr clockRanges;
     int n, pipe;
-    DisplayModePtr saved_mode, availModes;
+    DisplayModePtr saved_mode, availModes = NULL;
     int saved_virtualX = 0, saved_virtualY = 0, saved_displayWidth = 0;
     Bool pipes_reconfigured = FALSE;
 
diff-tree 6d1d105d68d9c25890c3fd2ebad1367529c2a991 (from 52e8231a19f28bd4744f983aee2197a18c20aa3a)
Author: Eric Anholt <anholt at FreeBSD.org>
Date:   Mon Jun 26 10:14:27 2006 +0200

    Unset pipe current mode on EnterVT, so we reprogram the mode for sure.

diff --git a/src/i830_driver.c b/src/i830_driver.c
index 32beb8a..7af5fb7 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -3954,10 +3954,13 @@ I830BIOSEnterVT(int scrnIndex, int flags
    ResetState(pScrn, FALSE);
    SetHWOperatingState(pScrn);
 
+   /* Mark that we'll need to re-set the mode for sure */
+   memset(pI830->pipeCurMode, 0, sizeof(pI830->pipeCurMode));
+
    /* Detect monitor change and switch to suitable mode */
    if (!pI830->starting)
       I830DetectMonitorChange(pScrn);
-	    
+
    if (!i830SetMode(pScrn, pScrn->currentMode))
       return FALSE;
    
diff-tree 52e8231a19f28bd4744f983aee2197a18c20aa3a (from f5e5f8aeddb3e0d6d073471aeff6176fb54576e2)
Author: Eric Anholt <anholt at FreeBSD.org>
Date:   Mon Jun 26 07:46:28 2006 +0200

    Major cleanup of mode reprobing:
    - Don't mess with pScrn->monitor->Modes, and instead make our own availModes.
    - Don't re-program the pipe with the same values (no flicker at xrandr)
    - Move a bunch of stuff that should be exposed through the public API (probably)
      to i830_xf86Modes.c
    - Use a table with established modes plus GTF to come up with modes from EDID,
      instead of trying to walk and find one in pScrn->monitor->Modes.  I think
      this is correct.
    - Reset clone state if we've detected new pipes, which should turn on the
      cursor.

diff --git a/src/Makefile.am b/src/Makefile.am
index 8970db1..f8aaad1 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -63,8 +63,9 @@ i810_drv_la_SOURCES = \
          i830_video.c \
          i830_rotate.c \
 	 i830_randr.c \
-	 i830_sdvo.c
-
+	 i830_sdvo.c \
+	 i830_xf86Modes.h \
+	 i830_xf86Modes.c
 if DRI
 i810_drv_la_SOURCES += \
          i810_dri.c \
diff --git a/src/i830.h b/src/i830.h
index c4a4771..b3a0895 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -403,6 +403,7 @@ typedef struct _I830Rec {
    int planeEnabled[MAX_DISPLAY_PIPES];
    xf86MonPtr pipeMon[MAX_DISPLAY_PIPES];
    DisplayModePtr pipeModes[MAX_DISPLAY_PIPES];
+   DisplayModeRec pipeCurMode[MAX_DISPLAY_PIPES];
 
    /* Driver phase/state information */
    Bool preinit;
diff --git a/src/i830_display.c b/src/i830_display.c
index 50f4940..1546c37 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -35,6 +35,7 @@
 #include "i830_bios.h"
 #include "i830_display.h"
 #include "i830_debug.h"
+#include "i830_xf86Modes.h"
 
 /** Returns the pixel clock for the given refclk and divisors. */
 static int i830_clock(int refclk, int m1, int m2, int n, int p1, int p2)
@@ -299,6 +300,8 @@ i830PipeSetMode(ScrnInfoPtr pScrn, Displ
 	    pMode = pBest;
 	}
     }
+    if (I830ModesEqual(&pI830->pipeCurMode[pipe], pMode))
+	return TRUE;
 
     ErrorF("Requested pix clock: %d\n", pMode->Clock);
 
@@ -629,6 +632,8 @@ i830PipeSetMode(ScrnInfoPtr pScrn, Displ
 	OUTREG(SDVOC, sdvoc);
     }
 
+    pI830->pipeCurMode[pipe] = *pMode;
+
     return TRUE;
 }
 
diff --git a/src/i830_modes.c b/src/i830_modes.c
index faa843e..e1e5fd5 100644
--- a/src/i830_modes.c
+++ b/src/i830_modes.c
@@ -42,9 +42,11 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <assert.h>
 
 #include "xf86.h"
 #include "i830.h"
+#include "i830_xf86Modes.h"
 
 #include <math.h>
 
@@ -92,6 +94,8 @@ static struct
     {720, 400, 70},
 };
 
+#define DEBUG_REPROBE 1
+
 extern const int i830refreshes[];
 
 void
@@ -157,6 +161,23 @@ I830PrintModes(ScrnInfoPtr scrp)
     } while (p != NULL && p != scrp->modes);
 }
 
+/**
+ * Allocates and returns a copy of pMode, including pointers within pMode.
+ */
+static DisplayModePtr
+I830DuplicateMode(DisplayModePtr pMode)
+{
+    DisplayModePtr pNew;
+
+    pNew = xnfalloc(sizeof(DisplayModeRec));
+    *pNew = *pMode;
+    pNew->next = NULL;
+    pNew->prev = NULL;
+    pNew->name = xnfstrdup(pMode->name);
+
+    return pNew;
+}
+
 /* This function will sort all modes according to their resolution.
  * Highest resolution first.
  */
@@ -200,32 +221,31 @@ I830xf86SortModes(DisplayModePtr *new, D
 }
 
 /**
- * Calculates the vertical refresh of a mode.
+ * Gets a new pointer to a VESA established mode.
  *
- * Taken directly from xf86Mode.c, and should be put back there --Eric Anholt
+ * \param i index into the VESA established modes table.
  */
-static double
-I830ModeVRefresh(DisplayModePtr mode)
+static DisplayModePtr
+I830GetVESAEstablishedMode(ScrnInfoPtr pScrn, int i)
 {
-    double refresh = 0.0;
+    DisplayModePtr pMode;
 
-    if (mode->VRefresh > 0.0)
-	refresh = mode->VRefresh;
-    else if (mode->HTotal > 0 && mode->VTotal > 0) {
-	refresh = mode->Clock * 1000.0 / mode->HTotal / mode->VTotal;
-	if (mode->Flags & V_INTERLACE)
-	    refresh *= 2.0;
-	if (mode->Flags & V_DBLSCAN)
-	    refresh /= 2.0;
-	if (mode->VScan > 1)
-	    refresh /= (float)(mode->VScan);
+    for (pMode = I830xf86DefaultModes; pMode->name != NULL; pMode = pMode->next)
+    {
+	if (pMode->HDisplay == est_timings[i].hsize &&
+	    pMode->VDisplay == est_timings[i].vsize &&
+	    fabs(I830ModeVRefresh(pMode) - est_timings[i].refresh) < 1.0)
+	{
+	    DisplayModePtr pNew = I830DuplicateMode(pMode);
+	    pNew->VRefresh = I830ModeVRefresh(pMode);
+	    return pNew;
+	}
     }
-    return refresh;
+    return NULL;
 }
 
 DisplayModePtr I830GetDDCModes(ScrnInfoPtr pScrn, xf86MonPtr ddc)
 {
-    DisplayModePtr  p;
     DisplayModePtr  last  = NULL;
     DisplayModePtr  new   = NULL;
     DisplayModePtr  first = NULL;
@@ -289,7 +309,16 @@ DisplayModePtr I830GetDDCModes(ScrnInfoP
     for (j = 0; j < 8; j++) {
         if (ddc->timings2[j].hsize == 0 || ddc->timings2[j].vsize == 0)
                continue;
+#if 1
+	new = i830GetGTF(ddc->timings2[j].hsize, ddc->timings2[j].vsize,
+			 ddc->timings2[j].refresh, FALSE, FALSE);
+	new->status = MODE_OK;
+	new->type |= M_T_DEFAULT;
+
+	I830xf86SortModes(&new, &first, &last);
+#else
 	for (p = pScrn->monitor->Modes; p && p->next; p = p->next->next) {
+
 	    /* Ignore all double scan modes */
 	    if ((ddc->timings2[j].hsize == p->HDisplay) &&
 		(ddc->timings2[j].vsize == p->VDisplay)) {
@@ -318,39 +347,27 @@ DisplayModePtr I830GetDDCModes(ScrnInfoP
 		}
 	    }
 	}
+#endif
     }
 
     /* Search thru established modes from EDID */
     tmp = (ddc->timings1.t1 << 8) | ddc->timings1.t2;
     for (j = 0; j < 16; j++) {
 	if (tmp & (1 << j)) {
-	    for (p = pScrn->monitor->Modes; p && p->next; p = p->next->next) {
-		if ((est_timings[j].hsize == p->HDisplay) &&
-		    (est_timings[j].vsize == p->VDisplay)) {
-		    float  refresh =
-			(float)p->Clock * 1000.0 / p->HTotal / p->VTotal;
-		    float err = (float)est_timings[j].refresh - refresh;
-
-		    if (err < 1.0) {
-			/* Is this good enough? */
-			new = xnfcalloc(1, sizeof (DisplayModeRec));
-			memcpy(new, p, sizeof(DisplayModeRec));
-			new->name = xnfalloc(strlen(p->name) + 1);
-			strcpy(new->name, p->name);
-			new->status = MODE_OK;
-			new->type   = M_T_DEFAULT;
-
-			count++;
-
-			xf86DrvMsg(pScrn->scrnIndex, X_INFO,
-				   "Valid Mode from established timing "
-				   "table: %s\n", new->name);
-
-			I830xf86SortModes(&new, &first, &last);
-			break;
-		    }
-		}
-	    }
+	    DisplayModePtr pNew;
+
+	    pNew = I830GetVESAEstablishedMode(pScrn, j);
+	    assert(pNew != NULL); /* We'd better have all the est. modes. */
+
+	    new->status = MODE_OK;
+	    new->type = M_T_DEFAULT;
+
+	    count++;
+
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Valid Mode from established "
+		       "timing table: %s\n", new->name);
+
+	    I830xf86SortModes(&new, &first, &last);
 	}
     }
 
@@ -512,23 +529,6 @@ i830GetLVDSModes(ScrnInfoPtr pScrn, char
 }
 
 /**
- * Allocates and returns a copy of pMode, including pointers within pMode.
- */
-static DisplayModePtr
-I830DuplicateMode(DisplayModePtr pMode)
-{
-    DisplayModePtr pNew;
-
-    pNew = xnfalloc(sizeof(DisplayModeRec));
-    *pNew = *pMode;
-    pNew->next = NULL;
-    pNew->prev = NULL;
-    pNew->name = xnfstrdup(pMode->name);
-
-    return pNew;
-}
-
-/**
  * Injects a list of probed modes into another mode list.
  *
  * Take the doubly-linked list of modes we've probed for the device, and injects
@@ -536,11 +536,11 @@ I830DuplicateMode(DisplayModePtr pMode)
  * eventual call to xf86ValidateModes will do this for us.  I think.
  */
 int
-I830InjectProbedModes(ScrnInfoPtr pScrn, DisplayModePtr modeList,
-		      char **ppModeName, DisplayModePtr addModes)
+I830InjectProbedModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList,
+		      DisplayModePtr addModes)
 {
-    DisplayModePtr  last = modeList;
-    DisplayModePtr  first = modeList;
+    DisplayModePtr  last = *modeList;
+    DisplayModePtr  first = *modeList;
     DisplayModePtr  addMode;
     int count = 0;
 
@@ -551,12 +551,14 @@ I830InjectProbedModes(ScrnInfoPtr pScrn,
 	 */
 
 	pNew = I830DuplicateMode(addMode);
+#if 0
 	/* If the user didn't specify any modes, mark all modes as M_T_USERDEF
 	 * so that we can cycle through them, etc.  XXX: really need to?
 	 */
-	if (ppModeName[0] == NULL) {
+	if (pScrn->display->modes[0] == NULL) {
 	    pNew->type |= M_T_USERDEF;
 	}
+#endif
 
 	/* Insert pNew into modeList */
 	if (last) {
@@ -571,6 +573,7 @@ I830InjectProbedModes(ScrnInfoPtr pScrn,
 
 	count++;
     }
+    *modeList = first;
 
     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 	       "Injected %d modes detected from the monitor\n", count);
@@ -578,97 +581,6 @@ I830InjectProbedModes(ScrnInfoPtr pScrn,
     return count;
 }
 
-/*
- * I830xf86SetModeCrtc
- *
- * Initialises the Crtc parameters for a mode.  The initialisation includes
- * adjustments for interlaced and double scan modes.
- *
- * Taken directly from xf86Mode.c:xf86SetModeCrtc -- Eric Anholt
- *   (and it should be put back there!)
- */
-static void
-I830xf86SetModeCrtc(DisplayModePtr p, int adjustFlags)
-{
-    if ((p == NULL) || ((p->type & M_T_CRTC_C) == M_T_BUILTIN))
-	return;
-
-    p->CrtcHDisplay             = p->HDisplay;
-    p->CrtcHSyncStart           = p->HSyncStart;
-    p->CrtcHSyncEnd             = p->HSyncEnd;
-    p->CrtcHTotal               = p->HTotal;
-    p->CrtcHSkew                = p->HSkew;
-    p->CrtcVDisplay             = p->VDisplay;
-    p->CrtcVSyncStart           = p->VSyncStart;
-    p->CrtcVSyncEnd             = p->VSyncEnd;
-    p->CrtcVTotal               = p->VTotal;
-    if (p->Flags & V_INTERLACE) {
-	if (adjustFlags & INTERLACE_HALVE_V) {
-	    p->CrtcVDisplay         /= 2;
-	    p->CrtcVSyncStart       /= 2;
-	    p->CrtcVSyncEnd         /= 2;
-	    p->CrtcVTotal           /= 2;
-	}
-	/* Force interlaced modes to have an odd VTotal */
-	/* maybe we should only do this when INTERLACE_HALVE_V is set? */
-	p->CrtcVTotal |= 1;
-    }
-
-    if (p->Flags & V_DBLSCAN) {
-        p->CrtcVDisplay         *= 2;
-        p->CrtcVSyncStart       *= 2;
-        p->CrtcVSyncEnd         *= 2;
-        p->CrtcVTotal           *= 2;
-    }
-    if (p->VScan > 1) {
-        p->CrtcVDisplay         *= p->VScan;
-        p->CrtcVSyncStart       *= p->VScan;
-        p->CrtcVSyncEnd         *= p->VScan;
-        p->CrtcVTotal           *= p->VScan;
-    }
-    p->CrtcHAdjusted = FALSE;
-    p->CrtcVAdjusted = FALSE;
-
-    /*
-     * XXX
-     *
-     * The following is taken from VGA, but applies to other cores as well.
-     */
-    p->CrtcVBlankStart = min(p->CrtcVSyncStart, p->CrtcVDisplay);
-    p->CrtcVBlankEnd = max(p->CrtcVSyncEnd, p->CrtcVTotal);
-    if ((p->CrtcVBlankEnd - p->CrtcVBlankStart) >= 127) {
-        /* 
-         * V Blanking size must be < 127.
-         * Moving blank start forward is safer than moving blank end
-         * back, since monitors clamp just AFTER the sync pulse (or in
-         * the sync pulse), but never before.
-         */
-        p->CrtcVBlankStart = p->CrtcVBlankEnd - 127;
-	/*
-	 * If VBlankStart is now > VSyncStart move VBlankStart
-	 * to VSyncStart using the maximum width that fits into
-	 * VTotal.
-	 */
-	if (p->CrtcVBlankStart > p->CrtcVSyncStart) {
-	    p->CrtcVBlankStart = p->CrtcVSyncStart;
-	    p->CrtcVBlankEnd = min(p->CrtcHBlankStart + 127, p->CrtcVTotal);
-	}
-    }
-    p->CrtcHBlankStart = min(p->CrtcHSyncStart, p->CrtcHDisplay);
-    p->CrtcHBlankEnd = max(p->CrtcHSyncEnd, p->CrtcHTotal);
-
-    if ((p->CrtcHBlankEnd - p->CrtcHBlankStart) >= 63 * 8) {
-        /*
-         * H Blanking size must be < 63*8. Same remark as above.
-         */
-        p->CrtcHBlankStart = p->CrtcHBlankEnd - 63 * 8;
-	if (p->CrtcHBlankStart > p->CrtcHSyncStart) {
-	    p->CrtcHBlankStart = p->CrtcHSyncStart;
-	    p->CrtcHBlankEnd = min(p->CrtcHBlankStart + 63 * 8, p->CrtcHTotal);
-	}
-    }
-}
-
 /**
  * Performs probing of modes available on the output connected to the given
  * pipe.
@@ -740,14 +652,21 @@ I830ReprobePipeModeList(ScrnInfoPtr pScr
     /* Set the vertical refresh, which is used by the choose-best-mode-per-pipe
      * code later on.
      */
+#ifdef DEBUG_REPROBE
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Printing probed modes for pipe %d\n",
+	       pipe);
+#endif
     for (pMode = pI830->pipeModes[pipe]; pMode != NULL; pMode = pMode->next) {
 	pMode->VRefresh = I830ModeVRefresh(pMode);
+#ifdef DEBUG_REPROBE
+	PrintModeline(pScrn->scrnIndex, pMode);
+#endif
     }
 }
 
 /**
  * This function removes a mode from a list of modes.  It should probably be
- * moved to xf86Mode.c
+ * moved to xf86Mode.c.
  *
  * There are different types of mode lists:
  *
@@ -795,8 +714,9 @@ I830ValidateXF86ModeList(ScrnInfoPtr pSc
     I830Ptr pI830 = I830PTR(pScrn);
     ClockRangePtr clockRanges;
     int n, pipe;
-    DisplayModePtr saved_mode;
+    DisplayModePtr saved_mode, availModes;
     int saved_virtualX = 0, saved_virtualY = 0, saved_displayWidth = 0;
+    Bool pipes_reconfigured = FALSE;
 
     for (pipe = 0; pipe < MAX_DISPLAY_PIPES; pipe++) {
 	I830ReprobePipeModeList(pScrn, pipe);
@@ -815,6 +735,9 @@ I830ValidateXF86ModeList(ScrnInfoPtr pSc
 	    } else {
 		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 			   "Enabled new CRT on pipe A\n");
+		pipes_reconfigured = TRUE;
+		/* Clear the current mode, so we reprogram the pipe for sure. */
+		memset(&pI830->pipeCurMode[0], 0, sizeof(pI830->pipeCurMode[0]));
 	    }
 	} else if (((pI830->operatingDevices >> 8) & 0xff) == PIPE_NONE) {
 	    pI830->operatingDevices |= PIPE_CRT << 8;
@@ -825,19 +748,24 @@ I830ValidateXF86ModeList(ScrnInfoPtr pSc
 	    } else {
 		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 			   "Enabled new CRT on pipe B\n");
+		pipes_reconfigured = TRUE;
+		/* Clear the current mode, so we reprogram the pipe for sure. */
+		memset(&pI830->pipeCurMode[1], 0, sizeof(pI830->pipeCurMode[1]));
 	    }
 	}
     }
 
-    /* XXX: Clean out modes previously injected by our driver */
-
+    /* Start by injecting the XFree86 default modes and user-configured
+     * modelines.  XXX: This actually isn't of use if we've got any DDC, as DDC
+     * currently has higher priority than the validated modelist.  We need to
+     * deal with that.
+     */
+    I830InjectProbedModes(pScrn, &availModes, pScrn->monitor->Modes);
     if (pI830->pipeModes[0] != NULL) {
-	I830InjectProbedModes(pScrn, pScrn->monitor->Modes,
-			      pScrn->display->modes, pI830->pipeModes[0]);
+	I830InjectProbedModes(pScrn, &availModes, pI830->pipeModes[0]);
     }
     if (pI830->pipeModes[1] != NULL) {
-	I830InjectProbedModes(pScrn, pScrn->monitor->Modes,
-			      pScrn->display->modes, pI830->pipeModes[1]);
+	I830InjectProbedModes(pScrn, &availModes, pI830->pipeModes[1]);
     }
 
    /*
@@ -872,7 +800,7 @@ I830ValidateXF86ModeList(ScrnInfoPtr pSc
      *      capabilities of our pipes.
      */
     n = xf86ValidateModes(pScrn,
-			  pScrn->monitor->Modes, /* availModes */
+			  availModes, /* availModes */
 			  pScrn->display->modes, /* modeNames */
 			  clockRanges, /* clockRanges */
 			  !first_time ? &pScrn->displayWidth : NULL, /* linePitches */
@@ -886,6 +814,12 @@ I830ValidateXF86ModeList(ScrnInfoPtr pSc
 			  pI830->FbMapSize, /* apertureSize */
 			  LOOKUP_BEST_REFRESH /* strategy */);
 
+    /* availModes is of no more use as xf86ValidateModes has duplicated and
+     * saved everything it needs.
+     */
+    while (availModes != NULL)
+	xf86DeleteMode(&availModes, availModes);
+
     if (!first_time) {
 	/* Restore things that may have been damaged by xf86ValidateModes. */
 	pScrn->virtualX = saved_virtualX;
@@ -900,6 +834,19 @@ I830ValidateXF86ModeList(ScrnInfoPtr pSc
 
     xf86PruneDriverModes(pScrn);
 
+#if DEBUG_REPROBE
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Modes post revalidate\n");
+    do {
+	DisplayModePtr pMode;
+
+	for (pMode = pScrn->modes; ; pMode = pMode->next) {
+	    PrintModeline(pScrn->scrnIndex, pMode);
+	    if (pMode->next == pScrn->modes)
+		break;
+	}
+    } while (0);
+#endif
+
     /* Try to find the closest equivalent of the previous mode pointer to switch
      * to.
      */
@@ -926,5 +873,23 @@ I830ValidateXF86ModeList(ScrnInfoPtr pSc
 	xfree(saved_mode->name);
 	xfree(saved_mode);
     }
+
+    /* If we've enabled/disabled some pipes, we need to reset cloning mode
+     * support.
+     */
+    if (pipes_reconfigured) {
+	if ((pI830->operatingDevices & 0x00ff) &&
+	    (pI830->operatingDevices & 0xff00))
+	{
+	    pI830->Clone = TRUE;
+	} else {
+	    pI830->Clone = FALSE;
+	}
+
+	/* If HW cursor currently showing, reset cursor state */
+	if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn)
+	    pI830->CursorInfoRec->ShowCursor(pScrn);
+    }
+
     return n;
 }
diff --git a/src/i830_sdvo.h b/src/i830_sdvo.h
index d52eb60..52621e0 100644
--- a/src/i830_sdvo.h
+++ b/src/i830_sdvo.h
@@ -66,3 +66,6 @@ i830SDVOPostRestore(ScrnInfoPtr pScrn, i
 
 Bool
 I830DetectSDVODisplays(ScrnInfoPtr pScrn, int output_index);
+
+void
+I830DumpSDVO(ScrnInfoPtr pScrn);
diff --git a/src/i830_xf86Modes.c b/src/i830_xf86Modes.c
new file mode 100644
index 0000000..16a8cd8
--- /dev/null
+++ b/src/i830_xf86Modes.c
@@ -0,0 +1,348 @@
+/* $XdotOrg: xserver/xorg/hw/xfree86/common/xf86Mode.c,v 1.10 2006/03/07 16:00:57 libv Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/common/xf86Mode.c,v 1.69 2003/10/08 14:58:28 dawes Exp $ */
+/*
+ * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of the copyright holder(s)
+ * and author(s) shall not be used in advertising or otherwise to promote
+ * the sale, use or other dealings in this Software without prior written
+ * authorization from the copyright holder(s) and author(s).
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "xf86.h"
+#include "i830.h"
+#include "i830_xf86Modes.h"
+
+/**
+ * @file this file contains symbols from xf86Mode.c and friends that are static
+ * there but we still want to use.  We need to come up with better API here.
+ */
+
+/**
+ * Calculates the vertical refresh of a mode.
+ *
+ * Exact copy of xf86Mode.c's.
+ */
+double
+I830ModeVRefresh(DisplayModePtr mode)
+{
+    double refresh = 0.0;
+
+    if (mode->VRefresh > 0.0)
+	refresh = mode->VRefresh;
+    else if (mode->HTotal > 0 && mode->VTotal > 0) {
+	refresh = mode->Clock * 1000.0 / mode->HTotal / mode->VTotal;
+	if (mode->Flags & V_INTERLACE)
+	    refresh *= 2.0;
+	if (mode->Flags & V_DBLSCAN)
+	    refresh /= 2.0;
+	if (mode->VScan > 1)
+	    refresh /= (float)(mode->VScan);
+    }
+    return refresh;
+}
+
+/*
+ * I830xf86SetModeCrtc
+ *
+ * Initialises the Crtc parameters for a mode.  The initialisation includes
+ * adjustments for interlaced and double scan modes.
+ *
+ * Exact copy of xf86Mode.c's.
+ */
+void
+I830xf86SetModeCrtc(DisplayModePtr p, int adjustFlags)
+{
+    if ((p == NULL) || ((p->type & M_T_CRTC_C) == M_T_BUILTIN))
+	return;
+
+    p->CrtcHDisplay             = p->HDisplay;
+    p->CrtcHSyncStart           = p->HSyncStart;
+    p->CrtcHSyncEnd             = p->HSyncEnd;
+    p->CrtcHTotal               = p->HTotal;
+    p->CrtcHSkew                = p->HSkew;
+    p->CrtcVDisplay             = p->VDisplay;
+    p->CrtcVSyncStart           = p->VSyncStart;
+    p->CrtcVSyncEnd             = p->VSyncEnd;
+    p->CrtcVTotal               = p->VTotal;
+    if (p->Flags & V_INTERLACE) {
+	if (adjustFlags & INTERLACE_HALVE_V) {
+	    p->CrtcVDisplay         /= 2;
+	    p->CrtcVSyncStart       /= 2;
+	    p->CrtcVSyncEnd         /= 2;
+	    p->CrtcVTotal           /= 2;
+	}
+	/* Force interlaced modes to have an odd VTotal */
+	/* maybe we should only do this when INTERLACE_HALVE_V is set? */
+	p->CrtcVTotal |= 1;
+    }
+
+    if (p->Flags & V_DBLSCAN) {
+        p->CrtcVDisplay         *= 2;
+        p->CrtcVSyncStart       *= 2;
+        p->CrtcVSyncEnd         *= 2;
+        p->CrtcVTotal           *= 2;
+    }
+    if (p->VScan > 1) {
+        p->CrtcVDisplay         *= p->VScan;
+        p->CrtcVSyncStart       *= p->VScan;
+        p->CrtcVSyncEnd         *= p->VScan;
+        p->CrtcVTotal           *= p->VScan;
+    }
+    p->CrtcHAdjusted = FALSE;
+    p->CrtcVAdjusted = FALSE;
+
+    /*
+     * XXX
+     *
+     * The following is taken from VGA, but applies to other cores as well.
+     */
+    p->CrtcVBlankStart = min(p->CrtcVSyncStart, p->CrtcVDisplay);
+    p->CrtcVBlankEnd = max(p->CrtcVSyncEnd, p->CrtcVTotal);
+    if ((p->CrtcVBlankEnd - p->CrtcVBlankStart) >= 127) {
+        /* 
+         * V Blanking size must be < 127.
+         * Moving blank start forward is safer than moving blank end
+         * back, since monitors clamp just AFTER the sync pulse (or in
+         * the sync pulse), but never before.
+         */
+        p->CrtcVBlankStart = p->CrtcVBlankEnd - 127;
+	/*
+	 * If VBlankStart is now > VSyncStart move VBlankStart
+	 * to VSyncStart using the maximum width that fits into
+	 * VTotal.
+	 */
+	if (p->CrtcVBlankStart > p->CrtcVSyncStart) {
+	    p->CrtcVBlankStart = p->CrtcVSyncStart;
+	    p->CrtcVBlankEnd = min(p->CrtcHBlankStart + 127, p->CrtcVTotal);
+	}
+    }
+    p->CrtcHBlankStart = min(p->CrtcHSyncStart, p->CrtcHDisplay);
+    p->CrtcHBlankEnd = max(p->CrtcHSyncEnd, p->CrtcHTotal);
+
+    if ((p->CrtcHBlankEnd - p->CrtcHBlankStart) >= 63 * 8) {
+        /*
+         * H Blanking size must be < 63*8. Same remark as above.
+         */
+        p->CrtcHBlankStart = p->CrtcHBlankEnd - 63 * 8;
+	if (p->CrtcHBlankStart > p->CrtcHSyncStart) {
+	    p->CrtcHBlankStart = p->CrtcHSyncStart;
+	    p->CrtcHBlankEnd = min(p->CrtcHBlankStart + 63 * 8, p->CrtcHTotal);
+	}
+    }
+}
+
+/**
+ * Returns true if the given modes should program to the same timings.
+ *
+ * This doesn't use Crtc values, as it might be used on ModeRecs without the
+ * Crtc values set.  So, it's assumed that the other numbers are enough.
+ *
+ * This isn't in xf86Modes.c, but it might deserve to be there.
+ */
+Bool
+I830ModesEqual(DisplayModePtr pMode1, DisplayModePtr pMode2)
+{
+     if (pMode1->Clock == pMode2->Clock &&
+	 pMode1->HDisplay == pMode2->HDisplay &&
+	 pMode1->HSyncStart == pMode2->HSyncStart &&
+	 pMode1->HSyncEnd == pMode2->HSyncEnd &&
+	 pMode1->HTotal == pMode2->HTotal &&
+	 pMode1->HSkew == pMode2->HSkew &&
+	 pMode1->VDisplay == pMode2->VDisplay &&
+	 pMode1->VSyncStart == pMode2->VSyncStart &&
+	 pMode1->VSyncEnd == pMode2->VSyncEnd &&
+	 pMode1->VTotal == pMode2->VTotal &&
+	 pMode1->VScan == pMode2->VScan &&
+	 pMode1->Flags == pMode2->Flags)
+     {
+	return TRUE;
+     } else {
+	return FALSE;
+     }
+}
+
+/* exact copy of xf86Mode.c */
+static void
+add(char **p, char *new)
+{
+    *p = xnfrealloc(*p, strlen(*p) + strlen(new) + 2);
+    strcat(*p, " ");
+    strcat(*p, new);
+}
+
+/**
+ * Print out a modeline.
+ *
+ * Convenient VRefresh printing was added, though, compared to xf86Mode.c
+ */
+void
+PrintModeline(int scrnIndex,DisplayModePtr mode)
+{
+    char tmp[256];
+    char *flags = xnfcalloc(1, 1);
+
+    if (mode->HSkew) { 
+	snprintf(tmp, 256, "hskew %i", mode->HSkew); 
+	add(&flags, tmp);
+    }
+    if (mode->VScan) { 
+	snprintf(tmp, 256, "vscan %i", mode->VScan); 
+	add(&flags, tmp);
+    }
+    if (mode->Flags & V_INTERLACE) add(&flags, "interlace");
+    if (mode->Flags & V_CSYNC) add(&flags, "composite");
+    if (mode->Flags & V_DBLSCAN) add(&flags, "doublescan");
+    if (mode->Flags & V_BCAST) add(&flags, "bcast");
+    if (mode->Flags & V_PHSYNC) add(&flags, "+hsync");
+    if (mode->Flags & V_NHSYNC) add(&flags, "-hsync");
+    if (mode->Flags & V_PVSYNC) add(&flags, "+vsync");
+    if (mode->Flags & V_NVSYNC) add(&flags, "-vsync");
+    if (mode->Flags & V_PCSYNC) add(&flags, "+csync");
+    if (mode->Flags & V_NCSYNC) add(&flags, "-csync");
+#if 0
+    if (mode->Flags & V_CLKDIV2) add(&flags, "vclk/2");
+#endif
+    xf86DrvMsg(scrnIndex, X_ERROR,
+		   "Modeline \"%s\"x%.01f  %6.2f  %i %i %i %i  %i %i %i %i%s\n",
+		   mode->name, mode->VRefresh, mode->Clock/1000., mode->HDisplay,
+		   mode->HSyncStart, mode->HSyncEnd, mode->HTotal,
+		   mode->VDisplay, mode->VSyncStart, mode->VSyncEnd,
+		   mode->VTotal, flags);
+    xfree(flags);
+}
+
+#define MODEPREFIX(name) NULL, NULL, name, MODE_OK, M_T_DEFAULT
+#define MODESUFFIX       0,0, 0,0,0,0,0,0,0, 0,0,0,0,0,0,FALSE,FALSE,0,NULL,0,0.0,0.0
+
+/**
+ * List of VESA established modes, taken from xf86DefaultModes but trimmed down.
+ * (not trimming should be harmless).
+ */
+DisplayModeRec I830xf86DefaultModes[] = {
+/* 640x350 @ 85Hz (VESA) hsync: 37.9kHz */
+	{MODEPREFIX("640x350"),31500, 640,672,736,832,0, 350,382,385,445,0, V_PHSYNC | V_NVSYNC, MODESUFFIX},
+	{MODEPREFIX("320x175"),15750, 320,336,368,416,0, 175,191,192,222,0, V_PHSYNC | V_NVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 640x400 @ 85Hz (VESA) hsync: 37.9kHz */
+	{MODEPREFIX("640x400"),31500, 640,672,736,832,0, 400,401,404,445,0, V_NHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("320x200"),15750, 320,336,368,416,0, 200,200,202,222,0, V_NHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 720x400 @ 85Hz (VESA) hsync: 37.9kHz */
+	{MODEPREFIX("720x400"),35500, 720,756,828,936,0, 400,401,404,446,0, V_NHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("360x200"),17750, 360,378,414,468,0, 200,200,202,223,0, V_NHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 640x480 @ 72Hz (VESA) hsync: 37.9kHz */
+	{MODEPREFIX("640x480"),31500, 640,664,704,832,0, 480,489,491,520,0, V_NHSYNC | V_NVSYNC, MODESUFFIX},
+	{MODEPREFIX("320x240"),15750, 320,332,352,416,0, 240,244,245,260,0, V_NHSYNC | V_NVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 640x480 @ 75Hz (VESA) hsync: 37.5kHz */
+	{MODEPREFIX("640x480"),31500, 640,656,720,840,0, 480,481,484,500,0, V_NHSYNC | V_NVSYNC, MODESUFFIX},
+	{MODEPREFIX("320x240"),15750, 320,328,360,420,0, 240,240,242,250,0, V_NHSYNC | V_NVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 640x480 @ 85Hz (VESA) hsync: 43.3kHz */
+	{MODEPREFIX("640x480"),36000, 640,696,752,832,0, 480,481,484,509,0, V_NHSYNC | V_NVSYNC, MODESUFFIX},
+	{MODEPREFIX("320x240"),18000, 320,348,376,416,0, 240,240,242,254,0, V_NHSYNC | V_NVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 800x600 @ 56Hz (VESA) hsync: 35.2kHz */
+	{MODEPREFIX("800x600"),36000, 800,824,896,1024,0, 600,601,603,625,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("400x300"),18000, 400,412,448,512,0, 300,300,301,312,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 800x600 @ 60Hz (VESA) hsync: 37.9kHz */
+	{MODEPREFIX("800x600"),40000, 800,840,968,1056,0, 600,601,605,628,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("400x300"),20000, 400,420,484,528,0, 300,300,302,314,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 800x600 @ 72Hz (VESA) hsync: 48.1kHz */
+	{MODEPREFIX("800x600"),50000, 800,856,976,1040,0, 600,637,643,666,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("400x300"),25000, 400,428,488,520,0, 300,318,321,333,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 800x600 @ 75Hz (VESA) hsync: 46.9kHz */
+	{MODEPREFIX("800x600"),49500, 800,816,896,1056,0, 600,601,604,625,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("400x300"),24750, 400,408,448,528,0, 300,300,302,312,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 800x600 @ 85Hz (VESA) hsync: 53.7kHz */
+	{MODEPREFIX("800x600"),56300, 800,832,896,1048,0, 600,601,604,631,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("400x300"),28150, 400,416,448,524,0, 300,300,302,315,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1024x768 @ 60Hz (VESA) hsync: 48.4kHz */
+	{MODEPREFIX("1024x768"),65000, 1024,1048,1184,1344,0, 768,771,777,806,0, V_NHSYNC | V_NVSYNC, MODESUFFIX},
+	{MODEPREFIX("512x384"),32500, 512,524,592,672,0, 384,385,388,403,0, V_NHSYNC | V_NVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1024x768 @ 70Hz (VESA) hsync: 56.5kHz */
+	{MODEPREFIX("1024x768"),75000, 1024,1048,1184,1328,0, 768,771,777,806,0, V_NHSYNC | V_NVSYNC, MODESUFFIX},
+	{MODEPREFIX("512x384"),37500, 512,524,592,664,0, 384,385,388,403,0, V_NHSYNC | V_NVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1024x768 @ 75Hz (VESA) hsync: 60.0kHz */
+	{MODEPREFIX("1024x768"),78800, 1024,1040,1136,1312,0, 768,769,772,800,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("512x384"),39400, 512,520,568,656,0, 384,384,386,400,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1024x768 @ 85Hz (VESA) hsync: 68.7kHz */
+	{MODEPREFIX("1024x768"),94500, 1024,1072,1168,1376,0, 768,769,772,808,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("512x384"),47250, 512,536,584,688,0, 384,384,386,404,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1152x864 @ 75Hz (VESA) hsync: 67.5kHz */
+	{MODEPREFIX("1152x864"),108000, 1152,1216,1344,1600,0, 864,865,868,900,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("576x432"),54000, 576,608,672,800,0, 432,432,434,450,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1280x960 @ 60Hz (VESA) hsync: 60.0kHz */
+	{MODEPREFIX("1280x960"),108000, 1280,1376,1488,1800,0, 960,961,964,1000,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("640x480"),54000, 640,688,744,900,0, 480,480,482,500,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1280x960 @ 85Hz (VESA) hsync: 85.9kHz */
+	{MODEPREFIX("1280x960"),148500, 1280,1344,1504,1728,0, 960,961,964,1011,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("640x480"),74250, 640,672,752,864,0, 480,480,482,505,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1280x1024 @ 60Hz (VESA) hsync: 64.0kHz */
+	{MODEPREFIX("1280x1024"),108000, 1280,1328,1440,1688,0, 1024,1025,1028,1066,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("640x512"),54000, 640,664,720,844,0, 512,512,514,533,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1280x1024 @ 75Hz (VESA) hsync: 80.0kHz */
+	{MODEPREFIX("1280x1024"),135000, 1280,1296,1440,1688,0, 1024,1025,1028,1066,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("640x512"),67500, 640,648,720,844,0, 512,512,514,533,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1280x1024 @ 85Hz (VESA) hsync: 91.1kHz */
+	{MODEPREFIX("1280x1024"),157500, 1280,1344,1504,1728,0, 1024,1025,1028,1072,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("640x512"),78750, 640,672,752,864,0, 512,512,514,536,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1600x1200 @ 60Hz (VESA) hsync: 75.0kHz */
+	{MODEPREFIX("1600x1200"),162000, 1600,1664,1856,2160,0, 1200,1201,1204,1250,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("800x600"),81000, 800,832,928,1080,0, 600,600,602,625,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1600x1200 @ 65Hz (VESA) hsync: 81.3kHz */
+	{MODEPREFIX("1600x1200"),175500, 1600,1664,1856,2160,0, 1200,1201,1204,1250,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("800x600"),87750, 800,832,928,1080,0, 600,600,602,625,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1600x1200 @ 70Hz (VESA) hsync: 87.5kHz */
+	{MODEPREFIX("1600x1200"),189000, 1600,1664,1856,2160,0, 1200,1201,1204,1250,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("800x600"),94500, 800,832,928,1080,0, 600,600,602,625,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1600x1200 @ 75Hz (VESA) hsync: 93.8kHz */
+	{MODEPREFIX("1600x1200"),202500, 1600,1664,1856,2160,0, 1200,1201,1204,1250,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("800x600"),101250, 800,832,928,1080,0, 600,600,602,625,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1600x1200 @ 85Hz (VESA) hsync: 106.3kHz */
+	{MODEPREFIX("1600x1200"),229500, 1600,1664,1856,2160,0, 1200,1201,1204,1250,0, V_PHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("800x600"),114750, 800,832,928,1080,0, 600,600,602,625,0, V_PHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1792x1344 @ 60Hz (VESA) hsync: 83.6kHz */
+	{MODEPREFIX("1792x1344"),204800, 1792,1920,2120,2448,0, 1344,1345,1348,1394,0, V_NHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("896x672"),102400, 896,960,1060,1224,0, 672,672,674,697,0, V_NHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1792x1344 @ 75Hz (VESA) hsync: 106.3kHz */
+	{MODEPREFIX("1792x1344"),261000, 1792,1888,2104,2456,0, 1344,1345,1348,1417,0, V_NHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("896x672"),130500, 896,944,1052,1228,0, 672,672,674,708,0, V_NHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1856x1392 @ 60Hz (VESA) hsync: 86.3kHz */
+	{MODEPREFIX("1856x1392"),218300, 1856,1952,2176,2528,0, 1392,1393,1396,1439,0, V_NHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("928x696"),109150, 928,976,1088,1264,0, 696,696,698,719,0, V_NHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1856x1392 @ 75Hz (VESA) hsync: 112.5kHz */
+	{MODEPREFIX("1856x1392"),288000, 1856,1984,2208,2560,0, 1392,1393,1396,1500,0, V_NHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("928x696"),144000, 928,992,1104,1280,0, 696,696,698,750,0, V_NHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1920x1440 @ 60Hz (VESA) hsync: 90.0kHz */
+	{MODEPREFIX("1920x1440"),234000, 1920,2048,2256,2600,0, 1440,1441,1444,1500,0, V_NHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("960x720"),117000, 960,1024,1128,1300,0, 720,720,722,750,0, V_NHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+/* 1920x1440 @ 75Hz (VESA) hsync: 112.5kHz */
+	{MODEPREFIX("1920x1440"),297000, 1920,2064,2288,2640,0, 1440,1441,1444,1500,0, V_NHSYNC | V_PVSYNC, MODESUFFIX},
+	{MODEPREFIX("960x720"),148500, 960,1032,1144,1320,0, 720,720,722,750,0, V_NHSYNC | V_PVSYNC | V_DBLSCAN, MODESUFFIX},
+
+	/* Terminator */
+	{MODEPREFIX(NULL), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, MODESUFFIX}
+};
diff --git a/src/i830_xf86Modes.h b/src/i830_xf86Modes.h
new file mode 100644
index 0000000..ba7d820
--- /dev/null
+++ b/src/i830_xf86Modes.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright © 2006 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Eric Anholt <eric at anholt.net>
+ *
+ */
+
+double
+I830ModeVRefresh(DisplayModePtr mode);
+
+void
+I830xf86SetModeCrtc(DisplayModePtr p, int adjustFlags);
+
+Bool
+I830ModesEqual(DisplayModePtr pMode1, DisplayModePtr pMode2);
+
+void
+PrintModeline(int scrnIndex,DisplayModePtr mode);
+
+extern DisplayModeRec I830xf86DefaultModes[];



More information about the xorg-commit mailing list