$NetBSD: patch-ab,v 1.1 2007/04/09 14:28:01 xtraeme Exp $

--- src/tdfx_driver.c.orig	2006-09-02 14:03:07.000000000 -0400
+++ src/tdfx_driver.c	2007-03-27 23:19:20.000000000 -0400
@@ -141,6 +141,8 @@
 static void TDFXDisplayPowerManagementSet(ScrnInfoPtr pScrn, 
 					int PowerManagermentMode, int flags);
 
+static xf86MonPtr doTDFXDDC(ScrnInfoPtr pScrn);
+
 _X_EXPORT DriverRec TDFX = {
   TDFX_VERSION,
   TDFX_DRIVER_NAME,
@@ -217,6 +219,13 @@
 static const char *ddcSymbols[] = {
     "xf86PrintEDID",
     "xf86SetDDCproperties",
+    "xf86DoEDID_DDC2",
+    NULL
+};
+
+static const char *i2cSymbols[] = {
+    "xf86CreateI2CBusRec",
+    "xf86I2CBusInit",
     NULL
 };
 
@@ -677,6 +686,7 @@
 {
   TDFXPtr pTDFX;
   ClockRangePtr clockRanges;
+  xf86MonPtr pMon;
   int i;
   MessageType from;
   int flags24;
@@ -978,32 +988,6 @@
   availableMem = pScrn->videoRam - 4096 -
 		 (((255 <= CMDFIFO_PAGES) ? 255 : CMDFIFO_PAGES) << 12);
 
-  i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
-			pScrn->display->modes, clockRanges,
-			0, 320, 2048, 16*pScrn->bitsPerPixel, 
-			200, 2047,
-			pScrn->display->virtualX, pScrn->display->virtualY,
-			availableMem, LOOKUP_BEST_REFRESH);
-
-  if (i==-1) {
-    TDFXFreeRec(pScrn);
-    return FALSE;
-  }
-
-  xf86PruneDriverModes(pScrn);
-
-  if (!i || !pScrn->modes) {
-    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
-    TDFXFreeRec(pScrn);
-    return FALSE;
-  }
-
-  xf86SetCrtcForModes(pScrn, 0);
-
-  pScrn->currentMode = pScrn->modes;
-
-  xf86PrintModes(pScrn);
-
   xf86SetDpi(pScrn, 0, 0);
 
   if (!xf86LoadSubModule(pScrn, "fb")) {
@@ -1046,18 +1030,26 @@
     xf86LoaderReqSymLists(ramdacSymbols, NULL);
   }
 
-#if USE_INT10
-#if !defined(__powerpc__)
-  /* Load DDC if needed */
-  /* This gives us DDC1 - we should be able to get DDC2B using i2c */
+  if (!xf86LoadSubModule(pScrn, "i2c")) {
+    TDFXFreeRec(pScrn);
+    return FALSE;
+  }
+  xf86LoaderReqSymLists(i2cSymbols, NULL);
+
   if (!xf86LoadSubModule(pScrn, "ddc")) {
     TDFXFreeRec(pScrn);
     return FALSE;
   }
   xf86LoaderReqSymLists(ddcSymbols, NULL);
 
-  /* Initialize DDC1 if possible */
-  if (xf86LoadSubModule(pScrn, "vbe")) {
+  pMon = doTDFXDDC(pScrn);
+  if (pMon != NULL) {
+    xf86SetDDCproperties(pScrn, xf86PrintEDID(pMon));
+  } else {
+    /* Initialize DDC1 if possible */
+#if USE_INT10
+#if !defined(__powerpc__)
+    if (xf86LoadSubModule(pScrn, "vbe")) {
       xf86MonPtr pMon;
       vbeInfoPtr pVbe = VBEInit(NULL,pTDFX->pEnt->index);
 
@@ -1065,14 +1057,40 @@
       pMon = vbeDoEDID(pVbe, NULL);
       vbeFree(pVbe);
       xf86SetDDCproperties(pScrn,xf86PrintEDID(pMon));
-  }
+    }
 #endif
 #endif
+  }
 
   if (xf86ReturnOptValBool(pTDFX->Options, OPTION_USE_PIO, FALSE)) {
     pTDFX->usePIO=TRUE;
   }
 
+  i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
+		pScrn->display->modes, clockRanges,
+		0, 320, 2048, 16*pScrn->bitsPerPixel,
+		200, 2047,
+		pScrn->display->virtualX, pScrn->display->virtualY,
+		availableMem, LOOKUP_BEST_REFRESH);
+  if (i==-1) {
+    TDFXFreeRec(pScrn);
+    return FALSE;
+  }
+
+  xf86PruneDriverModes(pScrn);
+
+  if (!i || !pScrn->modes) {
+    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
+    TDFXFreeRec(pScrn);
+    return FALSE;
+  }
+
+  xf86SetCrtcForModes(pScrn, 0);
+
+  pScrn->currentMode = pScrn->modes;
+
+  xf86PrintModes(pScrn);
+
 #if X_BYTE_ORDER == X_BIG_ENDIAN
   pTDFX->ModeReg.miscinit0 = pTDFX->readLong(pTDFX, MISCINIT0);
   pTDFX->SavedReg.miscinit0 = pTDFX->ModeReg.miscinit0;
