xf86-video-nv: src/g80_output.c src/g80_sor.c src/g80_type.h

Aaron Plattner aplattner at kemper.freedesktop.org
Mon Jun 30 10:37:53 PDT 2008


 src/g80_output.c |   62 ++++++++++++++++++++++++++++++++++++++++++++-----------
 src/g80_sor.c    |   19 +++++++++++++++-
 src/g80_type.h   |    5 +++-
 3 files changed, 71 insertions(+), 15 deletions(-)

New commits:
commit 91d8778176f1db54c8222a95315610a043198648
Author: Aaron Plattner <aplattner at nvidia.com>
Date:   Sun Jun 29 21:26:57 2008 -0700

    G80: Handle extended I2C ports and LVDS panels with DDC-based EDIDs.

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 */
diff --git a/src/g80_sor.c b/src/g80_sor.c
index 202e838..c1ef42d 100644
--- a/src/g80_sor.c
+++ b/src/g80_sor.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
@@ -143,7 +143,15 @@ G80SorDetect(xf86OutputPtr output)
 static xf86OutputStatus
 G80SorLVDSDetect(xf86OutputPtr output)
 {
-    /* Assume LVDS is always connected */
+    G80OutputPrivPtr pPriv = output->driver_private;
+
+    if(pPriv->i2c) {
+        /* If LVDS has an I2C port, use the normal probe routine to get the
+         * EDID, if possible. */
+        G80SorDetect(output);
+    }
+
+    /* Ignore G80SorDetect and assume LVDS is always connected */
     return XF86OutputStatusConnected;
 }
 
@@ -242,6 +250,13 @@ static DisplayModePtr
 G80SorGetLVDSModes(xf86OutputPtr output)
 {
     G80OutputPrivPtr pPriv = output->driver_private;
+
+    /* If an EDID was read during detection, use the modes from that. */
+    DisplayModePtr modes = G80OutputGetDDCModes(output);
+    if(modes)
+        return modes;
+
+    /* Otherwise, feed in the mode we read during initialization. */
     return xf86DuplicateMode(pPriv->nativeMode);
 }
 
diff --git a/src/g80_type.h b/src/g80_type.h
index 30ef3fe..0cebae7 100644
--- a/src/g80_type.h
+++ b/src/g80_type.h
@@ -7,6 +7,8 @@
 #include <xf86Crtc.h>
 #include <xf86int10.h>
 
+#define G80_NUM_I2C_PORTS 6
+
 typedef enum Head {
     HEAD0 = 0,
     HEAD1
@@ -51,10 +53,11 @@ typedef struct G80Rec {
     struct {
         ORNum           dac;
         ORNum           sor;
-    } i2cMap[4];
+    } i2cMap[G80_NUM_I2C_PORTS];
     struct {
         Bool            present;
         ORNum           or;
+        int             i2cPort;
     } lvds;
     unsigned            loadVal;
 


More information about the xorg-commit mailing list