? Makefile
? savage.4.html
? savage._man
? xorg-savage-dualhead.diff
Index: savage_accel.c
===================================================================
RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/savage/savage_accel.c,v
retrieving revision 1.7
diff -u -r1.7 savage_accel.c
--- savage_accel.c	23 Sep 2004 23:28:03 -0000	1.7
+++ savage_accel.c	27 Sep 2004 04:41:17 -0000
@@ -31,6 +31,8 @@
 #include "savage_dri.h"
 #endif
 
+extern int gSavageEntityIndex;
+
 /* Forward declaration of functions used in the driver */
 
 static void SavageSetupForScreenToScreenCopy(
@@ -663,24 +665,35 @@
      *  = 0  standard VGA address and stride registers
      *       are used to control the primary streams
      */
-    OUTREG8(CRT_ADDRESS_REG,0x67); 
-    byte =  INREG8(CRT_DATA_REG) | 0x08;
-    OUTREG8(CRT_DATA_REG,byte);
-    
-    /* IGA 2 */
-    OUTREG16(SEQ_ADDRESS_REG,SELECT_IGA2_READS_WRITES);
-
-    OUTREG8(CRT_ADDRESS_REG,0x67); 
-    byte =  INREG8(CRT_DATA_REG) | 0x08;
-    OUTREG8(CRT_DATA_REG,byte);
+    if (psav->IsPrimary) {
+    	OUTREG8(CRT_ADDRESS_REG,0x67); 
+    	byte =  INREG8(CRT_DATA_REG) | 0x08;
+    	OUTREG8(CRT_DATA_REG,byte);
+    } else if (psav->IsSecondary) {
+    	/* IGA 2 */
+    	OUTREG16(SEQ_ADDRESS_REG,SELECT_IGA2_READS_WRITES);
+
+    	OUTREG8(CRT_ADDRESS_REG,0x67); 
+    	byte =  INREG8(CRT_DATA_REG) | 0x08;
+    	OUTREG8(CRT_DATA_REG,byte);
              
-    OUTREG16(SEQ_ADDRESS_REG,SELECT_IGA1);
-
-#if 0
+    	OUTREG16(SEQ_ADDRESS_REG,SELECT_IGA1);
+    } else {
+    	OUTREG8(CRT_ADDRESS_REG,0x67); 
+    	byte =  INREG8(CRT_DATA_REG) | 0x08;
+    	OUTREG8(CRT_DATA_REG,byte);
+    	/* IGA 2 */
+    	OUTREG16(SEQ_ADDRESS_REG,SELECT_IGA2_READS_WRITES);
+    	OUTREG8(CRT_ADDRESS_REG,0x67); 
+    	byte =  INREG8(CRT_DATA_REG) | 0x08;
+    	OUTREG8(CRT_DATA_REG,byte);             
+    	OUTREG16(SEQ_ADDRESS_REG,SELECT_IGA1);
+    }
     /* Set primary stream to bank 0 */
     OUTREG8(CRT_ADDRESS_REG, MEMORY_CTRL0_REG);/* CRCA */
     byte =  INREG8(CRT_DATA_REG) & ~(MEM_PS1 + MEM_PS2) ;
     OUTREG8(CRT_DATA_REG,byte);
+#if 0
     /*
      * if we have 8MB of frame buffer here then we must really be a 16MB
      * card and that means that the second device is always in the upper
@@ -694,11 +707,19 @@
 #endif
 
     /* MM81C0 and 81C4 are used to control primary stream. */
-    OUTREG32(PRI_STREAM_FBUF_ADDR0,0x00000000);
-    OUTREG32(PRI_STREAM_FBUF_ADDR1,0x00000000);
-    OUTREG32(PRI_STREAM2_FBUF_ADDR0,0x00000000);
-    OUTREG32(PRI_STREAM2_FBUF_ADDR1,0x00000000);
-
+    if (psav->IsPrimary) {
+    	OUTREG32(PRI_STREAM_FBUF_ADDR0,pScrn->fbOffset & 0x7fffff);
+    	OUTREG32(PRI_STREAM_FBUF_ADDR1,pScrn->fbOffset & 0x7fffff);
+    } else if (psav->IsSecondary) {
+    	OUTREG32(PRI_STREAM2_FBUF_ADDR0,pScrn->fbOffset & 0x7fffff);
+    	OUTREG32(PRI_STREAM2_FBUF_ADDR1,pScrn->fbOffset & 0x7fffff);
+    } else {
+    	OUTREG32(PRI_STREAM_FBUF_ADDR0,pScrn->fbOffset & 0x7fffff);
+    	OUTREG32(PRI_STREAM_FBUF_ADDR1,pScrn->fbOffset & 0x7fffff);
+    	OUTREG32(PRI_STREAM2_FBUF_ADDR0,pScrn->fbOffset & 0x7fffff);
+    	OUTREG32(PRI_STREAM2_FBUF_ADDR1,pScrn->fbOffset & 0x7fffff);
+    }
+ 
     /*
      *  Program Primary Stream Stride Register.
      *
@@ -710,28 +731,59 @@
      *  bytes padded up to an even number of tilewidths.
      */
     if (!psav->bTiled) {
-        OUTREG32(PRI_STREAM_STRIDE,
+ 	if (psav->IsPrimary) {
+            OUTREG32(PRI_STREAM_STRIDE,
+                 (((psav->lDelta * 2) << 16) & 0x3FFF0000) |
+                 (psav->lDelta & 0x00003fff));
+	} else if (psav->IsSecondary) {
+            OUTREG32(PRI_STREAM2_STRIDE,
+                 (((psav->lDelta * 2) << 16) & 0x3FFF0000) |
+                 (psav->lDelta & 0x00003fff));
+	} else {
+            OUTREG32(PRI_STREAM_STRIDE,
                  (((psav->lDelta * 2) << 16) & 0x3FFF0000) |
                  (psav->lDelta & 0x00003fff));
-        OUTREG32(PRI_STREAM2_STRIDE,
+            OUTREG32(PRI_STREAM2_STRIDE,
                  (((psav->lDelta * 2) << 16) & 0x3FFF0000) |
                  (psav->lDelta & 0x00003fff));
+	}
+
     } else if (pScrn->bitsPerPixel == 16) {
         /* Scanline-length-in-bytes/128-bytes-per-tile * 256 Qwords/tile */
-        OUTREG32(PRI_STREAM_STRIDE,
+	if (psav->IsPrimary) {
+            OUTREG32(PRI_STREAM_STRIDE,
                  (((psav->lDelta * 2) << 16) & 0x3FFF0000)
                  | 0x80000000 | (psav->lDelta & 0x00003fff));
-        OUTREG32(PRI_STREAM2_STRIDE,
+        } else if (psav->IsSecondary) {
+            OUTREG32(PRI_STREAM2_STRIDE,
                  (((psav->lDelta * 2) << 16) & 0x3FFF0000)
                  | 0x80000000 | (psav->lDelta & 0x00003fff));
-        
+        } else {
+            OUTREG32(PRI_STREAM_STRIDE,
+                 (((psav->lDelta * 2) << 16) & 0x3FFF0000)
+                 | 0x80000000 | (psav->lDelta & 0x00003fff));
+            OUTREG32(PRI_STREAM2_STRIDE,
+                 (((psav->lDelta * 2) << 16) & 0x3FFF0000)
+                 | 0x80000000 | (psav->lDelta & 0x00003fff));
+	}
+
     } else if (pScrn->bitsPerPixel == 32) {
-        OUTREG32(PRI_STREAM_STRIDE,
+	if (psav->IsPrimary) {
+            OUTREG32(PRI_STREAM_STRIDE,
+                 (((psav->lDelta * 2) << 16) & 0x3FFF0000)
+                 | 0xC0000000 | (psav->lDelta & 0x00003fff));
+	} else if (psav->IsSecondary) {
+            OUTREG32(PRI_STREAM2_STRIDE,
                  (((psav->lDelta * 2) << 16) & 0x3FFF0000)
                  | 0xC0000000 | (psav->lDelta & 0x00003fff));
-        OUTREG32(PRI_STREAM2_STRIDE,
+	} else {
+            OUTREG32(PRI_STREAM_STRIDE,
                  (((psav->lDelta * 2) << 16) & 0x3FFF0000)
                  | 0xC0000000 | (psav->lDelta & 0x00003fff));
+            OUTREG32(PRI_STREAM2_STRIDE,
+                 (((psav->lDelta * 2) << 16) & 0x3FFF0000)
+                 | 0xC0000000 | (psav->lDelta & 0x00003fff));
+	}
     }
 
     OUTREG32(0x8128, 0xFFFFFFFFL);
@@ -790,20 +842,26 @@
         psav->GlobalBD.bd1.HighPart.ResBWTile = tile16;/* 16 bit */
 
             ulTmp =  ((psav->lDelta / 2) >> 6) << 24;
-        OUTREG32(TILED_SURFACE_REGISTER_0,ulTmp | TILED_SURF_BPP16);
+	if (psav->IsSecondary)
+            OUTREG32(TILED_SURFACE_REGISTER_1,ulTmp | TILED_SURF_BPP16 | pScrn->fbOffset);
+	else 
+            OUTREG32(TILED_SURFACE_REGISTER_0,ulTmp | TILED_SURF_BPP16 | pScrn->fbOffset);
     }
     else if (pScrn->bitsPerPixel == 32) {
         psav->GlobalBD.bd1.HighPart.ResBWTile = tile32;/* 32 bit */
      
             ulTmp =  ((psav->lDelta / 4) >> 5) << 24;        
-        OUTREG32(TILED_SURFACE_REGISTER_0,ulTmp | TILED_SURF_BPP32);
+	if (psav->IsSecondary)
+            OUTREG32(TILED_SURFACE_REGISTER_1,ulTmp | TILED_SURF_BPP32 | pScrn->fbOffset);
+	else 
+            OUTREG32(TILED_SURFACE_REGISTER_0,ulTmp | TILED_SURF_BPP32 | pScrn->fbOffset);
     }
     
     psav->GlobalBD.bd1.HighPart.ResBWTile |= 0x10;/* disable block write */
     /* HW uses width */
     psav->GlobalBD.bd1.HighPart.Stride = (ushort)(psav->lDelta / (pScrn->bitsPerPixel >> 3));
     psav->GlobalBD.bd1.HighPart.Bpp = (uchar) (pScrn->bitsPerPixel);
-    psav->GlobalBD.bd1.Offset = 0;    
+    psav->GlobalBD.bd1.Offset = pScrn->fbOffset;    
 
 
     /*
@@ -811,9 +869,14 @@
      *       bit 0 = 1, Enable 8 Mbytes of display memory thru 64K window
      *                  at A000:0.
      */
+#if 0
     OUTREG8(CRT_ADDRESS_REG,MEMORY_CONFIG_REG); /* cr31 */
     byte = INREG8(CRT_DATA_REG) & (~(ENABLE_CPUA_BASE_A0000));
     OUTREG8(CRT_DATA_REG,byte);
+#endif
+    OUTREG8(CRT_ADDRESS_REG,MEMORY_CONFIG_REG); /* cr31 */
+    byte = (INREG8(CRT_DATA_REG) | 0x04) & 0xFE;
+    OUTREG8(CRT_DATA_REG,byte);
 
     /* program the GBD and SBD's */
     OUTREG32(S3_GLB_BD_LOW,psav->GlobalBD.bd2.LoPart );
@@ -860,18 +923,32 @@
      *  = 0  standard VGA address and stride registers
      *       are used to control the primary streams
      */
-    OUTREG8(CRT_ADDRESS_REG,0x67); 
-    byte =  INREG8(CRT_DATA_REG) | 0x08;
-    OUTREG8(CRT_DATA_REG,byte);
+    if (psav->IsPrimary) {
+    	OUTREG8(CRT_ADDRESS_REG,0x67); 
+    	byte =  INREG8(CRT_DATA_REG) | 0x08;
+    	OUTREG8(CRT_DATA_REG,byte);
+    } else if (psav->IsSecondary) {
+    	/* IGA 2 */
+    	OUTREG16(SEQ_ADDRESS_REG,SELECT_IGA2_READS_WRITES);
+
+    	OUTREG8(CRT_ADDRESS_REG,0x67); 
+    	byte =  INREG8(CRT_DATA_REG) | 0x08;
+    	OUTREG8(CRT_DATA_REG,byte);
     
-    /* IGA 2 */
-    OUTREG16(SEQ_ADDRESS_REG,SELECT_IGA2_READS_WRITES);
-
-    OUTREG8(CRT_ADDRESS_REG,0x67); 
-    byte =  INREG8(CRT_DATA_REG) | 0x08;
-    OUTREG8(CRT_DATA_REG,byte);
+    	OUTREG16(SEQ_ADDRESS_REG,SELECT_IGA1);
+    } else {
+    	OUTREG8(CRT_ADDRESS_REG,0x67); 
+    	byte =  INREG8(CRT_DATA_REG) | 0x08;
+    	OUTREG8(CRT_DATA_REG,byte);
+    	/* IGA 2 */
+    	OUTREG16(SEQ_ADDRESS_REG,SELECT_IGA2_READS_WRITES);
+
+    	OUTREG8(CRT_ADDRESS_REG,0x67); 
+    	byte =  INREG8(CRT_DATA_REG) | 0x08;
+    	OUTREG8(CRT_DATA_REG,byte);
     
-    OUTREG16(SEQ_ADDRESS_REG,SELECT_IGA1);
+    	OUTREG16(SEQ_ADDRESS_REG,SELECT_IGA1);
+    }
 
     /*
      * load ps1 active registers as determined by MM81C0/81C4
@@ -892,37 +969,73 @@
      *  bytes padded up to an even number of tilewidths.
      */
     if (!psav->bTiled) {
-        OUTREG32(PRI_STREAM_STRIDE,
+	if (psav->IsPrimary) {
+            OUTREG32(PRI_STREAM_STRIDE,
+                 (((psav->lDelta * 2) << 16) & 0x3FFF0000) |
+                 (psav->lDelta & 0x00001fff));
+	} else if (psav->IsSecondary) {
+            OUTREG32(PRI_STREAM2_STRIDE,
+                 (((psav->lDelta * 2) << 16) & 0x3FFF0000) |
+                 (psav->lDelta & 0x00001fff));
+	} else {
+            OUTREG32(PRI_STREAM_STRIDE,
                  (((psav->lDelta * 2) << 16) & 0x3FFF0000) |
                  (psav->lDelta & 0x00001fff));
-        OUTREG32(PRI_STREAM2_STRIDE,
+            OUTREG32(PRI_STREAM2_STRIDE,
                  (((psav->lDelta * 2) << 16) & 0x3FFF0000) |
                  (psav->lDelta & 0x00001fff));
+	}
     } else if (pScrn->bitsPerPixel == 16) {
         /* Scanline-length-in-bytes/128-bytes-per-tile * 256 Qwords/tile */
-        OUTREG32(PRI_STREAM_STRIDE,
+	if (psav->IsPrimary) {
+            OUTREG32(PRI_STREAM_STRIDE,
+                 (((psav->lDelta * 2) << 16) & 0x3FFF0000)
+                 | 0x80000000 | (psav->lDelta & 0x00001fff));
+	} else if (psav->IsSecondary) {
+            OUTREG32(PRI_STREAM2_STRIDE,
                  (((psav->lDelta * 2) << 16) & 0x3FFF0000)
                  | 0x80000000 | (psav->lDelta & 0x00001fff));
-        OUTREG32(PRI_STREAM2_STRIDE,
+	} else {
+            OUTREG32(PRI_STREAM_STRIDE,
                  (((psav->lDelta * 2) << 16) & 0x3FFF0000)
                  | 0x80000000 | (psav->lDelta & 0x00001fff));
+            OUTREG32(PRI_STREAM2_STRIDE,
+                 (((psav->lDelta * 2) << 16) & 0x3FFF0000)
+                 | 0x80000000 | (psav->lDelta & 0x00001fff));
+	}
         
     } else if (pScrn->bitsPerPixel == 32) {
-        OUTREG32(PRI_STREAM_STRIDE,
+	if (psav->IsPrimary) {
+            OUTREG32(PRI_STREAM_STRIDE,
                  (((psav->lDelta * 2) << 16) & 0x3FFF0000)
                  | 0xC0000000 | (psav->lDelta & 0x00001fff));
-        OUTREG32(PRI_STREAM2_STRIDE,
+	} else if (psav->IsSecondary) {
+            OUTREG32(PRI_STREAM2_STRIDE,
                  (((psav->lDelta * 2) << 16) & 0x3FFF0000)
                  | 0xC0000000 | (psav->lDelta & 0x00001fff));
+	} else {
+            OUTREG32(PRI_STREAM_STRIDE,
+                 (((psav->lDelta * 2) << 16) & 0x3FFF0000)
+                 | 0xC0000000 | (psav->lDelta & 0x00001fff));
+            OUTREG32(PRI_STREAM2_STRIDE,
+                 (((psav->lDelta * 2) << 16) & 0x3FFF0000)
+                 | 0xC0000000 | (psav->lDelta & 0x00001fff));
+	}
     }
     
     /* MM81C0 and 81C4 are used to control primary stream. */
-    /*OUTREG32(PRI_STREAM_FBUF_ADDR0,0x80000000);*/
-    OUTREG32(PRI_STREAM_FBUF_ADDR0,0x00000000);
-    OUTREG32(PRI_STREAM_FBUF_ADDR1,0x00000000);
-    /*OUTREG32(PRI_STREAM2_FBUF_ADDR0,0x80000000);*/
-    OUTREG32(PRI_STREAM2_FBUF_ADDR0,0x00000000);
-    OUTREG32(PRI_STREAM2_FBUF_ADDR1,0x00000000);
+    if (psav->IsPrimary) {
+        OUTREG32(PRI_STREAM_FBUF_ADDR0,pScrn->fbOffset);
+        OUTREG32(PRI_STREAM_FBUF_ADDR1,0x80000000);
+    } else if (psav->IsSecondary) {
+        OUTREG32(PRI_STREAM2_FBUF_ADDR0,(pScrn->fbOffset & 0xfffffffc) | 0x80000000);
+        OUTREG32(PRI_STREAM2_FBUF_ADDR1,pScrn->fbOffset & 0xffffffc);
+    } else {
+        OUTREG32(PRI_STREAM_FBUF_ADDR0,pScrn->fbOffset);
+        OUTREG32(PRI_STREAM_FBUF_ADDR1,0x80000000);
+        OUTREG32(PRI_STREAM2_FBUF_ADDR0,(pScrn->fbOffset & 0xfffffffc) | 0x80000000);
+        OUTREG32(PRI_STREAM2_FBUF_ADDR1,pScrn->fbOffset & 0xffffffc);
+    }
     
     OUTREG32(0x8128, 0xFFFFFFFFL);
     OUTREG32(0x812C, 0xFFFFFFFFL);
@@ -948,20 +1061,26 @@
         psav->GlobalBD.bd1.HighPart.ResBWTile = tile16;/* tile format destination */
         
         ulTmp =  (((pScrn->virtualX + 0x3f) & 0x0000ffc0) >> 6) << 20;
-        OUTREG32(TILED_SURFACE_REGISTER_0,ulTmp | TILED_SURF_BPP16);
+	if (psav->IsSecondary)
+            OUTREG32(TILED_SURFACE_REGISTER_1,ulTmp | TILED_SURF_BPP16 | (pScrn->fbOffset>>5)); /* 5 or 6? */
+	else 
+            OUTREG32(TILED_SURFACE_REGISTER_0,ulTmp | TILED_SURF_BPP16 | (pScrn->fbOffset>>5)); /* 5 or 6? */
     }
     else if (pScrn->bitsPerPixel == 32) {
         psav->GlobalBD.bd1.HighPart.ResBWTile = tile32;/* tile format destination */
         
         ulTmp =  (((pScrn->virtualX + 0x1f) & 0x0000ffe0) >> 5) << 20;        
-        OUTREG32(TILED_SURFACE_REGISTER_0,ulTmp | TILED_SURF_BPP32);
+	if (psav->IsSecondary)
+            OUTREG32(TILED_SURFACE_REGISTER_1,ulTmp | TILED_SURF_BPP32 | (pScrn->fbOffset>>5)); /* 5 or 6? */
+	else 
+            OUTREG32(TILED_SURFACE_REGISTER_0,ulTmp | TILED_SURF_BPP32 | (pScrn->fbOffset>>5)); /* 5 or 6? */
     }
     
     psav->GlobalBD.bd1.HighPart.ResBWTile |= 0x10;/* disable block write */
     /* HW uses width */
     psav->GlobalBD.bd1.HighPart.Stride = (ushort)(psav->lDelta / (pScrn->bitsPerPixel >> 3));
     psav->GlobalBD.bd1.HighPart.Bpp = (uchar) (pScrn->bitsPerPixel);
-    psav->GlobalBD.bd1.Offset = 0;    
+    psav->GlobalBD.bd1.Offset = pScrn->fbOffset;    
 
     /*
      * CR31, bit 0 = 0, Disable address offset bits(CR6A_6-0).
@@ -975,18 +1094,59 @@
     /* program the GBD and SBDs */
     OUTREG32(S3_GLB_BD_LOW,psav->GlobalBD.bd2.LoPart );
     OUTREG32(S3_GLB_BD_HIGH,(psav->GlobalBD.bd2.HiPart 
-			     | bci_enable | S3_LITTLE_ENDIAN | 0x10000000 | S3_BD64));
+			     | bci_enable /* AGD: shouldn't BCI be enabled? */
+                             | S3_LITTLE_ENDIAN | 0x10000000 | S3_BD64));
     OUTREG32(S3_PRI_BD_LOW,psav->GlobalBD.bd2.LoPart);
     OUTREG32(S3_PRI_BD_HIGH,psav->GlobalBD.bd2.HiPart);
     OUTREG32(S3_SEC_BD_LOW,psav->GlobalBD.bd2.LoPart);
     OUTREG32(S3_SEC_BD_HIGH,psav->GlobalBD.bd2.HiPart);
-    
+
     /* turn on screen */
     OUTREG8(SEQ_ADDRESS_REG,0x01);
     byte = INREG8(SEQ_DATA_REG) & ~0x20;
     OUTREG8(SEQ_DATA_REG,byte);
 }
 
+static
+void SavageRestoreAccelState(ScrnInfoPtr pScrn)
+{
+    SavagePtr psav = SAVPTR(pScrn);
+    int bci_enable;
+    ulong cmd;
+
+    BCI_GET_PTR;
+
+    if (psav->Chipset == S3_SAVAGE_MX)
+    	bci_enable = BCI_ENABLE;
+    else
+	bci_enable = BCI_ENABLE_TWISTER;
+
+    psav->WaitIdleEmpty(psav);
+
+    /* may only need to update the GBD */    
+#if 1
+    psav->WaitQueue(psav, 2);
+
+    cmd = BCI_SET_REGISTER | 0xE0 | (2<<16);
+    BCI_SEND(cmd);
+    BCI_SEND(psav->GlobalBD.bd2.LoPart);
+    BCI_SEND((psav->GlobalBD.bd2.HiPart
+                             | bci_enable | S3_LITTLE_ENDIAN | S3_BD64));
+#endif
+#if 0
+    /* program the GBD */
+    OUTREG32(S3_GLB_BD_LOW,psav->GlobalBD.bd2.LoPart );
+    OUTREG32(S3_GLB_BD_HIGH,(psav->GlobalBD.bd2.HiPart
+                             | bci_enable | S3_LITTLE_ENDIAN | S3_BD64));
+    OUTREG32(S3_PRI_BD_LOW,psav->GlobalBD.bd2.LoPart);
+    OUTREG32(S3_PRI_BD_HIGH,psav->GlobalBD.bd2.HiPart);
+    OUTREG32(S3_SEC_BD_LOW,psav->GlobalBD.bd2.LoPart);
+    OUTREG32(S3_SEC_BD_HIGH,psav->GlobalBD.bd2.HiPart);
+#endif
+
+    return;
+}
+
 /* Acceleration init function, sets up pointers to our accelerated functions */
 
 Bool 
@@ -1040,6 +1200,21 @@
 
     xaaptr->Sync = SavageAccelSync;
 
+    if(xf86IsEntityShared(pScrn->entityList[0]))
+    {
+        DevUnion* pPriv;
+        SavageEntPtr pEnt;
+        pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
+                gSavageEntityIndex);
+        pEnt = pPriv->ptr;
+        
+        /*if there are more than one devices sharing this entity, we
+          have to assign this call back, otherwise the XAA will be
+          disabled */
+        if(pEnt->HasSecondary)
+           xaaptr->RestoreAccelState           = SavageRestoreAccelState;
+    }
+
 
     /* ScreenToScreen copies */
 
@@ -1230,7 +1405,7 @@
                     pScrn->bitsPerPixel,
                     widthBytes,bufferSize);
 
-        pSAVAGEDRIServer->frontOffset = 0; /* AGD: should probably be pScrn->fbOffset */
+        pSAVAGEDRIServer->frontOffset = pScrn->fbOffset; /* 0 */
         pSAVAGEDRIServer->frontPitch = widthBytes;
 
         /* Try for front, back, depth, and two framebuffers worth of
Index: savage_bci.h
===================================================================
RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/savage/savage_bci.h,v
retrieving revision 1.5
diff -u -r1.5 savage_bci.h
--- savage_bci.h	23 Sep 2004 23:28:03 -0000	1.5
+++ savage_bci.h	27 Sep 2004 04:41:17 -0000
@@ -112,6 +112,8 @@
 #define BCI_BD_GET_STRIDE(bd)        ((bd) & 0xFFFF)
 #define BCI_BD_SET_STRIDE(bd, st)    ((bd) |= ((st) & 0xFFFF))
 
+#define BCI_SET_REGISTER             0x96000000
+
 #define BCI_W_H(w, h)                ((((h) << 16) | (w)) & 0x0FFF0FFF)
 #define BCI_X_Y(x, y)                ((((y) << 16) | (x)) & 0x0FFF0FFF)
 #define BCI_X_W(x, y)                ((((w) << 16) | (x)) & 0x0FFF0FFF)
Index: savage_cursor.c
===================================================================
RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/savage/savage_cursor.c,v
retrieving revision 1.4
diff -u -r1.4 savage_cursor.c
--- savage_cursor.c	16 Sep 2004 22:00:48 -0000	1.4
+++ savage_cursor.c	27 Sep 2004 04:41:17 -0000
@@ -120,13 +120,22 @@
     return xf86InitCursor(pScreen, infoPtr);
 }
 
-
+/*
+ * Supposedly bit 2 of CR45 enables cursor two (rest of the cursor regs are shadowed via SR26), 
+ * but I can't seem to enable it. For now it's disabled. - AGD
+ */
 
 void
 SavageShowCursor(ScrnInfoPtr pScrn)
 {
+    SavagePtr psav = SAVPTR(pScrn);
+
    /* Turn cursor on. */
-   outCRReg( 0x45, inCRReg(0x45) | 0x01 );
+   if (psav->IsSecondary) {
+       outCRReg( 0x45, inCRReg(0x45) | 0x04 ); /* cursor2 bit 2*/
+   } else {
+       outCRReg( 0x45, inCRReg(0x45) | 0x01 );
+   }
    SAVPTR(pScrn)->hwc_on = TRUE;
 }
 
@@ -134,13 +143,19 @@
 void
 SavageHideCursor(ScrnInfoPtr pScrn)
 {
+    SavagePtr psav = SAVPTR(pScrn);
+
     /* Turn cursor off. */
 
     if( S3_SAVAGE4_SERIES( SAVPTR(pScrn)->Chipset ) )
     {
        waitHSync(5);
     }
-    outCRReg( 0x45, inCRReg(0x45) & 0xfe );
+    if (psav->IsSecondary) {
+	outCRReg( 0x45, inCRReg(0x45) & 0xfb ); /* cursor2 */
+    } else {
+        outCRReg( 0x45, inCRReg(0x45) & 0xfe );
+    }
     SAVPTR(pScrn)->hwc_on = FALSE;
 }
 
@@ -152,8 +167,16 @@
     SavagePtr psav = SAVPTR(pScrn);
 
     /* Set cursor location in frame buffer.  */
-    outCRReg( 0x4d, (0xff & (CARD32)psav->CursorKByte));
-    outCRReg( 0x4c, (0xff00 & (CARD32)psav->CursorKByte) >> 8);
+    if (psav->IsSecondary) {
+	SelectIGA2();
+    	/* Set cursor location in frame buffer.  */
+    	outCRReg( 0x4d, (0xff & psav->CursorKByte));
+    	outCRReg( 0x4c, (0xff00 & psav->CursorKByte) >> 8);
+	SelectIGA1();
+    } else {
+        outCRReg( 0x4d, (0xff & (CARD32)psav->CursorKByte));
+        outCRReg( 0x4c, (0xff00 & (CARD32)psav->CursorKByte) >> 8);
+    }
 
     /* Upload the cursor image to the frame buffer. */
     memcpy(psav->FBBase + psav->CursorKByte * 1024, src, 1024);
@@ -174,6 +197,7 @@
      int x, 
      int y)
 {
+    SavagePtr psav = SAVPTR(pScrn);
     unsigned char xoff, yoff;
 
     if( S3_SAVAGE4_SERIES( SAVPTR(pScrn)->Chipset ) )
@@ -210,12 +234,23 @@
     }
 
     /* This is the recomended order to move the cursor */
-    outCRReg( 0x46, (x & 0xff00)>>8 );
-    outCRReg( 0x47, (x & 0xff) );
-    outCRReg( 0x49, (y & 0xff) );
-    outCRReg( 0x4e, xoff );
-    outCRReg( 0x4f, yoff );
-    outCRReg( 0x48, (y & 0xff00)>>8 );
+        if (psav->IsSecondary) {
+	SelectIGA2();
+    	outCRReg( 0x46, (x & 0xff00)>>8 );
+    	outCRReg( 0x47, (x & 0xff) );
+    	outCRReg( 0x49, (y & 0xff) );
+    	outCRReg( 0x4e, xoff );
+    	outCRReg( 0x4f, yoff );
+    	outCRReg( 0x48, (y & 0xff00)>>8 );
+	SelectIGA1();
+    } else {
+        outCRReg( 0x46, (x & 0xff00)>>8 );
+        outCRReg( 0x47, (x & 0xff) );
+        outCRReg( 0x49, (y & 0xff) );
+        outCRReg( 0x4e, xoff );
+        outCRReg( 0x4f, yoff );
+        outCRReg( 0x48, (y & 0xff00)>>8 );
+    }
 }
 
 
@@ -243,19 +278,36 @@
 	) 
     {
 	/* Do it straight, full 24 bit color. */
-      
-	/* Reset the cursor color stack pointer */
-	inCRReg(0x45);
-	/* Write low, mid, high bytes - foreground */
-	outCRReg(0x4a, fg);
-	outCRReg(0x4a, fg >> 8);
-	outCRReg(0x4a, fg >> 16);
-	/* Reset the cursor color stack pointer */
-	inCRReg(0x45);
-	/* Write low, mid, high bytes - background */
-	outCRReg(0x4b, bg);
-	outCRReg(0x4b, bg >> 8);
-	outCRReg(0x4b, bg >> 16);
+       if (psav->IsSecondary) {
+            /* cursor 2 */
+	    /* Reset the cursor color stack pointer */
+	    inCRReg(0x45);
+	    SelectIGA2();
+	    /* Write low, mid, high bytes - foreground */
+	    outCRReg(0x4a, fg);
+	    outCRReg(0x4a, fg >> 8);
+	    outCRReg(0x4a, fg >> 16);
+	    /* Reset the cursor color stack pointer */
+	    inCRReg(0x45);
+	    /* Write low, mid, high bytes - background */
+	    outCRReg(0x4b, bg);
+	    outCRReg(0x4b, bg >> 8);
+	    outCRReg(0x4b, bg >> 16);
+	    SelectIGA1();
+	} else {      
+	    /* Reset the cursor color stack pointer */
+	    inCRReg(0x45);
+	    /* Write low, mid, high bytes - foreground */
+	    outCRReg(0x4a, fg);
+	    outCRReg(0x4a, fg >> 8);
+	    outCRReg(0x4a, fg >> 16);
+	    /* Reset the cursor color stack pointer */
+	    inCRReg(0x45);
+	    /* Write low, mid, high bytes - background */
+	    outCRReg(0x4b, bg);
+	    outCRReg(0x4b, bg >> 8);
+	    outCRReg(0x4b, bg >> 16);
+	}
 	return;
     }
 #if 0
Index: savage_driver.c
===================================================================
RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/savage/savage_driver.c,v
retrieving revision 1.9
diff -u -r1.9 savage_driver.c
--- savage_driver.c	18 Sep 2004 20:23:32 -0000	1.9
+++ savage_driver.c	27 Sep 2004 04:41:19 -0000
@@ -106,6 +106,8 @@
 #define TRACE(prms)  
 #endif
 
+int gSavageEntityIndex = -1;
+
 DriverRec SAVAGE =
 {
     SAVAGE_VERSION,
@@ -215,6 +217,7 @@
     ,OPTION_BCI_FOR_XV
     ,OPTION_AGP_MODE
     ,OPTION_AGP_SIZE
+    ,OPTION_DVI
 } SavageOpts;
 
 
@@ -241,6 +244,7 @@
     { OPTION_BCI_FOR_XV,   "BCIforXv",    OPTV_BOOLEAN, {0}, FALSE },
     { OPTION_AGP_MODE,     "AGPMode",   OPTV_INTEGER, {0}, FALSE },
     { OPTION_AGP_SIZE,     "AGPSize",   OPTV_INTEGER, {0}, FALSE },
+    { OPTION_DVI,          "DVI",       OPTV_BOOLEAN, {0}, FALSE },
     { -1,		NULL,		OPTV_NONE,    {0}, FALSE }
 };
 
@@ -424,6 +428,15 @@
 
 XF86ModuleData savageModuleData = { &SavageVersRec, SavageSetup, NULL };
 
+static SavageEntPtr SavageEntPriv(ScrnInfoPtr pScrn)
+{
+    DevUnion     *pPriv;
+    SavagePtr  psav   = SAVPTR(pScrn);
+    pPriv = xf86GetEntityPrivate(psav->pEnt->index,
+                                 gSavageEntityIndex);
+    return pPriv->ptr;
+}
+
 static pointer SavageSetup(pointer module, pointer opts, int *errmaj,
 			   int *errmin)
 {
@@ -736,25 +749,65 @@
 	foundScreen = TRUE;
     else
 	for (i=0; i<numUsed; i++) {
-	    ScrnInfoPtr pScrn = xf86AllocateScreen(drv, 0);
+            EntityInfoPtr pEnt;
+	    /*ScrnInfoPtr pScrn = xf86AllocateScreen(drv, 0);*/
+            ScrnInfoPtr pScrn;
+            pScrn    = NULL;
+	    pEnt = xf86GetEntityInfo(usedChips[i]);
+            if((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i],
+                 SavagePciChipsets, 0, 0, 0, 0, 0)))
+            {
+
+ 	        pScrn->driverVersion = SAVAGE_VERSION;
+	        pScrn->driverName = DRIVER_NAME;
+	        pScrn->name = "SAVAGE";
+	        pScrn->Probe = SavageProbe;
+	        pScrn->PreInit = SavagePreInit;
+	        pScrn->ScreenInit = SavageScreenInit;
+	        pScrn->SwitchMode = SavageSwitchMode;
+	        pScrn->AdjustFrame = SavageAdjustFrame;
+	        pScrn->EnterVT = SavageEnterVT;
+	        pScrn->LeaveVT = SavageLeaveVT;
+	        pScrn->FreeScreen = NULL;
+	        pScrn->ValidMode = SavageValidMode;
+	        foundScreen = TRUE;
+	    }
+
+            pEnt = xf86GetEntityInfo(usedChips[i]);
+
+            /* MX, IX, SuperSavage cards support Dual-Head, mark the entity as sharable*/
+            if(pEnt->chipset == S3_SAVAGE_MX || pEnt->chipset == S3_SUPERSAVAGE)
+            {
+		DevUnion   *pPriv;
+		SavageEntPtr pSavageEnt;
 
-	    pScrn->driverVersion = SAVAGE_VERSION;
-	    pScrn->driverName = DRIVER_NAME;
-	    pScrn->name = "SAVAGE";
-	    pScrn->Probe = SavageProbe;
-	    pScrn->PreInit = SavagePreInit;
-	    pScrn->ScreenInit = SavageScreenInit;
-	    pScrn->SwitchMode = SavageSwitchMode;
-	    pScrn->AdjustFrame = SavageAdjustFrame;
-	    pScrn->EnterVT = SavageEnterVT;
-	    pScrn->LeaveVT = SavageLeaveVT;
-	    pScrn->FreeScreen = NULL;
-	    pScrn->ValidMode = SavageValidMode;
-	    foundScreen = TRUE;
-	    xf86ConfigActivePciEntity(pScrn, usedChips[i], SavagePciChipsets,
-				     NULL, NULL, NULL, NULL, NULL);
+		xf86SetEntitySharable(usedChips[i]);
+
+		if (gSavageEntityIndex == -1)
+		    gSavageEntityIndex = xf86AllocateEntityPrivateIndex();
+
+		pPriv = xf86GetEntityPrivate(pEnt->index,
+					     gSavageEntityIndex);
+
+		if (!pPriv->ptr) {
+		    int j;
+		    int instance = xf86GetNumEntityInstances(pEnt->index);
+
+		    for (j = 0; j < instance; j++)
+			xf86SetEntityInstanceForScreen(pScrn, pEnt->index, j);
+
+		    pPriv->ptr = xnfcalloc(sizeof(SavageEntRec), 1);
+		    pSavageEnt = pPriv->ptr;
+		    pSavageEnt->HasSecondary = FALSE;
+		} else {
+		    pSavageEnt = pPriv->ptr;
+		    pSavageEnt->HasSecondary = TRUE;
+		}
+	    }
+	    xfree(pEnt);
 	}
 
+
     xfree(usedChips);
     return foundScreen;
 }
