xf86-video-intel: Branch 'nonrandr-setup' - 13 commits - src/i810_reg.h src/i830_bios.c src/i830_crt.c src/i830_debug.c src/i830_display.c src/i830_display.h src/i830_driver.c src/i830_dvo.c src/i830.h src/i830_lvds.c src/i830_randr.c src/i830_sdvo.c src/i830_tv.c src/i830_xf86Crtc.h

Keith Packard keithp at kemper.freedesktop.org
Wed Dec 6 22:56:14 EET 2006


 src/i810_reg.h      |   19 ++
 src/i830.h          |   13 -
 src/i830_bios.c     |   48 +++--
 src/i830_crt.c      |   20 +-
 src/i830_debug.c    |  264 ++++++++++++++++++++++++-----
 src/i830_display.c  |  463 +++++++++++++++++++++++++++++-----------------------
 src/i830_display.h  |    1 
 src/i830_driver.c   |   67 +++----
 src/i830_dvo.c      |   49 +++--
 src/i830_lvds.c     |  125 ++++++++------
 src/i830_randr.c    |    3 
 src/i830_sdvo.c     |   53 +++--
 src/i830_tv.c       |   35 +++
 src/i830_xf86Crtc.h |   56 ++++--
 14 files changed, 775 insertions(+), 441 deletions(-)

New commits:
diff-tree 6ee63364f5fabbc5578bcc9ded38c778595f5a6d (from parents)
Merge: 56f71194157ef929b62fe34a89c840bd59e56301 b75ecdb48309a15eb7c52b279c7f8523a95bcd48
Author: Keith Packard <keithp at bouzouki.jf.intel.com>
Date:   Wed Dec 6 12:53:22 2006 -0800

    Merge branch 'modesetting' into nonrandr-setup
    
    Also, fix buffer overflow in i830_debug.c

diff --cc src/i830_debug.c
index f732389,b1902ff..9f4dd29
@@@ -33,8 -33,157 +33,157 @@@
  #include "i830.h"
  #include "i830_debug.h"
  
