xf86-video-intel: Branch 'modesetting' - src/i810_reg.h src/i830_debug.c src/i830_debug.h src/i830_display.c src/i830_driver.c src/i830.h src/i830_modes.c src/i830_sdvo.c src/i830_sdvo_regs.h

Keith Packard keithp at kemper.freedesktop.org
Sun Jun 4 10:21:01 EEST 2006


 src/i810_reg.h       |    3 
 src/i830.h           |    2 
 src/i830_debug.c     |   13 +
 src/i830_debug.h     |    1 
 src/i830_display.c   |   30 ++--
 src/i830_driver.c    |   32 +++-
 src/i830_modes.c     |  366 +++++++++++++++++++++++++++++++++++++++++++++++++++
 src/i830_sdvo.c      |   91 ++++++++++--
 src/i830_sdvo_regs.h |    2 
 9 files changed, 510 insertions(+), 30 deletions(-)

New commits:
diff-tree 34f6a8204f1edec015283fc6b5f196e47897e3de (from c1c46f882f9a11c383c8d1d1ce393be8fda55ed0)
Author: Keith Packard <keithp at mactel.(none)>
Date:   Sun Jun 4 00:15:06 2006 -0700

    Get sDVO output working on mac mini.
    Add lots of register debugging to track delta from BIOS settings.
    Fix various mode settings to mirror BIOS sDVO values.
    Disable analog/lvds output on pipe with sDVO.
    Borrow Dave Airlie's I830xf86ValidateDDCModes code.
    Fix various sDVO I2C messages to mirror Dave's code.

diff --git a/src/i810_reg.h b/src/i810_reg.h
index 53c65bb..92e3342 100644
--- a/src/i810_reg.h
+++ b/src/i810_reg.h
@@ -748,6 +748,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN
 # define TV_HOTPLUG_INT_STATUS			(1 << 10)
 # define SDVOC_HOTPLUG_INT_STATUS		(1 << 7)
 # define SDVOB_HOTPLUG_INT_STATUS		(1 << 6)
+#define SDVOB_PRESERVE_MASK			((1 << 17) | (1 << 16) | (1 << 14))
 
 #define SDVOB			0x61140
 #define SDVOC			0x61160
@@ -765,7 +766,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN
 #define SDVOB_PCIE_CONCURRENCY			(1 << 3)
 #define SDVO_DETECTED				(1 << 2)
 /* Bits to be preserved when writing */
-#define SDVO_PRESERVE_MASK			(1 << 17)
+#define SDVOC_PRESERVE_MASK			(1 << 17)
 
 #define I830_HTOTAL_MASK 	0xfff0000
 #define I830_HACTIVE_MASK	0x7ff