@@ -772,6 +825,132 @@
     return -1;
 }
 
+static void SavageDoDDC(ScrnInfoPtr pScrn)
+{
+    SavagePtr psav= SAVPTR(pScrn);
+    pointer ddc;
+
+    /* Do the DDC dance. */ /* S3/VIA's DDC code */
+    ddc = xf86LoadSubModule(pScrn, "ddc");
+    if (ddc) {
+        xf86LoaderReqSymLists(ddcSymbols, NULL);
+        switch( psav->Chipset ) {
+            case S3_SAVAGE3D:
+            case S3_SAVAGE_MX:
+            case S3_SUPERSAVAGE:
+                psav->DDCPort = 0xAA;
+                psav->I2CPort = 0xA0;
+                break;
+
+            case S3_SAVAGE4:
+            case S3_PROSAVAGE:
+            case S3_TWISTER:
+            case S3_PROSAVAGEDDR:
+                psav->DDCPort = 0xB1;
+                psav->I2CPort = 0xA0;
+                break;
+                
+            case S3_SAVAGE2000:
+                psav->DDCPort = 0xAA;
+                psav->I2CPort = 0xA0;
+                break;
+        }
+
+        if (!SavageDDC1(pScrn->scrnIndex)) {
+            /* DDC1 failed,switch to DDC2 */
+            if (xf86LoadSubModule(pScrn, "i2c")) {
+                xf86LoaderReqSymLists(i2cSymbols,NULL);
+                if (SavageI2CInit(pScrn)) {
+                    unsigned char tmp;
+                    
+                    InI2CREG(tmp,psav->DDCPort);
+                    OutI2CREG(tmp | 0x13,psav->DDCPort);
+                    xf86SetDDCproperties(pScrn,xf86PrintEDID(
+                                             xf86DoEDID_DDC2(pScrn->scrnIndex,psav->I2C)));
+                    OutI2CREG(tmp,psav->DDCPort);
+                }
+            }
+        }
+    }
+}
+
+static void SavageGetPanelInfo(ScrnInfoPtr pScrn)
+{
+    SavagePtr psav= SAVPTR(pScrn);
+    vgaHWPtr hwp;
+    unsigned char cr6b;
+    int panelX, panelY;
+    char * sTechnology = "Unknown";
+    enum ACTIVE_DISPLAYS { /* These are the bits in CR6B */
+	ActiveCRT = 0x01,
+	ActiveLCD = 0x02,
+	ActiveTV = 0x04,
+	ActiveCRT2 = 0x20,
+	ActiveDUO = 0x80
+    };
+
+    hwp = VGAHWPTR(pScrn);
+
+    /* Check LCD panel information */
+
+    cr6b = hwp->readCrtc( hwp, 0x6b );
+
+    panelX = (hwp->readSeq(hwp, 0x61) + 
+	    ((hwp->readSeq(hwp, 0x66) & 0x02) << 7) + 1) * 8;
+    panelY = hwp->readSeq(hwp, 0x69) + 
+	    ((hwp->readSeq(hwp, 0x6e) & 0x70) << 4) + 1;
+
+
+	/* OK, I admit it.  I don't know how to limit the max dot clock
+	 * for LCD panels of various sizes.  I thought I copied the formula
+	 * from the BIOS, but many users have informed me of my folly.
+	 *
+	 * Instead, I'll abandon any attempt to automatically limit the 
+	 * clock, and add an LCDClock option to XF86Config.  Some day,
+	 * I should come back to this.
+	 */
+
+
+    if( (hwp->readSeq( hwp, 0x39 ) & 0x03) == 0 )
+    {
+	sTechnology = "TFT";
+    }
+    else if( (hwp->readSeq( hwp, 0x30 ) & 0x01) == 0 )
+    {
+	sTechnology = "DSTN";
+    }
+    else
+    {
+	sTechnology = "STN";
+    }
+
+    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+		   "%dx%d %s LCD panel detected %s\n", 
+		   panelX, panelY, sTechnology,
+		   cr6b & ActiveLCD ? "and active" : "but not active");
+
+    if( cr6b & ActiveLCD ) {
+	    /* If the LCD is active and panel expansion is enabled, */
+	    /* we probably want to kill the HW cursor. */
+
+	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+		       "- Limiting video mode to %dx%d\n",
+		       panelX, panelY );
+	    
+	psav->PanelX = panelX;
+	psav->PanelY = panelY;
+
+	if( psav->LCDClock > 0.0 )
+	{
+	    psav->maxClock = psav->LCDClock * 1000.0;
+	    xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
+			    "- Limiting dot clock to %1.2f MHz\n",
+			    psav->LCDClock );
+	}
+    }
+}
+
+
 static Bool SavagePreInit(ScrnInfoPtr pScrn, int flags)
 {
     EntityInfoPtr pEnt;
@@ -784,7 +963,7 @@
     int mclk;
     vgaHWPtr hwp;
     int vgaCRIndex, vgaCRReg;
-    pointer ddc;
+    Bool dvi;
 
     TRACE(("SavagePreInit(%d)\n", flags));
 
@@ -1007,7 +1186,6 @@
     /*psav->agpMode = SAVAGE_MAX_AGP_MODE;*/
     psav->agpSize = 16;
     
-    /* temporatly remove by Jiayo */
     if (xf86GetOptValInteger(psav->Options,
                              OPTION_AGP_MODE, &(psav->agpMode))) {
         if (psav->agpMode < 1) {
@@ -1113,15 +1291,11 @@
         xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
                    "Option: %s Tile Mode and Program it \n",(psav->bDisableTile?"Disable":"Enable"));
     }
-    psav->bDisableXvMC = FALSE; /* if you want to free up more mem for DRI,etc. */
+    psav->bDisableXvMC = TRUE; /* if you want to free up more mem for DRI,etc. */
     if (xf86GetOptValBool(psav->Options, OPTION_DISABLE_XVMC, &psav->bDisableXvMC)) {
         xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
                    "Option: %s Hardware XvMC support\n",(psav->bDisableXvMC?"Disable":"Enable"));
     }
