From 7e0e5c1fb38922add99db33f282baf2ee1531685 Mon Sep 17 00:00:00 2001 From: root Date: Sun, 11 Mar 2007 00:38:11 -0800 Subject: Initial RandR 1.2 support for G80. Mostly just rearranging code. --- src/g80_output.c | 264 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 src/g80_output.c (limited to 'src/g80_output.c') diff --git a/src/g80_output.c b/src/g80_output.c new file mode 100644 index 0000000..481dd85 --- /dev/null +++ b/src/g80_output.c @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2007 NVIDIA, Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "g80_type.h" +#include "g80_ddc.h" +#include "g80_output.h" + +static Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv) +{ + unsigned char *table2; + unsigned char headerSize, entries; + int i; + CARD16 a; + CARD32 b; + + /* Clear the i2c map to invalid */ + for(i = 0; i < 4; i++) + pNv->i2cMap[i].dac = pNv->i2cMap[i].sor = -1; + + if(*(CARD16*)pNv->table1 != 0xaa55) goto fail; + + a = *(CARD16*)(pNv->table1 + 0x36); + table2 = (unsigned char*)pNv->table1 + a; + + if(table2[0] != 0x40) goto fail; + + b = *(CARD32*)(table2 + 6); + if(b != 0x4edcbdcb) goto fail; + + headerSize = table2[1]; + entries = table2[2]; + + for(i = 0; i < entries; i++) { + CARD32 type, port; + ORNum or; + + b = *(CARD32*)&table2[headerSize + 8*i]; + type = b & 0xf; + port = (b >> 4) & 0xf; + or = ffs((b >> 24) & 0xf) - 1; + + if(type < 4 && port != 0xf) { + switch(type) { + case 0: /* CRT */ + case 1: /* TV */ + if(pNv->i2cMap[port].dac != -1) { + xf86DrvMsg(scrnIndex, X_WARNING, + "DDC routing table corrupt! DAC %i -> %i " + "for port %i\n", + or, pNv->i2cMap[port].dac, port); + } + pNv->i2cMap[port].dac = or; + break; + case 2: /* TMDS */ + case 3: /* LVDS */ + if(pNv->i2cMap[port].sor != -1) + xf86DrvMsg(scrnIndex, X_WARNING, + "DDC routing table corrupt! SOR %i -> %i " + "for port %i\n", + or, pNv->i2cMap[port].sor, port); + pNv->i2cMap[port].sor = or; + break; + } + } + } + + xf86DrvMsg(scrnIndex, X_PROBED, "I2C map:\n"); + for(i = 0; i < 4; i++) { + if(pNv->i2cMap[i].dac != -1) + xf86DrvMsg(scrnIndex, X_PROBED, " Bus %i -> DAC%i\n", i, pNv->i2cMap[i].dac); + if(pNv->i2cMap[i].sor != -1) + xf86DrvMsg(scrnIndex, X_PROBED, " Bus %i -> SOR%i\n", i, pNv->i2cMap[i].sor); + } + + return TRUE; + +fail: + xf86DrvMsg(scrnIndex, X_ERROR, "Couldn't find the DDC routing table. " + "Mode setting will probably fail!\n"); + return FALSE; +} + +static void G80_I2CPutBits(I2CBusPtr b, int clock, int data) +{ + G80Ptr pNv = G80PTR(xf86Screens[b->scrnIndex]); + const int off = b->DriverPrivate.val * 0x18; + + pNv->reg[(0x0000E138+off)/4] = 4 | clock | data << 1; +} + +static void G80_I2CGetBits(I2CBusPtr b, int *clock, int *data) +{ + G80Ptr pNv = G80PTR(xf86Screens[b->scrnIndex]); + const int off = b->DriverPrivate.val * 0x18; + unsigned char val; + + val = pNv->reg[(0x0000E138+off)/4]; + *clock = !!(val & 1); + *data = !!(val & 2); +} + +Bool +G80I2CInit(xf86OutputPtr output, const int port) +{ + G80OutputPrivPtr pPriv = output->driver_private; + I2CBusPtr i2c; + + /* Allocate the I2C bus structure */ + i2c = xf86CreateI2CBusRec(); + if(!i2c) return FALSE; + + i2c->BusName = output->name; + i2c->scrnIndex = output->scrn->scrnIndex; + i2c->I2CPutBits = G80_I2CPutBits; + i2c->I2CGetBits = G80_I2CGetBits; + i2c->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */ + i2c->StartTimeout = 550; + i2c->BitTimeout = 40; + i2c->ByteTimeout = 40; + i2c->AcknTimeout = 40; + i2c->DriverPrivate.val = port; + + if(xf86I2CBusInit(i2c)) { + pPriv->i2c = i2c; + return TRUE; + } else { + xfree(i2c); + return FALSE; + } +} + +void +G80OutputSetPClk(xf86OutputPtr output, int pclk) +{ + G80OutputPrivPtr pPriv = output->driver_private; + pPriv->set_pclk(output, pclk); +} + +int +G80OutputModeValid(xf86OutputPtr output, DisplayModePtr mode) +{ + if(mode->Clock > 400000 || mode->Clock < 25000) + return MODE_CLOCK_RANGE; + + return MODE_OK; +} + +Bool +G80OutputModeFixup(xf86OutputPtr output, DisplayModePtr mode, + DisplayModePtr adjusted_mode) +{ + return TRUE; +} + +void +G80OutputPrepare(xf86OutputPtr output) +{ +} + +void +G80OutputCommit(xf86OutputPtr output) +{ +} + +DisplayModePtr +G80OutputGetDDCModes(xf86OutputPtr output) +{ + ScrnInfoPtr pScrn = output->scrn; + 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); + 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 ? + "DFP" : "CRT"); + xf86PrintEDID(monInfo); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, " ... none found\n"); + } + + return modes; +} + +void +G80OutputDestroy(xf86OutputPtr output) +{ + G80OutputPrivPtr pPriv = output->driver_private; + + xf86DestroyI2CBusRec(pPriv->i2c, TRUE, TRUE); + pPriv->i2c = NULL; +} + +Bool +G80CreateOutputs(ScrnInfoPtr pScrn) +{ + G80Ptr pNv = G80PTR(pScrn); + xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); + int i, count = 0; + + if(!G80ReadPortMapping(pScrn->scrnIndex, pNv)) + return FALSE; + + /* For each DDC port, create an output for the attached ORs */ + for(i = 0; i < 4; i++) { + if(pNv->i2cMap[i].dac != -1) + G80CreateDac(pScrn, pNv->i2cMap[i].dac, i); + if(pNv->i2cMap[i].sor != -1) + G80CreateSor(pScrn, pNv->i2cMap[i].sor, i); + } + + /* For each output, set the crtc and clone masks */ + for(i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + G80OutputPrivPtr pPriv = output->driver_private; + + /* Any output can connect to any head */ + output->possible_crtcs = 0x3; + output->possible_clones = 0; + } + + return TRUE; +} + -- cgit v1.2.3 From ad4abba20b8a6db7b52898bc7159809539cbed43 Mon Sep 17 00:00:00 2001 From: Aaron Plattner Date: Tue, 27 Mar 2007 14:49:30 -0700 Subject: Fix warnings. --- src/g80_output.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/g80_output.c') diff --git a/src/g80_output.c b/src/g80_output.c index 481dd85..b56bf00 100644 --- a/src/g80_output.c +++ b/src/g80_output.c @@ -236,7 +236,7 @@ G80CreateOutputs(ScrnInfoPtr pScrn) { G80Ptr pNv = G80PTR(pScrn); xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); - int i, count = 0; + int i; if(!G80ReadPortMapping(pScrn->scrnIndex, pNv)) return FALSE; @@ -252,7 +252,6 @@ G80CreateOutputs(ScrnInfoPtr pScrn) /* For each output, set the crtc and clone masks */ for(i = 0; i < xf86_config->num_output; i++) { xf86OutputPtr output = xf86_config->output[i]; - G80OutputPrivPtr pPriv = output->driver_private; /* Any output can connect to any head */ output->possible_crtcs = 0x3; -- cgit v1.2.3 From 4b8ed8497a9ab6ef1316bfcce9f31d96dd4b3540 Mon Sep 17 00:00:00 2001 From: Aaron Plattner Date: Tue, 27 Mar 2007 13:33:11 -0700 Subject: G80: Create output partners. Each pair of outputs shares an I2C rec. This will be used in a future change for the detect and get_modes routines. --- src/g80_output.c | 56 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 13 deletions(-) (limited to 'src/g80_output.c') diff --git a/src/g80_output.c b/src/g80_output.c index b56bf00..d847e2e 100644 --- a/src/g80_output.c +++ b/src/g80_output.c @@ -127,18 +127,17 @@ static void G80_I2CGetBits(I2CBusPtr b, int *clock, int *data) *data = !!(val & 2); } -Bool -G80I2CInit(xf86OutputPtr output, const int port) +static I2CBusPtr +G80I2CInit(ScrnInfoPtr pScrn, const char *name, const int port) { - G80OutputPrivPtr pPriv = output->driver_private; I2CBusPtr i2c; /* Allocate the I2C bus structure */ i2c = xf86CreateI2CBusRec(); - if(!i2c) return FALSE; + if(!i2c) return NULL; - i2c->BusName = output->name; - i2c->scrnIndex = output->scrn->scrnIndex; + i2c->BusName = strdup(name); + i2c->scrnIndex = pScrn->scrnIndex; i2c->I2CPutBits = G80_I2CPutBits; i2c->I2CGetBits = G80_I2CGetBits; i2c->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */ @@ -149,11 +148,10 @@ G80I2CInit(xf86OutputPtr output, const int port) i2c->DriverPrivate.val = port; if(xf86I2CBusInit(i2c)) { - pPriv->i2c = i2c; - return TRUE; + return i2c; } else { xfree(i2c); - return FALSE; + return NULL; } } @@ -227,7 +225,10 @@ G80OutputDestroy(xf86OutputPtr output) { G80OutputPrivPtr pPriv = output->driver_private; - xf86DestroyI2CBusRec(pPriv->i2c, TRUE, TRUE); + if(pPriv->partner) + ((G80OutputPrivPtr)pPriv->partner->driver_private)->partner = NULL; + else + xf86DestroyI2CBusRec(pPriv->i2c, TRUE, TRUE); pPriv->i2c = NULL; } @@ -243,10 +244,40 @@ G80CreateOutputs(ScrnInfoPtr pScrn) /* For each DDC port, create an output for the attached ORs */ for(i = 0; i < 4; i++) { + xf86OutputPtr dac = NULL, sor = NULL; + I2CBusPtr i2c; + char i2cName[16]; + + if(pNv->i2cMap[i].dac == -1 && pNv->i2cMap[i].sor == -1) + /* No outputs on this port */ + continue; + + snprintf(i2cName, sizeof(i2cName), "I2C%i", i); + i2c = G80I2CInit(pScrn, i2cName, i); + if(!i2c) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Failed to initialize I2C for port %i.\n", + i); + continue; + } + if(pNv->i2cMap[i].dac != -1) - G80CreateDac(pScrn, pNv->i2cMap[i].dac, i); + dac = G80CreateDac(pScrn, pNv->i2cMap[i].dac); if(pNv->i2cMap[i].sor != -1) - G80CreateSor(pScrn, pNv->i2cMap[i].sor, i); + sor = G80CreateSor(pScrn, pNv->i2cMap[i].sor); + + if(dac) { + G80OutputPrivPtr pPriv = dac->driver_private; + + pPriv->partner = sor; + pPriv->i2c = i2c; + } + if(sor) { + G80OutputPrivPtr pPriv = sor->driver_private; + + pPriv->partner = dac; + pPriv->i2c = i2c; + } } /* For each output, set the crtc and clone masks */ @@ -260,4 +291,3 @@ G80CreateOutputs(ScrnInfoPtr pScrn) return TRUE; } - -- cgit v1.2.3 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_output.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 11 deletions(-) (limited to 'src/g80_output.c') 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 -- cgit v1.2.3 From 2971fd0a18e947c5d39d6af78b0b77d6e4fe00d8 Mon Sep 17 00:00:00 2001 From: Aaron Plattner Date: Fri, 20 Apr 2007 13:40:33 -0700 Subject: Remove unused g80_ddc.h. --- src/g80_output.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/g80_output.c') diff --git a/src/g80_output.c b/src/g80_output.c index a3b28a5..fd32f98 100644 --- a/src/g80_output.c +++ b/src/g80_output.c @@ -30,7 +30,6 @@ #include #include "g80_type.h" -#include "g80_ddc.h" #include "g80_output.h" static Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv) -- cgit v1.2.3