diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2007-07-24 20:36:04 -0700 |
---|---|---|
committer | Aaron Plattner <aaron@weasel.nvidia.com> | 2007-07-24 20:36:04 -0700 |
commit | 08b68473351081fe1ed96ba7e206ed0d301b8a91 (patch) | |
tree | daa06fca777bb68abb66d8b124d0c533edc5109f | |
parent | f0ebb42ee94eac4b294d12d02f4406a444b347ff (diff) |
G80: Allow DVI scaling.
Revamp how the scaling code works. When a mode is set on a DVI output,
determine the current preferred mode and scale to that. Add a new scaling
option, "off", which disables scaling and scans out the actual timings in the
mode to be set.
-rw-r--r-- | man/nv.man | 4 | ||||
-rw-r--r-- | src/g80_dac.c | 11 | ||||
-rw-r--r-- | src/g80_display.c | 46 | ||||
-rw-r--r-- | src/g80_display.h | 4 | ||||
-rw-r--r-- | src/g80_output.c | 10 | ||||
-rw-r--r-- | src/g80_output.h | 2 | ||||
-rw-r--r-- | src/g80_sor.c | 143 |
7 files changed, 147 insertions, 73 deletions
@@ -175,8 +175,10 @@ Valid values: .B scale Control how the image is scaled to fit the flat panel. Note that some flat panels perform their own scaling, overriding this option. +.RB \*q off \*q +is not valid for laptop flat panels (LVDS). Valid values: -.RB \*q aspect "\*q, \*q" fill "\*q, and \*q" center \*q. +.RB \*q off "\*q, \*q" aspect "\*q, \*q" fill "\*q, and \*q" center \*q. Default: .RB \*q aspect \*q. .\" ******************** end G80 section ******************** diff --git a/src/g80_dac.c b/src/g80_dac.c index 7848de2..30413cd 100644 --- a/src/g80_dac.c +++ b/src/g80_dac.c @@ -76,6 +76,13 @@ G80DacDPMSSet(xf86OutputPtr output, int mode) pNv->reg[(0x0061A004+off)/4] = tmp; } +Bool +G80DacModeFixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + return TRUE; +} + static void G80DacModeSet(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode) @@ -99,6 +106,8 @@ G80DacModeSet(xf86OutputPtr output, DisplayModePtr mode, C(0x00000404 + dacOff, (adjusted_mode->Flags & V_NHSYNC) ? 1 : 0 | (adjusted_mode->Flags & V_NVSYNC) ? 2 : 0); + + G80CrtcSetScale(output->crtc, adjusted_mode, G80_SCALE_OFF); } /* @@ -165,7 +174,7 @@ static const xf86OutputFuncsRec G80DacOutputFuncs = { .save = NULL, .restore = NULL, .mode_valid = G80OutputModeValid, - .mode_fixup = G80OutputModeFixup, + .mode_fixup = G80DacModeFixup, .prepare = G80OutputPrepare, .commit = G80OutputCommit, .mode_set = G80DacModeSet, diff --git a/src/g80_display.c b/src/g80_display.c index 14352aa..542a68e 100644 --- a/src/g80_display.c +++ b/src/g80_display.c @@ -42,7 +42,6 @@ typedef struct G80CrtcPrivRec { Bool cursorVisible; Bool skipModeFixup; Bool dither; - enum G80ScaleMode scale; } G80CrtcPrivRec, *G80CrtcPrivPtr; static void G80CrtcShowHideCursor(xf86CrtcPtr crtc, Bool show, Bool update); @@ -307,31 +306,35 @@ G80DispShutdown(ScrnInfoPtr pScrn) while((pNv->reg[0x61C830/4] & 0x10000000)); } +void +G80CrtcDoModeFixup(DisplayModePtr dst, const DisplayModePtr src) +{ + /* Magic mode timing fudge factor */ + const int fudge = ((src->Flags & V_INTERLACE) && (src->Flags & V_DBLSCAN)) ? 2 : 1; + const int interlaceDiv = (src->Flags & V_INTERLACE) ? 2 : 1; + + /* Stash the src timings in the Crtc fields in dst */ + dst->CrtcHBlankStart = src->CrtcVTotal << 16 | src->CrtcHTotal; + dst->CrtcHSyncEnd = ((src->CrtcVSyncEnd - src->CrtcVSyncStart) / interlaceDiv - 1) << 16 | + (src->CrtcHSyncEnd - src->CrtcHSyncStart - 1); + dst->CrtcHBlankEnd = ((src->CrtcVBlankEnd - src->CrtcVSyncStart) / interlaceDiv - fudge) << 16 | + (src->CrtcHBlankEnd - src->CrtcHSyncStart - 1); + dst->CrtcHTotal = ((src->CrtcVTotal - src->CrtcVSyncStart + src->CrtcVBlankStart) / interlaceDiv - fudge) << 16 | + (src->CrtcHTotal - src->CrtcHSyncStart + src->CrtcHBlankStart - 1); + dst->CrtcHSkew = ((src->CrtcVTotal + src->CrtcVBlankEnd - src->CrtcVSyncStart) / 2 - 2) << 16 | + ((2*src->CrtcVTotal - src->CrtcVSyncStart + src->CrtcVBlankStart) / 2 - 2); +} + static Bool G80CrtcModeFixup(xf86CrtcPtr crtc, DisplayModePtr mode, DisplayModePtr adjusted_mode) { G80CrtcPrivPtr pPriv = crtc->driver_private; - int interlaceDiv, fudge; if(pPriv->skipModeFixup) return TRUE; - /* Magic mode timing fudge factor */ - fudge = ((adjusted_mode->Flags & V_INTERLACE) && (adjusted_mode->Flags & V_DBLSCAN)) ? 2 : 1; - interlaceDiv = (adjusted_mode->Flags & V_INTERLACE) ? 2 : 1; - - /* Stash the mode timings in the Crtc fields in adjusted_mode */ - adjusted_mode->CrtcHBlankStart = mode->CrtcVTotal << 16 | mode->CrtcHTotal; - adjusted_mode->CrtcHSyncEnd = ((mode->CrtcVSyncEnd - mode->CrtcVSyncStart) / interlaceDiv - 1) << 16 | - (mode->CrtcHSyncEnd - mode->CrtcHSyncStart - 1); - adjusted_mode->CrtcHBlankEnd = ((mode->CrtcVBlankEnd - mode->CrtcVSyncStart) / interlaceDiv - fudge) << 16 | - (mode->CrtcHBlankEnd - mode->CrtcHSyncStart - 1); - adjusted_mode->CrtcHTotal = ((mode->CrtcVTotal - mode->CrtcVSyncStart + mode->CrtcVBlankStart) / interlaceDiv - fudge) << 16 | - (mode->CrtcHTotal - mode->CrtcHSyncStart + mode->CrtcHBlankStart - 1); - adjusted_mode->CrtcHSkew = ((mode->CrtcVTotal + mode->CrtcVBlankEnd - mode->CrtcVSyncStart) / 2 - 2) << 16 | - ((2*mode->CrtcVTotal - mode->CrtcVSyncStart + mode->CrtcVBlankStart) / 2 - 2); - + G80CrtcDoModeFixup(adjusted_mode, mode); return TRUE; } @@ -365,7 +368,6 @@ G80CrtcModeSet(xf86CrtcPtr crtc, DisplayModePtr mode, case 24: C(0x00000870 + headOff, 0xCF00); break; } G80CrtcSetDither(crtc, pPriv->dither, FALSE); - G80CrtcSetScale(crtc, adjusted_mode, pPriv->scale, FALSE); C(0x000008A8 + headOff, 0x40000); C(0x000008C0 + headOff, y << 16 | x); C(0x000008C8 + headOff, VDisplay << 16 | HDisplay); @@ -504,20 +506,19 @@ static void ComputeAspectScale(DisplayModePtr mode, int *outX, int *outY) } void G80CrtcSetScale(xf86CrtcPtr crtc, DisplayModePtr mode, - enum G80ScaleMode scale, Bool update) + enum G80ScaleMode scale) { ScrnInfoPtr pScrn = crtc->scrn; G80CrtcPrivPtr pPriv = crtc->driver_private; const int headOff = 0x400 * pPriv->head; int outX, outY; - pPriv->scale = scale; - switch(scale) { case G80_SCALE_ASPECT: ComputeAspectScale(mode, &outX, &outY); break; + case G80_SCALE_OFF: case G80_SCALE_FILL: outX = mode->CrtcHDisplay; outY = mode->CrtcVDisplay; @@ -537,8 +538,6 @@ void G80CrtcSetScale(xf86CrtcPtr crtc, DisplayModePtr mode, } C(0x000008D8 + headOff, outY << 16 | outX); C(0x000008DC + headOff, outY << 16 | outX); - - if(update) C(0x00000080, 0); } static void @@ -600,7 +599,6 @@ G80DispCreateCrtcs(ScrnInfoPtr pScrn) g80_crtc = xnfcalloc(sizeof(*g80_crtc), 1); g80_crtc->head = head; g80_crtc->dither = pNv->Dither; - g80_crtc->scale = G80_SCALE_ASPECT; crtc->driver_private = g80_crtc; } } diff --git a/src/g80_display.h b/src/g80_display.h index 8bd3bfb..2031fed 100644 --- a/src/g80_display.h +++ b/src/g80_display.h @@ -1,4 +1,5 @@ enum G80ScaleMode { + G80_SCALE_OFF, G80_SCALE_ASPECT, G80_SCALE_FILL, G80_SCALE_CENTER, @@ -13,12 +14,13 @@ void G80DispCommand(ScrnInfoPtr, CARD32 addr, CARD32 data); Head G80CrtcGetHead(xf86CrtcPtr); +void G80CrtcDoModeFixup(DisplayModePtr dst, const DisplayModePtr src); void G80CrtcBlankScreen(xf86CrtcPtr, Bool blank); void G80CrtcEnableCursor(xf86CrtcPtr, Bool update); void G80CrtcDisableCursor(xf86CrtcPtr, Bool update); void G80CrtcSetCursorPosition(xf86CrtcPtr, int x, int y); void G80CrtcSkipModeFixup(xf86CrtcPtr); void G80CrtcSetDither(xf86CrtcPtr, Bool dither, Bool update); -void G80CrtcSetScale(xf86CrtcPtr, DisplayModePtr, enum G80ScaleMode, Bool update); +void G80CrtcSetScale(xf86CrtcPtr, DisplayModePtr, enum G80ScaleMode); void G80DispCreateCrtcs(ScrnInfoPtr pScrn); diff --git a/src/g80_output.c b/src/g80_output.c index 448864f..8bd2096 100644 --- a/src/g80_output.c +++ b/src/g80_output.c @@ -29,6 +29,7 @@ #include <strings.h> #include "g80_type.h" +#include "g80_display.h" #include "g80_output.h" static Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv) @@ -173,13 +174,6 @@ G80OutputModeValid(xf86OutputPtr output, DisplayModePtr mode) return MODE_OK; } -Bool -G80OutputModeFixup(xf86OutputPtr output, DisplayModePtr mode, - DisplayModePtr adjusted_mode) -{ - return TRUE; -} - void G80OutputPrepare(xf86OutputPtr output) { @@ -329,12 +323,14 @@ G80CreateOutputs(ScrnInfoPtr pScrn) pPriv->partner = sor; pPriv->i2c = i2c; + pPriv->scale = G80_SCALE_OFF; } if(sor) { G80OutputPrivPtr pPriv = sor->driver_private; pPriv->partner = dac; pPriv->i2c = i2c; + pPriv->scale = G80_SCALE_ASPECT; } } diff --git a/src/g80_output.h b/src/g80_output.h index 900b76d..33514c6 100644 --- a/src/g80_output.h +++ b/src/g80_output.h @@ -3,6 +3,7 @@ typedef struct G80OutputPrivRec { ORNum or; PanelType panelType; DisplayModePtr nativeMode; + enum G80ScaleMode scale; xf86OutputPtr partner; I2CBusPtr i2c; @@ -14,7 +15,6 @@ typedef struct G80OutputPrivRec { void G80OutputSetPClk(xf86OutputPtr, int pclk); int G80OutputModeValid(xf86OutputPtr, DisplayModePtr); -Bool G80OutputModeFixup(xf86OutputPtr, DisplayModePtr mode, DisplayModePtr adjusted_mode); void G80OutputPrepare(xf86OutputPtr); void G80OutputCommit(xf86OutputPtr); void G80OutputPartnersDetect(xf86OutputPtr dac, xf86OutputPtr sor, I2CBusPtr i2c); diff --git a/src/g80_sor.c b/src/g80_sor.c index 8ba3425..c98b66d 100644 --- a/src/g80_sor.c +++ b/src/g80_sor.c @@ -122,6 +122,8 @@ G80SorModeSet(xf86OutputPtr output, DisplayModePtr mode, type | ((adjusted_mode->Flags & V_NHSYNC) ? 0x1000 : 0) | ((adjusted_mode->Flags & V_NVSYNC) ? 0x2000 : 0)); + + G80CrtcSetScale(output->crtc, adjusted_mode, pPriv->scale); } static xf86OutputStatus @@ -151,49 +153,90 @@ G80SorDestroy(xf86OutputPtr output) G80OutputDestroy(output); - if(pPriv->nativeMode) { - if(pPriv->nativeMode->name) - xfree(pPriv->nativeMode->name); - xfree(pPriv->nativeMode); - } + xf86DeleteMode(&pPriv->nativeMode, pPriv->nativeMode); xfree(output->driver_private); output->driver_private = NULL; } -/******************** LVDS ********************/ +static void G80SorSetModeBackend(DisplayModePtr dst, const DisplayModePtr src) +{ + // Stash the backend mode timings from src into dst + dst->Clock = src->Clock; + dst->Flags = src->Flags; + dst->CrtcHDisplay = src->CrtcHDisplay; + dst->CrtcHBlankStart = src->CrtcHBlankStart; + dst->CrtcHSyncStart = src->CrtcHSyncStart; + dst->CrtcHSyncEnd = src->CrtcHSyncEnd; + dst->CrtcHBlankEnd = src->CrtcHBlankEnd; + dst->CrtcHTotal = src->CrtcHTotal; + dst->CrtcHSkew = src->CrtcHSkew; + dst->CrtcVDisplay = src->CrtcVDisplay; + dst->CrtcVBlankStart = src->CrtcVBlankStart; + dst->CrtcVSyncStart = src->CrtcVSyncStart; + dst->CrtcVSyncEnd = src->CrtcVSyncEnd; + dst->CrtcVBlankEnd = src->CrtcVBlankEnd; + dst->CrtcVTotal = src->CrtcVTotal; + dst->CrtcHAdjusted = src->CrtcHAdjusted; + dst->CrtcVAdjusted = src->CrtcVAdjusted; +} + static Bool -G80SorModeFixupScale(xf86OutputPtr output, DisplayModePtr mode, - DisplayModePtr adjusted_mode) +G80SorModeFixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) { G80OutputPrivPtr pPriv = output->driver_private; DisplayModePtr native = pPriv->nativeMode; - // Stash the saved mode timings in adjusted_mode - adjusted_mode->Clock = native->Clock; - adjusted_mode->Flags = native->Flags; - adjusted_mode->CrtcHDisplay = native->CrtcHDisplay; - adjusted_mode->CrtcHBlankStart = native->CrtcHBlankStart; - adjusted_mode->CrtcHSyncStart = native->CrtcHSyncStart; - adjusted_mode->CrtcHSyncEnd = native->CrtcHSyncEnd; - adjusted_mode->CrtcHBlankEnd = native->CrtcHBlankEnd; - adjusted_mode->CrtcHTotal = native->CrtcHTotal; - adjusted_mode->CrtcHSkew = native->CrtcHSkew; - adjusted_mode->CrtcVDisplay = native->CrtcVDisplay; - adjusted_mode->CrtcVBlankStart = native->CrtcVBlankStart; - adjusted_mode->CrtcVSyncStart = native->CrtcVSyncStart; - adjusted_mode->CrtcVSyncEnd = native->CrtcVSyncEnd; - adjusted_mode->CrtcVBlankEnd = native->CrtcVBlankEnd; - adjusted_mode->CrtcVTotal = native->CrtcVTotal; - adjusted_mode->CrtcHAdjusted = native->CrtcHAdjusted; - adjusted_mode->CrtcVAdjusted = native->CrtcVAdjusted; - - // This mode is already "fixed" - G80CrtcSkipModeFixup(output->crtc); + if(native && pPriv->scale != G80_SCALE_OFF) { + G80SorSetModeBackend(adjusted_mode, native); + // This mode is already "fixed" + G80CrtcSkipModeFixup(output->crtc); + } return TRUE; } +static Bool +G80SorTMDSModeFixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + int scrnIndex = output->scrn->scrnIndex; + G80OutputPrivPtr pPriv = output->driver_private; + DisplayModePtr modes = output->probed_modes; + + xf86DeleteMode(&pPriv->nativeMode, pPriv->nativeMode); + + if(modes) { + // Find the preferred mode and use that as the "native" mode. + // If no preferred mode is available, use the first one. + DisplayModePtr mode; + + // Find the preferred mode. + for(mode = modes; mode; mode = mode->next) { + if(mode->type & M_T_PREFERRED) { + xf86DrvMsgVerb(scrnIndex, X_INFO, 5, + "%s: preferred mode is %s\n", + output->name, mode->name); + break; + } + } + + // XXX: May not want to allow scaling if no preferred mode is found. + if(!mode) { + mode = modes; + xf86DrvMsgVerb(scrnIndex, X_INFO, 5, + "%s: no preferred mode found, using %s\n", + output->name, mode->name); + } + + pPriv->nativeMode = xf86DuplicateMode(mode); + G80CrtcDoModeFixup(pPriv->nativeMode, mode); + } + + return G80SorModeFixup(output, mode, adjusted_mode); +} + static DisplayModePtr G80SorGetLVDSModes(xf86OutputPtr output) { @@ -268,6 +311,8 @@ G80SorCreateResources(xf86OutputPtr output) static Bool G80SorSetProperty(xf86OutputPtr output, Atom prop, RRPropertyValuePtr val) { + G80OutputPrivPtr pPriv = output->driver_private; + if(prop == properties.dither.atom) { INT32 i; @@ -282,13 +327,13 @@ G80SorSetProperty(xf86OutputPtr output, Atom prop, RRPropertyValuePtr val) return TRUE; } else if(prop == properties.scale.atom) { const char *s; - enum G80ScaleMode scale; - DisplayModePtr mode; + enum G80ScaleMode oldScale, scale; int i; const struct { const char *name; enum G80ScaleMode scale; } modes[] = { + { "off", G80_SCALE_OFF }, { "aspect", G80_SCALE_ASPECT }, { "fill", G80_SCALE_FILL }, { "center", G80_SCALE_CENTER }, @@ -310,12 +355,34 @@ G80SorSetProperty(xf86OutputPtr output, Atom prop, RRPropertyValuePtr val) } if(!modes[i].name) return FALSE; + if(scale == G80_SCALE_OFF && pPriv->panelType == LVDS) + // LVDS requires scaling + return FALSE; - /* Need to construct an adjusted mode */ - mode = xf86DuplicateMode(&output->crtc->mode); - output->funcs->mode_fixup(output, &output->crtc->mode, mode); - G80CrtcSetScale(output->crtc, mode, scale, TRUE); - xfree(mode); + oldScale = pPriv->scale; + pPriv->scale = scale; + if(output->crtc) { + xf86CrtcPtr crtc = output->crtc; + + if(!xf86CrtcSetMode(crtc, &crtc->desiredMode, crtc->desiredRotation, + crtc->desiredX, crtc->desiredY)) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "Failed to set scaling to %s for output %s\n", + modes[i].name, output->name); + + // Restore old scale and try again. + pPriv->scale = oldScale; + if(!xf86CrtcSetMode(crtc, &crtc->desiredMode, + crtc->desiredRotation, crtc->desiredX, + crtc->desiredY)) { + xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, + "Failed to restore old scaling for output %s\n", + output->name); + } + + return FALSE; + } + } return TRUE; } @@ -328,7 +395,7 @@ static const xf86OutputFuncsRec G80SorTMDSOutputFuncs = { .save = NULL, .restore = NULL, .mode_valid = G80TMDSModeValid, - .mode_fixup = G80OutputModeFixup, + .mode_fixup = G80SorTMDSModeFixup, .prepare = G80OutputPrepare, .commit = G80OutputCommit, .mode_set = G80SorModeSet, @@ -346,7 +413,7 @@ static const xf86OutputFuncsRec G80SorLVDSOutputFuncs = { .save = NULL, .restore = NULL, .mode_valid = G80LVDSModeValid, - .mode_fixup = G80SorModeFixupScale, + .mode_fixup = G80SorModeFixup, .prepare = G80OutputPrepare, .commit = G80OutputCommit, .mode_set = G80SorModeSet, |