-    if (S3_SAVAGE3D_SERIES(psav->Chipset)) {
-	psav->bDisableXvMC = TRUE; /* no xvmc on old savages */
-        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "No Hardware XvMC support on Savage3D based chips.\n");
-    }
     psav->disableCOB = FALSE; /* if you are having problems on savage4+ */
     if (xf86GetOptValBool(psav->Options, OPTION_DISABLE_COB, &psav->disableCOB)) {
         xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
@@ -1137,6 +1311,11 @@
         xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
                    "Option: %s use of the BCI for Xv\n",(psav->BCIforXv?"Enable":"Disable"));
     }
+    psav->dvi = FALSE;
+    if (xf86GetOptValBool(psav->Options, OPTION_DVI, &psav->dvi)) {
+        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+                   "%s DVI port support (Savage4 only)\n",(psav->dvi?"Force":"Disable"));
+    }
 
     /* Add more options here. */
 
@@ -1201,6 +1380,46 @@
 
     xfree(pEnt);
 
+    psav               = SAVPTR(pScrn);
+    psav->IsSecondary  = FALSE;
+    psav->IsPrimary    = FALSE;
+    psav->pEnt         = xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]);
+
+    if (xf86IsEntityShared(psav->pEnt->index)) {
+	if (xf86IsPrimInitDone(psav->pEnt->index)) {
+
+	    SavageEntPtr pSavageEnt = SavageEntPriv(pScrn);
+
+	    psav->IsSecondary = TRUE;
+	    pSavageEnt->pSecondaryScrn = pScrn;
+	} else {
+	    SavageEntPtr pSavageEnt = SavageEntPriv(pScrn);
+
+	    xf86SetPrimInitDone(psav->pEnt->index);
+
+	    psav->IsPrimary = TRUE;
+	    pSavageEnt->pPrimaryScrn        = pScrn;
+	}
+    }
+
+    switch(psav->Chipset) {
+	case S3_SAVAGE_MX:
+	case S3_SUPERSAVAGE:
+	    psav->HasCRTC2 = TRUE;
+	    break;
+        default: 
+            psav->HasCRTC2 = FALSE;
+    }
+
+    /* until I figure out why cursor2 doesn't work, disable it for crtc2. -- AGD */
+    if (psav->IsSecondary) {
+	psav->hwcursor = FALSE;
+        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "HWCursor currently disabled for crtc2.\n");
+    }
+
+    if ((psav->IsSecondary || psav->IsPrimary) && !psav->UseBIOS)
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "BIOS currently required for Dualhead mode setting.\n");
+
     /* maybe throw in some more sanity checks here */
 
     xf86DrvMsg(pScrn->scrnIndex, from, "Engine: \"%s\"\n", pScrn->chipset);
@@ -1376,6 +1595,25 @@
     psav->CursorKByte = (psav->cobOffset >> 10) - 4;
     psav->endfb = (psav->CursorKByte << 10) - 1;
 
