From 2d8d5bd597d760968b683d41ced6a0a76518ec26 Mon Sep 17 00:00:00 2001 From: Aaron Plattner Date: Tue, 27 Mar 2007 17:12:21 -0700 Subject: G80: Improve output detection. Detect output status for paired outputs together and cache status until the BlockHandler to avoid redundantly probing for EDIDs or performing load detection. --- src/g80_dac.c | 18 +++++++++++-- src/g80_driver.c | 2 ++ src/g80_output.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++-------- src/g80_output.h | 5 ++++ src/g80_sor.c | 20 ++++++--------- 5 files changed, 96 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/g80_dac.c b/src/g80_dac.c index bb86748..ac82616 100644 --- a/src/g80_dac.c +++ b/src/g80_dac.c @@ -75,6 +75,19 @@ G80DacModeSet(xf86OutputPtr output, DisplayModePtr mode, */ static xf86OutputStatus G80DacDetect(xf86OutputPtr output) +{ + G80OutputPrivPtr pPriv = output->driver_private; + + /* Assume physical status isn't going to change before the BlockHandler */ + if(pPriv->cached_status != XF86OutputStatusUnknown) + return pPriv->cached_status; + + G80OutputPartnersDetect(output, pPriv->partner, pPriv->i2c); + return pPriv->cached_status; +} + +Bool +G80DacLoadDetect(xf86OutputPtr output) { ScrnInfoPtr pScrn = output->scrn; G80Ptr pNv = G80PTR(pScrn); @@ -99,11 +112,11 @@ G80DacDetect(xf86OutputPtr output) // Use this DAC if all three channels show load. if((load & 0x38000000) == 0x38000000) { xf86ErrorF("found one!\n"); - return XF86OutputStatusConnected; + return TRUE; } xf86ErrorF("nothing.\n"); - return XF86OutputStatusDisconnected; + return FALSE; } static void @@ -144,6 +157,7 @@ G80CreateDac(ScrnInfoPtr pScrn, ORNum or) pPriv->type = DAC; pPriv->or = or; + pPriv->cached_status = XF86OutputStatusUnknown; pPriv->set_pclk = G80DacSetPClk; output->driver_private = pPriv; output->interlaceAllowed = TRUE; diff --git a/src/g80_driver.c b/src/g80_driver.c index 8dff209..4c72bbb 100644 --- a/src/g80_driver.c +++ b/src/g80_driver.c @@ -482,6 +482,8 @@ G80BlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask) if(pNv->DMAKickoffCallback) (*pNv->DMAKickoffCallback)(pScrnInfo); + G80OutputResetCachedStatus(pScrnInfo); + pScreen->BlockHandler = pNv->BlockHandler; (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); pScreen->BlockHandler = G80BlockHandler; diff --git a/src/g80_output.c b/src/g80_output.c index d847e2e..a3b28a5 100644 --- a/src/g80_output.c +++ b/src/g80_output.c @@ -188,26 +188,21 @@ G80OutputCommit(xf86OutputPtr output) { } -DisplayModePtr -G80OutputGetDDCModes(xf86OutputPtr output) +static xf86MonPtr +ProbeDDC(I2CBusPtr i2c) { - ScrnInfoPtr pScrn = output->scrn; + ScrnInfoPtr pScrn = xf86Screens[i2c->scrnIndex]; G80Ptr pNv = G80PTR(pScrn); - G80OutputPrivPtr pPriv = output->driver_private; - I2CBusPtr i2c = pPriv->i2c; xf86MonPtr monInfo = NULL; - DisplayModePtr modes; const int bus = i2c->DriverPrivate.val, off = bus * 0x18; xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Probing for EDID on I2C bus %i...\n", bus); pNv->reg[(0x0000E138+off)/4] = 7; - monInfo = xf86OutputGetEDID(output, i2c); + /* Should probably use xf86OutputGetEDID here */ + monInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, i2c); pNv->reg[(0x0000E138+off)/4] = 3; - xf86OutputSetEDID(output, monInfo); - modes = xf86OutputGetEDIDModes(output); - if(monInfo) { xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "DDC detected a %s:\n", monInfo->features.input_type ? @@ -217,7 +212,67 @@ G80OutputGetDDCModes(xf86OutputPtr output) xf86DrvMsg(pScrn->scrnIndex, X_INFO, " ... none found\n"); } - return modes; + return monInfo; +} + +/* + * Read an EDID from the i2c port. Perform load detection on the DAC (if + * present) to see if the display is connected via VGA. Sets the cached status + * of both outputs. The status is marked dirty again in the BlockHandler. + */ +void G80OutputPartnersDetect(xf86OutputPtr dac, xf86OutputPtr sor, I2CBusPtr i2c) +{ + xf86MonPtr monInfo = ProbeDDC(i2c); + xf86OutputPtr connected = NULL; + Bool load = dac && G80DacLoadDetect(dac); + + if(dac) { + G80OutputPrivPtr pPriv = dac->driver_private; + + if(load) { + pPriv->cached_status = XF86OutputStatusConnected; + connected = dac; + } else { + pPriv->cached_status = XF86OutputStatusDisconnected; + } + } + + if(sor) { + G80OutputPrivPtr pPriv = sor->driver_private; + + if(monInfo && !load) { + pPriv->cached_status = XF86OutputStatusConnected; + connected = sor; + } else { + pPriv->cached_status = XF86OutputStatusDisconnected; + } + } + + if(connected) + xf86OutputSetEDID(connected, monInfo); +} + +/* + * Reset the cached output status for all outputs. Called from G80BlockHandler. + */ +void +G80OutputResetCachedStatus(ScrnInfoPtr pScrn) +{ + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int i; + + for(i = 0; i < xf86_config->num_output; i++) { + G80OutputPrivPtr pPriv = xf86_config->output[i]->driver_private; + pPriv->cached_status = XF86OutputStatusUnknown; + } +} + +DisplayModePtr +G80OutputGetDDCModes(xf86OutputPtr output) +{ + /* The EDID is read as part of the detect step */ + output->funcs->detect(output); + return xf86OutputGetEDIDModes(output); } void diff --git a/src/g80_output.h b/src/g80_output.h index 819df15..0b666f5 100644 --- a/src/g80_output.h +++ b/src/g80_output.h @@ -5,6 +5,8 @@ typedef struct G80OutputPrivRec { xf86OutputPtr partner; I2CBusPtr i2c; + xf86OutputStatus cached_status; + void (*set_pclk)(xf86OutputPtr, int pclk); } G80OutputPrivRec, *G80OutputPrivPtr; @@ -13,12 +15,15 @@ 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); +void G80OutputResetCachedStatus(ScrnInfoPtr); DisplayModePtr G80OutputGetDDCModes(xf86OutputPtr); void G80OutputDestroy(xf86OutputPtr); Bool G80CreateOutputs(ScrnInfoPtr); /* g80_dac.c */ xf86OutputPtr G80CreateDac(ScrnInfoPtr, ORNum); +Bool G80DacLoadDetect(xf86OutputPtr); /* g80_sor.c */ xf86OutputPtr G80CreateSor(ScrnInfoPtr, ORNum); diff --git a/src/g80_sor.c b/src/g80_sor.c index 55a643f..fe34e7e 100644 --- a/src/g80_sor.c +++ b/src/g80_sor.c @@ -25,8 +25,6 @@ #include "config.h" #endif -#include - #include "g80_type.h" #include "g80_display.h" #include "g80_output.h" @@ -74,20 +72,15 @@ G80SorModeSet(xf86OutputPtr output, DisplayModePtr mode, static xf86OutputStatus G80SorDetect(xf86OutputPtr output) { - return XF86OutputStatusUnknown; -#if 0 - DisplayModePtr modes = output->funcs->get_modes(output); - xf86OutputStatus status; + G80OutputPrivPtr pPriv = output->driver_private; - if(modes) - status = XF86OutputStatusConnected; - else - status = XF86OutputStatusDisconnected; - xfree(modes); + /* Assume physical status isn't going to change before the BlockHandler */ + if(pPriv->cached_status != XF86OutputStatusUnknown) + return pPriv->cached_status; - return status; -#endif + G80OutputPartnersDetect(pPriv->partner, output, pPriv->i2c); + return pPriv->cached_status; } static void @@ -128,6 +121,7 @@ G80CreateSor(ScrnInfoPtr pScrn, ORNum or) pPriv->type = SOR; pPriv->or = or; + pPriv->cached_status = XF86OutputStatusUnknown; pPriv->set_pclk = G80SorSetPClk; output->driver_private = pPriv; output->interlaceAllowed = TRUE; -- cgit v1.2.3