diff --git a/src/i830.h b/src/i830.h
index c60bfbe..8cf7b71 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -420,6 +420,7 @@ typedef struct _I830Rec {
    Bool devicePresence;
 
    OsTimerPtr devicesTimer;
+   int MaxClock;
 
    int ddc2;
    int num_outputs;
@@ -589,6 +590,7 @@ extern Rotation I830GetRotation(ScreenPt
 extern Bool I830RandRInit(ScreenPtr pScreen, int rotation);
 extern Bool I830I2CInit(ScrnInfoPtr pScrn, I2CBusPtr *bus_ptr, int i2c_reg,
 			char *name);
+int I830xf86ValidateDDCModes(ScrnInfoPtr pScrn1, char **ppModeName);
 
 /*
  * 12288 is set as the maximum, chosen because it is enough for
diff --git a/src/i830_debug.c b/src/i830_debug.c
index b544257..6d43cd6 100644
--- a/src/i830_debug.c
+++ b/src/i830_debug.c
@@ -35,7 +35,7 @@
 
 /* XXX: What was the syntax for sticking quotes around the "reg" argument? */
 #define DEFINEREG(reg) \
-	{ reg, NULL, 0 }
+	{ reg, #reg, 0 }
 
 static struct i830SnapshotRec {
     int reg;
@@ -129,3 +129,14 @@ void i830CompareRegsToSnapshot(ScrnInfoP
 	}
     }
 }
+
+void i830DumpRegs (ScrnInfoPtr pScrn)
+{
+    I830Ptr pI830 = I830PTR(pScrn);
+    int i;
+
+    for (i = 0; i < NUM_I830_SNAPSHOTREGS; i++) {
+	xf86DrvMsg (pScrn->scrnIndex, X_WARNING, "%10.10s: 0x%08x\n",
+		    i830_snapshot[i].name, (unsigned int) INREG(i830_snapshot[i].reg));
+    }
+}
diff --git a/src/i830_debug.h b/src/i830_debug.h
index 269f03e..a8e3839 100644
--- a/src/i830_debug.h
+++ b/src/i830_debug.h
@@ -27,3 +27,4 @@
 
 void i830TakeRegSnapshot(ScrnInfoPtr pScrn);
 void i830CompareRegsToSnapshot(ScrnInfoPtr pScrn);
+void i830DumpRegs (ScrnInfoPtr pScrn);
diff --git a/src/i830_display.c b/src/i830_display.c
index 95fa936..d49da1f 100644
--- a/src/i830_display.c
+++ b/src/i830_display.c
@@ -34,6 +34,7 @@
 #include "i830.h"
 #include "i830_bios.h"
 #include "i830_display.h"
+#include "i830_debug.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)
@@ -255,7 +256,8 @@ i830PipeSetMode(ScrnInfoPtr pScrn, Displ
     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, adpa, sdvoc = 0;
+    CARD32 pipesrc, dspsize, adpa;
+    CARD32 sdvob = 0, sdvoc= 0;
     Bool ok, is_sdvo;
     int refclk, pixel_clock;
     int outputs;
@@ -391,13 +393,14 @@ i830PipeSetMode(ScrnInfoPtr pScrn, Displ
 
 	ErrorF("DVOB: %08x\nDVOC: %08x\n", (int)INREG(SDVOB), (int)INREG(SDVOC));
 
-	sdvoc = INREG(SDVOC) & SDVO_PRESERVE_MASK;
-	sdvoc |= SDVO_ENABLE;
+        sdvob = INREG(SDVOB) & SDVOB_PRESERVE_MASK;
+	sdvoc = INREG(SDVOC) & SDVOC_PRESERVE_MASK;
+	sdvob |= SDVO_ENABLE | (9 << 19) | SDVO_BORDER_ENABLE;
+	sdvoc |= 9 << 19;
 	if (pipe == 1)
-	    sdvoc |= SDVO_PIPE_B_SELECT;
-	//	sdvoc |= SDVO_PHASE_SELECT_DEFAULT;
-	sdvoc |= SDVO_BORDER_ENABLE;
+	    sdvob |= SDVO_PIPE_B_SELECT;
 	OUTREG(SDVOC, INREG(SDVOC) & ~SDVO_ENABLE);
+	OUTREG(SDVOB, INREG(SDVOB) & ~SDVO_ENABLE);
     }
 
     fp = ((n - 2) << 16) | ((m1 - 2) << 8) | (m2 - 2);
@@ -434,7 +437,10 @@ i830PipeSetMode(ScrnInfoPtr pScrn, Displ
 	FatalError("unknown display bpp\n");
     }
 
-    adpa = ADPA_DAC_ENABLE;
+    if (is_sdvo)
+	adpa = ADPA_DAC_DISABLE;
+    else
+	adpa = ADPA_DAC_ENABLE;
     if (pMode->Flags & V_PHSYNC)
 	adpa |= ADPA_HSYNC_ACTIVE_HIGH;
     if (pMode->Flags & V_PVSYNC)
@@ -466,9 +472,6 @@ i830PipeSetMode(ScrnInfoPtr pScrn, Displ
 	OUTREG(FPA0, fp);
 	OUTREG(DPLL_A, dpll);
 
-	if (is_sdvo)
-	  OUTREG(SDVOC, sdvoc);
-
 	OUTREG(HTOTAL_A, htot);
 	OUTREG(HBLANK_A, hblank);
 	OUTREG(HSYNC_A, hsync);
@@ -487,6 +490,11 @@ i830PipeSetMode(ScrnInfoPtr pScrn, Displ
 
 	/* And then turn the plane on */
 	OUTREG(DSPACNTR, dspcntr);
+
+	if (is_sdvo) {
+	  OUTREG(SDVOB, sdvob);
+	  OUTREG(SDVOC, sdvoc);
+	}
     } else {
 	/* Always make sure the LVDS is off before we play with DPLLs and pipe
 	 * configuration.
@@ -637,6 +645,8 @@ done:
 	I830DRIUnlock(pScrn);
 #endif
 
+    i830DumpRegs (pScrn);
+    I830DumpSDVO (pScrn);
     return ok;
 }
 
diff --git a/src/i830_driver.c b/src/i830_driver.c
index 425ddd5..c91bf43 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -2386,14 +2386,17 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
 	      "Maximum space available for video modes: %d kByte\n", memsize);
 
+     pI830->MaxClock = 300000;
+
    /*
      * Setup the ClockRanges, which describe what clock ranges are available,
      * and what sort of modes they can be used for.
      */
     clockRanges = xnfcalloc(sizeof(ClockRange), 1);
     clockRanges->next = NULL;
-    clockRanges->minClock = 12000;	/* XXX: Random number */
-    clockRanges->maxClock = 400000;	/* XXX: May be lower */
+    /* 25MHz appears to be the smallest that works. */
+    clockRanges->minClock = 25000;
+    clockRanges->maxClock = pI830->MaxClock;
     clockRanges->clockIndex = -1;		/* programmable */
     clockRanges->interlaceAllowed = TRUE;	/* XXX check this */
     clockRanges->doubleScanAllowed = FALSE;	/* XXX check this */
@@ -2412,16 +2415,17 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
       }
       n = i830ValidateFPModes(pScrn, pScrn->display->modes);
    } else {
+      I830xf86ValidateDDCModes(pScrn, pScrn->display->modes);
       /* XXX minPitch, minHeight are random numbers. */
       n = xf86ValidateModes(pScrn,
 			    pScrn->monitor->Modes, /* availModes */
 			    pScrn->display->modes, /* modeNames */
 			    clockRanges, /* clockRanges */
 			    NULL, /* linePitches */
-			    256, /* minPitch */
+			    320, /* minPitch */
 			    MAX_DISPLAY_PITCH, /* maxPitch */
-			    64, /* pitchInc */
-			    pScrn->bitsPerPixel, /* minHeight */
+			    64 * pScrn->bitsPerPixel, /* pitchInc */
+			    200, /* minHeight */
 			    MAX_DISPLAY_HEIGHT, /* maxHeight */
 			    pScrn->display->virtualX, /* virtualX */
 			    pScrn->display->virtualY, /* virtualY */
@@ -2444,6 +2448,24 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int f
 
    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
 
+   /*
+    * Fix up modes to make hblank start at hsync start.
+    * I don't know why the xf86 code mangles this...
+    */
+    {
+	DisplayModePtr	p;
+
+	for (p = pScrn->modes; p;) {
+	    xf86DrvMsg (pScrn->scrnIndex,
+			X_INFO, "move blank start from %d to %d\n",
+			p->CrtcHBlankStart, p->CrtcHDisplay);
+	    p->CrtcHBlankStart = p->CrtcHDisplay;
+	    p = p->next;
+	    if (p == pScrn->modes)
+		break;
+	}
+    }
+   
    pScrn->currentMode = pScrn->modes;
 
 #ifndef USE_PITCHES
diff --git a/src/i830_modes.c b/src/i830_modes.c
index 16576bb..ce86d8c 100644
--- a/src/i830_modes.c
+++ b/src/i830_modes.c
@@ -44,6 +44,52 @@
 #include "xf86.h"
 #include "i830.h"
 
+#include <math.h>
+
+#define rint(x) floor(x)
+
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+
+#define MARGIN_PERCENT    1.8   /* % of active vertical image                */
+#define CELL_GRAN         8.0   /* assumed character cell granularity        */
+#define MIN_PORCH         1     /* minimum front porch                       */
+#define V_SYNC_RQD        3     /* width of vsync in lines                   */
+#define H_SYNC_PERCENT    8.0   /* width of hsync as % of total line         */
+#define MIN_VSYNC_PLUS_BP 550.0 /* min time of vsync + back porch (microsec) */
+#define M                 600.0 /* blanking formula gradient                 */
+#define C                 40.0  /* blanking formula offset                   */
+#define K                 128.0 /* blanking formula scaling factor           */
+#define J                 20.0  /* blanking formula scaling factor           */
+
+/* C' and M' are part of the Blanking Duty Cycle computation */
+
+#define C_PRIME           (((C - J) * K/256.0) + J)
+#define M_PRIME           (K/256.0 * M)
+/* Established timings from EDID standard */
+static struct
+{
+    int hsize;
+    int vsize;
+    int refresh;
+} est_timings[] = {
+    {1280, 1024, 75},
+    {1024, 768, 75},
+    {1024, 768, 70},
+    {1024, 768, 60},
+    {1024, 768, 87},
+    {832, 624, 75},
+    {800, 600, 75},
+    {800, 600, 72},
+    {800, 600, 60},
+    {800, 600, 56},
+    {640, 480, 75},
+    {640, 480, 72},
+    {640, 480, 67},
+    {640, 480, 60},
+    {720, 400, 88},
+    {720, 400, 70},
+};
+
 extern const int i830refreshes[];
 
 void
@@ -108,3 +154,323 @@ I830PrintModes(ScrnInfoPtr scrp)
 	p = p->next;
     } while (p != NULL && p != scrp->modes);
 }
+
+/* This function will sort all modes according to their resolution.
+ * Highest resolution first.
+ */
+void
+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;
+	    break;
+	}
+	if (!p->prev) {
+	    (*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;
+    }
+}
+
+DisplayModePtr I830xf86DDCModes(ScrnInfoPtr pScrn)
+{
+    DisplayModePtr  p;
+    DisplayModePtr  last  = NULL;
+    DisplayModePtr  new   = NULL;
+    DisplayModePtr  first = NULL;
+    int             count = 0;
+    int             j, tmp;
+    char            stmp[32];
+    xf86MonPtr      ddc   = pScrn->monitor->DDC;
+
+    /* Go thru detailed timing table first */
+    for (j = 0; j < 4; j++) {
+	if (ddc->det_mon[j].type == 0) {
+	    struct detailed_timings *d_timings =
+		&ddc->det_mon[j].section.d_timings;
+
+	    if (d_timings->h_active == 0 || d_timings->v_active == 0) break;
+
+	    new = xnfcalloc(1, sizeof (DisplayModeRec));
+	    memset(new, 0, sizeof (DisplayModeRec));
+
+	    new->HDisplay   = d_timings->h_active;
+	    new->VDisplay   = d_timings->v_active;
+
+	    sprintf(stmp, "%dx%d", new->HDisplay, new->VDisplay);
+	    new->name       = xnfalloc(strlen(stmp) + 1);
+	    strcpy(new->name, stmp);
+
+	    new->HTotal     = new->HDisplay + d_timings->h_blanking;
+	    new->HSyncStart = new->HDisplay + d_timings->h_sync_off;
+	    new->HSyncEnd   = new->HSyncStart + d_timings->h_sync_width;
+	    new->VTotal     = new->VDisplay + d_timings->v_blanking;
+	    new->VSyncStart = new->VDisplay + d_timings->v_sync_off;
+	    new->VSyncEnd   = new->VSyncStart + d_timings->v_sync_width;
+	    new->Clock      = d_timings->clock / 1000;
+	    new->Flags      = (d_timings->interlaced ? V_INTERLACE : 0);
+	    new->status     = MODE_OK;
+	    new->type       = M_T_DEFAULT;
+
+	    if (d_timings->sync == 3) {
+		switch (d_timings->misc) {
+		case 0: new->Flags |= V_NHSYNC | V_NVSYNC; break;
+		case 1: new->Flags |= V_PHSYNC | V_NVSYNC; break;
+		case 2: new->Flags |= V_NHSYNC | V_PVSYNC; break;
+		case 3: new->Flags |= V_PHSYNC | V_PVSYNC; break;
+		}
+	    }
+	    count++;
+
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		       "Valid Mode from Detailed timing table: %s (ht %d hss %d hse %d vt %d vss %d vse %d)\n",
+		       new->name,
+		       new->HTotal, new->HSyncStart, new->HSyncEnd,
+		       new->VTotal, new->VSyncStart, new->VSyncEnd);
+
+	    I830xf86SortModes(&new, &first, &last);
+	}
+    }
+
+    /* Search thru standard VESA modes from EDID */
+    for (j = 0; j < 8; j++) {
+        if (ddc->timings2[j].hsize == 0 || ddc->timings2[j].vsize == 0)
+               continue;
+	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)) {
+		float  refresh =
+		    (float)p->Clock * 1000.0 / p->HTotal / p->VTotal;
+		float err = (float)ddc->timings2[j].refresh - refresh;
+
+		if (err < 0) err = -err;
+		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 standard timing table: %s\n",
+			       new->name);
+
+		    I830xf86SortModes(&new, &first, &last);
+		    break;
+		}
+	    }
+	}
+    }
+
+    /* 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;
+		    }
+		}
+	    }
+	}
+    }
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+	       "Total of %d mode(s) found.\n", count);
+
+    return first;
+}
+
+/* XFree86's xf86ValidateModes routine doesn't work well with DDC modes,
+ * so here is our own validation routine.
+ */
+int I830xf86ValidateDDCModes(ScrnInfoPtr pScrn1, char **ppModeName)
+{
+    DisplayModePtr  p;
+    DisplayModePtr  last       = NULL;
+    DisplayModePtr  first      = NULL;
+    DisplayModePtr  ddcModes   = NULL;
+    int             count      = 0;
+    int             i, width, height;
+    ScrnInfoPtr pScrn = pScrn1;
+
+    pScrn->virtualX = pScrn1->display->virtualX;
+    pScrn->virtualY = pScrn1->display->virtualY;
+
+    if (pScrn->monitor->DDC) {
+	int  maxVirtX = pScrn->virtualX;
+	int  maxVirtY = pScrn->virtualY;
+
+	/* Collect all of the DDC modes */
+	first = last = ddcModes = I830xf86DDCModes(pScrn);
+
+	for (p = ddcModes; p; p = p->next) {
+
+	    maxVirtX = MAX(maxVirtX, p->HDisplay);
+	    maxVirtY = MAX(maxVirtY, p->VDisplay);
+	    count++;
+
+	    last = p;
+	}
+
+	/* Match up modes that are specified in the XF86Config file */
+	if (ppModeName[0]) {
+	    DisplayModePtr  next;
+
+	    /* Reset the max virtual dimensions */
+	    maxVirtX = pScrn->virtualX;
+	    maxVirtY = pScrn->virtualY;
+
+	    /* Reset list */
+	    first = last = NULL;
+
+	    for (i = 0; ppModeName[i]; i++) {
+		/* FIXME: Use HDisplay and VDisplay instead of mode string */
+		if (sscanf(ppModeName[i], "%dx%d", &width, &height) == 2) {
+		    for (p = ddcModes; p; p = next) {
+			next = p->next;
+
+			if (p->HDisplay == width && p->VDisplay == height) {
+			    /* We found a DDC mode that matches the one
+                               requested in the XF86Config file */
+			    p->type |= M_T_USERDEF;
+
+			    /* Update  the max virtual setttings */
+			    maxVirtX = MAX(maxVirtX, width);
+			    maxVirtY = MAX(maxVirtY, height);
+
+			    /* Unhook from DDC modes */
+			    if (p->prev) p->prev->next = p->next;
+			    if (p->next) p->next->prev = p->prev;
+			    if (p == ddcModes) ddcModes = p->next;
+
+			    /* Add to used modes */
+			    if (last) {
+				last->next = p;
+				p->prev = last;
+			    } else {
+				first = p;
+				p->prev = NULL;
+			    }
+			    p->next = NULL;
+			    last = p;
+
+			    break;
+			}
+		    }
+		}
+	    }
+
+	    /*
+	     * Add remaining DDC modes if they're smaller than the user
+	     * specified modes
+	     */
+	    for (p = ddcModes; p; p = next) {
+		next = p->next;
+		if (p->HDisplay <= maxVirtX && p->VDisplay <= maxVirtY) {
+		    /* Unhook from DDC modes */
+		    if (p->prev) p->prev->next = p->next;
+		    if (p->next) p->next->prev = p->prev;
+		    if (p == ddcModes) ddcModes = p->next;
+
+		    /* Add to used modes */
+		    if (last) {
+			last->next = p;
+			p->prev = last;
+		    } else {
+			first = p;
+			p->prev = NULL;
+		    }
+		    p->next = NULL;
+		    last = p;
+		}
+	    }
+
+	    /* Delete unused modes */
+	    while (ddcModes)
+		xf86DeleteMode(&ddcModes, ddcModes);
+	} else {
+	    /*
+	     * No modes were configured, so we make the DDC modes
+	     * available for the user to cycle through.
+	     */
+	    for (p = ddcModes; p; p = p->next)
+		p->type |= M_T_USERDEF;
+	}
+
+	pScrn->virtualX = pScrn->display->virtualX = maxVirtX;
+	pScrn->virtualY = pScrn->display->virtualY = maxVirtY;
+    }
+
+    /* Close the doubly-linked mode list, if we found any usable modes */
+    if (last) {
+      DisplayModePtr  temp      = NULL;
+        /* we should add these to pScrn monitor modes */
+      last->next   = pScrn->monitor->Modes;
+      temp = pScrn->monitor->Modes->prev;
+      pScrn->monitor->Modes->prev = first;
+      pScrn->monitor->Modes->prev = last;
+
+      first->prev = temp;
+      if (temp)
+	temp->next = first;
+
+      pScrn->monitor->Modes = first;
+    }
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+	       "Total number of valid DDC mode(s) found: %d\n", count);
+
+    return count;
+}
diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c
index 579f77a..7d23975 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -139,7 +139,7 @@ I830SDVOSetTargetInput(I830SDVOPtr s, Bo
     s->sdvo_regs[SDVO_I2C_ARG_0] = target_1;
     s->sdvo_regs[SDVO_I2C_ARG_1] = target_2;
 
-    I830SDVOWriteOutputs(s, 1);
+    I830SDVOWriteOutputs(s, 2);
 
     I830SDVOReadInputRegs(s);
 
@@ -218,7 +218,7 @@ I830SDVOSetTargetOutput(I830SDVOPtr s, B
     s->sdvo_regs[SDVO_I2C_ARG_0] = target_1;
     s->sdvo_regs[SDVO_I2C_ARG_1] = target_2;
 
-    I830SDVOWriteOutputs(s, 1);
+    I830SDVOWriteOutputs(s, 2);
     I830SDVOReadInputRegs(s);
 
     return TRUE;
@@ -259,7 +259,7 @@ I830SDVOGetTimings(I830SDVOPtr s, i830_s
     return TRUE;
 }
 
-/* Fetches either input or output timings to *dtd, depending on cmd. */
+/* Sets either input or output timings to *dtd, depending on cmd. */
 Bool
 I830SDVOSetTimings(I830SDVOPtr s, i830_sdvo_dtd *dtd, CARD8 cmd)
 {
@@ -286,7 +286,7 @@ I830SDVOSetTimings(I830SDVOPtr s, i830_s
     s->sdvo_regs[SDVO_I2C_ARG_5] = dtd->sdvo_flags;
     s->sdvo_regs[SDVO_I2C_ARG_6] = dtd->v_sync_off_high;
     s->sdvo_regs[SDVO_I2C_ARG_7] = dtd->reserved;
-    I830SDVOWriteOutputs(s, 8);
+    I830SDVOWriteOutputs(s, 7);
     I830SDVOReadInputRegs(s);
 
     return TRUE;
@@ -477,6 +477,7 @@ I830SDVOPreSetMode(I830SDVOPtr s, Displa
     CARD8 c17a[8];
     CARD16 out_timings[6];
     CARD16 clock_min, clock_max;
+    Bool out1, out2;
 
     /* do some mode translations */
     h_blank_len = mode->CrtcHBlankEnd - mode->CrtcHBlankStart;
@@ -516,30 +517,41 @@ I830SDVOPreSetMode(I830SDVOPtr s, Displa
     out_timings[4] = c17a[5] | ((short)c17a[4] << 8);
     out_timings[5] = c17a[3] | ((short)c17a[2] << 8);
 
-    I830SDVOSetTargetInput(s, TRUE, TRUE);
+    I830SDVOSetTargetInput(s, FALSE, FALSE);
     I830SDVOGetInputPixelClockRange(s, &clock_min, &clock_max);
     ErrorF("clock min/max: %d %d\n", clock_min, clock_max);
 
+    I830SDVOGetActiveOutputs(s, &out1, &out2);
+    
     I830SDVOSetActiveOutputs(s, FALSE, FALSE);
 
-    I830SDVOSetTargetOutput(s, TRUE, TRUE);
+    I830SDVOSetTargetOutput(s, TRUE, FALSE);
     I830SDVOSetOutputTimingsPart1(s, clock, out_timings[0], out_timings[1],
 				  out_timings[2]);
     I830SDVOSetOutputTimingsPart2(s, out_timings[3], out_timings[4],
 				  out_timings[5]);
 
+    I830SDVOSetTargetInput (s, FALSE, FALSE);
+    
     I830SDVOCreatePreferredInputTiming(s, clock, width, height);
     I830SDVOGetPreferredInputTimingPart1(s);
     I830SDVOGetPreferredInputTimingPart2(s);
+    
+    I830SDVOSetTargetInput (s, FALSE, FALSE);
+    
     I830SDVOSetInputTimingsPart1(s, clock, curr_table[0], curr_table[1],
 				 curr_table[2]);
     I830SDVOSetInputTimingsPart2(s, curr_table[3], curr_table[4],
 				 out_timings[5]);
 
-    /*if (mode->PrivFlags & I830_MFLAG_DOUBLE)
-	I830SDVOSetClockRateMult(s, 0x02);
-    else */
-	I830SDVOSetClockRateMult(s, 0x01);
+    I830SDVOSetTargetInput (s, FALSE, FALSE);
+    
+    if (clock >= 10000)
+	I830SDVOSetClockRateMult(s, SDVO_CLOCK_RATE_MULT_1X);
+    else if (clock >= 5000)
+	I830SDVOSetClockRateMult(s, SDVO_CLOCK_RATE_MULT_2X);
+    else
+	I830SDVOSetClockRateMult(s, SDVO_CLOCK_RATE_MULT_4X);
 
     return TRUE;
 }
@@ -548,6 +560,7 @@ Bool
 I830SDVOPostSetMode(I830SDVOPtr s, DisplayModePtr mode)
 {
     Bool ret = TRUE;
+    Bool out1, out2;
 
     /* the BIOS writes out 6 commands post mode set */
     /* two 03s, 04 05, 10, 1d */
@@ -564,7 +577,9 @@ I830SDVOPostSetMode(I830SDVOPtr s, Displ
 	ret = FALSE;
     }
 
-    I830SDVOSetActiveOutputs(s, TRUE, TRUE);
+    I830SDVOGetActiveOutputs (s, &out1, &out2);
+    I830SDVOSetActiveOutputs(s, TRUE, FALSE);
+    I830SDVOSetTargetInput (s, FALSE, FALSE);
 
     return ret;
 }
@@ -580,7 +595,7 @@ i830SDVOSave(ScrnInfoPtr pScrn, int outp
 			     &sdvo->save_sdvo_active_2);
 
     if (sdvo->caps.caps & 0x1) {
-       I830SDVOSetTargetInput(sdvo, TRUE, FALSE);
+       I830SDVOSetTargetInput(sdvo, FALSE, FALSE);
        I830SDVOGetTimings(sdvo, &sdvo->save_input_dtd_1,
 			  SDVO_CMD_GET_INPUT_TIMINGS_PART1);
     }
@@ -622,7 +637,7 @@ i830SDVOPostRestore(ScrnInfoPtr pScrn, i
     I830SDVOPtr sdvo = pI830->output[output_index].sdvo_drv;
 
     if (sdvo->caps.caps & 0x1) {
-       I830SDVOSetTargetInput(sdvo, TRUE, FALSE);
+       I830SDVOSetTargetInput(sdvo, FALSE, FALSE);
        I830SDVOSetTimings(sdvo, &sdvo->save_input_dtd_1,
 			  SDVO_CMD_SET_INPUT_TIMINGS_PART1);
     }
@@ -830,3 +845,53 @@ I830SDVOInit(ScrnInfoPtr pScrn, int outp
 
     return sdvo;
 }
+
+static void
+I830DumpSDVOCmd (I830SDVOPtr s, int opcode)
+{
+    memset (s->sdvo_regs, 0, sizeof (s->sdvo_regs));
+    s->sdvo_regs[SDVO_I2C_OPCODE] = opcode;
+    I830SDVOWriteOutputs (s, 0);
+    I830SDVOReadInputRegs (s);
+}
+
+static void
+I830DumpOneSDVO (I830SDVOPtr s)
+{
+    ErrorF ("Dump %s\n", s->d.DevName);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_DEVICE_CAPS);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_FIRMWARE_REV);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_TRAINED_INPUTS);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_ACTIVE_OUTPUTS);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_IN_OUT_MAP);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_ATTACHED_DISPLAYS);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_HOT_PLUG_SUPPORT);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_ACTIVE_HOT_PLUG);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_INTR_EVENT_SOURCE);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_INPUT_TIMINGS_PART1);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_INPUT_TIMINGS_PART2);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_OUTPUT_TIMINGS_PART1);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_OUTPUT_TIMINGS_PART2);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART1);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_PREFERRED_INPUT_TIMING_PART2);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_INPUT_PIXEL_CLOCK_RANGE);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_OUTPUT_PIXEL_CLOCK_RANGE);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_SUPPORTED_CLOCK_RATE_MULTS);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_CLOCK_RATE_MULT);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_SUPPORTED_TV_FORMATS);
+    I830DumpSDVOCmd (s, SDVO_CMD_GET_TV_FORMAT);
+}
+		 
+void
+I830DumpSDVO (ScrnInfoPtr pScrn)
+{
+    I830Ptr pI830 = I830PTR(pScrn);
+    I830SDVOPtr	s;
+    int	i;
+
+    for (i = 0; i < 4; i++) {
+	s = pI830->output[i].sdvo_drv;
+	if (s)
+	    I830DumpOneSDVO (s);
+    }
+}
diff --git a/src/i830_sdvo_regs.h b/src/i830_sdvo_regs.h
index 37cfcf2..a35d5a4 100644
--- a/src/i830_sdvo_regs.h
+++ b/src/i830_sdvo_regs.h
@@ -157,7 +157,9 @@
 #define SDVO_CMD_SET_CLOCK_RATE_MULT			0x21
 # define SDVO_CLOCK_RATE_MULT_1X				(1 << 0)
 # define SDVO_CLOCK_RATE_MULT_2X				(1 << 1)
+# define SDVO_CLOCK_RATE_MULT_3X				(1 << 2)
 # define SDVO_CLOCK_RATE_MULT_4X				(1 << 3)
+# define SDVO_CLOCK_RATE_MULT_5X				(1 << 4)
 
 #define SDVO_CMD_GET_SUPPORTED_TV_FORMATS		0x27
 



More information about the xorg-commit mailing list