summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/nv.man4
-rw-r--r--src/g80_dac.c11
-rw-r--r--src/g80_display.c46
-rw-r--r--src/g80_display.h4
-rw-r--r--src/g80_output.c10
-rw-r--r--src/g80_output.h2
-rw-r--r--src/g80_sor.c143
7 files changed, 147 insertions, 73 deletions
diff --git a/man/nv.man b/man/nv.man
index f27cd6d..7b9d946 100644
--- a/man/nv.man
+++ b/man/nv.man
@@ -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,