+    if (psav->IsPrimary) {
+        pScrn->videoRam /= 2;
+	psav->videoRambytes = pScrn->videoRam * 1024;
+	psav->CursorKByte = (psav->videoRambytes >> 10) - 4;
+	psav->endfb = (psav->CursorKByte << 10) - 1;
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, 
+		"Using %dk of videoram for primary head\n",
+		pScrn->videoRam);
+    }
+
+    if(psav->IsSecondary)
+    {  
+        pScrn->videoRam /= 2;
+	psav->videoRambytes = pScrn->videoRam * 1024;
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, 
+		"Using %dk of videoram for secondary head\n",
+		pScrn->videoRam);
+    }
+
     /* reset graphics engine to avoid memory corruption */
     VGAOUT8(vgaCRIndex, 0x66);
     cr66 = VGAIN8(vgaCRReg);
@@ -1413,48 +1651,32 @@
 	    break;
     }
 
-    /* Do the DDC dance. */ /* S3/VIA's DDC code */
-    ddc = xf86LoadSubModule(pScrn, "ddc");
-    if (ddc) {
-        xf86LoaderReqSymLists(ddcSymbols, NULL);
-        switch( psav->Chipset ) {
-            case S3_SAVAGE3D:
-            case S3_SAVAGE_MX:
-            case S3_SUPERSAVAGE:
-                psav->DDCPort = 0xAA;
-                psav->I2CPort = 0xA0;
-                break;
-
-            case S3_SAVAGE4:
-            case S3_PROSAVAGE:
-            case S3_TWISTER:
-            case S3_PROSAVAGEDDR:
-                psav->DDCPort = 0xB1;
-                psav->I2CPort = 0xA0;
-                break;
-                
-            case S3_SAVAGE2000:
-                psav->DDCPort = 0xAA;
-                psav->I2CPort = 0xA0;
-                break;
-        }
+    /* check for DVI/flat panel */
+    dvi = FALSE;
+    if (psav->Chipset == S3_SAVAGE4) {
+	unsigned char sr30 = 0x00; 
+	VGAOUT8(0x3c4, 0x30);
+    	sr30 = VGAIN8(0x3c5);
+    	if (sr30 & 0x02) {
+            dvi = TRUE;
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Digital Flat Panel Detected\n");
+	}
+    }
 
-        if (!SavageDDC1(pScrn->scrnIndex)) {
-            /* DDC1 failed,switch to DDC2 */
-            if (xf86LoadSubModule(pScrn, "i2c")) {
-                xf86LoaderReqSymLists(i2cSymbols,NULL);
-                if (SavageI2CInit(pScrn)) {
-                    unsigned char tmp;
-                    
-                    InI2CREG(tmp,psav->DDCPort);
-                    OutI2CREG(tmp | 0x13,psav->DDCPort);
-                    xf86SetDDCproperties(pScrn,xf86PrintEDID(
-                                             xf86DoEDID_DDC2(pScrn->scrnIndex,psav->I2C)));
-                    OutI2CREG(tmp,psav->DDCPort);
-                }
-            }
-        }
+    if( (S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
+	S3_MOBILE_TWISTER_SERIES(psav->Chipset)) && !psav->CrtOnly ) {
+	psav->DisplayType = MT_LCD;
+    } else if (dvi || ((psav->Chipset == S3_SAVAGE4) && psav->dvi)) {
+	psav->DisplayType = MT_DFP;
+    } else {
+	psav->DisplayType = MT_CRT;
     }
+    
+    if (psav->IsSecondary)
+	psav->DisplayType = MT_CRT;
+
+    /* Do the DDC dance. */ 
+    SavageDoDDC(pScrn);
 
     /* Savage ramdac speeds */
     pScrn->numClocks = 4;
@@ -1503,72 +1725,9 @@
 
     /* Check LCD panel information */
 
-    if( (S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
-	S3_MOBILE_TWISTER_SERIES(psav->Chipset)) && !psav->CrtOnly )
+    if(psav->DisplayType == MT_LCD)
     {
-	unsigned char cr6b = hwp->readCrtc( hwp, 0x6b );
-
-	int panelX = (hwp->readSeq(hwp, 0x61) + 
-	    ((hwp->readSeq(hwp, 0x66) & 0x02) << 7) + 1) * 8;
-	int panelY = hwp->readSeq(hwp, 0x69) + 
-	    ((hwp->readSeq(hwp, 0x6e) & 0x70) << 4) + 1;
-
-	char * sTechnology = "Unknown";
-
-	/* OK, I admit it.  I don't know how to limit the max dot clock
-	 * for LCD panels of various sizes.  I thought I copied the formula
-	 * from the BIOS, but many users have informed me of my folly.
-	 *
-	 * Instead, I'll abandon any attempt to automatically limit the 
-	 * clock, and add an LCDClock option to XF86Config.  Some day,
-	 * I should come back to this.
-	 */
-
-	enum ACTIVE_DISPLAYS { /* These are the bits in CR6B */
-	    ActiveCRT = 0x01,
-	    ActiveLCD = 0x02,
-	    ActiveTV = 0x04,
-	    ActiveCRT2 = 0x20,
-	    ActiveDUO = 0x80
-	};
-
-	if( (hwp->readSeq( hwp, 0x39 ) & 0x03) == 0 )
-	{
-	    sTechnology = "TFT";
-	}
-	else if( (hwp->readSeq( hwp, 0x30 ) & 0x01) == 0 )
-	{
-	    sTechnology = "DSTN";
-	}
-	else
-	{
-	    sTechnology = "STN";
-	}
-
-	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
-		   "%dx%d %s LCD panel detected %s\n", 
-		   panelX, panelY, sTechnology,
-		   cr6b & ActiveLCD ? "and active" : "but not active");
-
-	if( cr6b & ActiveLCD ) {
-	    /* If the LCD is active and panel expansion is enabled, */
-	    /* we probably want to kill the HW cursor. */
-
-	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
-		       "- Limiting video mode to %dx%d\n",
-		       panelX, panelY );
-	    
-	    psav->PanelX = panelX;
-	    psav->PanelY = panelY;
-
-	    if( psav->LCDClock > 0.0 )
-	    {
-		psav->maxClock = psav->LCDClock * 1000.0;
-		xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
-			    "- Limiting dot clock to %1.2f MHz\n",
-			    psav->LCDClock );
-	    }
-	}
+	SavageGetPanelInfo(pScrn);
     }
   
 #if 0
@@ -1583,41 +1742,6 @@
     }
 #endif
 
-    clockRanges = xnfalloc(sizeof(ClockRange));
-    clockRanges->next = NULL;
-    clockRanges->minClock = psav->minClock;
-    clockRanges->maxClock = psav->maxClock;
-    clockRanges->clockIndex = -1;
-    clockRanges->interlaceAllowed = TRUE;
-    clockRanges->doubleScanAllowed = TRUE;
-    clockRanges->ClockDivFactor = 1.0;
-    clockRanges->ClockMulFactor = 1.0;
-
-    i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
-			  pScrn->display->modes, clockRanges, NULL, 
-			  256, 2048, 16 * pScrn->bitsPerPixel,
-			  128, 2048, 
-			  pScrn->virtualX, pScrn->virtualY,
-			  psav->videoRambytes, LOOKUP_BEST_REFRESH);
-
-    if (i == -1) {
-	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86ValidateModes failure\n");
-	SavageFreeRec(pScrn);
-	vbeFree(psav->pVbe);
-	psav->pVbe = NULL;
-	return FALSE;
-    }
-
-    xf86PruneDriverModes(pScrn);
-
-    if (i == 0 || pScrn->modes == NULL) {
-	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
-	SavageFreeRec(pScrn);
-	vbeFree(psav->pVbe);
-	psav->pVbe = NULL;
-	return FALSE;
-    }
-
     if( psav->UseBIOS )
     {
 	/* Go probe the BIOS for all the modes and refreshes at this depth. */
@@ -1660,6 +1784,41 @@
 	}
     }
 
+    clockRanges = xnfalloc(sizeof(ClockRange));
+    clockRanges->next = NULL;
+    clockRanges->minClock = psav->minClock;
+    clockRanges->maxClock = psav->maxClock;
+    clockRanges->clockIndex = -1;
+    clockRanges->interlaceAllowed = TRUE;
+    clockRanges->doubleScanAllowed = TRUE;
+    clockRanges->ClockDivFactor = 1.0;
+    clockRanges->ClockMulFactor = 1.0;
+
+    i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
+			  pScrn->display->modes, clockRanges, NULL, 
+			  256, 4096, 16 * pScrn->bitsPerPixel,
+			  128, 4096, 
+			  pScrn->virtualX, pScrn->virtualY,
+			  psav->videoRambytes, LOOKUP_BEST_REFRESH);
+
+    if (i == -1) {
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86ValidateModes failure\n");
+	SavageFreeRec(pScrn);
+	vbeFree(psav->pVbe);
+	psav->pVbe = NULL;
+	return FALSE;
+    }
+
+    xf86PruneDriverModes(pScrn);
+
+    if (i == 0 || pScrn->modes == NULL) {
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
+	SavageFreeRec(pScrn);
+	vbeFree(psav->pVbe);
+	psav->pVbe = NULL;
+	return FALSE;
+    }
+
     xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
     pScrn->currentMode = pScrn->modes;
     xf86PrintModes(pScrn);
@@ -1731,8 +1890,8 @@
         psav->LockHeld = 0;
     }
 #endif
-
-    SavageSave(pScrn);
+    if (!psav->IsSecondary)
+    	SavageSave(pScrn);
     if(SavageModeInit(pScrn, pScrn->currentMode)) {
 	/* some BIOSes seem to enable HW cursor on PM resume */
 	if (!SAVPTR(pScrn)->hwc_on)
@@ -1976,6 +2135,13 @@
     }
 #endif
 
+    if (psav->IsSecondary) {
+	/* Set up the mode.  Don't clear video RAM. */
+	SavageSetVESAMode( psav, restore->mode | 0x8000, restore->refresh );
+	SavageSetGBD(pScrn);
+	return;
+    }
+
     if( Entering && 
 	(!S3_SAVAGE_MOBILE_SERIES(psav->Chipset) || (psav->ForceInit))
     )
@@ -2485,7 +2651,10 @@
 		       "Internal error: could not map framebuffer\n");
 	    return FALSE;
 	}
-	psav->FBStart = psav->FBBase;
+	if (psav->IsSecondary)
+	    psav->FBStart = psav->FBBase + 0x1000000;
+	else	
+	    psav->FBStart = psav->FBBase;
     }
 
     if (psav->Chipset == S3_SUPERSAVAGE)
@@ -2493,10 +2662,22 @@
         psav->ApertureBase =  psav->PciInfo->memBase[2];
     else
         psav->ApertureBase = psav->FrameBufferBase + 0x02000000;
-        
-    psav->ApertureMap = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
+
+    if (psav->IsSecondary) {
+    	psav->ApertureMap = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
+                                      psav->PciTag, psav->ApertureBase,
+                                      0x01000000 * 2);
+	psav->ApertureMap += 0x1000000;
+    } else if (psav->IsPrimary) {
+    	psav->ApertureMap = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
+                                      psav->PciTag, psav->ApertureBase,
+                                      0x01000000 * 2);
+    } else {
+        psav->ApertureMap = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
                                       psav->PciTag, psav->ApertureBase,
                                       0x01000000 * 5);
+    }
+
     if (!psav->ApertureMap) {
         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
                    "Internal error: could not map aperture\n");
@@ -2509,8 +2690,12 @@
 
     }
 
-    pScrn->memPhysBase = psav->PciInfo->memBase[0];
-    pScrn->fbOffset = 0;
+    if (psav->IsSecondary)
+	pScrn->fbOffset = pScrn->videoRam * 1024;
+    else
+    	pScrn->fbOffset = 0;
+
+    pScrn->memPhysBase = psav->PciInfo->memBase[0] + pScrn->fbOffset;
 
     return TRUE;
 }
@@ -2584,9 +2769,8 @@
         xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Sufficient Videoram available for 3D\n");
 	return TRUE;
     } else {
-        xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Insufficient Videoram available for 3D\n");
-        xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Try a lower color depth or smaller desktop.\n");
-	xf86DrvMsg(pScrn->scrnIndex,X_ERROR,
+        xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Insufficient Videoram available for 3D -- "
+					"Try a lower color depth or smaller desktop.  "
 			"For integrated savages try increasing the videoram in the BIOS.\n");
 	return FALSE;
     }
@@ -2658,7 +2842,16 @@
 	return FALSE;
 
 #ifdef XF86DRI
