summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Plattner <aplattner@nvidia.com>2007-03-27 17:12:21 -0700
committerAaron Plattner <aplattner@nvidia.com>2007-03-27 17:12:21 -0700
commit2d8d5bd597d760968b683d41ced6a0a76518ec26 (patch)
tree9476bfa3e635c4c73a557aafdd36c86f5d5799c1
parent4b8ed8497a9ab6ef1316bfcce9f31d96dd4b3540 (diff)
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.
-rw-r--r--src/g80_dac.c18
-rw-r--r--src/g80_driver.c2
-rw-r--r--src/g80_output.c77
-rw-r--r--src/g80_output.h5
-rw-r--r--src/g80_sor.c20
5 files changed, 96 insertions, 26 deletions
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
@@ -76,6 +76,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);
G80OutputPrivPtr pPriv = output->driver_private;
@@ -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 <X11/Xatom.h>
-
#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;