diff options
author | Eric Anholt <anholt@FreeBSD.org> | 2006-06-26 07:46:28 +0200 |
---|---|---|
committer | Eric Anholt <anholt@FreeBSD.org> | 2006-06-26 07:46:28 +0200 |
commit | 52e8231a19f28bd4744f983aee2197a18c20aa3a (patch) | |
tree | 4182ebb54e0930e089f9c05168eedad2790bf8e0 /src/i830_modes.c | |
parent | f5e5f8aeddb3e0d6d073471aeff6176fb54576e2 (diff) |
Major cleanup of mode reprobing:
- Don't mess with pScrn->monitor->Modes, and instead make our own availModes.
- Don't re-program the pipe with the same values (no flicker at xrandr)
- Move a bunch of stuff that should be exposed through the public API (probably)
to i830_xf86Modes.c
- Use a table with established modes plus GTF to come up with modes from EDID,
instead of trying to walk and find one in pScrn->monitor->Modes. I think
this is correct.
- Reset clone state if we've detected new pipes, which should turn on the
cursor.
Diffstat (limited to 'src/i830_modes.c')
-rw-r--r-- | src/i830_modes.c | 297 |
1 files changed, 131 insertions, 166 deletions
diff --git a/src/i830_modes.c b/src/i830_modes.c index faa843e3..e1e5fd53 100644 --- a/src/i830_modes.c +++ b/src/i830_modes.c @@ -42,9 +42,11 @@ #include <stdio.h> #include <string.h> +#include <assert.h> #include "xf86.h" #include "i830.h" +#include "i830_xf86Modes.h" #include <math.h> @@ -92,6 +94,8 @@ static struct {720, 400, 70}, }; +#define DEBUG_REPROBE 1 + extern const int i830refreshes[]; void @@ -157,6 +161,23 @@ I830PrintModes(ScrnInfoPtr scrp) } while (p != NULL && p != scrp->modes); } +/** + * Allocates and returns a copy of pMode, including pointers within pMode. + */ +static DisplayModePtr +I830DuplicateMode(DisplayModePtr pMode) +{ + DisplayModePtr pNew; + + pNew = xnfalloc(sizeof(DisplayModeRec)); + *pNew = *pMode; + pNew->next = NULL; + pNew->prev = NULL; + pNew->name = xnfstrdup(pMode->name); + + return pNew; +} + /* This function will sort all modes according to their resolution. * Highest resolution first. */ @@ -200,32 +221,31 @@ I830xf86SortModes(DisplayModePtr *new, DisplayModePtr *first, } /** - * Calculates the vertical refresh of a mode. + * Gets a new pointer to a VESA established mode. * - * Taken directly from xf86Mode.c, and should be put back there --Eric Anholt + * \param i index into the VESA established modes table. */ -static double -I830ModeVRefresh(DisplayModePtr mode) +static DisplayModePtr +I830GetVESAEstablishedMode(ScrnInfoPtr pScrn, int i) { - double refresh = 0.0; + DisplayModePtr pMode; - if (mode->VRefresh > 0.0) - refresh = mode->VRefresh; - else if (mode->HTotal > 0 && mode->VTotal > 0) { - refresh = mode->Clock * 1000.0 / mode->HTotal / mode->VTotal; - if (mode->Flags & V_INTERLACE) - refresh *= 2.0; - if (mode->Flags & V_DBLSCAN) - refresh /= 2.0; - if (mode->VScan > 1) - refresh /= (float)(mode->VScan); + for (pMode = I830xf86DefaultModes; pMode->name != NULL; pMode = pMode->next) + { + if (pMode->HDisplay == est_timings[i].hsize && + pMode->VDisplay == est_timings[i].vsize && + fabs(I830ModeVRefresh(pMode) - est_timings[i].refresh) < 1.0) + { + DisplayModePtr pNew = I830DuplicateMode(pMode); + pNew->VRefresh = I830ModeVRefresh(pMode); + return pNew; + } } - return refresh; + return NULL; } DisplayModePtr I830GetDDCModes(ScrnInfoPtr pScrn, xf86MonPtr ddc) { - DisplayModePtr p; DisplayModePtr last = NULL; DisplayModePtr new = NULL; DisplayModePtr first = NULL; @@ -289,7 +309,16 @@ DisplayModePtr I830GetDDCModes(ScrnInfoPtr pScrn, xf86MonPtr ddc) for (j = 0; j < 8; j++) { if (ddc->timings2[j].hsize == 0 || ddc->timings2[j].vsize == 0) continue; +#if 1 + new = i830GetGTF(ddc->timings2[j].hsize, ddc->timings2[j].vsize, + ddc->timings2[j].refresh, FALSE, FALSE); + new->status = MODE_OK; + new->type |= M_T_DEFAULT; + + I830xf86SortModes(&new, &first, &last); +#else for (p = pScrn->monitor->Modes; p && p->next; p = p->next->next) { + /* Ignore all double scan modes */ if ((ddc->timings2[j].hsize == p->HDisplay) && (ddc->timings2[j].vsize == p->VDisplay)) { @@ -318,39 +347,27 @@ DisplayModePtr I830GetDDCModes(ScrnInfoPtr pScrn, xf86MonPtr ddc) } } } +#endif } /* Search thru established modes from EDID */ tmp = (ddc->timings1.t1 << 8) | ddc->timings1.t2; for (j = 0; j < 16; j++) { if (tmp & (1 << j)) { - for (p = pScrn->monitor->Modes; p && p->next; p = p->next->next) { - if ((est_timings[j].hsize == p->HDisplay) && - (est_timings[j].vsize == p->VDisplay)) { - float refresh = - (float)p->Clock * 1000.0 / p->HTotal / p->VTotal; - float err = (float)est_timings[j].refresh - refresh; - - if (err < 1.0) { - /* Is this good enough? */ - new = xnfcalloc(1, sizeof (DisplayModeRec)); - memcpy(new, p, sizeof(DisplayModeRec)); - new->name = xnfalloc(strlen(p->name) + 1); - strcpy(new->name, p->name); - new->status = MODE_OK; - new->type = M_T_DEFAULT; - - count++; - - xf86DrvMsg(pScrn->scrnIndex, X_INFO, - "Valid Mode from established timing " - "table: %s\n", new->name); - - I830xf86SortModes(&new, &first, &last); - break; - } - } - } + DisplayModePtr pNew; + + pNew = I830GetVESAEstablishedMode(pScrn, j); + assert(pNew != NULL); /* We'd better have all the est. modes. */ + + new->status = MODE_OK; + new->type = M_T_DEFAULT; + + count++; + + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Valid Mode from established " + "timing table: %s\n", new->name); + + I830xf86SortModes(&new, &first, &last); } } @@ -512,23 +529,6 @@ i830GetLVDSModes(ScrnInfoPtr pScrn, char **ppModeName) } /** - * Allocates and returns a copy of pMode, including pointers within pMode. - */ -static DisplayModePtr -I830DuplicateMode(DisplayModePtr pMode) -{ - DisplayModePtr pNew; - - pNew = xnfalloc(sizeof(DisplayModeRec)); - *pNew = *pMode; - pNew->next = NULL; - pNew->prev = NULL; - pNew->name = xnfstrdup(pMode->name); - - return pNew; -} - -/** * Injects a list of probed modes into another mode list. * * Take the doubly-linked list of modes we've probed for the device, and injects @@ -536,11 +536,11 @@ I830DuplicateMode(DisplayModePtr pMode) * eventual call to xf86ValidateModes will do this for us. I think. */ int -I830InjectProbedModes(ScrnInfoPtr pScrn, DisplayModePtr modeList, - char **ppModeName, DisplayModePtr addModes) +I830InjectProbedModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList, + DisplayModePtr addModes) { - DisplayModePtr last = modeList; - DisplayModePtr first = modeList; + DisplayModePtr last = *modeList; + DisplayModePtr first = *modeList; DisplayModePtr addMode; int count = 0; @@ -551,12 +551,14 @@ I830InjectProbedModes(ScrnInfoPtr pScrn, DisplayModePtr modeList, */ pNew = I830DuplicateMode(addMode); +#if 0 /* If the user didn't specify any modes, mark all modes as M_T_USERDEF * so that we can cycle through them, etc. XXX: really need to? */ - if (ppModeName[0] == NULL) { + if (pScrn->display->modes[0] == NULL) { pNew->type |= M_T_USERDEF; } +#endif /* Insert pNew into modeList */ if (last) { @@ -571,6 +573,7 @@ I830InjectProbedModes(ScrnInfoPtr pScrn, DisplayModePtr modeList, count++; } + *modeList = first; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Injected %d modes detected from the monitor\n", count); @@ -578,97 +581,6 @@ I830InjectProbedModes(ScrnInfoPtr pScrn, DisplayModePtr modeList, return count; } -/* - * I830xf86SetModeCrtc - * - * Initialises the Crtc parameters for a mode. The initialisation includes - * adjustments for interlaced and double scan modes. - * - * Taken directly from xf86Mode.c:xf86SetModeCrtc -- Eric Anholt - * (and it should be put back there!) - */ -static void -I830xf86SetModeCrtc(DisplayModePtr p, int adjustFlags) -{ - if ((p == NULL) || ((p->type & M_T_CRTC_C) == M_T_BUILTIN)) - return; - - p->CrtcHDisplay = p->HDisplay; - p->CrtcHSyncStart = p->HSyncStart; - p->CrtcHSyncEnd = p->HSyncEnd; - p->CrtcHTotal = p->HTotal; - p->CrtcHSkew = p->HSkew; - p->CrtcVDisplay = p->VDisplay; - p->CrtcVSyncStart = p->VSyncStart; - p->CrtcVSyncEnd = p->VSyncEnd; - p->CrtcVTotal = p->VTotal; - if (p->Flags & V_INTERLACE) { - if (adjustFlags & INTERLACE_HALVE_V) { - p->CrtcVDisplay /= 2; - p->CrtcVSyncStart /= 2; - p->CrtcVSyncEnd /= 2; - p->CrtcVTotal /= 2; - } - /* Force interlaced modes to have an odd VTotal */ - /* maybe we should only do this when INTERLACE_HALVE_V is set? */ - p->CrtcVTotal |= 1; - } - - if (p->Flags & V_DBLSCAN) { - p->CrtcVDisplay *= 2; - p->CrtcVSyncStart *= 2; - p->CrtcVSyncEnd *= 2; - p->CrtcVTotal *= 2; - } - if (p->VScan > 1) { - p->CrtcVDisplay *= p->VScan; - p->CrtcVSyncStart *= p->VScan; - p->CrtcVSyncEnd *= p->VScan; - p->CrtcVTotal *= p->VScan; - } - p->CrtcHAdjusted = FALSE; - p->CrtcVAdjusted = FALSE; - - /* - * XXX - * - * The following is taken from VGA, but applies to other cores as well. - */ - p->CrtcVBlankStart = min(p->CrtcVSyncStart, p->CrtcVDisplay); - p->CrtcVBlankEnd = max(p->CrtcVSyncEnd, p->CrtcVTotal); - if ((p->CrtcVBlankEnd - p->CrtcVBlankStart) >= 127) { - /* - * V Blanking size must be < 127. - * Moving blank start forward is safer than moving blank end - * back, since monitors clamp just AFTER the sync pulse (or in - * the sync pulse), but never before. - */ - p->CrtcVBlankStart = p->CrtcVBlankEnd - 127; - /* - * If VBlankStart is now > VSyncStart move VBlankStart - * to VSyncStart using the maximum width that fits into - * VTotal. - */ - if (p->CrtcVBlankStart > p->CrtcVSyncStart) { - p->CrtcVBlankStart = p->CrtcVSyncStart; - p->CrtcVBlankEnd = min(p->CrtcHBlankStart + 127, p->CrtcVTotal); - } - } - p->CrtcHBlankStart = min(p->CrtcHSyncStart, p->CrtcHDisplay); - p->CrtcHBlankEnd = max(p->CrtcHSyncEnd, p->CrtcHTotal); - - if ((p->CrtcHBlankEnd - p->CrtcHBlankStart) >= 63 * 8) { - /* - * H Blanking size must be < 63*8. Same remark as above. - */ - p->CrtcHBlankStart = p->CrtcHBlankEnd - 63 * 8; - if (p->CrtcHBlankStart > p->CrtcHSyncStart) { - p->CrtcHBlankStart = p->CrtcHSyncStart; - p->CrtcHBlankEnd = min(p->CrtcHBlankStart + 63 * 8, p->CrtcHTotal); - } - } -} - /** * Performs probing of modes available on the output connected to the given * pipe. @@ -740,14 +652,21 @@ I830ReprobePipeModeList(ScrnInfoPtr pScrn, int pipe) /* Set the vertical refresh, which is used by the choose-best-mode-per-pipe * code later on. */ +#ifdef DEBUG_REPROBE + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Printing probed modes for pipe %d\n", + pipe); +#endif for (pMode = pI830->pipeModes[pipe]; pMode != NULL; pMode = pMode->next) { pMode->VRefresh = I830ModeVRefresh(pMode); +#ifdef DEBUG_REPROBE + PrintModeline(pScrn->scrnIndex, pMode); +#endif } } /** * This function removes a mode from a list of modes. It should probably be - * moved to xf86Mode.c + * moved to xf86Mode.c. * * There are different types of mode lists: * @@ -795,8 +714,9 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time) I830Ptr pI830 = I830PTR(pScrn); ClockRangePtr clockRanges; int n, pipe; - DisplayModePtr saved_mode; + DisplayModePtr saved_mode, availModes; int saved_virtualX = 0, saved_virtualY = 0, saved_displayWidth = 0; + Bool pipes_reconfigured = FALSE; for (pipe = 0; pipe < MAX_DISPLAY_PIPES; pipe++) { I830ReprobePipeModeList(pScrn, pipe); @@ -815,6 +735,9 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time) } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Enabled new CRT on pipe A\n"); + pipes_reconfigured = TRUE; + /* Clear the current mode, so we reprogram the pipe for sure. */ + memset(&pI830->pipeCurMode[0], 0, sizeof(pI830->pipeCurMode[0])); } } else if (((pI830->operatingDevices >> 8) & 0xff) == PIPE_NONE) { pI830->operatingDevices |= PIPE_CRT << 8; @@ -825,19 +748,24 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time) } else { xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Enabled new CRT on pipe B\n"); + pipes_reconfigured = TRUE; + /* Clear the current mode, so we reprogram the pipe for sure. */ + memset(&pI830->pipeCurMode[1], 0, sizeof(pI830->pipeCurMode[1])); } } } - /* XXX: Clean out modes previously injected by our driver */ - + /* Start by injecting the XFree86 default modes and user-configured + * modelines. XXX: This actually isn't of use if we've got any DDC, as DDC + * currently has higher priority than the validated modelist. We need to + * deal with that. + */ + I830InjectProbedModes(pScrn, &availModes, pScrn->monitor->Modes); if (pI830->pipeModes[0] != NULL) { - I830InjectProbedModes(pScrn, pScrn->monitor->Modes, - pScrn->display->modes, pI830->pipeModes[0]); + I830InjectProbedModes(pScrn, &availModes, pI830->pipeModes[0]); } if (pI830->pipeModes[1] != NULL) { - I830InjectProbedModes(pScrn, pScrn->monitor->Modes, - pScrn->display->modes, pI830->pipeModes[1]); + I830InjectProbedModes(pScrn, &availModes, pI830->pipeModes[1]); } /* @@ -872,7 +800,7 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time) * capabilities of our pipes. */ n = xf86ValidateModes(pScrn, - pScrn->monitor->Modes, /* availModes */ + availModes, /* availModes */ pScrn->display->modes, /* modeNames */ clockRanges, /* clockRanges */ !first_time ? &pScrn->displayWidth : NULL, /* linePitches */ @@ -886,6 +814,12 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time) pI830->FbMapSize, /* apertureSize */ LOOKUP_BEST_REFRESH /* strategy */); + /* availModes is of no more use as xf86ValidateModes has duplicated and + * saved everything it needs. + */ + while (availModes != NULL) + xf86DeleteMode(&availModes, availModes); + if (!first_time) { /* Restore things that may have been damaged by xf86ValidateModes. */ pScrn->virtualX = saved_virtualX; @@ -900,6 +834,19 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time) xf86PruneDriverModes(pScrn); +#if DEBUG_REPROBE + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Modes post revalidate\n"); + do { + DisplayModePtr pMode; + + for (pMode = pScrn->modes; ; pMode = pMode->next) { + PrintModeline(pScrn->scrnIndex, pMode); + if (pMode->next == pScrn->modes) + break; + } + } while (0); +#endif + /* Try to find the closest equivalent of the previous mode pointer to switch * to. */ @@ -926,5 +873,23 @@ I830ValidateXF86ModeList(ScrnInfoPtr pScrn, Bool first_time) xfree(saved_mode->name); xfree(saved_mode); } + + /* If we've enabled/disabled some pipes, we need to reset cloning mode + * support. + */ + if (pipes_reconfigured) { + if ((pI830->operatingDevices & 0x00ff) && + (pI830->operatingDevices & 0xff00)) + { + pI830->Clone = TRUE; + } else { + pI830->Clone = FALSE; + } + + /* If HW cursor currently showing, reset cursor state */ + if (pI830->CursorInfoRec && !pI830->SWCursor && pI830->cursorOn) + pI830->CursorInfoRec->ShowCursor(pScrn); + } + return n; } |