-    if (((psav->Chipset == S3_TWISTER)
+    if (psav->IsSecondary) {
+	    psav->directRenderingEnabled = FALSE;
+    } else if (xf86IsEntityShared(psav->pEnt->index)) {
+	    /* Xinerama has sync problem with DRI, disable it for now */
+	    psav->directRenderingEnabled = FALSE;
+	    xf86DrvMsg(scrnIndex, X_WARNING,
+			"Direct Rendering Disabled -- "
+			"Dual-head configuration is not working with "
+			"DRI at present.\n");
+    } else if (((psav->Chipset == S3_TWISTER)
         || (psav->Chipset == S3_PROSAVAGE)
         || (psav->Chipset == S3_SAVAGE4)
         || (psav->Chipset == S3_SAVAGE_MX)
@@ -2847,8 +3040,13 @@
 #endif
 
 #ifdef XvExtension
-    if( !psav->FBStart2nd && !psav->NoAccel && !SavagePanningCheck(pScrn) )
-	SavageInitVideo( pScreen );
+    if( !psav->FBStart2nd && !psav->NoAccel  /*&& !SavagePanningCheck(pScrn)*/ ) {
+	if (psav->IsSecondary)
+            /* Xv should work on crtc2, but I haven't gotten there yet.  -- AGD */
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Xv currently disabled for crtc2.\n");
+	else
+	    SavageInitVideo( pScreen );
+    }
 #endif
 
     if ((psav->directRenderingEnabled) && (!psav->bDisableXvMC)) {
@@ -2900,12 +3098,7 @@
     }
 
     if (!psav->FBStart2nd) {
-#if 0
-	ret = fbScreenInit(pScreen, FBStart, width, height,
-			   pScrn->xDpi, pScrn->yDpi,
-			   displayWidth,
-			   pScrn->bitsPerPixel);
-#endif
+
         ret = fbScreenInit(pScreen, FBStart, width, height,
                            pScrn->xDpi, pScrn->yDpi,
                            psav->ulAperturePitch / (pScrn->bitsPerPixel >> 3), /*displayWidth,*/
@@ -2947,6 +3140,7 @@
 {
     ScrnInfoPtr pScrn = xf86Screens[index];
     SavagePtr psav = SAVPTR(pScrn);
+    int refresh;
 
     TRACE(("SavageValidMode\n"));
 
@@ -2962,16 +3156,19 @@
 	    return MODE_VIRTUAL_Y;
 
     }
-    if( 
-	!psav->CrtOnly &&
-	psav->PanelX &&
-	( 
-	    (pMode->HDisplay > psav->PanelX) ||
-	    (pMode->VDisplay > psav->PanelY)
-	)
-    )
+
+    if((psav->DisplayType == MT_LCD) &&
+      ((pMode->HDisplay > psav->PanelX) ||
+       (pMode->VDisplay > psav->PanelY)))
 	    return MODE_PANEL;
 
+    if (psav->UseBIOS) {
+        refresh = (pMode->Clock * 1000) / (pMode->HTotal * pMode->VTotal);
+        return (SavageMatchBiosMode(pScrn,pMode->HDisplay,
+                                   pMode->VDisplay,
+                                   refresh,NULL,NULL));
+    }
+
     return MODE_OK;
 }
 
@@ -2985,6 +3182,8 @@
     SavageRegPtr new = &psav->ModeReg;
     vgaRegPtr vganew = &hwp->ModeReg;
     int vgaCRIndex, vgaCRReg, vgaIOBase;
+    int refresh;
+    unsigned int newmode=0, newrefresh=0;
 
     vgaIOBase = hwp->IOBase;
     vgaCRIndex = vgaIOBase + 4;
@@ -3012,6 +3211,24 @@
 	    mode->CrtcVTotal);
 #endif
 
+    if (psav->IsSecondary) {
+        refresh = (mode->Clock * 1000) / (mode->HTotal * mode->VTotal);
+
+        SavageMatchBiosMode(pScrn,mode->HDisplay,mode->VDisplay,refresh,
+                            &newmode,&newrefresh);
+	new->mode = newmode;
+	new->refresh = newrefresh;
+
+        /* do it! */
+        SavageWriteMode(pScrn, vganew, new, TRUE);
+        SavageStreamsOn(pScrn);
+
+        if (psav->FBStart2nd)
+	    SavageInitSecondaryStream(pScrn);
+
+        SavageAdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
+	return TRUE;
+    }
 
 
     if (pScrn->bitsPerPixel == 8)
@@ -3077,63 +3294,14 @@
 
     if( psav->UseBIOS ) {
 	int refresh;
-	SavageModeEntryPtr pmt;
-
-	/* Scan through our BIOS list to locate the closest valid mode. */
-
-	/* If we ever break 4GHz clocks on video boards, we'll need to
-	 * change this.
-	 */
+	unsigned int newmode=0, newrefresh=0;
 
         refresh = (mode->Clock * 1000) / (mode->HTotal * mode->VTotal);
 
-#ifdef EXTENDED_DEBUG
-	ErrorF( "Desired refresh rate = %dHz\n", refresh );
-#endif
-
-	for( i = 0, pmt = psav->ModeTable->Modes; 
-	    i < psav->ModeTable->NumModes;
-	    i++, pmt++ )
-	{
-	    if( (pmt->Width == mode->HDisplay) && 
-	        (pmt->Height == mode->VDisplay) )
-	    {
-		int jDelta = 99;
-		int jBest = 0;
-
-		/* We have an acceptable mode.  Find a refresh rate. */
-
-		new->mode = pmt->VesaMode;
-		for( j = 0; j < pmt->RefreshCount; j++ )
-		{
-		    if( pmt->RefreshRate[j] == refresh )
-		    {
-			/* Exact match. */
-			jBest = j;
-			break;
-		    }
-		    else if( iabs(pmt->RefreshRate[j] - refresh) < jDelta )
-		    {
-			jDelta = iabs(pmt->RefreshRate[j] - refresh);
-			jBest = j;
-		    }
-		}
-
-		new->refresh = pmt->RefreshRate[jBest];
-		break;
-	    }
-	}
-
-	if( new->mode ) {
-	    /* Success: we found a match in the BIOS. */
-	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 
-		      "Chose mode %x at %dHz.\n", new->mode, new->refresh );
-	}
-	else {
-	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 
-		      "No suitable BIOS mode found for %dx%d %dMHz.\n",
-		      mode->HDisplay, mode->VDisplay, mode->Clock/1000 );
-	}
+        SavageMatchBiosMode(pScrn,mode->HDisplay,mode->VDisplay,refresh,
+                            &newmode,&newrefresh);
+	new->mode = newmode;
+	new->refresh = newrefresh;
     }
 
     if( !new->mode ) {
@@ -3389,10 +3557,22 @@
     return vgaHWSaveScreen(pScreen, mode);
 }
 
+void SavageAdjustFrame(int scrnIndex, int x, int y, int flags)
+{
+    ScrnInfoPtr    pScrn      = xf86Screens[scrnIndex];
+    SavagePtr psav = SAVPTR(pScrn);
+
+    if (psav->IsSecondary) {
+	SavageDoAdjustFrame(pScrn, x, y, TRUE);
+    } else {
+	SavageDoAdjustFrame(pScrn, x, y, FALSE);
+    }
+
+}
+
 void
-SavageAdjustFrame(int scrnIndex, int x, int y, int flags)
+SavageDoAdjustFrame(ScrnInfoPtr pScrn, int x, int y, int crtc2)
 {
-    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
     SavagePtr psav = SAVPTR(pScrn);
     DisplayModePtr currentMode = pScrn->currentMode;    
     int address=0,top=0,left=0;
@@ -3415,62 +3595,66 @@
         }
     }
     
+    address += pScrn->fbOffset;
+
     /*
      * because we align the viewport to the width and height of one tile
-     * we shoud update the locate of frame
+     * we should update the locate of frame
      */
     pScrn->frameX0 = left;
     pScrn->frameY0 = top;
     pScrn->frameX1 = left + currentMode->HDisplay - 1;
-    pScrn->frameY1 = top+ currentMode->VDisplay - 1;
+    pScrn->frameY1 = top + currentMode->VDisplay - 1;
 
-    if (S3_SAVAGE_MOBILE_SERIES(psav->Chipset)) {
-        OUTREG32(PRI_STREAM_FBUF_ADDR0,address |  0xFFFFFFFC); /* IGA1 */
-        OUTREG32(PRI_STREAM_FBUF_ADDR1,address |  0x80000000);
-        OUTREG32(PRI_STREAM2_FBUF_ADDR0,address |  0xFFFFFFFC); /* IGA2 */
-        OUTREG32(PRI_STREAM2_FBUF_ADDR1,address |  0x80000000);
+    if (psav->Chipset == S3_SAVAGE_MX) {
+	if (!crtc2) {
+            OUTREG32(PRI_STREAM_FBUF_ADDR0, address & 0xFFFFFFFC);
+            OUTREG32(PRI_STREAM_FBUF_ADDR1, address & 0xFFFFFFFC);/* IGA1 */
+        } else { 
+            OUTREG32(PRI_STREAM2_FBUF_ADDR0, address & 0xFFFFFFFC);/* IGA2 */
+            OUTREG32(PRI_STREAM2_FBUF_ADDR1, address & 0xFFFFFFFC);
+	}
+    } else if (psav->Chipset == S3_SUPERSAVAGE) {
+	if (!crtc2) {
+            /* IGA1 */
+            OUTREG32(PRI_STREAM_FBUF_ADDR0, 0x80000000);
+            OUTREG32(PRI_STREAM_FBUF_ADDR1, address & 0xFFFFFFF8);
+        } else {
+            /* IGA2 */
+            OUTREG32(PRI_STREAM2_FBUF_ADDR0, ((address & 0xFFFFFFF8) | 0x80000000));
+            OUTREG32(PRI_STREAM2_FBUF_ADDR1, address & 0xFFFFFFF8);
+	}
     } else {
-        OUTREG32(PSTREAM_FBADDR0_REG,address |  0xFFFFFFFC);
-        OUTREG32(PSTREAM_FBADDR1_REG,address |  0x80000000);
+        OUTREG32(PRI_STREAM_FBUF_ADDR0,address |  0xFFFFFFFC);
+        OUTREG32(PRI_STREAM_FBUF_ADDR1,address |  0x80000000);
     }
-    
+   
     return;
 }
 
-#if 0
-void SavageAdjustFrame(int scrnIndex, int x, int y, int flags)
+Bool SavageSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
 {
-    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
-    vgaHWPtr hwp = VGAHWPTR(pScrn);
+    ScrnInfoPtr    pScrn      = xf86Screens[scrnIndex];
     SavagePtr psav = SAVPTR(pScrn);
-    int Base;
-    int vgaCRIndex, vgaCRReg, vgaIOBase;
-    vgaIOBase = hwp->IOBase;
-    vgaCRIndex = vgaIOBase + 4;
-    vgaCRReg = vgaIOBase + 5;
+    Bool success;
 
-    TRACE(("SavageAdjustFrame(%d,%d,%x)\n", x, y, flags));
+    TRACE(("SavageSwitchMode\n"));
 
-    if (psav->ShowCache && y)
-	y += pScrn->virtualY - 1;
+    SavageStreamsOff(xf86Screens[scrnIndex]);
 
-    Base = ((y * pScrn->displayWidth + (x&~1)) *
-	    (psav->primStreamBpp / 8)) >> 2;
-    /* now program the start address registers */
-    VGAOUT16(vgaCRIndex, (Base & 0x00ff00) | 0x0c);
-    VGAOUT16(vgaCRIndex, ((Base & 0x00ff) << 8) | 0x0d);
-    VGAOUT8(vgaCRIndex, 0x69);
-    VGAOUT8(vgaCRReg, (Base & 0x7f0000) >> 16);
+    success = SavageModeInit(xf86Screens[scrnIndex], mode);
 
-    return;
-}
-#endif
+    /* switching mode on primary will reset secondary.  it needs to be reset as well*/
+    if (psav->IsPrimary) {
+        DevUnion* pPriv;
+        SavageEntPtr pSavEnt;
+        pPriv = xf86GetEntityPrivate(pScrn->entityList[0], 
+              gSavageEntityIndex);
+        pSavEnt = pPriv->ptr;
+        SavageModeInit(pSavEnt->pSecondaryScrn, pSavEnt->pSecondaryScrn->currentMode);
+    }
 
-Bool SavageSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
-{
-    TRACE(("SavageSwitchMode\n"));
-    SavageStreamsOff(xf86Screens[scrnIndex]);
-    return SavageModeInit(xf86Screens[scrnIndex], mode);
+    return success;
 }
 
 
@@ -3787,7 +3971,6 @@
     ErrorF("\n\n");
 }
 
-
 static void SavageDPMS(ScrnInfoPtr pScrn, int mode, int flags)
 {
     SavagePtr psav = SAVPTR(pScrn);
@@ -3795,34 +3978,39 @@
 
     TRACE(("SavageDPMS(%d,%x)\n", mode, flags));
 
-    VGAOUT8(0x3c4, 0x08);
-    sr8 = VGAIN8(0x3c5);
-    sr8 |= 0x06;
-    VGAOUT8(0x3c5, sr8);
-
-    VGAOUT8(0x3c4, 0x0d);
-    srd = VGAIN8(0x3c5);
-
-    srd &= 0x03;
+    if (psav->DisplayType == MT_CRT) {
+    	VGAOUT8(0x3c4, 0x08);
+    	sr8 = VGAIN8(0x3c5);
+    	sr8 |= 0x06;
+    	VGAOUT8(0x3c5, sr8);
+
+    	VGAOUT8(0x3c4, 0x0d);
+    	srd = VGAIN8(0x3c5);
+
+    	srd &= 0x03;
+
+    	switch (mode) {
+	    case DPMSModeOn:
+	    	break;
+	    case DPMSModeStandby:
+	    	srd |= 0x10;
+	    	break;
+	    case DPMSModeSuspend:
+	    	srd |= 0x40;
+	    	break;
+	    case DPMSModeOff:
+	    	srd |= 0x50;
+	    	break;
+	    default:
+	    	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid DPMS mode %d\n", mode);
+	    	break;
+    	}
 
-    switch (mode) {
-	case DPMSModeOn:
-	    break;
-	case DPMSModeStandby:
-	    srd |= 0x10;
-	    break;
-	case DPMSModeSuspend:
-	    srd |= 0x40;
-	    break;
-	case DPMSModeOff:
-	    srd |= 0x50;
-	    break;
-	default:
-	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid DPMS mode %d\n", mode);
-	    break;
+    	VGAOUT8(0x3c4, 0x0d);
+    	VGAOUT8(0x3c5, srd);
     }
- 
-    if ((!psav->CrtOnly) && psav->PanelX) {
+
+    if (psav->DisplayType == MT_LCD || psav->DisplayType == MT_DFP) {
 	if (S3_MOBILE_TWISTER_SERIES(psav->Chipset)) {
 	    SavageSetPanelEnabled(psav, (mode == DPMSModeOn));
 	} else {
@@ -3844,9 +4032,6 @@
         }
     }
 
-    VGAOUT8(0x3c4, 0x0d);
-    VGAOUT8(0x3c5, srd);
-
     return;
 }
 
Index: savage_driver.h
===================================================================
RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/savage/savage_driver.h,v
retrieving revision 1.5
diff -u -r1.5 savage_driver.h
--- savage_driver.h	18 Sep 2004 13:37:30 -0000	1.5
+++ savage_driver.h	27 Sep 2004 04:41:20 -0000
@@ -35,6 +35,22 @@
 #include "GL/glxint.h"
 #endif
 
+typedef enum {
+    MT_NONE,
+    MT_CRT,
+    MT_LCD,
+    MT_DFP,
+    MT_TV
+} SavageMonitorType;
+
+typedef struct
+{
+    Bool HasSecondary;
+
+    ScrnInfoPtr pSecondaryScrn;
+    ScrnInfoPtr pPrimaryScrn;
+  
+} SavageEntRec, *SavageEntPtr;
 
 #ifndef uint
 typedef unsigned int            uint;
@@ -361,6 +377,16 @@
     
     StatInfoRec     StatInfo; /* save the SVGA state */
 
+    /* for dvi option */
+    Bool  dvi;
+
+    SavageMonitorType   DisplayType;
+    /* DuoView stuff */
+    Bool		HasCRTC2;     /* MX, IX, Supersavage */
+    Bool		IsSecondary;  /* second Screen */	
+    Bool		IsPrimary;  /* first Screen */
+    EntityInfoPtr       pEnt;
+
 } SavageRec, *SavagePtr;
 
 /* Video flags. */
@@ -419,6 +445,7 @@
 			long freq_min, long freq_max,
 			unsigned char *mdiv, unsigned char *ndiv);
 void SavageAdjustFrame(int scrnIndex, int y, int x, int flags);
+void SavageDoAdjustFrame(ScrnInfoPtr pScrn, int y, int x, int crtc2);
 Bool SavageSwitchMode(int scrnIndex, DisplayModePtr mode, int flags);
 
 /* In savage_cursor.c. */
@@ -455,6 +482,8 @@
 void SavageSetPanelEnabled( SavagePtr psav, Bool active );
 void SavageFreeBIOSModeTable( SavagePtr psav, SavageModeTablePtr* ppTable );
 SavageModeTablePtr SavageGetBIOSModeTable( SavagePtr psav, int iDepth );
+ModeStatus SavageMatchBiosMode(ScrnInfoPtr pScrn,int width,int height,int refresh,
+                              unsigned int *vesaMode,unsigned int *newRefresh);
 
 unsigned short SavageGetBIOSModes( 
     SavagePtr psav,
Index: savage_regs.h
===================================================================
RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/savage/savage_regs.h,v
retrieving revision 1.4
diff -u -r1.4 savage_regs.h
--- savage_regs.h	16 Sep 2004 22:00:48 -0000	1.4
+++ savage_regs.h	27 Sep 2004 04:41:20 -0000
@@ -159,9 +159,21 @@
 #define S3_SEC_BD_LOW                      0X8178
 #define S3_SEC_BD_HIGH                     0X817c
 
+/* duoview */
+
 #define SELECT_IGA1                 0x4026
 #define SELECT_IGA2_READS_WRITES    0x4f26
 
+#define SelectIGA1()                 \
+do {                                    \
+    OUTREG16(SEQ_ADDRESS_REG,SELECT_IGA1); \
+} while (0)
+
+#define SelectIGA2()                 \
+do {                                    \
+    OUTREG16(SEQ_ADDRESS_REG,SELECT_IGA2_READS_WRITES); \
+} while (0)
+
 #define MEM_PS1                     0x10    /*CRCA_4 :Primary stream 1*/
 #define MEM_PS2                     0x20    /*CRCA_5 :Primary stream 2*/
 #define MEM_SS1                     0x40    /*CRCA_6 :Secondary stream 1*/
Index: savage_streams.c
===================================================================
RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/savage/savage_streams.c,v
retrieving revision 1.2
diff -u -r1.2 savage_streams.c
--- savage_streams.c	16 Sep 2004 22:00:48 -0000	1.2
+++ savage_streams.c	27 Sep 2004 04:41:20 -0000
@@ -130,27 +130,6 @@
 
     xf86ErrorFVerb(STREAMS_TRACE, "SavageInitStreams\n" );
 
-    /* Primary stream reflects the frame buffer. */
-
-    if (!psav->bTiled) {
-        OUTREG(PSTREAM_STRIDE_REG,
-                 (((psav->lDelta * 2) << 16) & 0x3FFFE000) |
-                 (psav->lDelta & 0x00001fff));
-    }
-    else if (pScrn->bitsPerPixel == 16) {
-        /* Scanline-length-in-bytes/128-bytes-per-tile * 256 Qwords/tile */
-        OUTREG(PSTREAM_STRIDE_REG,
-                 (((psav->lDelta * 2) << 16) & 0x3FFFE000)
-                 | 0x80000000 | (psav->lDelta & 0x00001fff));
-    }
-    else if (pScrn->bitsPerPixel == 32) {
-        OUTREG(PSTREAM_STRIDE_REG,
-                 (((psav->lDelta * 2) << 16) & 0x3FFFE000)
-                 | 0xC0000000 | (psav->lDelta & 0x00001fff));
-    }
-    OUTREG(PSTREAM_FBSIZE_REG, 
-		pScrn->virtualY * pScrn->virtualX * (pScrn->bitsPerPixel >> 3));
-
 
     if (psav->FBStart2nd) {
 	unsigned long jDelta = pScrn->displayWidth;
@@ -165,6 +144,8 @@
 	    case 16: format = 5 << 24; break;
 	    case 24: format = 7 << 24; break;
 	}
+        OUTREG(PSTREAM_FBSIZE_REG, 
+		pScrn->virtualY * pScrn->virtualX * (pScrn->bitsPerPixel >> 3));
     }
     
     OUTREG( PSTREAM_WINDOW_START_REG, OS_XY(0,0) );
