summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/i810_reg.h3
-rw-r--r--src/i830.h2
-rw-r--r--src/i830_debug.c13
-rw-r--r--src/i830_debug.h1
-rw-r--r--src/i830_display.c30
-rw-r--r--src/i830_driver.c32
-rw-r--r--src/i830_modes.c366
-rw-r--r--src/i830_sdvo.c91
-rw-r--r--src/i830_sdvo_regs.h2
9 files changed, 510 insertions, 30 deletions
diff --git a/src/i810_reg.h b/src/i810_reg.h
index 53c65bbf..92e3342f 100644
--- a/src/i810_reg.h
+++ b/src/i810_reg.h
@@ -748,6 +748,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# 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 THE SOFTWARE.
#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 c60bfbe6..8cf7b711 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(ScreenPtr pScreen);
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 b5442577..6d43cd60 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(ScrnInfoPtr pScrn)
}
}
}
+
+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 269f03ea..a8e38398 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 95fa936d..d49da1f5 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, DisplayModePtr pMode, int 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, 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, DisplayModePtr pMode, int pipe)
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, DisplayModePtr pMode, int pipe)
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, DisplayModePtr pMode, int pipe)
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, DisplayModePtr pMode, int pipe)
/* 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 425ddd5c..c91bf432 100644
--- a/src/i830_driver.c
+++ b/src/i830_driver.c
@@ -2386,14 +2386,17 @@ I830BIOSPreInit(ScrnInfoPtr pScrn, int flags)
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 flags)
}
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 flags)
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 16576bbe..ce86d8ca 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 579f77ab..7d239759 100644
--- a/src/i830_sdvo.c
+++ b/src/i830_sdvo.c
@@ -139,7 +139,7 @@ I830SDVOSetTargetInput(I830SDVOPtr s, Bool target_1, Bool target_2)
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, Bool target_1, Bool target_2)
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_sdvo_dtd *dtd, CARD8 cmd)
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_sdvo_dtd *dtd, CARD8 cmd)
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, DisplayModePtr mode)
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, DisplayModePtr mode)
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, DisplayModePtr mode)
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 output_index)
&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, int output_index)
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 output_index, CARD32 output_device)
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 37cfcf2e..a35d5a4e 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