+ #define DEBUGSTRING(func) static char *func(I830Ptr pI830, int reg, CARD32 val)
+ 
+ DEBUGSTRING(i830_debug_xyminus1)
+ {
+     return XNFprintf("%d, %d", (val & 0xffff) + 1,
+ 		     ((val & 0xffff0000) >> 16) + 1);
+ }
+ 
+ DEBUGSTRING(i830_debug_yxminus1)
+ {
+     return XNFprintf("%d, %d", ((val & 0xffff0000) >> 16) + 1,
+ 		     (val & 0xffff) + 1);
+ }
+ 
+ DEBUGSTRING(i830_debug_xy)
+ {
+     return XNFprintf("%d, %d", (val & 0xffff),
+ 		     ((val & 0xffff0000) >> 16));
+ }
+ 
+ DEBUGSTRING(i830_debug_dspstride)
+ {
+     return XNFprintf("%d bytes", val);
+ }
+ 
+ DEBUGSTRING(i830_debug_dspcntr)
+ {
+     char *enabled = val & DISPLAY_PLANE_ENABLE ? "enabled" : "disabled";
+     char plane = val & DISPPLANE_SEL_PIPE_B ? 'B' : 'A';
+     return XNFprintf("%s, pipe %c", enabled, plane);
+ }
+ 
+ DEBUGSTRING(i830_debug_pipeconf)
+ {
+     char *enabled = val & PIPEACONF_ENABLE ? "enabled" : "disabled";
+     char *wide = val & PIPEACONF_DOUBLE_WIDE ? "double-wide" : "single-wide";
+     return XNFprintf("%s, %s", enabled, wide);
+ }
+ 
+ DEBUGSTRING(i830_debug_hvtotal)
+ {
+     return XNFprintf("%d active, %d total", (val & 0xffff) + 1,
+ 		     ((val & 0xffff0000) >> 16) + 1);
+ }
+ 
+ DEBUGSTRING(i830_debug_hvsyncblank)
+ {
+     return XNFprintf("%d start, %d end", (val & 0xffff) + 1,
+ 		     ((val & 0xffff0000) >> 16) + 1);
+ }
+ 
+ DEBUGSTRING(i830_debug_vgacntrl)
+ {
+     return XNFprintf("%s", val & VGA_DISP_DISABLE ? "disabled" : "enabled");
+ }
+ 
+ DEBUGSTRING(i830_debug_fp)
+ {
+     return XNFprintf("n = %d, m1 = %d, m2 = %d",
+ 		     ((val & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT),
+ 		     ((val & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT),
+ 		     ((val & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT));
+ }
+ 
+ DEBUGSTRING(i830_debug_pp_status)
+ {
+     char *status = val & PP_ON ? "on" : "off";
+     char *ready = val & PP_READY ? "ready" : "not ready";
+     char *seq = "unknown";
+ 
+     switch (val & PP_SEQUENCE_MASK) {
+     case PP_SEQUENCE_NONE:
+ 	seq = "idle";
+ 	break;
+     case PP_SEQUENCE_ON:
+ 	seq = "on";
+ 	break;
+     case PP_SEQUENCE_OFF:
+ 	seq = "off";
+ 	break;
+     }
+ 
+     return XNFprintf("%s, %s, sequencing %s", status, ready, seq);
+ }
+ 
+ DEBUGSTRING(i830_debug_pp_control)
+ {
+     return XNFprintf("power target: %s",
+ 		     val & POWER_TARGET_ON ? "on" : "off");
+ }
+ 
+ DEBUGSTRING(i830_debug_dpll)
+ {
+     char *enabled = val & DPLL_VCO_ENABLE ? "enabled" : "disabled";
+     char *dvomode = val & DPLL_DVO_HIGH_SPEED ? "dvo" : "non-dvo";
+     char *vgamode = val & DPLL_VGA_MODE_DIS ? "" : ", VGA";
+     char *mode = "unknown";
+     char *clock = "unknown";
+     char *fpextra = val & DISPLAY_RATE_SELECT_FPA1 ? ", using FPx1!" : "";
 -    char sdvoextra[3];
++    char sdvoextra[20];
+     int p1, p2 = 0;
+ 
+     p1 = ffs((val & DPLL_FPA01_P1_POST_DIV_MASK) >>
+ 	     DPLL_FPA01_P1_POST_DIV_SHIFT);
+     switch (val & DPLL_MODE_MASK) {
+     case DPLLB_MODE_DAC_SERIAL:
+ 	mode = "dac/serial";
+ 	p2 = val & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? 5 : 10;
+ 	break;
+     case DPLLB_MODE_LVDS:
+ 	mode = "LVDS";
+ 	p2 = val & DPLLB_LVDS_P2_CLOCK_DIV_7 ? 7 : 14;
+ 	break;
+     }
+     switch (val & PLL_REF_INPUT_MASK) {
+     case PLL_REF_INPUT_DREFCLK:
+ 	clock = "default";
+ 	break;
+     case PLL_REF_INPUT_TVCLKINA:
+ 	clock = "TV A";
+ 	break;
+     case PLL_REF_INPUT_TVCLKINBC:
+ 	clock = "TV B/C";
+ 	break;
+     }
+     if (IS_I945G(pI830) || IS_I945GM(pI830)) {
+ 	sprintf(sdvoextra, "SDVO mult %d",
+ 		(int)(val & SDVO_MULTIPLIER_MASK) >>
+ 		SDVO_MULTIPLIER_SHIFT_HIRES);
+     } else {
+ 	sdvoextra[0] = '\0';
+     }
+ 
+     return XNFprintf("%s, %s%s, %s mode, %s clock, p1 = %d, "
+ 		     "p2 = %d%s%s",
+ 		     enabled, dvomode, vgamode, mode, clock, p1, p2,
+ 		     fpextra, sdvoextra);
+ }
+ 
+ DEBUGSTRING(i830_debug_lvds)
+ {
+     char pipe = val & LVDS_PIPEB_SELECT ? 'B' : 'A';
+     char *enable = val & LVDS_PORT_EN ? "enabled" : "disabled";
+ 
+     return XNFprintf("%s, pipe %c", enable, pipe);
+ }
+ 
  #define DEFINEREG(reg) \
- 	{ reg, #reg, 0 }
+ 	{ reg, #reg, NULL, 0 }
+ #define DEFINEREG2(reg, func) \
+ 	{ reg, #reg, func, 0 }
  
  static struct i830SnapshotRec {
      int reg;
diff --cc src/i830_randr.c
index 94d2221,d0ced37..2d986df
@@@ -608,11 -602,12 +609,13 @@@
  		return FALSE;
  	    }
  	    crtc->desiredMode = *mode;
 -	    i830PipeSetBase(crtc, x, y);
  	}
  	i830DisableUnusedFunctions (pScrn);
+ 
+ 	i830DumpRegs(pScrn);
      }
 +    if (pos_changed && mode)
 +	i830PipeSetBase(crtc, x, y);
      return xf86RandR12CrtcNotify (randr_crtc);
  }
  
diff --cc src/i830_xf86Crtc.h
index 9b7f788,10d4b72..21fc244
@@@ -27,13 -27,8 +27,14 @@@
  #include "i830_xf86Modes.h"
  
  typedef struct _xf86Crtc xf86CrtcRec, *xf86CrtcPtr;
+ typedef struct _xf86Output xf86OutputRec, *xf86OutputPtr;
  
 +typedef enum _xf86OutputStatus {
 +   XF86OutputStatusConnected,
 +   XF86OutputStatusDisconnected,
 +   XF86OutputStatusUnknown,
 +} xf86OutputStatus;
 +
  typedef struct _xf86CrtcFuncs {
     /**
      * Turns the crtc on/off, or sets intermediate power levels if available.
diff-tree b75ecdb48309a15eb7c52b279c7f8523a95bcd48 (from parents)
Merge: 1cb6311c1182fe98d2b8d237cef42509c3178f9a b3bb10e33e44c78f132d239e30931f97065a9fd6
Author: Eric Anholt <eric at anholt.net>
Date:   Wed Dec 6 11:59:33 2006 -0800

    Merge branch 'generic-mode-set' into modesetting

diff --cc src/i830_debug.c
index f732389,b14f981..b1902ff
@@@ -181,14 -331,31 +331,31 @@@
      int i;
  
      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 -	       "Comparing regs before/after X's VT usage\n");
 +	       "Comparing regs from server start up to %s\n", where);
      for (i = 0; i < NUM_I830_SNAPSHOTREGS; i++) {
  	CARD32 val = INREG(i830_snapshot[i].reg);
- 	if (i830_snapshot[i].regval != val) {
+ 	if (i830_snapshot[i].val == val)
+ 	    continue;
+ 
+ 	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ 		   "Register 0x%x (%s) changed from 0x%08x to 0x%08x\n",
+ 		   i830_snapshot[i].reg, i830_snapshot[i].name,
+ 		   (int)i830_snapshot[i].val, (int)val);
+ 
+ 	if (i830_snapshot[i].debug_output != NULL) {
+ 	    char *before, *after;
+ 
+ 	    before = i830_snapshot[i].debug_output(pI830,
+ 						   i830_snapshot[i].reg,
+ 						   i830_snapshot[i].val);
+ 	    after = i830_snapshot[i].debug_output(pI830,
+ 						  i830_snapshot[i].reg,
+ 						  val);
  	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
- 		       "Register 0x%x (%s) changed from 0x%08x to 0x%08x\n",
- 		       i830_snapshot[i].reg, i830_snapshot[i].name,
- 		       (int)i830_snapshot[i].regval, (int)val);
+ 		       "%s before: %s\n", i830_snapshot[i].name, before);
+ 	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ 		       "%s after: %s\n", i830_snapshot[i].name, after);
+ 
  	}
      }
  }
diff-tree b3bb10e33e44c78f132d239e30931f97065a9fd6 (from 47d07b1073c162ec00a8b173b8b6389dc4adbe88)
Author: Eric Anholt <eric at anholt.net>
Date:   Wed Dec 6 11:53:40 2006 -0800

    Fix LVDS: Don't change bits in LVDS other than port enable/pipe select.
    
    This behavior matches what we did before when LVDS worked.

diff --git a/src/i830_lvds.c b/src/i830_lvds.c
index 2c044e9..97f3852 100644
--- a/src/i830_lvds.c
+++ b/src/i830_lvds.c
@@ -199,7 +199,7 @@ i830_lvds_mode_set(xf86OutputPtr output,
      * This is an exception to the general rule that mode_set doesn't turn
      * things on.
      */
-    OUTREG(LVDS, LVDS_PORT_EN | LVDS_PIPEB_SELECT);
+    OUTREG(LVDS, INREG(LVDS) | LVDS_PORT_EN | LVDS_PIPEB_SELECT);
 
     /* Enable automatic panel scaling so that non-native modes fill the
      * screen.  Should be enabled before the pipe is enabled, according to
diff-tree 47d07b1073c162ec00a8b173b8b6389dc4adbe88 (from 727bf1cbf72362edcbdd68001a3558fd2b2b4eca)
Author: Eric Anholt <eric at anholt.net>
Date:   Wed Dec 6 10:56:38 2006 -0800

    More LVDS fixed mode fixing: use the EDID DTD's blank length.

diff --git a/src/i830_bios.c b/src/i830_bios.c
index 4a1bdb1..a9ef474 100644
--- a/src/i830_bios.c
+++ b/src/i830_bios.c
@@ -210,13 +210,14 @@ i830GetLVDSInfoFromBIOS(ScrnInfoPtr pScr
 		_H_SYNC_OFF(timing_ptr);
 	    fixed_mode->HSyncEnd   = fixed_mode->HSyncStart +
 		_H_SYNC_WIDTH(timing_ptr);
-	    fixed_mode->HTotal     = fixed_mode->HSyncEnd +
-		1;
+	    fixed_mode->HTotal     = fixed_mode->HDisplay +
+	        _H_BLANK(timing_ptr);
 	    fixed_mode->VSyncStart = fixed_mode->VDisplay +
 		_V_SYNC_OFF(timing_ptr);
 	    fixed_mode->VSyncEnd   = fixed_mode->VSyncStart +
 		_V_SYNC_WIDTH(timing_ptr);
-	    fixed_mode->VTotal     = fixed_mode->VSyncEnd + 1;
+	    fixed_mode->VTotal     = fixed_mode->VDisplay +
+	        _V_BLANK(timing_ptr);
 	    fixed_mode->Clock      = _PIXEL_CLOCK(timing_ptr) / 1000;
 	    fixed_mode->type       = M_T_PREFERRED;
 
diff-tree 727bf1cbf72362edcbdd68001a3558fd2b2b4eca (from 236c53be5d94798d55219651a6885fee32ce175b)
Author: Eric Anholt <eric at anholt.net>
Date:   Wed Dec 6 10:12:49 2006 -0800

    Add missing newlines to new debug output.

diff --git a/src/i830_debug.c b/src/i830_debug.c
index 68c4b5d..b14f981 100644
--- a/src/i830_debug.c
+++ b/src/i830_debug.c
@@ -352,9 +352,9 @@ void i830CompareRegsToSnapshot(ScrnInfoP
 						  i830_snapshot[i].reg,
 						  val);
 	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
-		       "%s before: %s", i830_snapshot[i].name, before);
+		       "%s before: %s\n", i830_snapshot[i].name, before);
 	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
-		       "%s after: %s", i830_snapshot[i].name, after);
+		       "%s after: %s\n", i830_snapshot[i].name, after);
 
 	}
     }
diff-tree 236c53be5d94798d55219651a6885fee32ce175b (from 1d94ec7de3387b70815679977cfc5d88200efa99)
Author: Eric Anholt <eric at anholt.net>
Date:   Wed Dec 6 10:10:27 2006 -0800

    Fix LVDS fixed mode code after generic-mode-set.

diff --git a/src/i830.h b/src/i830.h
index 4cfed4b..ae6b536 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -438,19 +438,8 @@ typedef struct _I830Rec {
 
    int ddc2;
 
-   /* Panel size pulled from the BIOS */
-   int PanelXRes, PanelYRes;
-
    /* The BIOS's fixed timings for the LVDS */
-   int panel_fixed_clock;
-   int panel_fixed_hactive;
-   int panel_fixed_hblank;
-   int panel_fixed_hsyncoff;
-   int panel_fixed_hsyncwidth;
-   int panel_fixed_vactive;
-   int panel_fixed_vblank;
-   int panel_fixed_vsyncoff;
-   int panel_fixed_vsyncwidth;
+   DisplayModePtr panel_fixed_mode;
 
    int backlight_duty_cycle;  /* restore backlight to this value */
    
diff --git a/src/i830_bios.c b/src/i830_bios.c
index 0821845..4a1bdb1 100644
--- a/src/i830_bios.c
+++ b/src/i830_bios.c
@@ -158,6 +158,7 @@ i830GetLVDSInfoFromBIOS(ScrnInfoPtr pScr
 	struct lvds_bdb_2 *lvds2;
 	struct lvds_bdb_2_fp_params *fpparam;
 	struct lvds_bdb_2_fp_edid_dtd *fptiming;
+	DisplayModePtr fixed_mode;
 	CARD8 *timing_ptr;
 
 	id = INTEL_BIOS_8(start);
@@ -197,32 +198,36 @@ i830GetLVDSInfoFromBIOS(ScrnInfoPtr pScr
 		    continue;
 	    }
 
-	    pI830->PanelXRes = fpparam->x_res;
-	    pI830->PanelYRes = fpparam->y_res;
-	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
-		       "Found panel of size %dx%d in BIOS VBT tables\n",
-		       pI830->PanelXRes, pI830->PanelYRes);
+	    fixed_mode = xnfalloc(sizeof(DisplayModeRec));
+	    memset(fixed_mode, 0, sizeof(*fixed_mode));
 
 	    /* Since lvds_bdb_2_fp_edid_dtd is just an EDID detailed timing
 	     * block, pull the contents out using EDID macros.
 	     */
-	    pI830->panel_fixed_clock = _PIXEL_CLOCK(timing_ptr) / 1000;
-	    pI830->panel_fixed_hactive = _H_ACTIVE(timing_ptr);
-	    pI830->panel_fixed_hblank = _H_BLANK(timing_ptr);
-	    pI830->panel_fixed_hsyncoff = _H_SYNC_OFF(timing_ptr);
-	    pI830->panel_fixed_hsyncwidth = _H_SYNC_WIDTH(timing_ptr);
-
-	    pI830->panel_fixed_vactive = _V_ACTIVE(timing_ptr);
-	    pI830->panel_fixed_vblank = _V_BLANK(timing_ptr);
-	    pI830->panel_fixed_vsyncoff = _V_SYNC_OFF(timing_ptr);
-	    pI830->panel_fixed_vsyncwidth = _V_SYNC_WIDTH(timing_ptr);
+	    fixed_mode->HDisplay   = _H_ACTIVE(timing_ptr);
+	    fixed_mode->VDisplay   = _V_ACTIVE(timing_ptr);
+	    fixed_mode->HSyncStart = fixed_mode->HDisplay +
+		_H_SYNC_OFF(timing_ptr);
+	    fixed_mode->HSyncEnd   = fixed_mode->HSyncStart +
+		_H_SYNC_WIDTH(timing_ptr);
+	    fixed_mode->HTotal     = fixed_mode->HSyncEnd +
+		1;
+	    fixed_mode->VSyncStart = fixed_mode->VDisplay +
+		_V_SYNC_OFF(timing_ptr);
+	    fixed_mode->VSyncEnd   = fixed_mode->VSyncStart +
+		_V_SYNC_WIDTH(timing_ptr);
+	    fixed_mode->VTotal     = fixed_mode->VSyncEnd + 1;
+	    fixed_mode->Clock      = _PIXEL_CLOCK(timing_ptr) / 1000;
+	    fixed_mode->type       = M_T_PREFERRED;
+
+	    xf86SetModeDefaultName(fixed_mode);
+
 	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
-		       "Panel mode h active %d blank %d rate %f v active %d blank %d rate %f\n",
-		       pI830->panel_fixed_hactive, pI830->panel_fixed_hblank,
-		       (double) pI830->panel_fixed_clock / (pI830->panel_fixed_hactive + pI830->panel_fixed_hblank),
-		       pI830->panel_fixed_vactive, pI830->panel_fixed_vblank,
-		       (double) pI830->panel_fixed_clock / 
-		       ((pI830->panel_fixed_hactive + pI830->panel_fixed_hblank) * (pI830->panel_fixed_vactive + pI830->panel_fixed_vblank)));
+		       "Found panel mode in BIOS VBT tables:\n");
+	    xf86PrintModeline(pScrn->scrnIndex, fixed_mode);
+
+	    pI830->panel_fixed_mode = fixed_mode;
+
 	    found_panel_info = TRUE;
 	    break;
 	}
diff --git a/src/i830_lvds.c b/src/i830_lvds.c
index a9c0e20..2c044e9 100644
--- a/src/i830_lvds.c
+++ b/src/i830_lvds.c
@@ -161,22 +161,16 @@ i830_lvds_mode_fixup(xf86OutputPtr outpu
      * with the panel scaling set up to source from the H/VDisplay
      * of the original mode.
      */
-    if (pI830->panel_fixed_hactive != 0) {
-	adjusted_mode->HDisplay = pI830->panel_fixed_hactive;
-	adjusted_mode->HTotal = adjusted_mode->HDisplay +
-	    pI830->panel_fixed_hblank;
-	adjusted_mode->HSyncStart = adjusted_mode->HDisplay +
-	    pI830->panel_fixed_hsyncoff;
-	adjusted_mode->HSyncStart = adjusted_mode->HSyncStart +
-	    pI830->panel_fixed_hsyncwidth;
-	adjusted_mode->VDisplay = pI830->panel_fixed_vactive;
-	adjusted_mode->VTotal = adjusted_mode->VDisplay +
-	    pI830->panel_fixed_hblank;
-	adjusted_mode->VSyncStart = adjusted_mode->VDisplay +
-	    pI830->panel_fixed_hsyncoff;
-	adjusted_mode->VSyncStart = adjusted_mode->VSyncStart +
-	    pI830->panel_fixed_hsyncwidth;
-	adjusted_mode->Clock = pI830->panel_fixed_clock;
+    if (pI830->panel_fixed_mode != NULL) {
+	adjusted_mode->HDisplay = pI830->panel_fixed_mode->HDisplay;
+	adjusted_mode->HSyncStart = pI830->panel_fixed_mode->HSyncStart;
+	adjusted_mode->HSyncEnd = pI830->panel_fixed_mode->HSyncEnd;
+	adjusted_mode->HTotal = pI830->panel_fixed_mode->HTotal;
+	adjusted_mode->VDisplay = pI830->panel_fixed_mode->VDisplay;
+	adjusted_mode->VSyncStart = pI830->panel_fixed_mode->VSyncStart;
+	adjusted_mode->VSyncEnd = pI830->panel_fixed_mode->VSyncEnd;
+	adjusted_mode->VTotal = pI830->panel_fixed_mode->VTotal;
+	adjusted_mode->Clock = pI830->panel_fixed_mode->Clock;
 	xf86SetModeCrtc(adjusted_mode, INTERLACE_HALVE_V);
     }
 
@@ -241,30 +235,16 @@ i830_lvds_get_modes(xf86OutputPtr output
 {
     ScrnInfoPtr	    pScrn = output->scrn;
     I830Ptr	    pI830 = I830PTR(pScrn);
-    DisplayModePtr  modes, new;
-    char	    stmp[32];
+    DisplayModePtr  modes;
 
     modes = i830_ddc_get_modes(output);
     if (modes != NULL)
 	return modes;
 
-    new             = xnfcalloc(1, sizeof (DisplayModeRec));
-    sprintf(stmp, "%dx%d", pI830->PanelXRes, pI830->PanelYRes);
-    new->name       = xnfalloc(strlen(stmp) + 1);
-    strcpy(new->name, stmp);
-    new->HDisplay   = pI830->PanelXRes;
-    new->VDisplay   = pI830->PanelYRes;
-    new->HSyncStart = pI830->panel_fixed_hactive + pI830->panel_fixed_hsyncoff;
-    new->HSyncEnd   = new->HSyncStart + pI830->panel_fixed_hsyncwidth;
-    new->HTotal     = new->HSyncEnd + 1;
-    new->VSyncStart = pI830->panel_fixed_vactive + pI830->panel_fixed_vsyncoff;
-    new->VSyncEnd   = new->VSyncStart + pI830->panel_fixed_vsyncwidth;
-    new->VTotal     = new->VSyncEnd + 1;
-    new->Clock      = pI830->panel_fixed_clock;
+    if (pI830->panel_fixed_mode != NULL)
+	return xf86DuplicateMode(pI830->panel_fixed_mode);
 
-    new->type       = M_T_PREFERRED;
-
-    return new;
+    return NULL;
 }
 
 static void
@@ -321,7 +301,9 @@ i830_lvds_init(ScrnInfoPtr pScrn)
 	     * display.
 	     */
 
-	    if (pI830->PanelXRes == 800 && pI830->PanelYRes == 600) {
+	    if (pI830->panel_fixed_mode != NULL &&
+		pI830->panel_fixed_mode->HDisplay == 800 &&
+		pI830->panel_fixed_mode->VDisplay == 600) {
 		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 			   "Suspected Mac Mini, ignoring the LVDS\n");
 		return;
diff-tree 1cb6311c1182fe98d2b8d237cef42509c3178f9a (from ffd8aacbe7c72b696ff7257609e3c1d45c057609)
Author: Wang Zhenyu <zhenyu.z.wang at intel.com>
Date:   Wed Dec 6 16:31:00 2006 +0800

    fix typo in checking xf86CrtcScreenInit return

diff --git a/src/i830_randr.c b/src/i830_randr.c
index 0077020..a6d71f2 100644
--- a/src/i830_randr.c
+++ b/src/i830_randr.c
@@ -900,7 +900,7 @@ xf86RandR12Init12 (ScreenPtr pScreen)
     ScrnInfoPtr		pScrn = xf86Screens[pScreen->myNum];
     rrScrPrivPtr	rp = rrGetScrPriv(pScreen);
 
-    if (xf86CrtcScreenInit (pScreen))
+    if (!xf86CrtcScreenInit (pScreen))
 	return FALSE;
 
     rp->rrGetInfo = xf86RandR12GetInfo12;
diff-tree 1d94ec7de3387b70815679977cfc5d88200efa99 (from eee23fdd0dadd38a2b80525ec886120150f91077)
Author: Eric Anholt <eric at anholt.net>
Date:   Tue Dec 5 18:22:59 2006 -0800

    Fix ordering of PIPE[AB]SRC debug output to be (x, y).

diff --git a/src/i830_debug.c b/src/i830_debug.c
index 97b0983..68c4b5d 100644
--- a/src/i830_debug.c
+++ b/src/i830_debug.c
@@ -41,6 +41,12 @@ DEBUGSTRING(i830_debug_xyminus1)
 		     ((val & 0xffff0000) >> 16) + 1);
 }
 
+DEBUGSTRING(i830_debug_yxminus1)
+{
+    return XNFprintf("%d, %d", ((val & 0xffff0000) >> 16) + 1,
+		     (val & 0xffff) + 1);
+}
+
 DEBUGSTRING(i830_debug_xy)
 {
     return XNFprintf("%d, %d", (val & 0xffff),
@@ -228,7 +234,7 @@ static struct i830SnapshotRec {
     DEFINEREG(DSPASURF),
     DEFINEREG(DSPATILEOFF),
     DEFINEREG2(PIPEACONF, i830_debug_pipeconf),
-    DEFINEREG2(PIPEASRC, i830_debug_xyminus1),
+    DEFINEREG2(PIPEASRC, i830_debug_yxminus1),
 
     DEFINEREG2(FPA0, i830_debug_fp),
     DEFINEREG2(FPA1, i830_debug_fp),
@@ -251,7 +257,7 @@ static struct i830SnapshotRec {
     DEFINEREG(DSPBSURF),
     DEFINEREG(DSPBTILEOFF),
     DEFINEREG2(PIPEBCONF, i830_debug_pipeconf),
-    DEFINEREG2(PIPEBSRC, i830_debug_xyminus1),
+    DEFINEREG2(PIPEBSRC, i830_debug_yxminus1),
 
     DEFINEREG2(FPB0, i830_debug_fp),
     DEFINEREG2(FPB1, i830_debug_fp),
diff-tree eee23fdd0dadd38a2b80525ec886120150f91077 (from 58c247c6de56508b00eadf77b4c145c94134270d)
Author: Eric Anholt <eric at anholt.net>
Date:   Tue Dec 5 18:19:49 2006 -0800

    Fix copy'n'paste-o of the ordering of h/v fields in DSP[AB]SIZE.

diff --git a/src/i830_display.c b/src/i830_display.c
index 03a7765..d822083 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -745,7 +745,7 @@ i830_crtc_mode_set(xf86CrtcPtr crtc, Dis
     /* pipesrc and dspsize control the size that is scaled from, which should
      * always be the user's requested size.
      */
-    OUTREG(dspsize_reg, ((mode->HDisplay - 1) << 16) | (mode->VDisplay - 1));
+    OUTREG(dspsize_reg, ((mode->VDisplay - 1) << 16) | (mode->HDisplay - 1));
     OUTREG(dsppos_reg, 0);
     i830PipeSetBase(crtc, crtc->x, crtc->y);
     OUTREG(pipesrc_reg, ((mode->HDisplay - 1) << 16) | (mode->VDisplay - 1));
diff-tree 58c247c6de56508b00eadf77b4c145c94134270d (from parents)
Merge: 0b4c3e7bff790e1e99ace5036a41e96046335b04 2e8c927f9308069a82f25b65bb0c62bc5a156832
Author: Eric Anholt <eric at anholt.net>
Date:   Tue Dec 5 15:28:21 2006 -0800

    Merge branch 'modesetting-origin' into modesetting
    
    Conflicts:
    
    	src/i830_display.c

diff --cc src/i830_display.c
index d7d7417,ac56528..03a7765
@@@ -506,20 -516,34 +576,20 @@@
      int dspstride_reg = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
      int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
      int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
-     int m1 = 0, m2 = 0, n = 0, p1 = 0, p2 = 0;
 -    int pipestat_reg = (pipe == 0) ? PIPEASTAT : PIPEBSTAT;
 -    Bool ret = FALSE;
 -#ifdef XF86DRI
 -    Bool didLock = FALSE;
 -#endif
 -
 -    if (xf86ModesEqual(&crtc->curMode, pMode))
 -	return TRUE;
 -
 -    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Requested pix clock: %d\n",
 -	       pMode->Clock);
 -
 -    crtc->enabled = i830PipeInUse (crtc);
 -    
 -    if (!crtc->enabled)
 -    {
 -	/* XXX disable crtc? */
 -	return TRUE;
 -    }
 +    int i;
 +    int refclk;
-     CARD32 dpll = 0, fp = 0, temp, dspcntr;
++    intel_clock_t clock;
++    CARD32 dpll = 0, fp = 0, dspcntr, pipeconf;
 +    Bool ok, is_sdvo = FALSE, is_dvo = FALSE;
 +    Bool is_crt = FALSE, is_lvds = FALSE, is_tv = FALSE;
  
 -#ifdef XF86DRI
 -    didLock = I830DRILock(pScrn);
 -#endif
 -    
 -    for (i = 0; i < pI830->xf86_config.num_output; i++) 
 -    {
 +    /* Set up some convenient bools for what outputs are connected to
 +     * our pipe, used in DPLL setup.
 +     */
 +    for (i = 0; i < pI830->xf86_config.num_output; i++) {
  	xf86OutputPtr  output = pI830->xf86_config.output[i];
 -	I830OutputPrivatePtr	intel_output = output->driver_private;
 +	I830OutputPrivatePtr intel_output = output->driver_private;
 +
  	if (output->crtc != crtc)
  	    continue;
  
@@@ -547,18 -643,15 +617,17 @@@
      } else {
  	refclk = 48000;
      }
 -    
 -    ok = i830FindBestPLL(crtc, pixel_clock, refclk, &clock);
 -    if (!ok) {
 -	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
 -		   "Couldn't find PLL settings for mode!\n");
 -	goto done;
 -    }
  
-     ok = i830FindBestPLL(crtc, adjusted_mode->Clock, refclk, &m1, &m2, &n,
- 			 &p1, &p2);
 -    dpll = DPLL_VCO_ENABLE | DPLL_VGA_MODE_DIS;
++    ok = i830FindBestPLL(crtc, adjusted_mode->Clock, refclk, &clock);
 +    if (!ok)
 +	FatalError("Couldn't find PLL settings for mode!\n");
 +
-     fp = ((n - 2) << 16) | ((m1 - 2) << 8) | (m2 - 2);
++    fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
 +
-     i830PrintPll("chosen", refclk, m1, m2, n, p1, p2);
++    i830PrintPll("chosen", &clock);
 +    ErrorF("clock regs: 0x%08x, 0x%08x\n", (int)dpll, (int)fp);
 +
 +    dpll = DPLL_VGA_MODE_DIS;
      if (IS_I9XX(pI830)) {
  	if (is_lvds)
  	    dpll |= DPLLB_MODE_LVDS;
@@@ -628,137 -739,101 +697,176 @@@
      else
  	dspcntr |= DISPPLANE_SEL_PIPE_B;
  
 -    OUTREG(VGACNTRL, VGA_DISP_DISABLE);
 -
 -    /* Finally, set the mode. */
 -    /* First, disable display planes */
 -    temp = INREG(dspcntr_reg);
 -    OUTREG(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
 -
 -    /* Wait for vblank for the disable to take effect */
 -    i830WaitForVblank(pScrn);
 -
 -    /* Next, disable display pipes */
 -    temp = INREG(pipeconf_reg);
 -    OUTREG(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
 -
 -    OUTREG(fp_reg, fp);
 -    OUTREG(dpll_reg, dpll);
 -
 -    /*
 -     * If the panel fitter is stuck on our pipe, turn it off.
 -     * The LVDS output will set it as necessary in post_set_mode.
 -     */
 -    if (!IS_I830(pI830)) {
 -	if (((INREG(PFIT_CONTROL) >> 29) & 0x3) == pipe)
 -	    OUTREG(PFIT_CONTROL, 0);
 -    }
 -
 -    for (i = 0; i < pI830->xf86_config.num_output; i++) {
 -	xf86OutputPtr  output = pI830->xf86_config.output[i];
 -	if (output->crtc == crtc)
 -	    (*output->funcs->post_set_mode)(output, pMode);
 -    }
 -
 -    OUTREG(htot_reg, htot);
 -    OUTREG(hblank_reg, hblank);
 -    OUTREG(hsync_reg, hsync);
 -    OUTREG(vtot_reg, vtot);
 -    OUTREG(vblank_reg, vblank);
 -    OUTREG(vsync_reg, vsync);
 -    OUTREG(dspstride_reg, pScrn->displayWidth * pI830->cpp);
 -    OUTREG(dspsize_reg, dspsize);
 -    OUTREG(dsppos_reg, 0);
 -    i830PipeSetBase(crtc, crtc->x, crtc->y);
 -    OUTREG(pipesrc_reg, pipesrc);
 -
 -    /* Then, turn the pipe on first */
 -    temp = INREG(pipeconf_reg);
 -    temp |= PIPEACONF_ENABLE;
 -    if (!IS_I9XX(pI830) && pipe == 0)
 -    {
++    pipeconf = INREG(pipeconf_reg);
++    if (!IS_I9XX(pI830) && pipe == 0) {
+ 	/*
+ 	 * The docs say this is needed when the dot clock is > 90% of the
+ 	 * core speed. Core speeds are indicated by bits in the PCI
+ 	 * config space and don't seem to ever be less than 200MHz,
+ 	 * which is a bit confusing.
+ 	 *
+ 	 * However, For one little 855/852 card I have, 135000 requires
+ 	 * double wide mode, but 108000 does not. That makes no sense
+ 	 * but we're used to that. It may be affected by pixel size,
+ 	 * but the BIOS mode setting code doesn't appear to use that.
+ 	 *
+ 	 * It doesn't seem to cause any harm, although it
+ 	 * does restrict some output options.
+ 	 */
 -	if (pixel_clock > 108000)
 -	    temp |= PIPEACONF_DOUBLE_WIDE;
++	if (adjusted_mode->Clock > 108000)
++	    pipeconf |= PIPEACONF_DOUBLE_WIDE;
+ 	else
 -	    temp &= ~PIPEACONF_DOUBLE_WIDE;
++	    pipeconf &= ~PIPEACONF_DOUBLE_WIDE;
++    }
++
 +    OUTREG(fp_reg, fp);
 +    OUTREG(dpll_reg, dpll);
 +    if (IS_I965G(pI830)) {
 +	/* Set the SDVO multiplier/divider to 1x for the sake of analog output.
 +	 * It will be updated by the SDVO code if SDVO had fixed up the clock
 +	 * for a higher multiplier.
 +	 */
 +	OUTREG(dpll_md_reg, 0);
 +    }
 +
 +    OUTREG(htot_reg, (adjusted_mode->CrtcHDisplay - 1) |
 +	((adjusted_mode->CrtcHTotal - 1) << 16));
 +    OUTREG(hblank_reg, (adjusted_mode->CrtcHBlankStart - 1) |
 +	((adjusted_mode->CrtcHBlankEnd - 1) << 16));
 +    OUTREG(hsync_reg, (adjusted_mode->CrtcHSyncStart - 1) |
 +	((adjusted_mode->CrtcHSyncEnd - 1) << 16));
 +    OUTREG(vtot_reg, (adjusted_mode->CrtcVDisplay - 1) |
 +	((adjusted_mode->CrtcVTotal - 1) << 16));
 +    OUTREG(vblank_reg, (adjusted_mode->CrtcVBlankStart - 1) |
 +	((adjusted_mode->CrtcVBlankEnd - 1) << 16));
 +    OUTREG(vsync_reg, (adjusted_mode->CrtcVSyncStart - 1) |
 +	((adjusted_mode->CrtcVSyncEnd - 1) << 16));
 +    OUTREG(dspstride_reg, pScrn->displayWidth * pI830->cpp);
 +    /* pipesrc and dspsize control the size that is scaled from, which should
 +     * always be the user's requested size.
 +     */
 +    OUTREG(dspsize_reg, ((mode->HDisplay - 1) << 16) | (mode->VDisplay - 1));
 +    OUTREG(dsppos_reg, 0);
 +    i830PipeSetBase(crtc, crtc->x, crtc->y);
 +    OUTREG(pipesrc_reg, ((mode->HDisplay - 1) << 16) | (mode->VDisplay - 1));
-     temp = INREG(pipeconf_reg);
-     OUTREG(pipeconf_reg, temp);
++    OUTREG(pipeconf_reg, pipeconf);
 +    OUTREG(dspcntr_reg, dspcntr);
 +
 +    /* Disable the panel fitter if it was on our pipe */
 +    if (!IS_I830(pI830) && ((INREG(PFIT_CONTROL) >> 29) & 0x3) == pipe)
 +	OUTREG(PFIT_CONTROL, 0);
 +}
 +
 +/**
 + * Sets the given video mode on the given pipe.
 + *
 + * Plane A is always output to pipe A, and plane B to pipe B.  The plane
 + * will not be enabled if plane_enable is FALSE, which is used for
 + * load detection, when something else will be output to the pipe other than
 + * display data.
 + */
 +Bool
 +i830PipeSetMode(xf86CrtcPtr crtc, DisplayModePtr pMode,
 +		Bool plane_enable)
 +{
 +    ScrnInfoPtr pScrn = crtc->scrn;
 +    I830Ptr pI830 = I830PTR(pScrn);
 +    int i;
 +    Bool ret = FALSE;
 +#ifdef XF86DRI
 +    Bool didLock = FALSE;
 +#endif
 +    DisplayModePtr adjusted_mode;
 +
 +    /* XXX: curMode */
 +
 +    adjusted_mode = xf86DuplicateMode(pMode);
 +
 +    crtc->enabled = i830PipeInUse (crtc);
 +    
 +    if (!crtc->enabled)
 +    {
 +	/* XXX disable crtc? */
 +	return TRUE;
 +    }
 +
 +#ifdef XF86DRI
 +    didLock = I830DRILock(pScrn);
 +#endif
 +
 +    /* Pass our mode to the outputs and the CRTC to give them a chance to
 +     * adjust it according to limitations or output properties, and also
 +     * a chance to reject the mode entirely.
 +     */
 +    for (i = 0; i < pI830->xf86_config.num_output; i++) {
 +	xf86OutputPtr output = pI830->xf86_config.output[i];
 +
 +	if (output->crtc != crtc)
 +	    continue;
 +
 +	if (!output->funcs->mode_fixup(output, pMode, adjusted_mode)) {
 +	    ret = FALSE;
 +	    goto done;
 +	}
      }
 -    OUTREG(pipeconf_reg, temp);
  
 -    if (plane_enable) {
 -	/* And then turn the plane on */
 -	OUTREG(dspcntr_reg, dspcntr);
 +    if (!crtc->funcs->mode_fixup(crtc, pMode, adjusted_mode)) {
 +	ret = FALSE;
 +	goto done;
 +    }
 +
 +    /* Disable the outputs and CRTCs before setting the mode. */
 +    for (i = 0; i < pI830->xf86_config.num_output; i++) {
 +	xf86OutputPtr output = pI830->xf86_config.output[i];
 +
 +	if (output->crtc != crtc)
 +	    continue;
 +
 +	/* Disable the output as the first thing we do. */
 +	output->funcs->dpms(output, DPMSModeOff);
 +    }
 +
 +    crtc->funcs->dpms(crtc, DPMSModeOff);
 +
 +    /* Set up the DPLL and any output state that needs to adjust or depend
 +     * on the DPLL.
 +     */
 +    crtc->funcs->mode_set(crtc, pMode, adjusted_mode);
 +    for (i = 0; i < pI830->xf86_config.num_output; i++) {
 +	xf86OutputPtr output = pI830->xf86_config.output[i];
 +	if (output->crtc == crtc)
 +	    output->funcs->mode_set(output, pMode, adjusted_mode);
 +    }
 +
 +    /* Now, enable the clocks, plane, pipe, and outputs that we set up. */
 +    crtc->funcs->dpms(crtc, DPMSModeOn);
 +    for (i = 0; i < pI830->xf86_config.num_output; i++) {
 +	xf86OutputPtr output = pI830->xf86_config.output[i];
 +	if (output->crtc == crtc)
 +	    output->funcs->dpms(output, DPMSModeOn);
      }
  
+ #if 0
+     /*
+      * If the display isn't solid, it may be running out
+      * of memory bandwidth. This code will dump out the
+      * pipe status, if bit 31 is on, the fifo underran
+      */
+     for (i = 0; i < 4; i++) {
+ 	i830WaitForVblank(pScrn);
+     
+ 	OUTREG(pipestat_reg, INREG(pipestat_reg) | 0x80000000);
+     
+ 	i830WaitForVblank(pScrn);
+     
+ 	temp = INREG(pipestat_reg);
+ 	ErrorF ("pipe status 0x%x\n", temp);
+     }
+ #endif
+     
      crtc->curMode = *pMode;
  
 +    /* XXX free adjustedmode */
      ret = TRUE;
  done:
  #ifdef XF86DRI
diff-tree 0b4c3e7bff790e1e99ace5036a41e96046335b04 (from 7844e576e71c004ed495bbc31f7bbe890d18b8d9)
Author: Eric Anholt <eric at anholt.net>
Date:   Tue Dec 5 14:39:47 2006 -0800

    Add a bunch of per-register debug code to i830DumpRegs().

diff --git a/src/i810_reg.h b/src/i810_reg.h
index 7312f8a..d525024 100644
--- a/src/i810_reg.h
+++ b/src/i810_reg.h
@@ -762,6 +762,18 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
 #define PP_STATUS	0x61200
 # define PP_ON					(1 << 31)
+/**
+ * Indicates that all dependencies of the panel are on:
+ *
+ * - PLL enabled
+ * - pipe enabled
+ * - LVDS/DVOB/DVOC on
+ */
+# define PP_READY				(1 << 30)
+# define PP_SEQUENCE_NONE			(0 << 28)
+# define PP_SEQUENCE_ON				(1 << 28)
+# define PP_SEQUENCE_OFF			(2 << 28)
+# define PP_SEQUENCE_MASK			0x30000000
 
 #define PP_CONTROL	0x61204
 # define POWER_TARGET_ON			(1 << 0)
@@ -796,12 +808,14 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN
 # define DPLL_VGA_MODE_DIS			(1 << 28)
 # define DPLLB_MODE_DAC_SERIAL			(1 << 26) /* i915 */
 # define DPLLB_MODE_LVDS			(2 << 26) /* i915 */
+# define DPLL_MODE_MASK				(3 << 26)
 # define DPLL_DAC_SERIAL_P2_CLOCK_DIV_10	(0 << 24) /* i915 */
 # define DPLL_DAC_SERIAL_P2_CLOCK_DIV_5		(1 << 24) /* i915 */
 # define DPLLB_LVDS_P2_CLOCK_DIV_14		(0 << 24) /* i915 */
 # define DPLLB_LVDS_P2_CLOCK_DIV_7		(1 << 24) /* i915 */
 # define DPLL_P2_CLOCK_DIV_MASK			0x03000000 /* i915 */
 # define DPLL_FPA01_P1_POST_DIV_MASK		0x00ff0000 /* i915 */
+# define DPLL_FPA01_P1_POST_DIV_SHIFT		16
 # define PLL_P2_DIVIDE_BY_4			(1 << 23) /* i830, required in DVO non-gang */
 # define DPLL_FPA01_P1_POS_DIV_MASK_I830	0x001f0000 /* i830 */
 # define PLL_P1_DIVIDE_BY_TWO			(1 << 21) /* i830 */
@@ -809,6 +823,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN
 # define PLL_REF_INPUT_TVCLKINA			(1 << 13) /* i830 */
 # define PLL_REF_INPUT_TVCLKINBC		(2 << 13) /* SDVO TVCLKIN */
 # define PLLB_REF_INPUT_SPREADSPECTRUMIN	(3 << 13)
+# define PLL_REF_INPUT_MASK			(3 << 13)
 # define PLL_LOAD_PULSE_PHASE_SHIFT		9
 /*
  * Parallel to Serial Load Pulse phase selection.
@@ -818,6 +833,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN
  */
 # define PLL_LOAD_PULSE_PHASE_MASK		(0xf << PLL_LOAD_PULSE_PHASE_SHIFT)
 # define DISPLAY_RATE_SELECT_FPA1		(1 << 8)
+
 /**
  * SDVO multiplier for 945G/GM. Not used on 965.
  *
@@ -906,8 +922,11 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN
 #define FPB0		0x06048
 #define FPB1		0x0604c
 # define FP_N_DIV_MASK				0x003f0000
+# define FP_N_DIV_SHIFT				16
 # define FP_M1_DIV_MASK				0x00003f00
+# define FP_M1_DIV_SHIFT			8
 # define FP_M2_DIV_MASK				0x0000003f
+# define FP_M2_DIV_SHIFT			0
 
 #define PORT_HOTPLUG_EN		0x61110
 # define SDVOB_HOTPLUG_INT_EN			(1 << 26)
diff --git a/src/i830_debug.c b/src/i830_debug.c
index d74d092..97b0983 100644
--- a/src/i830_debug.c
+++ b/src/i830_debug.c
@@ -33,13 +33,157 @@
 #include "i830.h"
 #include "i830_debug.h"
 
+#define DEBUGSTRING(func) static char *func(I830Ptr pI830, int reg, CARD32 val)
+
+DEBUGSTRING(i830_debug_xyminus1)
+{
+    return XNFprintf("%d, %d", (val & 0xffff) + 1,
+		     ((val & 0xffff0000) >> 16) + 1);
+}
+
+DEBUGSTRING(i830_debug_xy)
+{
+    return XNFprintf("%d, %d", (val & 0xffff),
+		     ((val & 0xffff0000) >> 16));
+}
+
+DEBUGSTRING(i830_debug_dspstride)
+{
+    return XNFprintf("%d bytes", val);
+}
+
+DEBUGSTRING(i830_debug_dspcntr)
+{
+    char *enabled = val & DISPLAY_PLANE_ENABLE ? "enabled" : "disabled";
+    char plane = val & DISPPLANE_SEL_PIPE_B ? 'B' : 'A';
+    return XNFprintf("%s, pipe %c", enabled, plane);
+}
+
+DEBUGSTRING(i830_debug_pipeconf)
+{
+    char *enabled = val & PIPEACONF_ENABLE ? "enabled" : "disabled";
+    char *wide = val & PIPEACONF_DOUBLE_WIDE ? "double-wide" : "single-wide";
+    return XNFprintf("%s, %s", enabled, wide);
+}
+
+DEBUGSTRING(i830_debug_hvtotal)
+{
+    return XNFprintf("%d active, %d total", (val & 0xffff) + 1,
+		     ((val & 0xffff0000) >> 16) + 1);
+}
+
+DEBUGSTRING(i830_debug_hvsyncblank)
+{
+    return XNFprintf("%d start, %d end", (val & 0xffff) + 1,
+		     ((val & 0xffff0000) >> 16) + 1);
+}
+
+DEBUGSTRING(i830_debug_vgacntrl)
+{
+    return XNFprintf("%s", val & VGA_DISP_DISABLE ? "disabled" : "enabled");
+}
+
+DEBUGSTRING(i830_debug_fp)
+{
+    return XNFprintf("n = %d, m1 = %d, m2 = %d",
+		     ((val & FP_N_DIV_MASK) >> FP_N_DIV_SHIFT),
+		     ((val & FP_M1_DIV_MASK) >> FP_M1_DIV_SHIFT),
+		     ((val & FP_M2_DIV_MASK) >> FP_M2_DIV_SHIFT));
+}
+
+DEBUGSTRING(i830_debug_pp_status)
+{
+    char *status = val & PP_ON ? "on" : "off";
+    char *ready = val & PP_READY ? "ready" : "not ready";
+    char *seq = "unknown";
+
+    switch (val & PP_SEQUENCE_MASK) {
+    case PP_SEQUENCE_NONE:
+	seq = "idle";
+	break;
+    case PP_SEQUENCE_ON:
+	seq = "on";
+	break;
+    case PP_SEQUENCE_OFF:
+	seq = "off";
+	break;
+    }
+
+    return XNFprintf("%s, %s, sequencing %s", status, ready, seq);
+}
+
+DEBUGSTRING(i830_debug_pp_control)
+{
+    return XNFprintf("power target: %s",
+		     val & POWER_TARGET_ON ? "on" : "off");
+}
+
+DEBUGSTRING(i830_debug_dpll)
+{
+    char *enabled = val & DPLL_VCO_ENABLE ? "enabled" : "disabled";
+    char *dvomode = val & DPLL_DVO_HIGH_SPEED ? "dvo" : "non-dvo";
+    char *vgamode = val & DPLL_VGA_MODE_DIS ? "" : ", VGA";
+    char *mode = "unknown";
+    char *clock = "unknown";
+    char *fpextra = val & DISPLAY_RATE_SELECT_FPA1 ? ", using FPx1!" : "";
+    char sdvoextra[3];
+    int p1, p2 = 0;
+
+    p1 = ffs((val & DPLL_FPA01_P1_POST_DIV_MASK) >>
+	     DPLL_FPA01_P1_POST_DIV_SHIFT);
+    switch (val & DPLL_MODE_MASK) {
+    case DPLLB_MODE_DAC_SERIAL:
+	mode = "dac/serial";
+	p2 = val & DPLL_DAC_SERIAL_P2_CLOCK_DIV_5 ? 5 : 10;
+	break;
+    case DPLLB_MODE_LVDS:
+	mode = "LVDS";
+	p2 = val & DPLLB_LVDS_P2_CLOCK_DIV_7 ? 7 : 14;
+	break;
+    }
+    switch (val & PLL_REF_INPUT_MASK) {
+    case PLL_REF_INPUT_DREFCLK:
+	clock = "default";
+	break;
+    case PLL_REF_INPUT_TVCLKINA:
+	clock = "TV A";
+	break;
+    case PLL_REF_INPUT_TVCLKINBC:
+	clock = "TV B/C";
+	break;
+    }
+    if (IS_I945G(pI830) || IS_I945GM(pI830)) {
+	sprintf(sdvoextra, "SDVO mult %d",
+		(int)(val & SDVO_MULTIPLIER_MASK) >>
+		SDVO_MULTIPLIER_SHIFT_HIRES);
+    } else {
+	sdvoextra[0] = '\0';
+    }
+
+    return XNFprintf("%s, %s%s, %s mode, %s clock, p1 = %d, "
+		     "p2 = %d%s%s",
+		     enabled, dvomode, vgamode, mode, clock, p1, p2,
+		     fpextra, sdvoextra);
+}
+
+DEBUGSTRING(i830_debug_lvds)
+{
+    char pipe = val & LVDS_PIPEB_SELECT ? 'B' : 'A';
+    char *enable = val & LVDS_PORT_EN ? "enabled" : "disabled";
+
+    return XNFprintf("%s, pipe %c", enable, pipe);
+}
+
 #define DEFINEREG(reg) \
-	{ reg, #reg, 0 }
+	{ reg, #reg, NULL, 0 }
+#define DEFINEREG2(reg, func) \
+	{ reg, #reg, func, 0 }
 
 static struct i830SnapshotRec {
     int reg;
     char *name;
-    CARD32 regval;
+    char *(*debug_output)(I830Ptr pI830, int reg, CARD32 val);
+    CARD32 val;
 } i830_snapshot[] = {
     DEFINEREG(VCLK_DIVISOR_VGA0),
     DEFINEREG(VCLK_DIVISOR_VGA1),
@@ -61,7 +205,7 @@ static struct i830SnapshotRec {
     DEFINEREG(DSPFW3),
 
     DEFINEREG(ADPA),
-    DEFINEREG(LVDS),
+    DEFINEREG2(LVDS, i830_debug_lvds),
     DEFINEREG(DVOA),
     DEFINEREG(DVOB),
     DEFINEREG(DVOC),
@@ -69,63 +213,63 @@ static struct i830SnapshotRec {
     DEFINEREG(DVOB_SRCDIM),
     DEFINEREG(DVOC_SRCDIM),
 
-    DEFINEREG(PP_CONTROL),
-    DEFINEREG(PP_STATUS),
+    DEFINEREG2(PP_CONTROL, i830_debug_pp_control),
+    DEFINEREG2(PP_STATUS, i830_debug_pp_status),
     DEFINEREG(PFIT_CONTROL),
     DEFINEREG(PFIT_PGM_RATIOS),
     DEFINEREG(PORT_HOTPLUG_EN),
     DEFINEREG(PORT_HOTPLUG_STAT),
 
-    DEFINEREG(DSPACNTR),
-    DEFINEREG(DSPASTRIDE),
-    DEFINEREG(DSPAPOS),
-    DEFINEREG(DSPASIZE),
+    DEFINEREG2(DSPACNTR, i830_debug_dspcntr),
+    DEFINEREG2(DSPASTRIDE, i830_debug_dspstride),
+    DEFINEREG2(DSPAPOS, i830_debug_xy),
+    DEFINEREG2(DSPASIZE, i830_debug_xyminus1),
     DEFINEREG(DSPABASE),
     DEFINEREG(DSPASURF),
     DEFINEREG(DSPATILEOFF),
-    DEFINEREG(PIPEACONF),
-    DEFINEREG(PIPEASRC),
+    DEFINEREG2(PIPEACONF, i830_debug_pipeconf),
+    DEFINEREG2(PIPEASRC, i830_debug_xyminus1),
 
-    DEFINEREG(FPA0),
-    DEFINEREG(FPA1),
-    DEFINEREG(DPLL_A),
+    DEFINEREG2(FPA0, i830_debug_fp),
+    DEFINEREG2(FPA1, i830_debug_fp),
+    DEFINEREG2(DPLL_A, i830_debug_dpll),
     DEFINEREG(DPLL_A_MD),
-    DEFINEREG(HTOTAL_A),
-    DEFINEREG(HBLANK_A),
-    DEFINEREG(HSYNC_A),
-    DEFINEREG(VTOTAL_A),
-    DEFINEREG(VBLANK_A),
-    DEFINEREG(VSYNC_A),
+    DEFINEREG2(HTOTAL_A, i830_debug_hvtotal),
+    DEFINEREG2(HBLANK_A, i830_debug_hvsyncblank),
+    DEFINEREG2(HSYNC_A, i830_debug_hvsyncblank),
+    DEFINEREG2(VTOTAL_A, i830_debug_hvtotal),
+    DEFINEREG2(VBLANK_A, i830_debug_hvsyncblank),
+    DEFINEREG2(VSYNC_A, i830_debug_hvsyncblank),
     DEFINEREG(BCLRPAT_A),
     DEFINEREG(VSYNCSHIFT_A),
 
-    DEFINEREG(DSPBCNTR),
-    DEFINEREG(DSPBSTRIDE),
-    DEFINEREG(DSPBPOS),
-    DEFINEREG(DSPBSIZE),
+    DEFINEREG2(DSPBCNTR, i830_debug_dspcntr),
+    DEFINEREG2(DSPBSTRIDE, i830_debug_dspstride),
+    DEFINEREG2(DSPBPOS, i830_debug_xy),
+    DEFINEREG2(DSPBSIZE, i830_debug_xyminus1),
     DEFINEREG(DSPBBASE),
     DEFINEREG(DSPBSURF),
     DEFINEREG(DSPBTILEOFF),
-    DEFINEREG(PIPEBCONF),
-    DEFINEREG(PIPEBSRC),
+    DEFINEREG2(PIPEBCONF, i830_debug_pipeconf),
+    DEFINEREG2(PIPEBSRC, i830_debug_xyminus1),
 
-    DEFINEREG(FPB0),
-    DEFINEREG(FPB1),
-    DEFINEREG(DPLL_B),
+    DEFINEREG2(FPB0, i830_debug_fp),
+    DEFINEREG2(FPB1, i830_debug_fp),
+    DEFINEREG2(DPLL_B, i830_debug_dpll),
     DEFINEREG(DPLL_B_MD),
-    DEFINEREG(HTOTAL_B),
-    DEFINEREG(HBLANK_B),
-    DEFINEREG(HSYNC_B),
-    DEFINEREG(VTOTAL_B),
-    DEFINEREG(VBLANK_B),
-    DEFINEREG(VSYNC_B),
+    DEFINEREG2(HTOTAL_B, i830_debug_hvtotal),
+    DEFINEREG2(HBLANK_B, i830_debug_hvsyncblank),
+    DEFINEREG2(HSYNC_B, i830_debug_hvsyncblank),
+    DEFINEREG2(VTOTAL_B, i830_debug_hvtotal),
+    DEFINEREG2(VBLANK_B, i830_debug_hvsyncblank),
+    DEFINEREG2(VSYNC_B, i830_debug_hvsyncblank),
     DEFINEREG(BCLRPAT_B),
     DEFINEREG(VSYNCSHIFT_B),
 
     DEFINEREG(VCLK_DIVISOR_VGA0),
     DEFINEREG(VCLK_DIVISOR_VGA1),
     DEFINEREG(VCLK_POST_DIV),
-    DEFINEREG(VGACNTRL),
+    DEFINEREG2(VGACNTRL, i830_debug_vgacntrl),
 
     DEFINEREG(TV_CTL),
     DEFINEREG(TV_DAC),
@@ -171,7 +315,7 @@ void i830TakeRegSnapshot(ScrnInfoPtr pSc
     int i;
 
     for (i = 0; i < NUM_I830_SNAPSHOTREGS; i++) {
-	i830_snapshot[i].regval = INREG(i830_snapshot[i].reg);
+	i830_snapshot[i].val = INREG(i830_snapshot[i].reg);
     }
 }
 
@@ -184,11 +328,28 @@ void i830CompareRegsToSnapshot(ScrnInfoP
 	       "Comparing regs before/after X's VT usage\n");
     for (i = 0; i < NUM_I830_SNAPSHOTREGS; i++) {
 	CARD32 val = INREG(i830_snapshot[i].reg);
-	if (i830_snapshot[i].regval != val) {
+	if (i830_snapshot[i].val == val)
+	    continue;
+
+	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+		   "Register 0x%x (%s) changed from 0x%08x to 0x%08x\n",
+		   i830_snapshot[i].reg, i830_snapshot[i].name,
+		   (int)i830_snapshot[i].val, (int)val);
+
+	if (i830_snapshot[i].debug_output != NULL) {
+	    char *before, *after;
+
+	    before = i830_snapshot[i].debug_output(pI830,
+						   i830_snapshot[i].reg,
+						   i830_snapshot[i].val);
+	    after = i830_snapshot[i].debug_output(pI830,
+						  i830_snapshot[i].reg,
+						  val);
+	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+		       "%s before: %s", i830_snapshot[i].name, before);
 	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
-		       "Register 0x%x (%s) changed from 0x%08x to 0x%08x\n",
-		       i830_snapshot[i].reg, i830_snapshot[i].name,
-		       (int)i830_snapshot[i].regval, (int)val);
+		       "%s after: %s", i830_snapshot[i].name, after);
+
 	}
     }
 }
@@ -220,8 +381,19 @@ void i830DumpRegs (ScrnInfoPtr pScrn)
 
     xf86DrvMsg (pScrn->scrnIndex, X_INFO, "DumpRegsBegin\n");
     for (i = 0; i < NUM_I830_SNAPSHOTREGS; i++) {
-	xf86DrvMsg (pScrn->scrnIndex, X_INFO, "%20.20s: 0x%08x\n",
-		    i830_snapshot[i].name, (unsigned int) INREG(i830_snapshot[i].reg));
+	CARD32 val = INREG(i830_snapshot[i].reg);
+
+	if (i830_snapshot[i].debug_output != NULL) {
+	    char *debug = i830_snapshot[i].debug_output(pI830,
+							i830_snapshot[i].reg,
+							val);
+	    xf86DrvMsg (pScrn->scrnIndex, X_INFO, "%20.20s: 0x%08x (%s)\n",
+			i830_snapshot[i].name, (unsigned int)val, debug);
+	    xfree(debug);
+	} else {
+	    xf86DrvMsg (pScrn->scrnIndex, X_INFO, "%20.20s: 0x%08x\n",
+			i830_snapshot[i].name, (unsigned int)val);
+	}
     }
     i830DumpIndexed (pScrn, "SR", 0x3c4, 0x3c5, 0, 7);
     msr = INREG8(0x3cc);
diff-tree 7844e576e71c004ed495bbc31f7bbe890d18b8d9 (from e777d38ce98d7220621b049b09df1deca5a5df42)
Author: Eric Anholt <eric at anholt.net>
Date:   Tue Dec 5 14:39:09 2006 -0800

    Move reg dump from i830PipeSetMode to after we set up the modes with RandR.

diff --git a/src/i830_display.c b/src/i830_display.c
index eab82f6..d7d7417 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -758,8 +758,6 @@ i830PipeSetMode(xf86CrtcPtr crtc, Displa
 
     crtc->curMode = *pMode;
 
-    i830DumpRegs(pScrn);
-
     /* XXX free adjustedmode */
     ret = TRUE;
 done:
diff --git a/src/i830_randr.c b/src/i830_randr.c
index 373403f..dd70bba 100644
--- a/src/i830_randr.c
+++ b/src/i830_randr.c
@@ -41,6 +41,7 @@
 
 #include "i830_xf86Crtc.h"
 #include "i830_randr.h"
+#include "i830_debug.h"
 #include "i830_display.h"
 #include "i830.h"
 
@@ -604,6 +605,8 @@ xf86RandR12CrtcSet (ScreenPtr	pScreen,
 	    i830PipeSetBase(crtc, x, y);
 	}
 	i830DisableUnusedFunctions (pScrn);
+
+	i830DumpRegs(pScrn);
     }
     return xf86RandR12CrtcNotify (randr_crtc);
 }
diff-tree e777d38ce98d7220621b049b09df1deca5a5df42 (from 81dde11d419c8f9198ab3502d9813d66d0bc6d6d)
Author: Eric Anholt <eric at anholt.net>
Date:   Tue Dec 5 10:01:31 2006 -0800

    WIP code to move mode set sequencing to XFree86 handlers.
    
    It compiles.  It definitely doesn't run.

diff --git a/src/i830_crt.c b/src/i830_crt.c
index 7a706d1..ebd83bc 100644
--- a/src/i830_crt.c
+++ b/src/i830_crt.c
@@ -93,13 +93,16 @@ i830_crt_mode_valid(xf86OutputPtr output
     return MODE_OK;
 }
 
-static void
-i830_crt_pre_set_mode (xf86OutputPtr output, DisplayModePtr pMode)
+static Bool
+i830_crt_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
+		    DisplayModePtr adjusted_mode)
 {
+    return TRUE;
 }
 
 static void
-i830_crt_post_set_mode (xf86OutputPtr output, DisplayModePtr pMode)
+i830_crt_mode_set(xf86OutputPtr output, DisplayModePtr mode,
+		  DisplayModePtr adjusted_mode)
 {
     ScrnInfoPtr		    pScrn = output->scrn;
     I830Ptr		    pI830 = I830PTR(pScrn);
@@ -122,11 +125,10 @@ i830_crt_post_set_mode (xf86OutputPtr ou
 	OUTREG(dpll_md_reg, dpll_md & ~DPLL_MD_UDI_MULTIPLIER_MASK);
     }
 
-    adpa = ADPA_DAC_ENABLE;
-
-    if (pMode->Flags & V_PHSYNC)
+    adpa = 0;
+    if (adjusted_mode->Flags & V_PHSYNC)
 	adpa |= ADPA_HSYNC_ACTIVE_HIGH;
-    if (pMode->Flags & V_PVSYNC)
+    if (adjusted_mode->Flags & V_PVSYNC)
 	adpa |= ADPA_VSYNC_ACTIVE_HIGH;
 
     if (i830_crtc->pipe == 0)
@@ -372,8 +374,8 @@ static const xf86OutputFuncsRec i830_crt
     .save = i830_crt_save,
     .restore = i830_crt_restore,
     .mode_valid = i830_crt_mode_valid,
-    .pre_set_mode = i830_crt_pre_set_mode,
-    .post_set_mode = i830_crt_post_set_mode,
+    .mode_fixup = i830_crt_mode_fixup,
+    .mode_set = i830_crt_mode_set,
     .detect = i830_crt_detect,
     .get_modes = i830_crt_get_modes,
     .destroy = i830_crt_destroy
diff --git a/src/i830_display.c b/src/i830_display.c
index 29b783b..eab82f6 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -408,34 +408,94 @@ i830PipeInUse (xf86CrtcPtr crtc)
     return FALSE;
 }
 
+static void
+i830_crtc_dpms(xf86CrtcPtr crtc, int mode)
+{
+    ScrnInfoPtr pScrn = crtc->scrn;
+    I830Ptr pI830 = I830PTR(pScrn);
+    I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
+    int pipe = intel_crtc->pipe;
+    int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
+    int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
+    int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
+    CARD32 temp;
+
+    /* XXX: When our outputs are all unaware of DPMS modes other than off and
+     * on, we should map those modes to DPMSModeOff in the CRTC.
+     */
+    switch (mode) {
+    case DPMSModeOn:
+    case DPMSModeStandby:
+    case DPMSModeSuspend:
+	/* Enable the DPLL */
+	temp = INREG(dpll_reg);
+	OUTREG(dpll_reg, temp | DPLL_VCO_ENABLE);
+
+	/* Wait for the clocks to stabilize. */
+	usleep(150);
+
+	/* Enable the pipe */
+	temp = INREG(pipeconf_reg);
+	OUTREG(pipeconf_reg, temp | PIPEACONF_ENABLE);
+
+	/* Enable the plane */
+	temp = INREG(dspcntr_reg);
+	OUTREG(dspcntr_reg, temp | DISPLAY_PLANE_ENABLE);
+	break;
+    case DPMSModeOff:
+	/* Disable display plane */
+	temp = INREG(dspcntr_reg);
+	OUTREG(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
+
+	/* Disable the VGA plane that we never use */
+	OUTREG(VGACNTRL, VGA_DISP_DISABLE);
+
+	if (!IS_I9XX(pI830)) {
+	    /* Wait for vblank for the disable to take effect */
+	    i830WaitForVblank(pScrn);
+	}
+
+	/* Next, disable display pipes */
+	temp = INREG(pipeconf_reg);
+	OUTREG(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
+
+	/* Wait for vblank for the disable to take effect. */
+	i830WaitForVblank(pScrn);
+
+	temp = INREG(dpll_reg);
+	OUTREG(dpll_reg, temp & ~DPLL_VCO_ENABLE);
+	break;
+    }
+}
+
+static Bool
+i830_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode,
+		     DisplayModePtr adjusted_mode)
+{
+    return TRUE;
+}
+
 /**
- * Sets the given video mode on the given pipe.
+ * Sets up registers for the given mode/adjusted_mode pair.
  *
- * Plane A is always output to pipe A, and plane B to pipe B.  The plane
- * will not be enabled if plane_enable is FALSE, which is used for
- * load detection, when something else will be output to the pipe other than
- * display data.
+ * The clocks, CRTCs and outputs attached to this CRTC must be off.
+ *
+ * This shouldn't enable any clocks, CRTCs, or outputs, but they should
+ * be easily turned on/off after this.
  */
-Bool
-i830PipeSetMode(xf86CrtcPtr crtc, DisplayModePtr pMode,
-		Bool plane_enable)
+static void
+i830_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode,
+		   DisplayModePtr adjusted_mode)
 {
     ScrnInfoPtr pScrn = crtc->scrn;
     I830Ptr pI830 = I830PTR(pScrn);
     I830CrtcPrivatePtr intel_crtc = crtc->driver_private;
     int pipe = intel_crtc->pipe;
-    int m1 = 0, m2 = 0, n = 0, p1 = 0, p2 = 0;
-    CARD32 dpll = 0, fp = 0, temp;
-    CARD32 htot, hblank, hsync, vtot, vblank, vsync, dspcntr;
-    CARD32 pipesrc, dspsize;
-    Bool ok, is_sdvo = FALSE, is_dvo = FALSE;
-    Bool is_crt = FALSE, is_lvds = FALSE, is_tv = FALSE;
-    int refclk, pixel_clock;
-    int i;
-    int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
-    int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
     int fp_reg = (pipe == 0) ? FPA0 : FPB0;
     int dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
+    int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD;
+    int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
+    int pipeconf_reg = (pipe == 0) ? PIPEACONF : PIPEBCONF;
     int htot_reg = (pipe == 0) ? HTOTAL_A : HTOTAL_B;
     int hblank_reg = (pipe == 0) ? HBLANK_A : HBLANK_B;
     int hsync_reg = (pipe == 0) ? HSYNC_A : HSYNC_B;
@@ -446,38 +506,23 @@ i830PipeSetMode(xf86CrtcPtr crtc, Displa
     int dspstride_reg = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
     int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
     int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
-    Bool ret = FALSE;
-#ifdef XF86DRI
-    Bool didLock = FALSE;
-#endif
-
-    if (xf86ModesEqual(&crtc->curMode, pMode))
-	return TRUE;
-
-    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Requested pix clock: %d\n",
-	       pMode->Clock);
-
-    crtc->enabled = i830PipeInUse (crtc);
-    
-    if (!crtc->enabled)
-    {
-	/* XXX disable crtc? */
-	return TRUE;
-    }
+    int m1 = 0, m2 = 0, n = 0, p1 = 0, p2 = 0;
+    int i;
+    int refclk;
+    CARD32 dpll = 0, fp = 0, temp, dspcntr;
+    Bool ok, is_sdvo = FALSE, is_dvo = FALSE;
+    Bool is_crt = FALSE, is_lvds = FALSE, is_tv = FALSE;
 
-#ifdef XF86DRI
-    didLock = I830DRILock(pScrn);
-#endif
-    
-    for (i = 0; i < pI830->xf86_config.num_output; i++) 
-    {
+    /* Set up some convenient bools for what outputs are connected to
+     * our pipe, used in DPLL setup.
+     */
+    for (i = 0; i < pI830->xf86_config.num_output; i++) {
 	xf86OutputPtr  output = pI830->xf86_config.output[i];
-	I830OutputPrivatePtr	intel_output = output->driver_private;
+	I830OutputPrivatePtr intel_output = output->driver_private;
+
 	if (output->crtc != crtc)
 	    continue;
 
-	(*output->funcs->pre_set_mode)(output, pMode);
-	
 	switch (intel_output->type) {
 	case I830_OUTPUT_LVDS:
 	    is_lvds = TRUE;
@@ -497,90 +542,23 @@ i830PipeSetMode(xf86CrtcPtr crtc, Displa
 	}
     }
 
-    if (is_lvds && (is_sdvo || is_dvo || is_tv || is_crt)) {
-	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-		   "Can't enable LVDS and non-LVDS on the same pipe\n");
-	goto done;
-    }
-    if (is_tv && (is_sdvo || is_dvo || is_crt || is_lvds)) {
-	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-		   "Can't enable a TV and any other output on the same "
-		   "pipe\n");
-	goto done;
-    }
-    if (pipe == 0 && is_lvds) {
-	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-		   "Can't support LVDS on pipe A\n");
-	goto done;
-    }
-
-    htot = (pMode->CrtcHDisplay - 1) | ((pMode->CrtcHTotal - 1) << 16);
-    hblank = (pMode->CrtcHBlankStart - 1) | ((pMode->CrtcHBlankEnd - 1) << 16);
-    hsync = (pMode->CrtcHSyncStart - 1) | ((pMode->CrtcHSyncEnd - 1) << 16);
-    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);
-    pixel_clock = pMode->Clock;
-
-    if (is_lvds && pI830->panel_fixed_hactive != 0) {
-	/* To enable panel fitting, we need to set the pipe timings to that of
-	 * the screen at its full resolution.  So, drop the timings from the
-	 * BIOS VBT tables here.
-	 */
-	htot = (pI830->panel_fixed_hactive - 1) |
-		((pI830->panel_fixed_hactive + pI830->panel_fixed_hblank - 1)
-		 << 16);
-	hblank = (pI830->panel_fixed_hactive - 1) |
-		((pI830->panel_fixed_hactive + pI830->panel_fixed_hblank - 1)
-		 << 16);
-	hsync = (pI830->panel_fixed_hactive + pI830->panel_fixed_hsyncoff - 1) |
-		((pI830->panel_fixed_hactive + pI830->panel_fixed_hsyncoff +
-		  pI830->panel_fixed_hsyncwidth - 1) << 16);
-
-	vtot = (pI830->panel_fixed_vactive - 1) |
-		((pI830->panel_fixed_vactive + pI830->panel_fixed_vblank - 1)
-		 << 16);
-	vblank = (pI830->panel_fixed_vactive - 1) |
-		((pI830->panel_fixed_vactive + pI830->panel_fixed_vblank - 1)
-		 << 16);
-	vsync = (pI830->panel_fixed_vactive + pI830->panel_fixed_vsyncoff - 1) |
-		((pI830->panel_fixed_vactive + pI830->panel_fixed_vsyncoff +
-		  pI830->panel_fixed_vsyncwidth - 1) << 16);
-	pixel_clock = pI830->panel_fixed_clock;
-
-	if (pMode->HDisplay <= pI830->panel_fixed_hactive &&
-	    pMode->HDisplay <= pI830->panel_fixed_vactive)
-	{
-	    pipesrc = ((pMode->HDisplay - 1) << 16) |
-		       (pMode->VDisplay - 1);
-	    dspsize = ((pMode->VDisplay - 1) << 16) |
-		       (pMode->HDisplay - 1);
-	}
-    }
-
-    /* Adjust the clock for pixel multiplication.
-     * See DPLL_MD_UDI_MULTIPLIER_MASK.
-     */
-    if (is_sdvo) {
-	pixel_clock *= i830_sdvo_get_pixel_multiplier(pMode);
-    }
-
     if (IS_I9XX(pI830)) {
 	refclk = 96000;
     } else {
 	refclk = 48000;
     }
-    ok = i830FindBestPLL(crtc, pixel_clock, refclk, &m1, &m2, &n,
+
+    ok = i830FindBestPLL(crtc, adjusted_mode->Clock, refclk, &m1, &m2, &n,
 			 &p1, &p2);
-    if (!ok) {
-	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
-		   "Couldn't find PLL settings for mode!\n");
-	goto done;
-    }
+    if (!ok)
+	FatalError("Couldn't find PLL settings for mode!\n");
+
+    fp = ((n - 2) << 16) | ((m1 - 2) << 8) | (m2 - 2);
+
+    i830PrintPll("chosen", refclk, m1, m2, n, p1, p2);
+    ErrorF("clock regs: 0x%08x, 0x%08x\n", (int)dpll, (int)fp);
 
-    dpll = DPLL_VCO_ENABLE | DPLL_VGA_MODE_DIS;
+    dpll = DPLL_VGA_MODE_DIS;
     if (IS_I9XX(pI830)) {
 	if (is_lvds)
 	    dpll |= DPLLB_MODE_LVDS;
@@ -615,33 +593,15 @@ i830PipeSetMode(xf86CrtcPtr crtc, Displa
 /*	dpll |= PLL_REF_INPUT_TVCLKINBC; */
 	dpll |= 3;
     }
-#if 0    
+#if 0
     else if (is_lvds)
 	dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
 #endif
-    else	
+    else
 	dpll |= PLL_REF_INPUT_DREFCLK;
 
-    fp = ((n - 2) << 16) | ((m1 - 2) << 8) | (m2 - 2);
-
-#if 1
-    ErrorF("hact: %d htot: %d hbstart: %d hbend: %d hsyncstart: %d hsyncend: %d\n",
-	(int)(htot & 0xffff) + 1, (int)(htot >> 16) + 1,
-	(int)(hblank & 0xffff) + 1, (int)(hblank >> 16) + 1,
-	(int)(hsync & 0xffff) + 1, (int)(hsync >> 16) + 1);
-    ErrorF("vact: %d vtot: %d vbstart: %d vbend: %d vsyncstart: %d vsyncend: %d\n",
-	(int)(vtot & 0xffff) + 1, (int)(vtot >> 16) + 1,
-	(int)(vblank & 0xffff) + 1, (int)(vblank >> 16) + 1,
-	(int)(vsync & 0xffff) + 1, (int)(vsync >> 16) + 1);
-    ErrorF("pipesrc: %dx%d, dspsize: %dx%d\n",
-	(int)(pipesrc >> 16) + 1, (int)(pipesrc & 0xffff) + 1,
-	(int)(dspsize & 0xffff) + 1, (int)(dspsize >> 16) + 1);
-#endif
-
-    i830PrintPll("chosen", refclk, m1, m2, n, p1, p2);
-    ErrorF("clock regs: 0x%08x, 0x%08x\n", (int)dpll, (int)fp);
-
-    dspcntr = DISPLAY_PLANE_ENABLE;
+    /* Set up the display plane register */
+    dspcntr = 0;
     switch (pScrn->bitsPerPixel) {
     case 8:
 	dspcntr |= DISPPLANE_8BPP | DISPPLANE_GAMMA_ENABLE;
@@ -668,61 +628,139 @@ i830PipeSetMode(xf86CrtcPtr crtc, Displa
     else
 	dspcntr |= DISPPLANE_SEL_PIPE_B;
 
-    OUTREG(VGACNTRL, VGA_DISP_DISABLE);
+    OUTREG(fp_reg, fp);
+    OUTREG(dpll_reg, dpll);
+    if (IS_I965G(pI830)) {
+	/* Set the SDVO multiplier/divider to 1x for the sake of analog output.
+	 * It will be updated by the SDVO code if SDVO had fixed up the clock
+	 * for a higher multiplier.
+	 */
+	OUTREG(dpll_md_reg, 0);
+    }
 
-    /* Finally, set the mode. */
-    /* First, disable display planes */
-    temp = INREG(dspcntr_reg);
-    OUTREG(dspcntr_reg, temp & ~DISPLAY_PLANE_ENABLE);
+    OUTREG(htot_reg, (adjusted_mode->CrtcHDisplay - 1) |
+	((adjusted_mode->CrtcHTotal - 1) << 16));
+    OUTREG(hblank_reg, (adjusted_mode->CrtcHBlankStart - 1) |
+	((adjusted_mode->CrtcHBlankEnd - 1) << 16));
+    OUTREG(hsync_reg, (adjusted_mode->CrtcHSyncStart - 1) |
+	((adjusted_mode->CrtcHSyncEnd - 1) << 16));
+    OUTREG(vtot_reg, (adjusted_mode->CrtcVDisplay - 1) |
+	((adjusted_mode->CrtcVTotal - 1) << 16));
+    OUTREG(vblank_reg, (adjusted_mode->CrtcVBlankStart - 1) |
+	((adjusted_mode->CrtcVBlankEnd - 1) << 16));
+    OUTREG(vsync_reg, (adjusted_mode->CrtcVSyncStart - 1) |
+	((adjusted_mode->CrtcVSyncEnd - 1) << 16));
+    OUTREG(dspstride_reg, pScrn->displayWidth * pI830->cpp);
+    /* pipesrc and dspsize control the size that is scaled from, which should
+     * always be the user's requested size.
+     */
+    OUTREG(dspsize_reg, ((mode->HDisplay - 1) << 16) | (mode->VDisplay - 1));
+    OUTREG(dsppos_reg, 0);
+    i830PipeSetBase(crtc, crtc->x, crtc->y);
+    OUTREG(pipesrc_reg, ((mode->HDisplay - 1) << 16) | (mode->VDisplay - 1));
+    temp = INREG(pipeconf_reg);
+    OUTREG(pipeconf_reg, temp);
+    OUTREG(dspcntr_reg, dspcntr);
 
-    /* Wait for vblank for the disable to take effect */
-    i830WaitForVblank(pScrn);
+    /* Disable the panel fitter if it was on our pipe */
+    if (!IS_I830(pI830) && ((INREG(PFIT_CONTROL) >> 29) & 0x3) == pipe)
+	OUTREG(PFIT_CONTROL, 0);
+}
 
-    /* Next, disable display pipes */
-    temp = INREG(pipeconf_reg);
-    OUTREG(pipeconf_reg, temp & ~PIPEACONF_ENABLE);
+/**
+ * Sets the given video mode on the given pipe.
+ *
+ * Plane A is always output to pipe A, and plane B to pipe B.  The plane
+ * will not be enabled if plane_enable is FALSE, which is used for
+ * load detection, when something else will be output to the pipe other than
+ * display data.
+ */
+Bool
+i830PipeSetMode(xf86CrtcPtr crtc, DisplayModePtr pMode,
+		Bool plane_enable)
+{
+    ScrnInfoPtr pScrn = crtc->scrn;
+    I830Ptr pI830 = I830PTR(pScrn);
+    int i;
+    Bool ret = FALSE;
+#ifdef XF86DRI
+    Bool didLock = FALSE;
+#endif
+    DisplayModePtr adjusted_mode;
 
-    OUTREG(fp_reg, fp);
-    OUTREG(dpll_reg, dpll);
+    /* XXX: curMode */
+
+    adjusted_mode = xf86DuplicateMode(pMode);
 
-    /*
-     * If the panel fitter is stuck on our pipe, turn it off.
-     * The LVDS output will set it as necessary in post_set_mode.
+    crtc->enabled = i830PipeInUse (crtc);
+    
+    if (!crtc->enabled)
+    {
+	/* XXX disable crtc? */
+	return TRUE;
+    }
+
+#ifdef XF86DRI
+    didLock = I830DRILock(pScrn);
+#endif
+
+    /* Pass our mode to the outputs and the CRTC to give them a chance to
+     * adjust it according to limitations or output properties, and also
+     * a chance to reject the mode entirely.
      */
-    if (!IS_I830(pI830)) {
-	if (((INREG(PFIT_CONTROL) >> 29) & 0x3) == pipe)
-	    OUTREG(PFIT_CONTROL, 0);
+    for (i = 0; i < pI830->xf86_config.num_output; i++) {
+	xf86OutputPtr output = pI830->xf86_config.output[i];
+
+	if (output->crtc != crtc)
+	    continue;
+
+	if (!output->funcs->mode_fixup(output, pMode, adjusted_mode)) {
+	    ret = FALSE;
+	    goto done;
+	}
     }
 
+    if (!crtc->funcs->mode_fixup(crtc, pMode, adjusted_mode)) {
+	ret = FALSE;
+	goto done;
+    }
+
+    /* Disable the outputs and CRTCs before setting the mode. */
     for (i = 0; i < pI830->xf86_config.num_output; i++) {
-	xf86OutputPtr  output = pI830->xf86_config.output[i];
-	if (output->crtc == crtc)
-	    (*output->funcs->post_set_mode)(output, pMode);
+	xf86OutputPtr output = pI830->xf86_config.output[i];
+
+	if (output->crtc != crtc)
+	    continue;
+
+	/* Disable the output as the first thing we do. */
+	output->funcs->dpms(output, DPMSModeOff);
     }
 
-    OUTREG(htot_reg, htot);
-    OUTREG(hblank_reg, hblank);
-    OUTREG(hsync_reg, hsync);
-    OUTREG(vtot_reg, vtot);
-    OUTREG(vblank_reg, vblank);
-    OUTREG(vsync_reg, vsync);
-    OUTREG(dspstride_reg, pScrn->displayWidth * pI830->cpp);
-    OUTREG(dspsize_reg, dspsize);
-    OUTREG(dsppos_reg, 0);
-    i830PipeSetBase(crtc, crtc->x, crtc->y);
-    OUTREG(pipesrc_reg, pipesrc);
+    crtc->funcs->dpms(crtc, DPMSModeOff);
 
-    /* Then, turn the pipe on first */
-    temp = INREG(pipeconf_reg);
-    OUTREG(pipeconf_reg, temp | PIPEACONF_ENABLE);
+    /* Set up the DPLL and any output state that needs to adjust or depend
+     * on the DPLL.
+     */
+    crtc->funcs->mode_set(crtc, pMode, adjusted_mode);
+    for (i = 0; i < pI830->xf86_config.num_output; i++) {
+	xf86OutputPtr output = pI830->xf86_config.output[i];
+	if (output->crtc == crtc)
+	    output->funcs->mode_set(output, pMode, adjusted_mode);
+    }
 
-    if (plane_enable) {
-	/* And then turn the plane on */
-	OUTREG(dspcntr_reg, dspcntr);
+    /* Now, enable the clocks, plane, pipe, and outputs that we set up. */
+    crtc->funcs->dpms(crtc, DPMSModeOn);
+    for (i = 0; i < pI830->xf86_config.num_output; i++) {
+	xf86OutputPtr output = pI830->xf86_config.output[i];
+	if (output->crtc == crtc)
+	    output->funcs->dpms(output, DPMSModeOn);
     }
 
     crtc->curMode = *pMode;
 
+    i830DumpRegs(pScrn);
+
+    /* XXX free adjustedmode */
     ret = TRUE;
 done:
 #ifdef XF86DRI
@@ -962,3 +1000,29 @@ i830ReleaseLoadDetectPipe(xf86OutputPtr 
 	i830DisableUnusedFunctions(pScrn);
     }
 }
+
+static const xf86CrtcFuncsRec i830_crtc_funcs = {
+    .dpms = i830_crtc_dpms,
+    .save = NULL, /* XXX */
+    .restore = NULL, /* XXX */
+    .mode_fixup = i830_crtc_mode_fixup,
+    .mode_set = i830_crtc_mode_set,
+    .destroy = NULL, /* XXX */
+};
+
+void
+i830_crtc_init(ScrnInfoPtr pScrn, int pipe)
+{
+    xf86CrtcPtr crtc;
+    I830CrtcPrivatePtr intel_crtc;
+
+    crtc = xf86CrtcCreate (pScrn, &i830_crtc_funcs);
+    if (crtc == NULL)
+	return;
+
+    intel_crtc = xnfcalloc (sizeof (I830CrtcPrivateRec), 1);
+    intel_crtc->pipe = pipe;
+
+    crtc->driver_private = intel_crtc;
+}
+
diff --git a/src/i830_display.h b/src/i830_display.h
index c80c3f7..c1725ab 100644
--- a/src/i830_display.h
+++ b/src/i830_display.h
@@ -41,6 +41,7 @@ void i830DescribeOutputConfiguration(Scr
 xf86CrtcPtr i830GetLoadDetectPipe(xf86OutputPtr output);
 void i830ReleaseLoadDetectPipe(xf86OutputPtr output);
 Bool i830PipeInUse(xf86CrtcPtr crtc);
+void i830_crtc_init(ScrnInfoPtr pScrn, int pipe);
 
 /** @{
  */
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 3aafe3a..8f017ab 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -715,28 +715,7 @@ I830SetupOutputs(ScrnInfoPtr pScrn)
  * Setup the CRTCs
  */
 
-static const xf86CrtcFuncsRec i830_crtc_funcs = {
-};
 
-static void
-I830SetupCrtcs(ScrnInfoPtr pScrn, int num_pipe)
-{
-    int	    p;
-
-    for (p = 0; p < num_pipe; p++)
-    {
-	xf86CrtcPtr    crtc = xf86CrtcCreate (pScrn, &i830_crtc_funcs);
-	I830CrtcPrivatePtr  intel_crtc;
-	
-	if (!crtc)
-	    break;
-	intel_crtc = xnfcalloc (sizeof (I830CrtcPrivateRec), 1);
-	intel_crtc->pipe = p;
-	
-	crtc->driver_private = intel_crtc;
-    }
-}
-    
 static void 
 I830PreInitDDC(ScrnInfoPtr pScrn)
 {
@@ -1340,7 +1319,9 @@ I830PreInit(ScrnInfoPtr pScrn, int flags
 
    I830PreInitDDC(pScrn);
    I830SetupOutputs(pScrn);
-   I830SetupCrtcs(pScrn, num_pipe);
+   for (i = 0; i < num_pipe; i++) {
+       i830_crtc_init(pScrn, i);
+   }
 
    if (xf86ReturnOptValBool(pI830->Options, OPTION_CLONE, FALSE)) {
       if (num_pipe == 1) {
@@ -2286,7 +2267,13 @@ RestoreHWState(ScrnInfoPtr pScrn)
    vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS);
    vgaHWLock(hwp);
 
-   /* First, disable display planes */
+   /* Disable outputs */
+   for (i = 0; i < pI830->xf86_config.num_output; i++) {
+      xf86OutputPtr   output = pI830->xf86_config.output[i];
+      output->funcs->dpms(output, DPMSModeOff);
+   }
+
+   /* Disable display planes */
    temp = INREG(DSPACNTR);
    OUTREG(DSPACNTR, temp & ~DISPLAY_PLANE_ENABLE);
    temp = INREG(DSPBCNTR);
@@ -2298,12 +2285,6 @@ RestoreHWState(ScrnInfoPtr pScrn)
    temp = INREG(PIPEBCONF);
    OUTREG(PIPEBCONF, temp & ~PIPEBCONF_ENABLE);
 
-   /* Disable outputs if necessary */
-   for (i = 0; i < pI830->xf86_config.num_output; i++) {
-      xf86OutputPtr   output = pI830->xf86_config.output[i];
-      (*output->funcs->pre_set_mode) (output, NULL);
-   }
-
    i830WaitForVblank(pScrn);
 
    OUTREG(FPA0, pI830->saveFPA0);
@@ -2311,6 +2292,16 @@ RestoreHWState(ScrnInfoPtr pScrn)
    OUTREG(DPLL_A, pI830->saveDPLL_A);
    if (IS_I965G(pI830))
       OUTREG(DPLL_A_MD, pI830->saveDPLL_A_MD);
+   if(pI830->xf86_config.num_crtc == 2) {
+      OUTREG(FPB0, pI830->saveFPB0);
+      OUTREG(FPB1, pI830->saveFPB1);
+      OUTREG(DPLL_B, pI830->saveDPLL_B);
+      if (IS_I965G(pI830))
+	 OUTREG(DPLL_B_MD, pI830->saveDPLL_B_MD);
+   }
+   /* Wait for clocks to stabilize */
+   usleep(150);
+
    OUTREG(HTOTAL_A, pI830->saveHTOTAL_A);
    OUTREG(HBLANK_A, pI830->saveHBLANK_A);
    OUTREG(HSYNC_A, pI830->saveHSYNC_A);
@@ -2327,11 +2318,6 @@ RestoreHWState(ScrnInfoPtr pScrn)
    }
 
    if(pI830->xf86_config.num_crtc == 2) {
-      OUTREG(FPB0, pI830->saveFPB0);
-      OUTREG(FPB1, pI830->saveFPB1);
-      OUTREG(DPLL_B, pI830->saveDPLL_B);
-      if (IS_I965G(pI830))
-	 OUTREG(DPLL_B_MD, pI830->saveDPLL_B_MD);
       OUTREG(HTOTAL_B, pI830->saveHTOTAL_B);
       OUTREG(HBLANK_B, pI830->saveHBLANK_B);
       OUTREG(HSYNC_B, pI830->saveHSYNC_B);
@@ -2348,12 +2334,8 @@ RestoreHWState(ScrnInfoPtr pScrn)
       }
    }
 
-   OUTREG(PFIT_CONTROL, pI830->savePFIT_CONTROL);
-
-   for (i = 0; i < pI830->xf86_config.num_output; i++) {
-      xf86OutputPtr   output = pI830->xf86_config.output[i];
-      (*output->funcs->restore) (output);
-   }
+   if (!IS_I830(pI830) && !IS_845G(pI830))
+     OUTREG(PFIT_CONTROL, pI830->savePFIT_CONTROL);
 
    if (IS_I965G(pI830)) {
       OUTREG(DSPASURF, pI830->saveDSPASURF);
@@ -2371,6 +2353,11 @@ RestoreHWState(ScrnInfoPtr pScrn)
    OUTREG(DSPACNTR, pI830->saveDSPACNTR);
    OUTREG(DSPBCNTR, pI830->saveDSPBCNTR);
 
+   for (i = 0; i < pI830->xf86_config.num_output; i++) {
+      xf86OutputPtr   output = pI830->xf86_config.output[i];
+      (*output->funcs->restore) (output);
+   }
+
    for(i = 0; i < 7; i++) {
 	   OUTREG(SWF0 + (i << 2), pI830->saveSWF[i]);
 	   OUTREG(SWF00 + (i << 2), pI830->saveSWF[i+7]);
diff --git a/src/i830_dvo.c b/src/i830_dvo.c
index 6fe3157..04d2038 100644
--- a/src/i830_dvo.c
+++ b/src/i830_dvo.c
@@ -59,11 +59,17 @@ struct _I830DVODriver i830_dvo_drivers[]
 static void
 i830_dvo_dpms(xf86OutputPtr output, int mode)
 {
+    ScrnInfoPtr		    pScrn = output->scrn;
+    I830Ptr		    pI830 = I830PTR(pScrn);
     I830OutputPrivatePtr    intel_output = output->driver_private;
-    if (mode == DPMSModeOn)
+
+    if (mode == DPMSModeOn) {
+	OUTREG(DVOC, INREG(DVOC) | DVO_ENABLE);
 	(*intel_output->i2c_drv->vid_rec->Power)(intel_output->i2c_drv->dev_priv, TRUE);
-    else
+    } else {
 	(*intel_output->i2c_drv->vid_rec->Power)(intel_output->i2c_drv->dev_priv, FALSE);
+	OUTREG(DVOC, INREG(DVOC) & ~DVO_ENABLE);
+    }
 }
 
 static void
@@ -113,48 +119,51 @@ i830_dvo_mode_valid(xf86OutputPtr output
 	return MODE_BAD;
 }
 
-static void
-i830_dvo_pre_set_mode(xf86OutputPtr output, DisplayModePtr pMode)
+static Bool
+i830_dvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
+		    DisplayModePtr adjusted_mode)
 {
-    ScrnInfoPtr		    pScrn = output->scrn;
-    I830Ptr		    pI830 = I830PTR(pScrn);
-    I830OutputPrivatePtr    intel_output = output->driver_private;
+    /* XXX: Hook this up to a DVO driver function */
 
-    (*intel_output->i2c_drv->vid_rec->Mode)(intel_output->i2c_drv->dev_priv, pMode);
-
-    OUTREG(DVOC, INREG(DVOC) & ~DVO_ENABLE);
+    return TRUE;
 }
 
 static void
-i830_dvo_post_set_mode(xf86OutputPtr output, DisplayModePtr pMode)
+i830_dvo_mode_set(xf86OutputPtr output, DisplayModePtr mode,
+		  DisplayModePtr adjusted_mode)
 {
     ScrnInfoPtr		    pScrn = output->scrn;
     I830Ptr		    pI830 = I830PTR(pScrn);
     xf86CrtcPtr	    crtc = output->crtc;
     I830CrtcPrivatePtr	    intel_crtc = crtc->driver_private;
+    I830OutputPrivatePtr    intel_output = output->driver_private;
     int			    pipe = intel_crtc->pipe;
     CARD32		    dvo;
     int			    dpll_reg = (pipe == 0) ? DPLL_A : DPLL_B;
 
+    intel_output->i2c_drv->vid_rec->Mode(intel_output->i2c_drv->dev_priv,
+					 mode);
+
     /* Save the data order, since I don't know what it should be set to. */
     dvo = INREG(DVOC) & (DVO_PRESERVE_MASK | DVO_DATA_ORDER_GBRG);
-    dvo |= DVO_ENABLE;
     dvo |= DVO_DATA_ORDER_FP | DVO_BORDER_ENABLE | DVO_BLANK_ACTIVE_HIGH;
 
     if (pipe == 1)
 	dvo |= DVO_PIPE_B_SELECT;
 
-    if (pMode->Flags & V_PHSYNC)
+    if (adjusted_mode->Flags & V_PHSYNC)
 	dvo |= DVO_HSYNC_ACTIVE_HIGH;
-    if (pMode->Flags & V_PVSYNC)
+    if (adjusted_mode->Flags & V_PVSYNC)
 	dvo |= DVO_VSYNC_ACTIVE_HIGH;
 
     OUTREG(dpll_reg, INREG(dpll_reg) | DPLL_DVO_HIGH_SPEED);
 
-    /*OUTREG(DVOB_SRCDIM, (pMode->HDisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
-      (pMode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/
-    OUTREG(DVOC_SRCDIM, (pMode->HDisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
-	   (pMode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));
+    /*OUTREG(DVOB_SRCDIM,
+      (adjusted_mode->HDisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
+      (adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));*/
+    OUTREG(DVOC_SRCDIM,
+	   (adjusted_mode->HDisplay << DVO_SRCDIM_HORIZONTAL_SHIFT) |
+	   (adjusted_mode->VDisplay << DVO_SRCDIM_VERTICAL_SHIFT));
     /*OUTREG(DVOB, dvo);*/
     OUTREG(DVOC, dvo);
 }
@@ -222,8 +231,8 @@ static const xf86OutputFuncsRec i830_dvo
     .save = i830_dvo_save,
     .restore = i830_dvo_restore,
     .mode_valid = i830_dvo_mode_valid,
-    .pre_set_mode = i830_dvo_pre_set_mode,
-    .post_set_mode = i830_dvo_post_set_mode,
+    .mode_fixup = i830_dvo_mode_fixup,
+    .mode_set = i830_dvo_mode_set,
     .detect = i830_dvo_detect,
     .get_modes = i830_ddc_get_modes,
     .destroy = i830_dvo_destroy
diff --git a/src/i830_lvds.c b/src/i830_lvds.c
index cf70956..a9c0e20 100644
--- a/src/i830_lvds.c
+++ b/src/i830_lvds.c
@@ -40,7 +40,7 @@ static void
 i830SetLVDSPanelPower(ScrnInfoPtr pScrn, Bool on)
 {
     I830Ptr pI830 = I830PTR(pScrn);
-    CARD32 pp_status, pp_control;
+    CARD32 pp_status;
     CARD32 blc_pwm_ctl;
     int backlight_duty_cycle;
 
@@ -77,6 +77,8 @@ i830_lvds_dpms (xf86OutputPtr output, in
 	i830SetLVDSPanelPower(pScrn, TRUE);
     else
 	i830SetLVDSPanelPower(pScrn, FALSE);
+
+    /* XXX: We never power down the LVDS pair. */
 }
 
 static void
@@ -128,28 +130,86 @@ i830_lvds_mode_valid(xf86OutputPtr outpu
    return MODE_OK;
 }
 
-static void
-i830_lvds_pre_set_mode(xf86OutputPtr output, DisplayModePtr pMode)
+static Bool
+i830_lvds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
+		     DisplayModePtr adjusted_mode)
 {
-    ScrnInfoPtr	pScrn = output->scrn;
-    /* Always make sure the LVDS is off before we play with DPLLs and pipe
-     * configuration.  We can skip this in some cases (for example, going
-     * between hi-res modes with automatic panel scaling are fine), but be
-     * conservative for now.
+    ScrnInfoPtr pScrn = output->scrn;
+    I830Ptr pI830 = I830PTR(pScrn);
+    I830CrtcPrivatePtr intel_crtc = output->crtc->driver_private;
+    int i;
+
+    for (i = 0; i < pI830->xf86_config.num_output; i++) {
+	xf86OutputPtr other_output = pI830->xf86_config.output[i];
+
+	if (other_output != output && other_output->crtc == output->crtc) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		       "Can't enable LVDS and another output on the same "
+		       "pipe\n");
+	    return FALSE;
+	}
+    }
+
+    if (intel_crtc->pipe == 0) {
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		   "Can't support LVDS on pipe A\n");
+	return FALSE;
+    }
+
+    /* If we have timings from the BIOS for the panel, put them in
+     * to the adjusted mode.  The CRTC will be set up for this mode,
+     * with the panel scaling set up to source from the H/VDisplay
+     * of the original mode.
+     */
+    if (pI830->panel_fixed_hactive != 0) {
+	adjusted_mode->HDisplay = pI830->panel_fixed_hactive;
+	adjusted_mode->HTotal = adjusted_mode->HDisplay +
+	    pI830->panel_fixed_hblank;
+	adjusted_mode->HSyncStart = adjusted_mode->HDisplay +
+	    pI830->panel_fixed_hsyncoff;
+	adjusted_mode->HSyncStart = adjusted_mode->HSyncStart +
+	    pI830->panel_fixed_hsyncwidth;
+	adjusted_mode->VDisplay = pI830->panel_fixed_vactive;
+	adjusted_mode->VTotal = adjusted_mode->VDisplay +
+	    pI830->panel_fixed_hblank;
+	adjusted_mode->VSyncStart = adjusted_mode->VDisplay +
+	    pI830->panel_fixed_hsyncoff;
+	adjusted_mode->VSyncStart = adjusted_mode->VSyncStart +
+	    pI830->panel_fixed_hsyncwidth;
+	adjusted_mode->Clock = pI830->panel_fixed_clock;
+	xf86SetModeCrtc(adjusted_mode, INTERLACE_HALVE_V);
+    }
+
+    /* XXX: if we don't have BIOS fixed timings (or we have
+     * a preferred mode from DDC, probably), we should use the
+     * DDC mode as the fixed timing.
      */
-    i830SetLVDSPanelPower(pScrn, FALSE);
+
+    /* XXX: It would be nice to support lower refresh rates on the
+     * panels to reduce power consumption, and perhaps match the
+     * user's requested refresh rate.
+     */
+
+    return TRUE;
 }
 
 static void
-i830_lvds_post_set_mode(xf86OutputPtr output, DisplayModePtr pMode)
+i830_lvds_mode_set(xf86OutputPtr output, DisplayModePtr mode,
+		   DisplayModePtr adjusted_mode)
 {
-    ScrnInfoPtr	pScrn = output->scrn;
-    I830Ptr	pI830 = I830PTR(pScrn);
-    CARD32	pfit_control;
+    ScrnInfoPtr pScrn = output->scrn;
+    I830Ptr pI830 = I830PTR(pScrn);
+    CARD32 pfit_control;
+
+    /* The LVDS pin pair needs to be on before the DPLLs are enabled.
+     * This is an exception to the general rule that mode_set doesn't turn
+     * things on.
+     */
+    OUTREG(LVDS, LVDS_PORT_EN | LVDS_PIPEB_SELECT);
 
     /* Enable automatic panel scaling so that non-native modes fill the
      * screen.  Should be enabled before the pipe is enabled, according to
-     * register description.
+     * register description and PRM.
      */
     pfit_control = (PFIT_ENABLE |
 		    VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
@@ -159,19 +219,6 @@ i830_lvds_post_set_mode(xf86OutputPtr ou
 	pfit_control |= PANEL_8TO6_DITHER_ENABLE;
 
     OUTREG(PFIT_CONTROL, pfit_control);
-
-    /* Disable the PLL before messing with LVDS enable */
-    OUTREG(FPB0, INREG(FPB0) & ~DPLL_VCO_ENABLE);
-
-    /* LVDS must be powered on before PLL is enabled and before power
-     * sequencing the panel.
-     */
-    OUTREG(LVDS, INREG(LVDS) | LVDS_PORT_EN | LVDS_PIPEB_SELECT);
-
-    /* Re-enable the PLL */
-    OUTREG(FPB0, INREG(FPB0) | DPLL_VCO_ENABLE);
-
-    i830SetLVDSPanelPower(pScrn, TRUE);
 }
 
 /**
@@ -234,8 +281,8 @@ static const xf86OutputFuncsRec i830_lvd
     .save = i830_lvds_save,
     .restore = i830_lvds_restore,
     .mode_valid = i830_lvds_mode_valid,
-    .pre_set_mode = i830_lvds_pre_set_mode,
-    .post_set_mode = i830_lvds_post_set_mode,
+    .mode_fixup = i830_lvds_mode_fixup,
+    .mode_set = i830_lvds_mode_set,
     .detect = i830_lvds_detect,
     .get_modes = i830_lvds_get_modes,
     .destroy = i830_lvds_destroy
diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index c75800d..7755252 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -534,15 +534,36 @@ i830_sdvo_set_clock_rate_mult(xf86Output
     return TRUE;
 }
 
+static Bool
+i830_sdvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
+		     DisplayModePtr adjusted_mode)
+{
+    /* 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;
+}
+
 static void
-i830_sdvo_pre_set_mode(xf86OutputPtr output, DisplayModePtr mode)
+i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode,
+		   DisplayModePtr adjusted_mode)
 {
     ScrnInfoPtr pScrn = output->scrn;
     I830Ptr pI830 = I830PTR(pScrn);
     I830OutputPrivatePtr    intel_output = output->driver_private;
     struct i830_sdvo_priv   *dev_priv = intel_output->dev_priv;
-    CARD16 width;
-    CARD16 height;
+    xf86CrtcPtr	    crtc = output->crtc;
+    I830CrtcPrivatePtr	    intel_crtc = crtc->driver_private;
+    Bool input1, input2;
+    CARD32 dpll, sdvox;
+    int dpll_reg = (intel_crtc->pipe == 0) ? DPLL_A : DPLL_B;
+    int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD;
+    int sdvo_pixel_multiply;
+    int i;
+    CARD8 status;
+    CARD16 width, height;
     CARD16 h_blank_len, h_sync_len, v_blank_len, v_sync_len;
     CARD16 h_sync_offset, v_sync_offset;
     struct i830_sdvo_dtd output_dtd;
@@ -633,26 +654,6 @@ i830_sdvo_pre_set_mode(xf86OutputPtr out
 	break;
     }
 
-    OUTREG(dev_priv->output_device, INREG(dev_priv->output_device) & ~SDVO_ENABLE);
-}
-
-static void
-i830_sdvo_post_set_mode(xf86OutputPtr output, DisplayModePtr mode)
-{
-    ScrnInfoPtr pScrn = output->scrn;
-    I830OutputPrivatePtr    intel_output = output->driver_private;
-    struct i830_sdvo_priv   *dev_priv = intel_output->dev_priv;
-    xf86CrtcPtr	    crtc = output->crtc;
-    I830CrtcPrivatePtr	    intel_crtc = crtc->driver_private;
-    I830Ptr pI830 = I830PTR(pScrn);
-    Bool input1, input2;
-    CARD32 dpll, sdvox;
-    int dpll_reg = (intel_crtc->pipe == 0) ? DPLL_A : DPLL_B;
-    int dpll_md_reg = (intel_crtc->pipe == 0) ? DPLL_A_MD : DPLL_B_MD;
-    int sdvo_pixel_multiply;
-    int i;
-    CARD8 status;
-
     /* Set the SDVO control regs. */
     sdvox = INREG(dev_priv->output_device);
     switch (dev_priv->output_device) {
@@ -663,7 +664,7 @@ i830_sdvo_post_set_mode(xf86OutputPtr ou
 	sdvox &= SDVOC_PRESERVE_MASK;
 	break;
     }
-    sdvox |= SDVO_ENABLE | (9 << 19) | SDVO_BORDER_ENABLE;
+    sdvox |= (9 << 19) | SDVO_BORDER_ENABLE;
     if (intel_crtc->pipe == 1)
 	sdvox |= SDVO_PIPE_B_SELECT;
 
@@ -1014,8 +1015,8 @@ static const xf86OutputFuncsRec i830_sdv
     .save = i830_sdvo_save,
     .restore = i830_sdvo_restore,
     .mode_valid = i830_sdvo_mode_valid,
-    .pre_set_mode = i830_sdvo_pre_set_mode,
-    .post_set_mode = i830_sdvo_post_set_mode,
+    .mode_fixup = i830_sdvo_mode_fixup,
+    .mode_set = i830_sdvo_mode_set,
     .detect = i830_sdvo_detect,
     .get_modes = i830_ddc_get_modes,
     .destroy = i830_sdvo_destroy
diff --git a/src/i830_tv.c b/src/i830_tv.c
index f5716f8..87aecda 100644
--- a/src/i830_tv.c
+++ b/src/i830_tv.c
@@ -295,8 +295,33 @@ static const CARD32 v_chroma[43] = {
     0x28003100, 0x28002F00, 0x00003100,
 };
 
+static Bool
+i830_tv_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
+		 DisplayModePtr adjusted_mode)
+{
+    ScrnInfoPtr pScrn = output->scrn;
+    I830Ptr pI830 = I830PTR(pScrn);
+    int i;
+
+    for (i = 0; i < pI830->xf86_config.num_output; i++) {
+	xf86OutputPtr other_output = pI830->xf86_config.output[i];
+
+	if (other_output != output && other_output->crtc == output->crtc) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		       "Can't enable TV and another output on the same "
+		       "pipe\n");
+	    return FALSE;
+	}
+    }
+
+    /* XXX: fill me in */
+
+    return TRUE;
+}
+
 static void
-i830_tv_post_set_mode(xf86OutputPtr output, DisplayModePtr pMode)
+i830_tv_mode_set(xf86OutputPtr output, DisplayModePtr mode,
+		 DisplayModePtr adjusted_mode)
 {
     ScrnInfoPtr		    pScrn = output->scrn;
     I830Ptr		    pI830 = I830PTR(pScrn);
@@ -359,7 +384,7 @@ i830_tv_post_set_mode(xf86OutputPtr outp
     vctl7 = (tv_mode->vburst_start_f4 << TV_VBURST_START_F4_SHIFT) |
 	(tv_mode->vburst_end_f4 << TV_VBURST_END_F4_SHIFT);
 
-    tv_ctl = TV_ENC_ENABLE;
+    tv_ctl = 0;
     if (intel_crtc->pipe == 1)
 	tv_ctl |= TV_ENC_PIPEB_SELECT;
 
@@ -403,7 +428,7 @@ i830_tv_post_set_mode(xf86OutputPtr outp
 	tv_ctl |= TV_ENC_C0_FIX | TV_ENC_SDP_FIX;
 
     tv_filter_ctl = TV_AUTO_SCALE;
-    if (pMode->HDisplay > 1024)
+    if (mode->HDisplay > 1024)
 	tv_ctl |= TV_V_FILTER_BYPASS;
 
     OUTREG(TV_H_CTL_1, hctl1);
@@ -635,8 +660,8 @@ static const xf86OutputFuncsRec i830_tv_
     .save = i830_tv_save,
     .restore = i830_tv_restore,
     .mode_valid = i830_tv_mode_valid,
-    .pre_set_mode = i830_tv_pre_set_mode,
-    .post_set_mode = i830_tv_post_set_mode,
+    .mode_fixup = i830_tv_mode_fixup,
+    .mode_set = i830_tv_mode_set,
     .detect = i830_tv_detect,
     .get_modes = i830_tv_get_modes,
     .destroy = i830_tv_destroy
diff --git a/src/i830_xf86Crtc.h b/src/i830_xf86Crtc.h
index 2952c8d..b5dbe51 100644
--- a/src/i830_xf86Crtc.h
+++ b/src/i830_xf86Crtc.h
@@ -27,14 +27,15 @@
 #include "i830_xf86Modes.h"
 
 typedef struct _xf86Crtc xf86CrtcRec, *xf86CrtcPtr;
+typedef struct _xf86Output xf86OutputRec, *xf86OutputPtr;
 
 typedef struct _xf86CrtcFuncs {
    /**
     * Turns the crtc on/off, or sets intermediate power levels if available.
     *
     * Unsupported intermediate modes drop to the lower power setting.  If the
-    * mode is DPMSModeOff, the crtc must be disabled, as the DPLL may be
-    * disabled afterwards.
+    * mode is DPMSModeOff, the crtc must be disabled sufficiently for it to
+    * be safe to call mode_set.
     */
    void
     (*dpms)(xf86CrtcPtr		crtc,
@@ -52,6 +53,27 @@ typedef struct _xf86CrtcFuncs {
    void
     (*restore)(xf86CrtcPtr	crtc);
 
+
+    /**
+     * Callback to adjust the mode to be set in the CRTC.
+     *
+     * This allows a CRTC to adjust the clock or even the entire set of
+     * timings, which is used for panels with fixed timings or for
+     * buses with clock limitations.
+     */
+    Bool
+    (*mode_fixup)(xf86CrtcPtr crtc,
+		  DisplayModePtr mode,
+		  DisplayModePtr adjusted_mode);
+
+    /**
+     * Callback for setting up a video mode after fixups have been made.
+     */
+    void
+    (*mode_set)(xf86CrtcPtr crtc,
+		DisplayModePtr mode,
+		DisplayModePtr adjusted_mode);
+
     /**
      * Clean up driver-specific bits of the crtc
      */
@@ -127,8 +149,6 @@ struct _xf86Crtc {
 #endif
 };
 
-typedef struct _xf86Output xf86OutputRec, *xf86OutputPtr;
-
 typedef struct _xf86OutputFuncs {
     /**
      * Turns the output on/off, or sets intermediate power levels if available.
@@ -157,7 +177,7 @@ typedef struct _xf86OutputFuncs {
      * Callback for testing a video mode for a given output.
      *
      * This function should only check for cases where a mode can't be supported
-     * on the pipe specifically, and not represent generic CRTC limitations.
+     * on the output specifically, and not represent generic CRTC limitations.
      *
      * \return MODE_OK if the mode is valid, or another MODE_* otherwise.
      */
@@ -166,22 +186,28 @@ typedef struct _xf86OutputFuncs {
 		  DisplayModePtr    pMode);
 
     /**
-     * Callback for setting up a video mode before any crtc/dpll changes.
+     * Callback to adjust the mode to be set in the CRTC.
      *
-     * \param pMode the mode that will be set, or NULL if the mode to be set is
-     * unknown (such as the restore path of VT switching).
+     * This allows an output to adjust the clock or even the entire set of
+     * timings, which is used for panels with fixed timings or for
+     * buses with clock limitations.
      */
-    void
-    (*pre_set_mode)(xf86OutputPtr   output,
-		    DisplayModePtr  pMode);
+    Bool
+    (*mode_fixup)(xf86OutputPtr output,
+		  DisplayModePtr mode,
+		  DisplayModePtr adjusted_mode);
 
     /**
-     * Callback for setting up a video mode after the DPLL update but before
-     * the plane is enabled.
+     * Callback for setting up a video mode after fixups have been made.
+     *
+     * This is only called while the output is disabled.  The dpms callback
+     * must be all that's necessary for the output, to turn the output on
+     * after this function is called.
      */
     void
-    (*post_set_mode)(xf86OutputPtr  output,
-		     DisplayModePtr pMode);
+    (*mode_set)(xf86OutputPtr  output,
+		DisplayModePtr mode,
+		DisplayModePtr adjusted_mode);
 
     /**
      * Probe for a connected output, and return detect_status.



More information about the xorg-commit mailing list