@@ -225,34 +206,28 @@
 
     xf86ErrorFVerb(STREAMS_TRACE, "SavageInitStreams\n" );
 
-    if( 
-	S3_SAVAGE_MOBILE_SERIES(psav->Chipset) && 
+    if ( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) && 
+	(psav->DisplayType == MT_LCD) &&
 	!psav->CrtOnly && 
-	!psav->TvOn 
-    ) {
+	!psav->TvOn )
+    {
 	OverlayParamInit( pScrn );
     }
 
-    /* Primary stream reflects the frame buffer. */
-    OUTREG32(PRI_STREAM_FBUF_ADDR0, pScrn->fbOffset);
-    if (!psav->bTiled) {
-        OUTREG(PRI_STREAM_STRIDE,
-                 (((psav->lDelta * 2) << 16) & 0x3FFFE000) |
-                 (psav->lDelta & 0x00001fff));
-    }
-    else if (pScrn->bitsPerPixel == 16) {
-        /* Scanline-length-in-bytes/128-bytes-per-tile * 256 Qwords/tile */
-        OUTREG(PRI_STREAM_STRIDE,
-                 (((psav->lDelta * 2) << 16) & 0x3FFFE000)
-                 | 0x80000000 | (psav->lDelta & 0x00001fff));
-    }
-    else if (pScrn->bitsPerPixel == 32) {
-        OUTREG(PRI_STREAM_STRIDE,
-                 (((psav->lDelta * 2) << 16) & 0x3FFFE000)
-                 | 0xC0000000 | (psav->lDelta & 0x00001fff));
-    }
-    OUTREG(PRI_STREAM_BUFFERSIZE,
+    if (psav->IsSecondary) {
+        OUTREG(PRI_STREAM2_BUFFERSIZE,
              pScrn->virtualX * pScrn->virtualY * (pScrn->bitsPerPixel >> 3));
+    } else if (psav->IsPrimary){
+        OUTREG(PRI_STREAM_BUFFERSIZE,
+             pScrn->virtualX * pScrn->virtualY * (pScrn->bitsPerPixel >> 3));
+    } else {
+        OUTREG(PRI_STREAM_BUFFERSIZE,
+             pScrn->virtualX * pScrn->virtualY * (pScrn->bitsPerPixel >> 3));
+#if 0
+        OUTREG(PRI_STREAM2_BUFFERSIZE,
+             pScrn->virtualX * pScrn->virtualY * (pScrn->bitsPerPixel >> 3));
+#endif
+    }
 
     if (psav->FBStart2nd) {
 	unsigned long jDelta = pScrn->displayWidth;
@@ -260,51 +235,88 @@
     	OUTREG( PRI_STREAM_FBUF_ADDR0, pScrn->fbOffset );
     	OUTREG( PRI_STREAM_STRIDE, jDelta );
     }
-#if 0 
-    else {
-	jDelta = pScrn->displayWidth * (pScrn->bitsPerPixel + 7) / 8;
-    }
-#endif
-    /*OUTREG( PRI_STREAM_BUFFERSIZE, jDelta * pScrn->virtualY >> 3 );*/
-    OUTREG( PRI_STREAM_FBUF_ADDR0, pScrn->fbOffset );
-    /*OUTREG( PRI_STREAM_STRIDE, jDelta );*/
-
-    OUTREG( SEC_STREAM_CKEY_LOW, 0 );
-    OUTREG( SEC_STREAM_CKEY_UPPER, 0 );
-    OUTREG( SEC_STREAM_HSCALING, 0 );
-    OUTREG( SEC_STREAM_VSCALING, 0 );
-    OUTREG( BLEND_CONTROL, 0 );
-    OUTREG( SEC_STREAM_FBUF_ADDR0, 0 );
-    OUTREG( SEC_STREAM_FBUF_ADDR1, 0 );
-    OUTREG( SEC_STREAM_FBUF_ADDR2, 0 );
-    OUTREG( SEC_STREAM_WINDOW_START, 0 );
-    OUTREG( SEC_STREAM_WINDOW_SZ, 0 );
-/*    OUTREG( SEC_STREAM_BUFFERSIZE, 0 ); */
-    OUTREG( SEC_STREAM_TILE_OFF, 0 );
-    OUTREG( SEC_STREAM_OPAQUE_OVERLAY, 0 );
-    OUTREG( SEC_STREAM_STRIDE, 0 );
-
-    /* These values specify brightness, contrast, saturation and hue. */
-    OUTREG( SEC_STREAM_COLOR_CONVERT1, 0x0000C892 );
-    OUTREG( SEC_STREAM_COLOR_CONVERT2, 0x00039F9A );
-    OUTREG( SEC_STREAM_COLOR_CONVERT3, 0x01F1547E );
-#if 0
-    {
-	vgaHWPtr hwp;
-	unsigned short vgaIOBase, vgaCRIndex, vgaCRReg;
-	hwp = VGAHWPTR(pScrn);
-	unsigned char cr90;
-
-	vgaHWGetIOBase(hwp);
-	vgaIOBase = hwp->IOBase;
-	vgaCRIndex = vgaIOBase + 4;
-	vgaCRReg = vgaIOBase + 5;
 
-	VGAOUT8(vgaCRIndex, 0x90);
-	cr90 = VGAIN8(vgaCRReg);
-	VGAOUT8(vgaCRReg, (cr90 & 0x7F));
-    }
+    if (psav->IsSecondary) {
+    	OUTREG( SEC_STREAM2_CKEY_LOW, 0 );
+    	OUTREG( SEC_STREAM2_CKEY_UPPER, 0 );
+    	OUTREG( SEC_STREAM2_HSCALING, 0 );
+    	OUTREG( SEC_STREAM2_VSCALING, 0 );
+    	OUTREG( BLEND_CONTROL, 0 );
+    	OUTREG( SEC_STREAM2_FBUF_ADDR0, 0 );
+    	OUTREG( SEC_STREAM2_FBUF_ADDR1, 0 );
+    	OUTREG( SEC_STREAM2_FBUF_ADDR2, 0 );
+    	OUTREG( SEC_STREAM2_WINDOW_START, 0 );
+    	OUTREG( SEC_STREAM2_WINDOW_SZ, 0 );
+/*    	OUTREG( SEC_STREAM2_BUFFERSIZE, 0 ); */
+    	OUTREG( SEC_STREAM2_OPAQUE_OVERLAY, 0 );
+    	OUTREG( SEC_STREAM2_STRIDE_LPB, 0 );
+
+    	/* These values specify brightness, contrast, saturation and hue. */
+    	OUTREG( SEC_STREAM2_COLOR_CONVERT1, 0x0000C892 );
+    	OUTREG( SEC_STREAM2_COLOR_CONVERT2, 0x00039F9A );
+    	OUTREG( SEC_STREAM2_COLOR_CONVERT3, 0x01F1547E );
+    } else if (psav->IsPrimary) {
+    	OUTREG( SEC_STREAM_CKEY_LOW, 0 );
+    	OUTREG( SEC_STREAM_CKEY_UPPER, 0 );
+    	OUTREG( SEC_STREAM_HSCALING, 0 );
+    	OUTREG( SEC_STREAM_VSCALING, 0 );
+    	OUTREG( BLEND_CONTROL, 0 );
+    	OUTREG( SEC_STREAM_FBUF_ADDR0, 0 );
+    	OUTREG( SEC_STREAM_FBUF_ADDR1, 0 );
+    	OUTREG( SEC_STREAM_FBUF_ADDR2, 0 );
+    	OUTREG( SEC_STREAM_WINDOW_START, 0 );
+    	OUTREG( SEC_STREAM_WINDOW_SZ, 0 );
+/*    	OUTREG( SEC_STREAM_BUFFERSIZE, 0 ); */
+    	OUTREG( SEC_STREAM_TILE_OFF, 0 );
+    	OUTREG( SEC_STREAM_OPAQUE_OVERLAY, 0 );
+    	OUTREG( SEC_STREAM_STRIDE, 0 );
+
+    	/* These values specify brightness, contrast, saturation and hue. */
+    	OUTREG( SEC_STREAM_COLOR_CONVERT1, 0x0000C892 );
+    	OUTREG( SEC_STREAM_COLOR_CONVERT2, 0x00039F9A );
+    	OUTREG( SEC_STREAM_COLOR_CONVERT3, 0x01F1547E );
+    } else {
+    	OUTREG( SEC_STREAM_CKEY_LOW, 0 );
+    	OUTREG( SEC_STREAM_CKEY_UPPER, 0 );
+    	OUTREG( SEC_STREAM_HSCALING, 0 );
+    	OUTREG( SEC_STREAM_VSCALING, 0 );
+    	OUTREG( BLEND_CONTROL, 0 );
+    	OUTREG( SEC_STREAM_FBUF_ADDR0, 0 );
+    	OUTREG( SEC_STREAM_FBUF_ADDR1, 0 );
+    	OUTREG( SEC_STREAM_FBUF_ADDR2, 0 );
+    	OUTREG( SEC_STREAM_WINDOW_START, 0 );
+    	OUTREG( SEC_STREAM_WINDOW_SZ, 0 );
+/*    	OUTREG( SEC_STREAM_BUFFERSIZE, 0 ); */
+    	OUTREG( SEC_STREAM_TILE_OFF, 0 );
+    	OUTREG( SEC_STREAM_OPAQUE_OVERLAY, 0 );
+    	OUTREG( SEC_STREAM_STRIDE, 0 );
+
+    	/* These values specify brightness, contrast, saturation and hue. */
+    	OUTREG( SEC_STREAM_COLOR_CONVERT1, 0x0000C892 );
+    	OUTREG( SEC_STREAM_COLOR_CONVERT2, 0x00039F9A );
+    	OUTREG( SEC_STREAM_COLOR_CONVERT3, 0x01F1547E );
+#if 0
+	sleep(1);
+    	OUTREG( SEC_STREAM2_CKEY_LOW, 0 );
+    	OUTREG( SEC_STREAM2_CKEY_UPPER, 0 );
+    	OUTREG( SEC_STREAM2_HSCALING, 0 );
+    	OUTREG( SEC_STREAM2_VSCALING, 0 );
+    	OUTREG( BLEND_CONTROL, 0 );
+    	OUTREG( SEC_STREAM2_FBUF_ADDR0, 0 );
+    	OUTREG( SEC_STREAM2_FBUF_ADDR1, 0 );
+    	OUTREG( SEC_STREAM2_FBUF_ADDR2, 0 );
+    	OUTREG( SEC_STREAM2_WINDOW_START, 0 );
+    	OUTREG( SEC_STREAM2_WINDOW_SZ, 0 );
+/*    	OUTREG( SEC_STREAM2_BUFFERSIZE, 0 ); */
+    	OUTREG( SEC_STREAM2_OPAQUE_OVERLAY, 0 );
+    	OUTREG( SEC_STREAM2_STRIDE_LPB, 0 );
+
+    	/* These values specify brightness, contrast, saturation and hue. */
+    	OUTREG( SEC_STREAM2_COLOR_CONVERT1, 0x0000C892 );
+    	OUTREG( SEC_STREAM2_COLOR_CONVERT2, 0x00039F9A );
+    	OUTREG( SEC_STREAM2_COLOR_CONVERT3, 0x01F1547E );
 #endif
+    }
 }
 
 /*
@@ -477,18 +489,50 @@
 
 	jStreamsControl = VGAIN8( vgaCRReg ) | ENABLE_STREAM1;
 
-	/* Wait for VBLANK. */
-	
-	VerticalRetraceWait();
-
-	/* Fire up streams! */
-
-	VGAOUT16( vgaCRIndex, (jStreamsControl << 8) | EXT_MISC_CTRL2 );
-
+	if (psav->IsSecondary) {
+	    SelectIGA2();
+	    /* Wait for VBLANK. */	
+	    VerticalRetraceWait();
+	    /* Fire up streams! */
+	    VGAOUT16( vgaCRIndex, (jStreamsControl << 8) | EXT_MISC_CTRL2 );
+	    SelectIGA1();
+	/* These values specify brightness, contrast, saturation and hue. */
+	    OUTREG( SEC_STREAM2_COLOR_CONVERT1, 0x0000C892 );
+	    OUTREG( SEC_STREAM2_COLOR_CONVERT2, 0x00039F9A );
+	    OUTREG( SEC_STREAM2_COLOR_CONVERT3, 0x01F1547E );
+	} else if (psav->IsPrimary) {
+	    /* Wait for VBLANK. */	
+	    VerticalRetraceWait();
+	    /* Fire up streams! */
+	    VGAOUT16( vgaCRIndex, (jStreamsControl << 8) | EXT_MISC_CTRL2 );
 	/* These values specify brightness, contrast, saturation and hue. */
-	OUTREG( SEC_STREAM_COLOR_CONVERT1, 0x0000C892 );
-	OUTREG( SEC_STREAM_COLOR_CONVERT2, 0x00039F9A );
-	OUTREG( SEC_STREAM_COLOR_CONVERT3, 0x01F1547E );
+	    OUTREG( SEC_STREAM_COLOR_CONVERT1, 0x0000C892 );
+	    OUTREG( SEC_STREAM_COLOR_CONVERT2, 0x00039F9A );
+	    OUTREG( SEC_STREAM_COLOR_CONVERT3, 0x01F1547E );
+	} else {
+	    /* Wait for VBLANK. */	
+	    VerticalRetraceWait();
+	    /* Fire up streams! */
+	    VGAOUT16( vgaCRIndex, (jStreamsControl << 8) | EXT_MISC_CTRL2 );
+#if 0
+	    SelectIGA2();
+	    /* Wait for VBLANK. */	
+	    VerticalRetraceWait();
+	    /* Fire up streams! */
+	    VGAOUT16( vgaCRIndex, (jStreamsControl << 8) | EXT_MISC_CTRL2 );
+	    SelectIGA1();
+#endif
+	/* These values specify brightness, contrast, saturation and hue. */
+	    OUTREG( SEC_STREAM_COLOR_CONVERT1, 0x0000C892 );
+	    OUTREG( SEC_STREAM_COLOR_CONVERT2, 0x00039F9A );
+	    OUTREG( SEC_STREAM_COLOR_CONVERT3, 0x01F1547E );
+#if 0
+	    sleep(1);
+	    OUTREG( SEC_STREAM2_COLOR_CONVERT1, 0x0000C892 );
+	    OUTREG( SEC_STREAM2_COLOR_CONVERT2, 0x00039F9A );
+	    OUTREG( SEC_STREAM2_COLOR_CONVERT3, 0x01F1547E );
+#endif
+	}
     }
     else
     {
@@ -545,8 +589,20 @@
     VerticalRetraceWait();
 
     /* Kill streams. */
-
-    VGAOUT16( vgaCRIndex, (jStreamsControl << 8) | EXT_MISC_CTRL2 );
+    if (psav->IsSecondary) {
+        SelectIGA2();
+        VGAOUT16( vgaCRIndex, (jStreamsControl << 8) | EXT_MISC_CTRL2 );
+	SelectIGA1();
+    } else if (psav->IsPrimary) {
+        VGAOUT16( vgaCRIndex, (jStreamsControl << 8) | EXT_MISC_CTRL2 );
+    } else {
+        VGAOUT16( vgaCRIndex, (jStreamsControl << 8) | EXT_MISC_CTRL2 );
+#if 0
+        SelectIGA2();
+        VGAOUT16( vgaCRIndex, (jStreamsControl << 8) | EXT_MISC_CTRL2 );
+	SelectIGA1();
+#endif
+    }
 
     VGAOUT16( vgaCRIndex, 0x0093 );
     VGAOUT8( vgaCRIndex, 0x92 );
Index: savage_vbe.c
===================================================================
RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/savage/savage_vbe.c,v
retrieving revision 1.4
diff -u -r1.4 savage_vbe.c
--- savage_vbe.c	18 Sep 2004 13:37:30 -0000	1.4
+++ savage_vbe.c	27 Sep 2004 04:41:20 -0000
@@ -3,6 +3,8 @@
 #include "savage_driver.h"
 #include "savage_vbe.h"
 
+#define iabs(a)	((int)(a)>0?(a):(-(a)))
+
 #if X_BYTE_ORDER == X_LITTLE_ENDIAN
 #define B_O16(x)  (x) 
 #define B_O32(x)  (x)
@@ -16,6 +18,8 @@
 Bool vbeModeInit( vbeInfoPtr, int );
 static int SavageGetDevice( SavagePtr psav );
 /*static int SavageGetTVType( SavagePtr psav );*/
+void SavageSetVESAModeCrtc1( SavagePtr psav, int n, int Refresh );
+void SavageSetVESAModeCrtc2( SavagePtr psav, int n, int Refresh );
 
 static void
 SavageClearVM86Regs( xf86Int10InfoPtr pInt )
@@ -49,6 +53,65 @@
     xf86ExecX86int10( psav->pVbe->pInt10 );
 }
 
