diff options
-rw-r--r-- | src/i810_reg.h | 3 | ||||
-rw-r--r-- | src/i830.h | 2 | ||||
-rw-r--r-- | src/i830_debug.c | 13 | ||||
-rw-r--r-- | src/i830_debug.h | 1 | ||||
-rw-r--r-- | src/i830_display.c | 30 | ||||
-rw-r--r-- | src/i830_driver.c | 32 | ||||
-rw-r--r-- | src/i830_modes.c | 366 | ||||
-rw-r--r-- | src/i830_sdvo.c | 91 | ||||
-rw-r--r-- | src/i830_sdvo_regs.h | 2 |
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 @@ -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 |