@@ -1640,8 +1658,8 @@
 
   /* Calculate the CRTC values */
   hd = (mode->CrtcHDisplay>>3)-1;
-  hss = (mode->CrtcHSyncStart>>3);
-  hse = (mode->CrtcHSyncEnd>>3);
+  hss = (mode->CrtcHSyncStart>>3)-1;
+  hse = (mode->CrtcHSyncEnd>>3)-1;
   ht = (mode->CrtcHTotal>>3)-5;
   hbs = (mode->CrtcHBlankStart>>3)-1;
   hbe = (mode->CrtcHBlankEnd>>3)-1;
@@ -2524,3 +2542,80 @@
   dacmode|=state;
   pTDFX->writeLong(pTDFX, DACMODE, dacmode);
 }
+
+void
+TDFXPutBits(I2CBusPtr b, int  scl, int  sda)
+{
+  TDFXPtr pTDFX;
+  CARD32 reg;
+
+  pTDFX = b->DriverPrivate.ptr;
+  reg = pTDFX->readLong(pTDFX, VIDSERIALPARALLELPORT);
+  reg = (reg & ~(VSP_SDA0_OUT | VSP_SCL0_OUT)) |
+        (scl ? VSP_SCL0_OUT : 0) |
+        (sda ? VSP_SDA0_OUT : 0);
+  pTDFX->writeLong(pTDFX, VIDSERIALPARALLELPORT, reg);
+  (void)pTDFX->readLong(pTDFX, VIDSERIALPARALLELPORT); /* flush */
+}
+
+void
+TDFXGetBits(I2CBusPtr b, int *scl, int *sda)
+{
+  TDFXPtr pTDFX;
+  CARD32 reg;
+
+  pTDFX = b->DriverPrivate.ptr;
+
+  reg = pTDFX->readLong(pTDFX, VIDSERIALPARALLELPORT);
+  *sda = (reg & VSP_SDA0_IN) ? 1 : 0;
+  *scl = (reg & VSP_SCL0_IN) ? 1 : 0;
+}
+
+static xf86MonPtr
+doTDFXDDC(ScrnInfoPtr pScrn)
+{
+  TDFXPtr pTDFX;
+  I2CBusPtr pI2CBus;
+  xf86MonPtr pMon = NULL;
+  CARD32 reg;
+
+  pTDFX = TDFXPTR(pScrn);
+
+  if (!(pI2CBus = xf86CreateI2CBusRec()))
+  {
+    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unable to allocate I2C Bus record.\n");
+    return NULL;
+  }
+
+  /* Fill in generic structure fields */
+  pI2CBus->BusName           = "DDC";
+  pI2CBus->scrnIndex         = pScrn->scrnIndex;
+  pI2CBus->I2CPutBits        = TDFXPutBits;
+  pI2CBus->I2CGetBits        = TDFXGetBits;
+
+  pI2CBus->DriverPrivate.ptr = pTDFX;
+
+  pI2CBus->ByteTimeout = 2200;
+  pI2CBus->StartTimeout = 550;
+  pI2CBus->BitTimeout = 40;
+  /*pI2CBus->ByteTimeout = 40;*/
+  pI2CBus->AcknTimeout = 40;
+
+#if 1
+  reg = pTDFX->readLong(pTDFX, VIDSERIALPARALLELPORT);
+  pTDFX->writeLong(pTDFX, VIDSERIALPARALLELPORT, reg | VSP_ENABLE_IIC0);
+#else
+  pTDFX->writeLong(pTDFX, VIDSERIALPARALLELPORT, 0xcffc0020);
+#endif
+
+  if (xf86I2CBusInit(pI2CBus))
+  {
+    pMon = xf86DoEDID_DDC2(pScrn->scrnIndex, pI2CBus);
+    if (pMon == NULL)
+      xf86Msg(X_WARNING, "No DDC2 capable monitor found\n");
+    xf86DestroyI2CBusRec(pI2CBus, TRUE, TRUE);
+  }
+  pTDFX->writeLong(pTDFX, VIDSERIALPARALLELPORT, reg);
+
+  return pMon;
+}