+void
+SavageSetVESAModeCrtc1(SavagePtr psav, int n, int refresh)
+{
+    unsigned char byte;
+
+    xf86Msg(X_INFO,"SavageSetVESAModeCrtc1:mode=0x%x,refresh=%dHZ\n",n,refresh);
+
+    SavageClearVM86Regs(psav->pVbe->pInt10);
+    
+    /* set active displays. */
+    psav->pVbe->pInt10->ax = S3_EXTBIOS_INFO;
+    psav->pVbe->pInt10->bx = S3_SET_ACTIVE_DISP;
+    if (psav->TvOn)
+    	psav->pVbe->pInt10->cx = 0x87; /* lcd, tv, crt, duoview */
+    else
+    	psav->pVbe->pInt10->cx = 0x83; /* lcd, crt, duoview */
+    xf86ExecX86int10(psav->pVbe->pInt10);
+    
+    SavageClearVM86Regs(psav->pVbe->pInt10);
+    
+    /* Establish the refresh rate for this mode. */
+    psav->pVbe->pInt10->ax = S3_EXTBIOS_INFO;
+    psav->pVbe->pInt10->bx = S3_SET_REFRESH;
+    psav->pVbe->pInt10->cx = n & 0x1ff;
+    psav->pVbe->pInt10->di = refresh & 0xffff;
+    xf86ExecX86int10(psav->pVbe->pInt10);
+
+    /* SR01:turn off screen */
+    OUTREG8 (SEQ_ADDRESS_REG,0x01);
+    byte = INREG8(SEQ_DATA_REG) | 0x20;
+    OUTREG8(SEQ_DATA_REG,byte);
+    
+    psav->pVbe->pInt10->ax = BIOS_SET_VBE_MODE;
+    psav->pVbe->pInt10->bx = n;
+    xf86ExecX86int10(psav->pVbe->pInt10);
+    
+}
+
+void
+SavageSetVESAModeCrtc2( SavagePtr psav, int n, int refresh )
+{
+
+    xf86Msg(X_INFO,"SavageSetVESAModeCrtc2:mode=0x%x,refresh=%dHZ\n",n,refresh);
+
+    SavageClearVM86Regs(psav->pVbe->pInt10);
+
+    UnLockExtRegs();
+    
+    psav->pVbe->pInt10->ax = S3_EXTBIOS_INFO;
+    psav->pVbe->pInt10->bx = S3_ALT_SET_ACTIVE_DISP;
+    if (psav->TvOn)
+    	psav->pVbe->pInt10->cx = 0x87; /* lcd, tv, crt, duoview */
+    else
+    	psav->pVbe->pInt10->cx = 0x83; /* lcd, crt, duoview */
+    psav->pVbe->pInt10->dx = n & 0x1ff;
+    psav->pVbe->pInt10->di = refresh & 0xffff;
+    xf86ExecX86int10(psav->pVbe->pInt10);
+
+}
 
 void
 SavageSetVESAMode( SavagePtr psav, int n, int Refresh )
@@ -56,6 +119,15 @@
     int iDevInfo;
     static int iCount = 0;
 
+    if (psav->IsSecondary) {
+        SavageSetVESAModeCrtc2(psav, n, Refresh);
+	return;
+    }
+    if (psav->IsPrimary) {
+        SavageSetVESAModeCrtc1(psav, n, Refresh);
+	return;
+    }
+
     /* Get current display device status. */
 
     iDevInfo = SavageGetDevice(psav);
@@ -318,3 +390,71 @@
 
     return iModeCount;
 }
+
+ModeStatus SavageMatchBiosMode(ScrnInfoPtr pScrn,int width,int height,int refresh,
+                              unsigned int *vesaMode,unsigned int *newRefresh)
+{
+    SavageModeEntryPtr pmt;
+    Bool found = FALSE;
+    SavagePtr psav = SAVPTR(pScrn);    
+    int i,j;
+    unsigned int chosenVesaMode = 0;
+    unsigned int chosenRefresh = 0;
+    
+    /* Scan through our BIOS list to locate the closest valid mode. */
+    
+    /*
+     * If we ever break 4GHz clocks on video boards, we'll need to
+     * change this.
+     * refresh = (mode->Clock * 1000) / (mode->HTotal * mode->VTotal);
+     * now we use VRefresh directly,instead of by calculating from dot clock
+     */
+
+    for( i = 0, pmt = psav->ModeTable->Modes; 
+	i < psav->ModeTable->NumModes;
+	i++, pmt++ )
+    {
+	if( (pmt->Width == width) && 
+	    (pmt->Height == height) )
+	{
+	    int jDelta = 99;
+	    int jBest = 0;
+
+	    /* We have an acceptable mode.  Find a refresh rate. */
+	    chosenVesaMode = pmt->VesaMode;
+            if (vesaMode)
+                *vesaMode = chosenVesaMode;
+	    for( j = 0; j < pmt->RefreshCount; j++ )
+	    {
+		if( pmt->RefreshRate[j] == refresh )
+		{
+		    /* Exact match. */
+		    jBest = j;
+		    break;
+		}
+		else if( iabs(pmt->RefreshRate[j] - refresh) < jDelta )
+		{
+		    jDelta = iabs(pmt->RefreshRate[j] - refresh);
+		    jBest = j;
+		}
+	    }
+	    chosenRefresh = pmt->RefreshRate[jBest];
+            if (newRefresh)
+                *newRefresh = chosenRefresh;
+            found = TRUE;
+	    break;
+	}
+    }
+
+    if( found ) {
+	/* Success: we found a match in the BIOS. */
+	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 
+		  "Chose mode %x at %dHz.\n", chosenVesaMode, chosenRefresh );
+        return MODE_OK;
+    } else {
+	xf86DrvMsg(pScrn->scrnIndex, X_PROBED, 
+		  "No suitable BIOS mode found for %dx%d %dHz.\n",
+		  width, height, refresh);
+        return MODE_NOMODE;
+    }
+}
Index: savage_vbe.h
===================================================================
RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/savage/savage_vbe.h,v
retrieving revision 1.2
diff -u -r1.2 savage_vbe.h
--- savage_vbe.h	23 Apr 2004 19:44:35 -0000	1.2
+++ savage_vbe.h	27 Sep 2004 04:41:20 -0000
@@ -16,6 +16,58 @@
 #ifndef _SAVAGEVBE_H
 #define _SAVAGEVBE_H
 
+/*
+ *  Common BIOS functions
+ */
+
+#define BIOS_SET_VBE_MODE       0x4F02
+#define BIOS_GET_VBE_MODE       0x4F03
+#define BIOS_SVGA_STATE         0x4F04
+#define BIOS_LOG_SCANLINE       0x4F06
+#define BIOS_VBE_PM_SERVICE     0x4F10
+#define S3_EXTBIOS_INFO         0x4F14  /* S3 Extended BIOS services */
+#define BIOS_VBE_DDC            0x4F15
+
+/*************************************************************************
+ *     Defines for BIOS compliant with S3 (Mobile and Desktop) PCI Video
+ *     Bios External Interface Specification, Core Revision 3.02+
+ *
+ *     e.g. used by Trio3D, GX-3
+ *************************************************************************/
+ 
+#define S3_GET_SVGA_BUF          0x0000
+#define S3_SAVE_SVGA_STATE       0x0001
+#define S3_RESTORE_SVGA_STATE    0x0002
+/*
+ * For S3_EXTBIOS_INFO (0x4F14) services
+ */
+#define S3_VBE_INFO         0x0000  /* fn0: Query S3/VBE info */
+
+#define S3_SET_REFRESH      0x0001  /* fn1,sub0: Set Refresh Rate for Mode */
+#define S3_GET_REFRESH      0x0101  /* fn1,sub1: Get Refresh Rate for Mode */
+#define S3_QUERY_REFRESH    0x0201  /* fn1,sub2: Query Refresh Rates for Mode */
+
+#define S3_QUERY_MODELIST   0x0202  /* fn2,sub2: Query Mode List */
+#define S3_GET_EXT_MODEINFO 0x0302  /* fn2,sub3: Get Extended Mode Info */
+
+#define S3_QUERY_ATTACHED   0x0004  /* fn4,sub0: Query detected displays */
+
+#define S3_GET_ACTIVE_DISP  0x0103  /* fn3,sub1: Get Active Display */
+#define S3_SET_ACTIVE_DISP  0x0003  /* fn3,sub0: Set Active Display */
+#define S3_ALT_SET_ACTIVE_DISP  0x8003  /* fn8003,sub0: Alternate Set Active Display */
+
+#define S3_SET_TV_CONFIG    0x0007  /* fn7,sub0: Set TV Configuration */
+#define S3_GET_TV_CONFIG    0x0107  /* fn7,sub1: Get TV Configuration */
+
+
+#define BIOS_CRT1_ONLY              0x01
+#define BIOS_LCD_ONLY               0x02
+#define BIOS_TV_NTSC                0x04
+#define BIOS_TV_PAL                 0x08
+#define BIOS_TV_ONLY                0x0c
+#define BIOS_DVI_ONLY               0x20
+#define BIOS_DEVICE_MASK            (BIOS_CRT1_ONLY|BIOS_LCD_ONLY|BIOS_TV_ONLY|BIOS_DVI_ONLY)
+
 /* structures for vbe 2.0 */
 
 #ifndef __GNUC__
