summaryrefslogtreecommitdiff
path: root/src/g80_output.c
diff options
context:
space:
mode:
authorAaron Plattner <aplattner@nvidia.com>2008-06-29 21:26:57 -0700
committerAaron Plattner <aplattner@nvidia.com>2008-06-30 10:36:16 -0700
commit91d8778176f1db54c8222a95315610a043198648 (patch)
tree980f9052c04c037e861bd449c062301d8f5c87de /src/g80_output.c
parentdb768cf105956fbea39383a2214227782bf827b0 (diff)
G80: Handle extended I2C ports and LVDS panels with DDC-based EDIDs.
Diffstat (limited to 'src/g80_output.c')
-rw-r--r--src/g80_output.c62
1 files changed, 50 insertions, 12 deletions
diff --git a/src/g80_output.c b/src/g80_output.c
index 1cf4669..e28b584 100644
--- a/src/g80_output.c
+++ b/src/g80_output.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007 NVIDIA, Corporation
+ * Copyright (c) 2007-2008 NVIDIA, Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
@@ -76,7 +76,7 @@ static Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv)
CARD32 b;
/* Clear the i2c map to invalid */
- for(i = 0; i < 4; i++)
+ for(i = 0; i < G80_NUM_I2C_PORTS; i++)
pNv->i2cMap[i].dac = pNv->i2cMap[i].sor = -1;
if(*(CARD16*)pNv->table1 != 0xaa55) goto fail;
@@ -162,6 +162,27 @@ static Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv)
case 3: /* LVDS */
pNv->lvds.present = TRUE;
pNv->lvds.or = or;
+ pNv->lvds.i2cPort = -1;
+
+ if(port == 15) {
+ xf86DrvMsg(scrnIndex, X_INFO, "LVDS has no I2C port\n");
+ break;
+ }
+ if(port >= table3Entries) {
+ xf86DrvMsg(scrnIndex, X_WARNING,
+ "LVDS: invalid port %d\n", port);
+ break;
+ }
+ b = *(CARD32*)&table3[table3EntSize * port];
+ port = b & 0xff;
+ portType = b >> 24;
+ if(portType != 5) {
+ xf86DrvMsg(scrnIndex, X_WARNING,
+ "LVDS: invalid port type %d\n", portType);
+ break;
+ }
+ pNv->lvds.i2cPort = port;
+
break;
default:
@@ -172,7 +193,7 @@ static Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv)
xf86DrvMsg(scrnIndex, X_PROBED, "Connector map:\n");
if(pNv->lvds.present)
xf86DrvMsg(scrnIndex, X_PROBED, " [N/A] -> SOR%i (LVDS)\n", pNv->lvds.or);
- for(i = 0; i < 4; i++) {
+ for(i = 0; i < G80_NUM_I2C_PORTS; 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)
@@ -190,21 +211,24 @@ fail:
return FALSE;
}
+static uint32_t i2cAddr(const int port)
+{
+ const uint32_t base = (port > 3) ? 0x0000E1E0 : 0x0000E138;
+ return base + port * 0x18;
+}
+
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;
+ pNv->reg[i2cAddr(b->DriverPrivate.val)/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];
+ val = pNv->reg[i2cAddr(b->DriverPrivate.val)/4];
*clock = !!(val & 1);
*data = !!(val & 2);
}
@@ -272,14 +296,15 @@ ProbeDDC(I2CBusPtr i2c)
ScrnInfoPtr pScrn = xf86Screens[i2c->scrnIndex];
G80Ptr pNv = G80PTR(pScrn);
xf86MonPtr monInfo = NULL;
- const int bus = i2c->DriverPrivate.val, off = bus * 0x18;
+ const int bus = i2c->DriverPrivate.val;
+ const uint32_t addr = i2cAddr(bus);
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Probing for EDID on I2C bus %i...\n", bus);
- pNv->reg[(0x0000E138+off)/4] = 7;
+ pNv->reg[addr/4] = 7;
/* Should probably use xf86OutputGetEDID here */
monInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, i2c);
- pNv->reg[(0x0000E138+off)/4] = 3;
+ pNv->reg[addr/4] = 3;
if(monInfo) {
xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
@@ -376,7 +401,7 @@ G80CreateOutputs(ScrnInfoPtr pScrn)
return FALSE;
/* For each DDC port, create an output for the attached ORs */
- for(i = 0; i < 4; i++) {
+ for(i = 0; i < G80_NUM_I2C_PORTS; i++) {
xf86OutputPtr dac = NULL, sor = NULL;
I2CBusPtr i2c;
char i2cName[16];
@@ -420,6 +445,19 @@ G80CreateOutputs(ScrnInfoPtr pScrn)
G80OutputPrivPtr pPriv = lvds->driver_private;
pPriv->scale = G80_SCALE_ASPECT;
+
+ if(pNv->lvds.i2cPort != -1) {
+ I2CBusPtr i2c;
+ char i2cName[16];
+
+ snprintf(i2cName, sizeof(i2cName), "I2C%i (LVDS)", pNv->lvds.i2cPort);
+ pPriv->i2c = G80I2CInit(pScrn, i2cName, pNv->lvds.i2cPort);
+ if(!pPriv->i2c) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to initialize I2C for port %i (LVDS)!\n",
+ pNv->lvds.i2cPort);
+ }
+ }
}
/* For each output, set the crtc and clone masks */