Index: savage_video.c
===================================================================
RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/savage/savage_video.c,v
retrieving revision 1.4
diff -u -r1.4 savage_video.c
--- savage_video.c	16 Sep 2004 22:00:48 -0000	1.4
+++ savage_video.c	27 Sep 2004 04:41:21 -0000
@@ -235,8 +235,16 @@
     if( (psav->Chipset == S3_SAVAGE_MX)  ||
 	(psav->Chipset == S3_SUPERSAVAGE) ||
         (psav->Chipset == S3_SAVAGE2000) ) {
-	OUTREG(SEC_STREAM_WINDOW_SZ, 0);
-  
+	if (psav->IsSecondary) {
+	    OUTREG(SEC_STREAM2_WINDOW_SZ, 0);
+	} else if (psav->IsPrimary) {
+	    OUTREG(SEC_STREAM_WINDOW_SZ, 0);
+	} else {
+	    OUTREG(SEC_STREAM_WINDOW_SZ, 0);
+#if 0
+	    OUTREG(SEC_STREAM2_WINDOW_SZ, 0);
+#endif
+  	}
     } else {
 	OUTREG( SSTREAM_WINDOW_SIZE_REG, 1);
 	OUTREG( SSTREAM_WINDOW_START_REG, 0x03ff03ff);
@@ -252,10 +260,8 @@
     int num_adaptors;
 
     xf86ErrorFVerb(XVTRACE,"SavageInitVideo\n");
-    if(
-	S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
-	(psav->Chipset == S3_SAVAGE2000)
-    )
+    if (S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
+       (psav->Chipset == S3_SAVAGE2000))
     {
 	newAdaptor = SavageSetupImageVideo(pScreen);
 	SavageInitOffscreenImages(pScreen);
@@ -370,40 +376,137 @@
     blue = (pPriv->colorKey & pScrn->mask.blue) >> pScrn->offset.blue;
 
     if( !pPriv->colorKey ) {
-	OUTREG( SEC_STREAM_CKEY_LOW, 0 );
-	OUTREG( SEC_STREAM_CKEY_UPPER, 0 );
-	OUTREG( BLEND_CONTROL, psav->blendBase | 0x08 );
+	if (psav->IsSecondary) {
+	    OUTREG( SEC_STREAM2_CKEY_LOW, 0 );
+	    OUTREG( SEC_STREAM2_CKEY_UPPER, 0 );
+	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 17) | (8 << 12) ));
+	} else if (psav->IsPrimary) {
+	    OUTREG( SEC_STREAM_CKEY_LOW, 0 );
+	    OUTREG( SEC_STREAM_CKEY_UPPER, 0 );
+	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 9) | 0x08 ));
+	} else {
+	    OUTREG( SEC_STREAM_CKEY_LOW, 0 );
+	    OUTREG( SEC_STREAM_CKEY_UPPER, 0 );
+	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 9) | 0x08 ));
+#if 0
+	    sleep(1);
+	    OUTREG( SEC_STREAM2_CKEY_LOW, 0 );
+	    OUTREG( SEC_STREAM2_CKEY_UPPER, 0 );
+	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 17) | (8 << 12) ));
+#endif
+	}
     }
     else {
 	switch (pScrn->depth) {
 	case 8:
-	    OUTREG( SEC_STREAM_CKEY_LOW, 
-		0x47000000 | (pPriv->colorKey & 0xFF) );
-	    OUTREG( SEC_STREAM_CKEY_UPPER,
-		0x47000000 | (pPriv->colorKey & 0xFF) );
+	    if (psav->IsSecondary) {
+	    	OUTREG( SEC_STREAM2_CKEY_LOW, 
+		    0x47000000 | (pPriv->colorKey & 0xFF) );
+	    	OUTREG( SEC_STREAM2_CKEY_UPPER,
+		    0x47000000 | (pPriv->colorKey & 0xFF) );
+	    } else if (psav->IsPrimary) {
+	    	OUTREG( SEC_STREAM_CKEY_LOW, 
+		    0x47000000 | (pPriv->colorKey & 0xFF) );
+	    	OUTREG( SEC_STREAM_CKEY_UPPER,
+		    0x47000000 | (pPriv->colorKey & 0xFF) );
+	    } else {
+	    	OUTREG( SEC_STREAM_CKEY_LOW, 
+		    0x47000000 | (pPriv->colorKey & 0xFF) );
+	    	OUTREG( SEC_STREAM_CKEY_UPPER,
+		    0x47000000 | (pPriv->colorKey & 0xFF) );
+#if 0
+	    	OUTREG( SEC_STREAM2_CKEY_LOW, 
+		    0x47000000 | (pPriv->colorKey & 0xFF) );
+	    	OUTREG( SEC_STREAM2_CKEY_UPPER,
+		    0x47000000 | (pPriv->colorKey & 0xFF) );
+#endif
+	    }
 	    break;
 	case 15:
-	    OUTREG( SEC_STREAM_CKEY_LOW, 
-		0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
-	    OUTREG( SEC_STREAM_CKEY_UPPER, 
-		0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
+	    if (psav->IsSecondary) {
+	    	OUTREG( SEC_STREAM2_CKEY_LOW, 
+		    0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
+	    	OUTREG( SEC_STREAM2_CKEY_UPPER, 
+		    0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
+	    } else if (psav->IsPrimary) {
+	    	OUTREG( SEC_STREAM_CKEY_LOW, 
+		    0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
+	    	OUTREG( SEC_STREAM_CKEY_UPPER, 
+		    0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
+	    } else {
+	    	OUTREG( SEC_STREAM_CKEY_LOW, 
+		    0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
+	    	OUTREG( SEC_STREAM_CKEY_UPPER, 
+		    0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
+#if 0
+	    	OUTREG( SEC_STREAM2_CKEY_LOW, 
+		    0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
+	    	OUTREG( SEC_STREAM2_CKEY_UPPER, 
+		    0x45000000 | (red<<19) | (green<<11) | (blue<<3) );
+#endif
+	    }
 	    break;
 	case 16:
-	    OUTREG( SEC_STREAM_CKEY_LOW, 
-		0x46000000 | (red<<19) | (green<<10) | (blue<<3) );
-	    OUTREG( SEC_STREAM_CKEY_UPPER, 
-		0x46020002 | (red<<19) | (green<<10) | (blue<<3) );
+	    if (psav->IsSecondary) {
+	    	OUTREG( SEC_STREAM2_CKEY_LOW, 
+		    0x46000000 | (red<<19) | (green<<10) | (blue<<3) );
+	    	OUTREG( SEC_STREAM2_CKEY_UPPER, 
+		    0x46020002 | (red<<19) | (green<<10) | (blue<<3) );
+	    } else if (psav->IsPrimary) {
+	    	OUTREG( SEC_STREAM_CKEY_LOW, 
+		    0x46000000 | (red<<19) | (green<<10) | (blue<<3) );
+	    	OUTREG( SEC_STREAM_CKEY_UPPER, 
+		    0x46020002 | (red<<19) | (green<<10) | (blue<<3) );
+	    } else {
+	    	OUTREG( SEC_STREAM_CKEY_LOW, 
+		    0x46000000 | (red<<19) | (green<<10) | (blue<<3) );
+	    	OUTREG( SEC_STREAM_CKEY_UPPER, 
+		    0x46020002 | (red<<19) | (green<<10) | (blue<<3) );
+#if 0
+	    	OUTREG( SEC_STREAM2_CKEY_LOW, 
+		    0x46000000 | (red<<19) | (green<<10) | (blue<<3) );
+	    	OUTREG( SEC_STREAM2_CKEY_UPPER, 
+		    0x46020002 | (red<<19) | (green<<10) | (blue<<3) );
+#endif
+	    }
 	    break;
 	case 24:
-	    OUTREG( SEC_STREAM_CKEY_LOW, 
-		0x47000000 | (red<<16) | (green<<8) | (blue) );
-	    OUTREG( SEC_STREAM_CKEY_UPPER, 
-		0x47000000 | (red<<16) | (green<<8) | (blue) );
+	    if (psav->IsSecondary) {
+	        OUTREG( SEC_STREAM2_CKEY_LOW, 
+		    0x47000000 | (red<<16) | (green<<8) | (blue) );
+	        OUTREG( SEC_STREAM2_CKEY_UPPER, 
+		    0x47000000 | (red<<16) | (green<<8) | (blue) );
+	    } else if (psav->IsPrimary) {
+	        OUTREG( SEC_STREAM_CKEY_LOW, 
+		    0x47000000 | (red<<16) | (green<<8) | (blue) );
+	        OUTREG( SEC_STREAM_CKEY_UPPER, 
+		    0x47000000 | (red<<16) | (green<<8) | (blue) );
+	    } else {
+	        OUTREG( SEC_STREAM_CKEY_LOW, 
+		    0x47000000 | (red<<16) | (green<<8) | (blue) );
+	        OUTREG( SEC_STREAM_CKEY_UPPER, 
+		    0x47000000 | (red<<16) | (green<<8) | (blue) );
+#if 0
+	        OUTREG( SEC_STREAM2_CKEY_LOW, 
+		    0x47000000 | (red<<16) | (green<<8) | (blue) );
+	        OUTREG( SEC_STREAM2_CKEY_UPPER, 
+		    0x47000000 | (red<<16) | (green<<8) | (blue) );
+#endif
+	    }
 	    break;
 	}    
 
 	/* We assume destination colorkey */
-	OUTREG( BLEND_CONTROL, psav->blendBase | 0x08 );
+	if (psav->IsSecondary) {
+	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 17) | (8 << 12) ));
+	} else if (psav->IsPrimary) {
+	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 9) | 0x08 ));
+	} else {
+	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 9) | 0x08 ));
+#if 0
+	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 17) | (8 << 12) ));
+#endif
+	}
     }
 }
 
@@ -453,7 +556,7 @@
     int k1, k2, k3, k4, k5, k6, k7, kb;
     double s = pPriv->saturation / 128.0;
     double h = pPriv->hue * 0.017453292;
-    unsigned long assembly;
+    unsigned long assembly1, assembly2, assembly3;
 
     xf86ErrorFVerb(XVTRACE, "bright %d, contrast %d, saturation %d, hue %d\n",
 	pPriv->brightness, (int)pPriv->contrast, (int)pPriv->saturation, pPriv->hue );
@@ -483,22 +586,39 @@
     k1 = (int)(dk1+0.5) & 0x1ff;
     k2 = (int)(dk2+0.5) & 0x1ff;
     k3 = (int)(dk3+0.5) & 0x1ff;
-    assembly = (k3<<18) | (k2<<9) | k1;
-    xf86ErrorFVerb(XVTRACE+1, "CC1 = %08lx  ", assembly );
-    OUTREG( SEC_STREAM_COLOR_CONVERT1, assembly );
+    assembly1 = (k3<<18) | (k2<<9) | k1;
+    xf86ErrorFVerb(XVTRACE+1, "CC1 = %08lx  ", assembly1 );
 
     k4 = (int)(dk4+0.5) & 0x1ff;
     k5 = (int)(dk5+0.5) & 0x1ff;
     k6 = (int)(dk6+0.5) & 0x1ff;
-    assembly = (k6<<18) | (k5<<9) | k4;
-    xf86ErrorFVerb(XVTRACE+1, "CC2 = %08lx  ", assembly );
-    OUTREG( SEC_STREAM_COLOR_CONVERT2, assembly );
+    assembly2 = (k6<<18) | (k5<<9) | k4;
+    xf86ErrorFVerb(XVTRACE+1, "CC2 = %08lx  ", assembly2 );
 
     k7 = (int)(dk7+0.5) & 0x1ff;
     kb = (int)(dkb+0.5) & 0xffff;
-    assembly = (kb<<9) | k7;
-    xf86ErrorFVerb(XVTRACE+1, "CC3 = %08lx\n", assembly );
-    OUTREG( SEC_STREAM_COLOR_CONVERT3, assembly );
+    assembly3 = (kb<<9) | k7;
+    xf86ErrorFVerb(XVTRACE+1, "CC3 = %08lx\n", assembly3 );
+
+    if (psav->IsSecondary) {
+	OUTREG( SEC_STREAM2_COLOR_CONVERT1, assembly1 );
+	OUTREG( SEC_STREAM2_COLOR_CONVERT2, assembly2 );
+	OUTREG( SEC_STREAM2_COLOR_CONVERT3, assembly3 );
+    } else if (psav->IsPrimary) {
+	OUTREG( SEC_STREAM_COLOR_CONVERT3, assembly1 );
+	OUTREG( SEC_STREAM_COLOR_CONVERT3, assembly2 );
+	OUTREG( SEC_STREAM_COLOR_CONVERT3, assembly3 );
+    } else {
+	OUTREG( SEC_STREAM_COLOR_CONVERT3, assembly1 );
+	OUTREG( SEC_STREAM_COLOR_CONVERT3, assembly2 );
+	OUTREG( SEC_STREAM_COLOR_CONVERT3, assembly3 );
+#if 0
+	sleep(1);
+	OUTREG( SEC_STREAM2_COLOR_CONVERT1, assembly1 );
+	OUTREG( SEC_STREAM2_COLOR_CONVERT2, assembly2 );
+	OUTREG( SEC_STREAM2_COLOR_CONVERT3, assembly3 );
+#endif
+    }
 }
 
 
@@ -976,12 +1096,20 @@
     SavagePtr psav = SAVPTR(pScrn);
 
     if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
-        (psav->Chipset == S3_SUPERSAVAGE) ||
         (psav->Chipset == S3_SAVAGE2000) )
     {
-	psav->blendBase = GetBlendForFourCC( id ) << 9;
+	psav->blendBase = GetBlendForFourCC( id );
 	xf86ErrorFVerb(XVTRACE+1,"Format %4.4s, blend is %08x\n", (char*)&id, psav->blendBase );
-	OUTREG( BLEND_CONTROL, psav->blendBase | 0x08 );
+	if (psav->IsSecondary) {
+	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 17) | (8 << 12) ));
+	} else if (psav->IsPrimary) {
+	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 9) | 0x08 ));
+	} else {
+	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 9) | 0x08 ));
+#if 0
+	    OUTREG( BLEND_CONTROL, (INREG32(BLEND_CONTROL) | (psav->blendBase << 17) | (8 << 12) ));
+#endif
+	}
     }
     psav->videoFourCC = id;
 }
@@ -1174,11 +1302,11 @@
     }
     else
     {
-	if( 
-	    S3_SAVAGE_MOBILE_SERIES(psav->Chipset) &&
+	if ( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) &&
+	    (psav->DisplayType == MT_LCD) &&
 	    !psav->CrtOnly &&
-	    !psav->TvOn
-	) {
+	    !psav->TvOn) 
+	{
 	    drw_w = (drw_w * psav->XExp1)/psav->XExp2 + 1;
 	    drw_h = (drw_h * psav->YExp1)/psav->YExp2 + 1;
 	    dstBox->x1 = (dstBox->x1 * psav->XExp1)/psav->XExp2;
@@ -1186,12 +1314,34 @@
 	    dstBox->x1 += psav->displayXoffset;
 	    dstBox->y1 += psav->displayYoffset;
 	}
-
-	OUTREG(SEC_STREAM_HSCALING, 
-	    ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF ));
-	/* BUGBUG need to add 00040000 if src stride > 2048 */
-	OUTREG(SEC_STREAM_VSCALING, 
-	    ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF ));
+#if 1
+	if (psav->IsSecondary) {
+	    OUTREG(SEC_STREAM2_HSCALING, 
+	        ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF ));
+	    /* BUGBUG need to add 00040000 if src stride > 2048 */
+	    OUTREG(SEC_STREAM2_VSCALING, 
+	        ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF ));
+	} else if (psav->IsPrimary) {
+	    OUTREG(SEC_STREAM_HSCALING, 
+	        ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF ));
+	    /* BUGBUG need to add 00040000 if src stride > 2048 */
+	    OUTREG(SEC_STREAM_VSCALING, 
+	        ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF ));
+	} else {
+#endif
+	    OUTREG(SEC_STREAM_HSCALING, 
+	        ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF ));
+	    /* BUGBUG need to add 00040000 if src stride > 2048 */
+	    OUTREG(SEC_STREAM_VSCALING, 
+	        ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF ));
+#if 0
+	    OUTREG(SEC_STREAM2_HSCALING, 
+	        ((src_w&0xfff)<<20) | ((65536 * src_w / drw_w) & 0x1FFFF ));
+	    /* BUGBUG need to add 00040000 if src stride > 2048 */
+	    OUTREG(SEC_STREAM2_VSCALING, 
+	        ((src_h&0xfff)<<20) | ((65536 * src_h / drw_h) & 0x1FFFF ));
+#endif
+	}
     }
 
     /*
@@ -1199,12 +1349,36 @@
      * are 2 bytes/pixel.
      */
 
-    OUTREG(SEC_STREAM_FBUF_ADDR0, (offset + (x1>>15)) 
+    if (psav->IsSecondary) {
+        OUTREG(SEC_STREAM2_FBUF_ADDR0, (offset + (x1>>15)) 
 	   & (0x7ffffff & ~BASE_PAD));
-    OUTREG(SEC_STREAM_STRIDE, pitch & 0xfff );
-    OUTREG(SEC_STREAM_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1) );
-    OUTREG(SEC_STREAM_WINDOW_SZ, ((dstBox->x2-dstBox->x1) << 16) 
+        OUTREG(SEC_STREAM2_STRIDE_LPB, pitch & 0xfff );
+        OUTREG(SEC_STREAM2_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1) );
+        OUTREG(SEC_STREAM2_WINDOW_SZ, ((dstBox->x2-dstBox->x1) << 16) 
 	   | (dstBox->x2-dstBox->x1) );
+    } else if (psav->IsPrimary) {
+        OUTREG(SEC_STREAM_FBUF_ADDR0, (offset + (x1>>15)) 
+	   & (0x7ffffff & ~BASE_PAD));
+        OUTREG(SEC_STREAM_STRIDE, pitch & 0xfff );
+        OUTREG(SEC_STREAM_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1) );
+        OUTREG(SEC_STREAM_WINDOW_SZ, ((dstBox->x2-dstBox->x1) << 16) 
+	   | (dstBox->x2-dstBox->x1) );
+    } else {
+        OUTREG(SEC_STREAM_FBUF_ADDR0, (offset + (x1>>15)) 
+	   & (0x7ffffff & ~BASE_PAD));
+        OUTREG(SEC_STREAM_STRIDE, pitch & 0xfff );
+        OUTREG(SEC_STREAM_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1) );
+        OUTREG(SEC_STREAM_WINDOW_SZ, ((dstBox->x2-dstBox->x1) << 16) 
+	   | (dstBox->x2-dstBox->x1) );
+#if 0
+        OUTREG(SEC_STREAM2_FBUF_ADDR0, (offset + (x1>>15)) 
+	   & (0x7ffffff & ~BASE_PAD));
+        OUTREG(SEC_STREAM2_STRIDE_LPB, pitch & 0xfff );
+        OUTREG(SEC_STREAM2_WINDOW_START, ((dstBox->x1+1) << 16) | (dstBox->y1+1) );
+        OUTREG(SEC_STREAM2_WINDOW_SZ, ((dstBox->x2-dstBox->x1) << 16) 
+	   | (dstBox->x2-dstBox->x1) );
+#endif
+    }
 
 #if 0
     /* Set color key on primary. */
@@ -1213,7 +1387,7 @@
 #endif
 
     /* Set FIFO L2 on second stream. */
-
+    /* Is CR92 shadowed for crtc2? -- AGD */
     if( pPriv->lastKnownPitch != pitch )
     {
 	unsigned char cr92;
