? Makefile
? dualhead.diff
? r128.4.html
? r128._man
? r128dh.diff
? radeon.4.html
? radeon._man
Index: r128.h
===================================================================
RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/ati/r128.h,v
retrieving revision 1.3
diff -u -r1.3 r128.h
--- r128.h	16 Jun 2004 09:43:58 -0000	1.3
+++ r128.h	10 Oct 2004 03:20:58 -0000
@@ -135,6 +135,13 @@
 
 				/* CRTC2 registers */
     CARD32     crtc2_gen_cntl;
+    CARD32     crtc2_h_total_disp;
+    CARD32     crtc2_h_sync_strt_wid;
+    CARD32     crtc2_v_total_disp;
+    CARD32     crtc2_v_sync_strt_wid;
+    CARD32     crtc2_offset;
+    CARD32     crtc2_offset_cntl;
+    CARD32     crtc2_pitch;
 
 				/* Flat panel registers */
     CARD32     fp_crtc_h_total_disp;
@@ -160,13 +167,29 @@
     CARD32     ppll_div_3;
     CARD32     htotal_cntl;
 
+				/* Computed values for PLL2 */
+    CARD32     dot_clock_freq_2;
+    CARD32     pll_output_freq_2;
+    int        feedback_div_2;
+    int        post_div_2;
+
+				/* PLL2 registers */
+    CARD32     p2pll_ref_div;
+    CARD32     p2pll_div_0;
+    CARD32     htotal_cntl2;
+
 				/* DDA register */
     CARD32     dda_config;
     CARD32     dda_on_off;
 
+				/* DDA2 register */
+    CARD32     dda2_config;
+    CARD32     dda2_on_off;
+
 				/* Pallet */
     Bool       palette_valid;
     CARD32     palette[256];
+    CARD32     palette2[256];
 } R128SaveRec, *R128SavePtr;
 
 typedef struct {
@@ -186,6 +209,25 @@
     DisplayModePtr     mode;
 } R128FBLayout;
 
+typedef enum
+{
+    MT_NONE,
+    MT_CRT,
+    MT_LCD,
+    MT_DFP,
+    MT_CTV,
+    MT_STV
+}R128MonitorType;
+
+typedef enum
+{
+    DDC_NONE_DETECTED,
+    DDC_MONID,
+    DDC_DVI,
+    DDC_VGA,
+    DDC_CRT2
+}R128DDCType;
+
 typedef struct {
     EntityInfoPtr     pEnt;
     pciVideoPtr       PciInfo;
@@ -401,6 +443,14 @@
     I2CBusPtr         pI2CBus;
     CARD32            DDCReg;
 
+    /****** Added for dualhead support *******************/
+    BOOL              HasCRTC2;     /* M3/M4 */
+    BOOL              IsSecondary;  /* second Screen */
+    BOOL              UseCRT;       /* force use CRT port as primary */
+    BOOL              SwitchingMode;
+    R128MonitorType DisplayType;  /* Monitor connected on*/
+    R128DDCType     DDCType;
+
 } R128InfoRec, *R128InfoPtr;
 
 #define R128WaitForFifo(pScrn, entries)                                      \
Index: r128_accel.c
===================================================================
RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/ati/r128_accel.c,v
retrieving revision 1.3
diff -u -r1.3 r128_accel.c
--- r128_accel.c	16 Jun 2004 09:43:58 -0000	1.3
+++ r128_accel.c	10 Oct 2004 03:20:59 -0000
@@ -82,6 +82,7 @@
 				/* Driver data structures */
 #include "r128.h"
 #include "r128_reg.h"
+#include "r128_probe.h"
 #ifdef XF86DRI
 #include "r128_sarea.h"
 #define _XF86DRI_SERVER_
@@ -117,6 +118,8 @@
     { R128_ROP3_ONE,  R128_ROP3_ONE  }  /* GXset          */
 };
 
+extern int gR128EntityIndex;
+
 /* Flush all dirty data in the Pixel Cache to memory. */
 void R128EngineFlush(ScrnInfoPtr pScrn)
 {
@@ -1017,7 +1020,7 @@
     R128TRACE(("Pitch for acceleration = %d\n", info->pitch));
 
     R128WaitForFifo(pScrn, 2);
-    OUTREG(R128_DEFAULT_OFFSET, 0);
+    OUTREG(R128_DEFAULT_OFFSET, pScrn->fbOffset);
     OUTREG(R128_DEFAULT_PITCH,  info->pitch);
 
     R128WaitForFifo(pScrn, 4);
@@ -1641,6 +1644,25 @@
                          &indirect, sizeof(drmR128Indirect));
 }
 
+/* This callback is required for multihead cards using XAA */
+static
+void R128RestoreCCEAccelState(ScrnInfoPtr pScrn)
+{
+    R128InfoPtr info        = R128PTR(pScrn);
+/*    unsigned char *R128MMIO = info->MMIO;  needed for OUTREG below */
+    /*xf86DrvMsg(pScrn->scrnIndex, X_INFO, "===>RestoreCP\n");*/
+
+    R128WaitForFifo(pScrn, 1);
+/* is this needed on r128
+    OUTREG( R128_DEFAULT_OFFSET, info->frontPitchOffset);
+*/
+    R128WaitForIdle(pScrn);
+
+    /* FIXME: May need to restore other things, 
+       like BKGD_CLK FG_CLK...*/
+
+}
+
 static void R128CCEAccelInit(ScrnInfoPtr pScrn, XAAInfoRecPtr a)
 {
     R128InfoPtr info = R128PTR(pScrn);
@@ -1701,9 +1723,32 @@
 					   | HARDWARE_PATTERN_PROGRAMMED_ORIGIN
 					   | HARDWARE_PATTERN_SCREEN_ORIGIN
 					   | BIT_ORDER_IN_BYTE_LSBFIRST);
+
+    if(!info->IsSecondary && xf86IsEntityShared(pScrn->entityList[0]))
+        a->RestoreAccelState           = R128RestoreCCEAccelState;
+
+
 }
 #endif
 
+/* This callback is required for multihead cards using XAA */
+static
+void R128RestoreAccelState(ScrnInfoPtr pScrn)
+{
+    R128InfoPtr info        = R128PTR(pScrn);
+    unsigned char *R128MMIO = info->MMIO;
+
+    R128WaitForFifo(pScrn, 2);
+    OUTREG(R128_DEFAULT_OFFSET, pScrn->fbOffset);
+    OUTREG(R128_DEFAULT_PITCH,  info->pitch);
+
+    /* FIXME: May need to restore other things, 
+       like BKGD_CLK FG_CLK...*/
+
+    R128WaitForIdle(pScrn);
+
+}
+
 static void R128MMIOAccelInit(ScrnInfoPtr pScrn, XAAInfoRecPtr a)
 {
     R128InfoPtr info = R128PTR(pScrn);
@@ -1782,6 +1827,22 @@
 					  | LEFT_EDGE_CLIPPING
 					  | LEFT_EDGE_CLIPPING_NEGATIVE_X
 					  | SCANLINE_PAD_DWORD;
+
+    if(xf86IsEntityShared(pScrn->entityList[0]))
+    {
+        DevUnion* pPriv;
+        R128EntPtr pR128Ent;
+        pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
+                gR128EntityIndex);
+        pR128Ent = 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(pR128Ent->HasSecondary || pR128Ent->BypassSecondary)
+           a->RestoreAccelState           = R128RestoreAccelState;
+    }
+
 }
 
 /* Initialize XAA for supported acceleration and also initialize the
Index: r128_cursor.c
===================================================================
RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/ati/r128_cursor.c,v
retrieving revision 1.2
diff -u -r1.2 r128_cursor.c
--- r128_cursor.c	23 Apr 2004 19:26:46 -0000	1.2
+++ r128_cursor.c	10 Oct 2004 03:20:59 -0000
@@ -72,8 +72,16 @@
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
 
-    OUTREG(R128_CUR_CLR0, bg);
-    OUTREG(R128_CUR_CLR1, fg);
+    if(info->IsSecondary)
+    {
+        OUTREG(R128_CUR2_CLR0, bg);
+        OUTREG(R128_CUR2_CLR1, fg);
+    }
+    else
+    {
+    	OUTREG(R128_CUR_CLR0, bg);
+    	OUTREG(R128_CUR_CLR1, fg);
+    }
 }
 
 /* Set cursor position to (x,y) with offset into cursor bitmap at
@@ -94,11 +102,25 @@
     if (xorigin >= cursor->MaxWidth)  xorigin = cursor->MaxWidth - 1;
     if (yorigin >= cursor->MaxHeight) yorigin = cursor->MaxHeight - 1;
 
-    OUTREG(R128_CUR_HORZ_VERT_OFF,  R128_CUR_LOCK | (xorigin << 16) | yorigin);
-    OUTREG(R128_CUR_HORZ_VERT_POSN, (R128_CUR_LOCK
+    if(!info->IsSecondary)
+    {
+    	OUTREG(R128_CUR_HORZ_VERT_OFF,  R128_CUR_LOCK | (xorigin << 16) | yorigin);
+    	OUTREG(R128_CUR_HORZ_VERT_POSN, (R128_CUR_LOCK
 				     | ((xorigin ? 0 : x) << 16)
 				     | (yorigin ? 0 : y)));
-    OUTREG(R128_CUR_OFFSET,         info->cursor_start + yorigin * 16);
+    	OUTREG(R128_CUR_OFFSET,         info->cursor_start + yorigin * 16);
+    } 
+    else 
+    {
+        OUTREG(R128_CUR2_HORZ_VERT_OFF,  (R128_CUR2_LOCK
+				       | (xorigin << 16)
+				       | yorigin));
+        OUTREG(R128_CUR2_HORZ_VERT_POSN, (R128_CUR2_LOCK
+				       | ((xorigin ? 0 : x) << 16)
+				       | (yorigin ? 0 : y)));
+        OUTREG(R128_CUR2_OFFSET,         
+			info->cursor_start + pScrn->fbOffset + yorigin * 16);
+    }
 }
 
 /* Copy cursor image from `image' to video memory.  R128SetCursorPosition
@@ -112,8 +134,16 @@
     int           y;
     CARD32        save;
 
-    save = INREG(R128_CRTC_GEN_CNTL);
-    OUTREG(R128_CRTC_GEN_CNTL, save & (CARD32)~R128_CRTC_CUR_EN);
+    if(!info->IsSecondary)
+    {
+    	save = INREG(R128_CRTC_GEN_CNTL);
+    	OUTREG(R128_CRTC_GEN_CNTL, save & (CARD32)~R128_CRTC_CUR_EN);
+    }
+    else
+    {
+        save = INREG(R128_CRTC2_GEN_CNTL);
+        OUTREG(R128_CRTC2_GEN_CNTL, save & (CARD32)~R128_CRTC2_CUR_EN);
+    }
 
 #if X_BYTE_ORDER == X_BIG_ENDIAN
     switch(info->CurrentLayout.pixel_bytes) {
@@ -169,7 +199,11 @@
     }
 
 
-    OUTREG(R128_CRTC_GEN_CNTL, save);
+    if(!info->IsSecondary)
+    	OUTREG(R128_CRTC_GEN_CNTL, save);
+    else
+        OUTREG(R128_CRTC2_GEN_CNTL, save);
+
 }
 
 /* Hide hardware cursor. */
@@ -178,7 +212,10 @@
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
 
-    OUTREGP(R128_CRTC_GEN_CNTL, 0, ~R128_CRTC_CUR_EN);
+     if(info->IsSecondary)
+        OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC2_CUR_EN);
+     else
+    	OUTREGP(R128_CRTC_GEN_CNTL, 0, ~R128_CRTC_CUR_EN);
 }
 
 /* Show hardware cursor. */
@@ -187,7 +224,16 @@
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
 
-    OUTREGP(R128_CRTC_GEN_CNTL, R128_CRTC_CUR_EN, ~R128_CRTC_CUR_EN);
+    if(info->IsSecondary)
+    {
+         OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC2_CUR_EN,
+               ~R128_CRTC2_CUR_EN);
+    }
+    else
+    {
+    	OUTREGP(R128_CRTC_GEN_CNTL, R128_CRTC_CUR_EN, ~R128_CRTC_CUR_EN);
+    }
+
 }
 
 /* Determine if hardware cursor is in use. */
Index: r128_driver.c
===================================================================
RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/ati/r128_driver.c,v
retrieving revision 1.10
diff -u -r1.10 r128_driver.c
--- r128_driver.c	15 Aug 2004 00:44:57 -0000	1.10
+++ r128_driver.c	10 Oct 2004 03:21:02 -0000
@@ -353,6 +353,8 @@
 		      NULL);
 }
 
+extern int gR128EntityIndex;
+
 /* Allocate our private R128InfoRec. */
 static Bool R128GetRec(ScrnInfoPtr pScrn)
 {
@@ -461,7 +463,7 @@
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
 
-    OUTREG8(R128_CLOCK_CNTL_INDEX, addr & 0x1f);
+    OUTREG8(R128_CLOCK_CNTL_INDEX, addr & 0x3f);
     return INREG(R128_CLOCK_CNTL_DATA);
 }
 
@@ -495,10 +497,46 @@
 {
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
-    if(info->isDFP)
-        OUTREGP(R128_FP_GEN_CNTL, R128_FP_BLANK_DIS, ~R128_FP_BLANK_DIS);
+
+    if(!info->IsSecondary)
+    {
+        switch(info->DisplayType)
+        {
+        case MT_LCD:
+            OUTREGP(R128_LVDS_GEN_CNTL, R128_LVDS_DISPLAY_DIS,
+                 ~R128_LVDS_DISPLAY_DIS);
+	    break;
+        case MT_CRT:
+            OUTREGP(R128_CRTC_EXT_CNTL, R128_CRTC_DISPLAY_DIS, ~R128_CRTC_DISPLAY_DIS);
+	    break;
+        case MT_DFP:
+            OUTREGP(R128_FP_GEN_CNTL, R128_FP_BLANK_DIS, ~R128_FP_BLANK_DIS);
+	    break;
+#if 0
+    OUTREGP(R128_CRTC_EXT_CNTL,
+	    R128_CRTC_DISPLAY_DIS |
+	    R128_CRTC_VSYNC_DIS |
+	    R128_CRTC_HSYNC_DIS,
+	  ~(R128_CRTC_DISPLAY_DIS |
+	    R128_CRTC_VSYNC_DIS |
+	    R128_CRTC_HSYNC_DIS));
+            break;
+#endif
+        case MT_NONE:
+        default:
+           break;
+        }
+    }
     else
-        OUTREGP(R128_CRTC_EXT_CNTL, R128_CRTC_DISPLAY_DIS, ~R128_CRTC_DISPLAY_DIS);
+    {
+            OUTREGP(R128_CRTC2_GEN_CNTL, 
+                 R128_CRTC2_DISP_DIS |
+	         R128_CRTC2_VSYNC_DIS |
+	         R128_CRTC2_HSYNC_DIS,
+	       ~(R128_CRTC2_DISP_DIS |
+	         R128_CRTC2_VSYNC_DIS |
+	         R128_CRTC2_HSYNC_DIS));
+    }
 }
 
 /* Unblank screen. */
@@ -507,12 +545,50 @@
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
 
-    if(info->isDFP)
-        OUTREGP(R128_FP_GEN_CNTL, 0, ~R128_FP_BLANK_DIS);
+    if(!info->IsSecondary)
+    {
+        switch(info->DisplayType)
+        {
+        case MT_LCD:
+            OUTREGP(R128_LVDS_GEN_CNTL, 0,
+                 ~R128_LVDS_DISPLAY_DIS);
+	    break;
+        case MT_CRT:
+            OUTREGP(R128_CRTC_EXT_CNTL, 0, ~R128_CRTC_DISPLAY_DIS);
+	    break;
+        case MT_DFP:
+            OUTREGP(R128_FP_GEN_CNTL, 0, ~R128_FP_BLANK_DIS);
+#if 0
+            OUTREGP(R128_CRTC_EXT_CNTL, 
+               R128_CRTC_CRT_ON,
+	  ~(R128_CRTC_DISPLAY_DIS |
+	    R128_CRTC_VSYNC_DIS |
+	    R128_CRTC_HSYNC_DIS));
+            break;
+#endif
+        case MT_NONE:
+        default:
+            break;
+        }
+    }
     else
-        OUTREGP(R128_CRTC_EXT_CNTL, 0, ~(R128_CRTC_DISPLAY_DIS |
-					 R128_CRTC_VSYNC_DIS |
-					 R128_CRTC_HSYNC_DIS));
+    {
+        switch(info->DisplayType)
+        {
+        case MT_LCD:
+        case MT_DFP:
+        case MT_CRT:
+            OUTREGP(R128_CRTC2_GEN_CNTL,
+                0,
+	       ~(R128_CRTC2_DISP_DIS |
+	         R128_CRTC2_VSYNC_DIS |
+	         R128_CRTC2_HSYNC_DIS));
+            break;
+        case MT_NONE:
+        default:
+            break;
+        }
+    }
 }
 
 /* Compute log base 2 of val. */
@@ -575,7 +651,73 @@
 		   "Video BIOS not found!\n");
     }
 
-    if (info->VBIOS && info->HasPanelRegs) {
+        if(info->HasCRTC2)
+        {                    
+             if(info->IsSecondary)
+             {  
+		/* there may be a way to detect this, for now, just assume 
+		   second head is CRT */
+                 info->DisplayType = MT_CRT;
+
+                 if(info->DisplayType > MT_NONE)
+                 {
+                     DevUnion* pPriv;
+                     R128EntPtr pR128Ent;
+                     pPriv = xf86GetEntityPrivate(pScrn->entityList[0], 
+                         gR128EntityIndex);
+                     pR128Ent = pPriv->ptr;
+                     pR128Ent->HasSecondary = TRUE;
+
+                 }
+                 else return FALSE;
+                     
+             }
+             else
+             {
+                 /* really need some sort of detection here */
+		 if (info->HasPanelRegs) {
+		 	info->DisplayType = MT_LCD;
+		 } else if (info->isDFP) {
+			info->DisplayType = MT_DFP;
+                 } else 
+                 {
+                     /*DVI port has no monitor connected, try CRT port.
+                     If something on CRT port, treat it as primary*/
+                     if(xf86IsEntityShared(pScrn->entityList[0]))
+                     {
+                         DevUnion* pPriv;
+                         R128EntPtr pR128Ent;
+                         pPriv = xf86GetEntityPrivate(pScrn->entityList[0], 
+                             gR128EntityIndex);
+                         pR128Ent = pPriv->ptr;
+                         pR128Ent->BypassSecondary = TRUE;
+                     }
+
+                     info->DisplayType = MT_CRT;
+#if 0
+                     {
+                         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                             "No monitor detected!!!\n");
+                         return FALSE;
+                     }
+#endif
+                 }
+             }
+         }
+         else
+         {
+             /*Regular Radeon ASIC, only one CRTC, but it could be
+               used for DFP with a DVI output, like AIW board*/
+             if(info->isDFP) info->DisplayType = MT_DFP;
+             else info->DisplayType = MT_CRT;
+         }
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s Display == Type %d\n",
+              (info->IsSecondary ? "Secondary" : "Primary"), 
+               info->DisplayType);
+
+
+    if (info->VBIOS && info->DisplayType == MT_LCD) {
 	info->FPBIOSstart = 0;
 
 	/* FIXME: There should be direct access to the start of the FP info
@@ -923,6 +1065,7 @@
     } else {
         info->isDFP = FALSE;
         info->isPro2 = FALSE;
+        info->HasCRTC2 = FALSE;
 	switch (info->Chipset) {
 	/* R128 Pro and Pro2 can have DFP, we will deal with it.
 	   No support for dual-head/xinerama yet.
@@ -972,7 +1115,11 @@
 	case PCI_CHIP_RAGE128LE:
 	case PCI_CHIP_RAGE128LF:
 	case PCI_CHIP_RAGE128MF:
-	case PCI_CHIP_RAGE128ML: info->HasPanelRegs = TRUE;  break;
+	case PCI_CHIP_RAGE128ML: 
+			info->HasPanelRegs = TRUE;  
+			/* which chips support dualhead? */
+			info->HasCRTC2 = TRUE;  
+			break;
 	case PCI_CHIP_RAGE128RE:
 	case PCI_CHIP_RAGE128RF:
 	case PCI_CHIP_RAGE128RG:
@@ -1005,6 +1152,23 @@
     else
 	pScrn->videoRam       = INREG(R128_CONFIG_MEMSIZE) / 1024;
 
+    if(info->IsSecondary)
+    {  
+	/*FIXME: For now, split FB into two equal sections. This should
+          be able to be adjusted by user with a config option*/
+        DevUnion* pPriv;
+        R128EntPtr pR128Ent;
+        R128InfoPtr   info1;
+        pPriv = xf86GetEntityPrivate(pScrn->entityList[0], 
+              gR128EntityIndex);
+        pR128Ent = pPriv->ptr;
+        pScrn->videoRam /= 2;
+        pR128Ent->pPrimaryScrn->videoRam = pScrn->videoRam;
+        info1 = R128PTR(pR128Ent->pPrimaryScrn);
+        info1->FbMapSize  = pScrn->videoRam * 1024;
+        info->LinearAddr += pScrn->videoRam * 1024;
+    }
+
     info->MemCntl             = INREG(R128_MEM_CNTL);
     info->BusCntl             = INREG(R128_BUS_CNTL);
 
@@ -1861,9 +2025,41 @@
 
     info               = R128PTR(pScrn);
 
+    info->IsSecondary  = FALSE;
+
     info->pEnt         = xf86GetEntityInfo(pScrn->entityList[0]);
     if (info->pEnt->location.type != BUS_PCI) goto fail;
 
+    if(xf86IsEntityShared(pScrn->entityList[0]))
+    {
+        if(xf86IsPrimInitDone(pScrn->entityList[0]))
+        {
+            DevUnion* pPriv;
+            R128EntPtr pR128Ent;
+            info->IsSecondary = TRUE;
+            pPriv = xf86GetEntityPrivate(pScrn->entityList[0], 
+                    gR128EntityIndex);
+            pR128Ent = pPriv->ptr;
+            if(pR128Ent->BypassSecondary) return FALSE;
+            pR128Ent->pSecondaryScrn = pScrn;
+        }
+        else
+        {
+            DevUnion* pPriv;
+            R128EntPtr pR128Ent;
+            xf86SetPrimInitDone(pScrn->entityList[0]);
+            pPriv = xf86GetEntityPrivate(pScrn->entityList[0], 
+                    gR128EntityIndex);
+            pR128Ent = pPriv->ptr;
+            pR128Ent->pPrimaryScrn = pScrn;
+            pR128Ent->IsDRIEnabled = FALSE;
+            pR128Ent->BypassSecondary = FALSE;
+            pR128Ent->HasSecondary = FALSE;
+            pR128Ent->RestorePrimary = FALSE;
+            pR128Ent->IsSecondaryRestored = FALSE;
+        }
+    }
+
     if (flags & PROBE_DETECT) {
 	R128ProbeDDC(pScrn, info->pEnt->index);
 	return TRUE;
@@ -1996,12 +2192,20 @@
 {
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
-    int           i;
+    int           i, j;
     int           idx;
     unsigned char r, g, b;
 
+    /* If the second monitor is connected, we also 
+       need to deal with the secondary palette*/
+    if (info->IsSecondary) j = 1;
+    else j = 0;
+    
+    PAL_SELECT(j);
+
+
     /* Select palette 0 (main CRTC) if using FP-enabled chip */
-    if (info->HasPanelRegs || info->isDFP) PAL_SELECT(0);
+    /*if (info->HasPanelRegs || info->isDFP) PAL_SELECT(0);*/
 
     if (info->CurrentLayout.depth == 15) {
 	/* 15bpp mode.  This sends 32 values. */
@@ -2079,6 +2283,7 @@
 
     if (!R128MapMem(pScrn)) return FALSE;
     pScrn->fbOffset    = 0;
+    if(info->IsSecondary) pScrn->fbOffset = pScrn->videoRam * 1024;
 #ifdef XF86DRI
     info->fbX          = 0;
     info->fbY          = 0;
@@ -2132,7 +2337,33 @@
 			info->CurrentLayout.pixel_bytes * 3 + 1023) / 1024);
 	    info->directRenderingEnabled = FALSE;
 	} else {
-	    info->directRenderingEnabled = R128DRIScreenInit(pScreen);
+            if(info->IsSecondary)
+                info->directRenderingEnabled = FALSE;
+            else 
+            {
+                /* Xinerama has sync problem with DRI, disable it for now */
+                if(xf86IsEntityShared(pScrn->entityList[0]))
+                {
+                    info->directRenderingEnabled = FALSE;
+ 	            xf86DrvMsg(scrnIndex, X_WARNING,
+                        "Direct Rendering Disabled -- "
+                        "Dual-head configuration is not working with DRI "
+                        "at present.\nPlease use only one Device/Screen "
+                        "section in your XFConfig file.\n");
+                }
+                else
+                info->directRenderingEnabled =
+                    R128DRIScreenInit(pScreen);
+                if(xf86IsEntityShared(pScrn->entityList[0]))
+                {
+                    DevUnion* pPriv;
+                    R128EntPtr pR128Ent;
+                    pPriv = xf86GetEntityPrivate(pScrn->entityList[0], 
+                        gR128EntityIndex);
+                    pR128Ent = pPriv->ptr;
+                    pR128Ent->IsDRIEnabled = info->directRenderingEnabled;
+                }
+            }
 	}
     }
 #endif
@@ -2445,11 +2676,12 @@
     /* DPMS setup - FIXME: also for mirror mode in non-fbdev case? - Michel */
     if (info->FBDev)
 	xf86DPMSInit(pScreen, fbdevHWDPMSSetWeak(), 0);
+
     else {
-	if (!info->HasPanelRegs || info->BIOSDisplay == R128_BIOS_DISPLAY_CRT)
-	    xf86DPMSInit(pScreen, R128DisplayPowerManagementSet, 0);
-	else if (info->HasPanelRegs || info->BIOSDisplay == R128_BIOS_DISPLAY_FP)
+	if (info->DisplayType == MT_LCD)
 	    xf86DPMSInit(pScreen, R128DisplayPowerManagementSetLCD, 0);
+	else
+	    xf86DPMSInit(pScreen, R128DisplayPowerManagementSet, 0);
     }
 
     R128InitVideo(pScreen);
@@ -2533,6 +2765,32 @@
     OUTREG(R128_CRTC_PITCH,           restore->crtc_pitch);
 }
 
+/* Write CRTC2 registers. */
+static void R128RestoreCrtc2Registers(ScrnInfoPtr pScrn,
+				       R128SavePtr restore)
+{
+    R128InfoPtr info        = R128PTR(pScrn);
+    unsigned char *R128MMIO = info->MMIO;
+
+/*    OUTREG(RADEON_CRTC2_GEN_CNTL,  restore->crtc2_gen_cntl);*/
+    OUTREGP(R128_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl,
+	    R128_CRTC2_VSYNC_DIS |
+	    R128_CRTC2_HSYNC_DIS |
+	    R128_CRTC2_DISP_DIS);
+
+/*    OUTREG(R128_DAC_CNTL2, restore->dac2_cntl);
+    OUTREG(R128_DISP_OUTPUT_CNTL, restore->disp_output_cntl);*/
+
+    OUTREG(R128_CRTC2_H_TOTAL_DISP,    restore->crtc2_h_total_disp);
+    OUTREG(R128_CRTC2_H_SYNC_STRT_WID, restore->crtc2_h_sync_strt_wid);
+    OUTREG(R128_CRTC2_V_TOTAL_DISP,    restore->crtc2_v_total_disp);
+    OUTREG(R128_CRTC2_V_SYNC_STRT_WID, restore->crtc2_v_sync_strt_wid);
+    OUTREG(R128_CRTC2_OFFSET,          restore->crtc2_offset);
+    OUTREG(R128_CRTC2_OFFSET_CNTL,     restore->crtc2_offset_cntl);
+    OUTREG(R128_CRTC2_PITCH,           restore->crtc2_pitch);
+
+}
+
 /* Write flat panel registers */
 static void R128RestoreFPRegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
 {
@@ -2582,7 +2840,27 @@
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
 
-    OUTPLLP(pScrn, R128_PPLL_REF_DIV, R128_PPLL_ATOMIC_UPDATE_W, 0xffff);
+    while (INPLL(pScrn, R128_PPLL_REF_DIV) & R128_PPLL_ATOMIC_UPDATE_R);
+
+    OUTPLLP(pScrn, R128_PPLL_REF_DIV, R128_PPLL_ATOMIC_UPDATE_W, 
+	    ~R128_PPLL_ATOMIC_UPDATE_W);
+}
+
+static void R128PLL2WaitForReadUpdateComplete(ScrnInfoPtr pScrn)
+{
+    while (INPLL(pScrn, R128_P2PLL_REF_DIV) & R128_P2PLL_ATOMIC_UPDATE_R);
+}
+
+static void R128PLL2WriteUpdate(ScrnInfoPtr pScrn)
+{
+    R128InfoPtr  info       = R128PTR(pScrn);
+    unsigned char *R128MMIO = info->MMIO;
+
+    while (INPLL(pScrn, R128_P2PLL_REF_DIV) & R128_P2PLL_ATOMIC_UPDATE_R);
+
+    OUTPLLP(pScrn, R128_P2PLL_REF_DIV,
+	    R128_P2PLL_ATOMIC_UPDATE_W,
+	    ~(R128_P2PLL_ATOMIC_UPDATE_W));
 }
 
 /* Write PLL registers. */
@@ -2591,33 +2869,44 @@
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
 
-    OUTREGP(R128_CLOCK_CNTL_INDEX, R128_PLL_DIV_SEL, 0xffff);
+
+    OUTPLLP(pScrn, R128_VCLK_ECP_CNTL,
+	    R128_VCLK_SRC_SEL_CPUCLK,
+	    ~(R128_VCLK_SRC_SEL_MASK));
 
     OUTPLLP(pScrn,
 	    R128_PPLL_CNTL,
 	    R128_PPLL_RESET
 	    | R128_PPLL_ATOMIC_UPDATE_EN
 	    | R128_PPLL_VGA_ATOMIC_UPDATE_EN,
-	    0xffff);
+	    ~(R128_PPLL_RESET
+	      | R128_PPLL_ATOMIC_UPDATE_EN
+	      | R128_PPLL_VGA_ATOMIC_UPDATE_EN));
 
-    R128PLLWaitForReadUpdateComplete(pScrn);
+    OUTREGP(R128_CLOCK_CNTL_INDEX, R128_PLL_DIV_SEL, ~(R128_PLL_DIV_SEL));
+
+    /*    R128PLLWaitForReadUpdateComplete(pScrn);*/
     OUTPLLP(pScrn, R128_PPLL_REF_DIV,
 	    restore->ppll_ref_div, ~R128_PPLL_REF_DIV_MASK);
-    R128PLLWriteUpdate(pScrn);
+    /*    R128PLLWriteUpdate(pScrn);*/
 
-    R128PLLWaitForReadUpdateComplete(pScrn);
+    /*    R128PLLWaitForReadUpdateComplete(pScrn);*/
     OUTPLLP(pScrn, R128_PPLL_DIV_3,
 	    restore->ppll_div_3, ~R128_PPLL_FB3_DIV_MASK);
-    R128PLLWriteUpdate(pScrn);
+    /*R128PLLWriteUpdate(pScrn);*/
     OUTPLLP(pScrn, R128_PPLL_DIV_3,
 	    restore->ppll_div_3, ~R128_PPLL_POST3_DIV_MASK);
-    R128PLLWriteUpdate(pScrn);
 
+    R128PLLWriteUpdate(pScrn);
     R128PLLWaitForReadUpdateComplete(pScrn);
+
     OUTPLL(R128_HTOTAL_CNTL, restore->htotal_cntl);
-    R128PLLWriteUpdate(pScrn);
+    /*R128PLLWriteUpdate(pScrn);*/
 
-    OUTPLLP(pScrn, R128_PPLL_CNTL, 0, ~R128_PPLL_RESET);
+    OUTPLLP(pScrn, R128_PPLL_CNTL, 0, ~(R128_PPLL_RESET 
+					| R128_PPLL_SLEEP
+					| R128_PPLL_ATOMIC_UPDATE_EN
+					| R128_PPLL_VGA_ATOMIC_UPDATE_EN));
 
     R128TRACE(("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
 	       restore->ppll_ref_div,
@@ -2628,6 +2917,85 @@
 	       restore->ppll_ref_div & R128_PPLL_REF_DIV_MASK,
 	       restore->ppll_div_3 & R128_PPLL_FB3_DIV_MASK,
 	       (restore->ppll_div_3 & R128_PPLL_POST3_DIV_MASK) >> 16));
+
+    usleep(5000); /* let the clock lock */
+
+    OUTPLLP(pScrn, R128_VCLK_ECP_CNTL,
+	    R128_VCLK_SRC_SEL_PPLLCLK,
+	    ~(R128_VCLK_SRC_SEL_MASK));
+
+}
+
+/* Write PLL2 registers. */
+static void R128RestorePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
+{
+    R128InfoPtr info        = R128PTR(pScrn);
+    unsigned char *R128MMIO = info->MMIO;
+
+    
+    OUTPLLP(pScrn, R128_V2CLK_VCLKTV_CNTL,
+	    R128_V2CLK_SRC_SEL_CPUCLK, 
+	    ~R128_V2CLK_SRC_SEL_MASK);
+    
+    OUTPLLP(pScrn,
+	    R128_P2PLL_CNTL,
+	    R128_P2PLL_RESET
+	    | R128_P2PLL_ATOMIC_UPDATE_EN
+	    | R128_P2PLL_VGA_ATOMIC_UPDATE_EN,
+	    ~(R128_P2PLL_RESET
+	      | R128_P2PLL_ATOMIC_UPDATE_EN
+	      | R128_P2PLL_VGA_ATOMIC_UPDATE_EN));
+
+#if 0
+    OUTREGP(R128_CLOCK_CNTL_INDEX, 0, R128_PLL2_DIV_SEL_MASK);
+#endif
+   
+    /*    R128PLL2WaitForReadUpdateComplete(pScrn);*/
+    
+    OUTPLLP(pScrn, R128_P2PLL_REF_DIV, restore->p2pll_ref_div, ~R128_P2PLL_REF_DIV_MASK);
+    
+    /*    R128PLL2WriteUpdate(pScrn);   
+    R128PLL2WaitForReadUpdateComplete(pScrn);
+    */   
+    OUTPLLP(pScrn, R128_P2PLL_DIV_0,
+			restore->p2pll_div_0, ~R128_P2PLL_FB0_DIV_MASK);
+    /*
+    R128PLL2WriteUpdate(pScrn);
+    R128PLL2WaitForReadUpdateComplete(pScrn);
+    */
+    ErrorF("p2pll_div_0 POST0 mask\n");
+    OUTPLLP(pScrn, R128_P2PLL_DIV_0,
+			restore->p2pll_div_0, ~R128_P2PLL_POST0_DIV_MASK);
+
+    R128PLL2WriteUpdate(pScrn);
+    R128PLL2WaitForReadUpdateComplete(pScrn);
+    
+    OUTPLL(R128_HTOTAL2_CNTL, restore->htotal_cntl2);
+    
+    /*    R128PLL2WriteUpdate(pScrn);*/
+    
+    OUTPLLP(pScrn, R128_P2PLL_CNTL, 0, ~(R128_P2PLL_RESET 
+					| R128_P2PLL_SLEEP
+					| R128_P2PLL_ATOMIC_UPDATE_EN
+					| R128_P2PLL_VGA_ATOMIC_UPDATE_EN));
+
+    R128TRACE(("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
+	       restore->p2pll_ref_div,
+	       restore->p2pll_div_0,
+	       restore->htotal_cntl2,
+	       INPLL(pScrn, RADEON_P2PLL_CNTL)));
+    R128TRACE(("Wrote: rd=%d, fd=%d, pd=%d\n",
+	       restore->p2pll_ref_div & RADEON_P2PLL_REF_DIV_MASK,
+	       restore->p2pll_div_0 & RADEON_P2PLL_FB3_DIV_MASK,
+	       (restore->p2pll_div_0 & RADEON_P2PLL_POST3_DIV_MASK) >>16));
+
+    usleep(5000); /* Let the clock to lock */
+
+    OUTPLLP(pScrn, R128_V2CLK_VCLKTV_CNTL,
+	    R128_V2CLK_SRC_SEL_P2PLLCLK, 
+	    ~R128_V2CLK_SRC_SEL_MASK);
+
+
 }
 
 /* Write DDA registers. */
@@ -2640,6 +3008,16 @@
     OUTREG(R128_DDA_ON_OFF, restore->dda_on_off);
 }
 
+/* Write DDA registers. */
+static void R128RestoreDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
+{
+    R128InfoPtr   info      = R128PTR(pScrn);
+    unsigned char *R128MMIO = info->MMIO;
+
+    OUTREG(R128_DDA2_CONFIG, restore->dda2_config);
+    OUTREG(R128_DDA2_ON_OFF, restore->dda2_on_off);
+}
+
 /* Write palette data. */
 static void R128RestorePalette(ScrnInfoPtr pScrn, R128SavePtr restore)
 {
@@ -2649,27 +3027,122 @@
 
     if (!restore->palette_valid) return;
 
+#if 0
     /* Select palette 0 (main CRTC) if using FP-enabled chip */
     if (info->HasPanelRegs || info->isDFP) PAL_SELECT(0);
 
     OUTPAL_START(0);
     for (i = 0; i < 256; i++) OUTPAL_NEXT_CARD32(restore->palette[i]);
+#endif
+
+/* from radeon_driver.c */
+    PAL_SELECT(1);
+    OUTPAL_START(0);
+    for (i = 0; i < 256; i++) {
+	R128WaitForFifo(pScrn, 32); /* delay */
+	OUTPAL_NEXT_CARD32(restore->palette2[i]);
+    }
+
+    PAL_SELECT(0);
+    OUTPAL_START(0);
+    for (i = 0; i < 256; i++) {
+	R128WaitForFifo(pScrn, 32); /* delay */
+	OUTPAL_NEXT_CARD32(restore->palette[i]);
+    }
+
 }
 
 /* Write out state to define a new video mode.  */
 static void R128RestoreMode(ScrnInfoPtr pScrn, R128SavePtr restore)
 {
     R128InfoPtr info = R128PTR(pScrn);
+    DevUnion* pPriv;
+    R128EntPtr pR128Ent;
+    static R128SaveRec restore0;
 
     R128TRACE(("R128RestoreMode(%p)\n", restore));
-    R128RestoreCommonRegisters(pScrn, restore);
-    R128RestoreCrtcRegisters(pScrn, restore);
-    if (!(info->HasPanelRegs) || info->BIOSDisplay == R128_BIOS_DISPLAY_CRT){
+    if(!info->HasCRTC2)
+    {
+    	R128RestoreCommonRegisters(pScrn, restore);
+        R128RestoreDDARegisters(pScrn, restore);
+    	R128RestoreCrtcRegisters(pScrn, restore);
+        if((info->DisplayType == MT_DFP) || 
+           (info->DisplayType == MT_LCD))
+        {
+	    R128RestoreFPRegisters(pScrn, restore);
+        }
         R128RestorePLLRegisters(pScrn, restore);
+        return;
+    }       
+    
+    pPriv = xf86GetEntityPrivate(pScrn->entityList[0], 
+                   gR128EntityIndex);
+    pR128Ent = pPriv->ptr;
+   
+
+    /*****
+      When changing mode with Dual-head card (VE/M6), care must
+      be taken for the special order in setting registers. CRTC2 has
+      to be set before changing CRTC_EXT register.
+      In the dual-head setup, X server calls this routine twice with
+      primary and secondary pScrn pointers respectively. The calls
+      can come with different order. Regardless the order of X server issuing 
+      the calls, we have to ensure we set registers in the right order!!! 
+      Otherwise we may get a blank screen.
+    *****/
+
+    if(info->IsSecondary)
+    {
+	if (!pR128Ent->RestorePrimary  && !info->SwitchingMode)
+	    R128RestoreCommonRegisters(pScrn, restore);
+        R128RestoreDDA2Registers(pScrn, restore);
+        R128RestoreCrtc2Registers(pScrn, restore);        
+        R128RestorePLL2Registers(pScrn, restore);
+        
+	if(info->SwitchingMode) return;
+
+        pR128Ent->IsSecondaryRestored = TRUE;
+
+        if(pR128Ent->RestorePrimary)
+        {
+            R128InfoPtr info0 = R128PTR(pR128Ent->pPrimaryScrn); 
+            pR128Ent->RestorePrimary = FALSE;
+
+            R128RestoreCrtcRegisters(pScrn, &restore0);
+            if((info0->DisplayType == MT_DFP) || 
+               (info0->DisplayType == MT_LCD))
+            {
+                R128RestoreFPRegisters(pScrn, &restore0);
+            }
+            
+            R128RestorePLLRegisters(pScrn, &restore0);   
+            pR128Ent->IsSecondaryRestored = FALSE;
+
+        }
+    }
+    else
+    {
+	if (!pR128Ent->IsSecondaryRestored)
+            R128RestoreCommonRegisters(pScrn, restore);
+        R128RestoreDDARegisters(pScrn, restore);
+        if(!pR128Ent->HasSecondary || pR128Ent->IsSecondaryRestored
+            || info->SwitchingMode)
+        {
+	    pR128Ent->IsSecondaryRestored = FALSE;
+            R128RestoreCrtcRegisters(pScrn, restore);
+            if((info->DisplayType == MT_DFP) || 
+               (info->DisplayType == MT_LCD))
+            {
+               R128RestoreFPRegisters(pScrn, restore);
+            }
+            R128RestorePLLRegisters(pScrn, restore);   
+        }
+        else
+        {
+            memcpy(&restore0, restore, sizeof(restore0));
+            pR128Ent->RestorePrimary = TRUE;
+        }
     }
-    R128RestoreDDARegisters(pScrn, restore);
-    if (info->HasPanelRegs || info->isDFP)
-        R128RestoreFPRegisters(pScrn, restore);
 
     R128RestorePalette(pScrn, restore);
 }
@@ -2720,7 +3193,7 @@
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
 
-    save->crtc2_gen_cntl       = INREG(R128_CRTC2_GEN_CNTL);
+    /*save->crtc2_gen_cntl       = INREG(R128_CRTC2_GEN_CNTL);*/
     save->fp_crtc_h_total_disp = INREG(R128_FP_CRTC_H_TOTAL_DISP);
     save->fp_crtc_v_total_disp = INREG(R128_FP_CRTC_V_TOTAL_DISP);
     save->fp_gen_cntl          = INREG(R128_FP_GEN_CNTL);
@@ -2734,6 +3207,24 @@
     save->tmds_transmitter_cntl = INREG(R128_TMDS_TRANSMITTER_CNTL);
 }
 
+/* Read CRTC2 registers. */
+static void R128SaveCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr save)
+{
+    R128InfoPtr info        = R128PTR(pScrn);
+    unsigned char *R128MMIO = info->MMIO;
+
+    /*save->dac_cntl             = INREG(R128_DAC_CNTL);*/
+
+    save->crtc2_gen_cntl        = INREG(R128_CRTC2_GEN_CNTL);
+    save->crtc2_h_total_disp    = INREG(R128_CRTC2_H_TOTAL_DISP);
+    save->crtc2_h_sync_strt_wid = INREG(R128_CRTC2_H_SYNC_STRT_WID);
+    save->crtc2_v_total_disp    = INREG(R128_CRTC2_V_TOTAL_DISP);
+    save->crtc2_v_sync_strt_wid = INREG(R128_CRTC2_V_SYNC_STRT_WID);
+    save->crtc2_offset          = INREG(R128_CRTC2_OFFSET);
+    save->crtc2_offset_cntl     = INREG(R128_CRTC2_OFFSET_CNTL);
+    save->crtc2_pitch           = INREG(R128_CRTC2_PITCH);
+}
+
 /* Read PLL registers. */
 static void R128SavePLLRegisters(ScrnInfoPtr pScrn, R128SavePtr save)
 {
@@ -2751,6 +3242,23 @@
 	       (save->ppll_div_3 & R128_PPLL_POST3_DIV_MASK) >> 16));
 }
 
+/* Read PLL2 registers. */
+static void R128SavePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr save)
+{
+    save->p2pll_ref_div        = INPLL(pScrn, R128_P2PLL_REF_DIV);
+    save->p2pll_div_0          = INPLL(pScrn, R128_P2PLL_DIV_0);
+    save->htotal_cntl2         = INPLL(pScrn, R128_HTOTAL2_CNTL);
+
+    R128TRACE(("Read: 0x%08x 0x%08x 0x%08x\n",
+	       save->p2pll_ref_div,
+	       save->p2pll_div_0,
+	       save->htotal_cntl2));
+    R128TRACE(("Read: rd=%d, fd=%d, pd=%d\n",
+	       save->p2pll_ref_div & R128_P2PLL_REF_DIV_MASK,
+	       save->p2pll_div_0 & R128_P2PLL_FB0_DIV_MASK,
+	       (save->p2pll_div_0 & R128_P2PLL_POST0_DIV_MASK) >> 16));
+}
+
 /* Read DDA registers. */
 static void R128SaveDDARegisters(ScrnInfoPtr pScrn, R128SavePtr save)
 {
@@ -2761,6 +3269,16 @@
     save->dda_on_off           = INREG(R128_DDA_ON_OFF);
 }
 
+/* Read DDA2 registers. */
+static void R128SaveDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr save)
+{
+    R128InfoPtr   info      = R128PTR(pScrn);
+    unsigned char *R128MMIO = info->MMIO;
+
+    save->dda2_config           = INREG(R128_DDA2_CONFIG);
+    save->dda2_on_off           = INREG(R128_DDA2_ON_OFF);
+}
+
 /* Read palette data. */
 static void R128SavePalette(ScrnInfoPtr pScrn, R128SavePtr save)
 {
@@ -2768,26 +3286,49 @@
     unsigned char *R128MMIO = info->MMIO;
     int           i;
 
+#if 0
     /* Select palette 0 (main CRTC) if using FP-enabled chip */
     if (info->HasPanelRegs || info->isDFP) PAL_SELECT(0);
 
     INPAL_START(0);
     for (i = 0; i < 256; i++) save->palette[i] = INPAL_NEXT();
     save->palette_valid = TRUE;
+#endif
+    PAL_SELECT(1);
+    INPAL_START(0);
+    for (i = 0; i < 256; i++) save->palette2[i] = INPAL_NEXT();
+    PAL_SELECT(0);
+    INPAL_START(0);
+    for (i = 0; i < 256; i++) save->palette[i] = INPAL_NEXT();
+    save->palette_valid = TRUE;
 }
 
 /* Save state that defines current video mode. */
 static void R128SaveMode(ScrnInfoPtr pScrn, R128SavePtr save)
 {
+    R128InfoPtr   info      = R128PTR(pScrn);
+
     R128TRACE(("R128SaveMode(%p)\n", save));
 
-    R128SaveCommonRegisters(pScrn, save);
-    R128SaveCrtcRegisters(pScrn, save);
-    if (R128PTR(pScrn)->HasPanelRegs || R128PTR(pScrn)->isDFP)
-	R128SaveFPRegisters(pScrn, save);
-    R128SavePLLRegisters(pScrn, save);
-    R128SaveDDARegisters(pScrn, save);
-    R128SavePalette(pScrn, save);
+    if(info->IsSecondary)
+    {
+        R128SaveCrtc2Registers(pScrn, save);
+        R128SavePLL2Registers(pScrn, save);
+        R128SaveDDA2Registers(pScrn, save);
+    }
+    else
+    {
+        R128SaveCommonRegisters(pScrn, save);
+        R128SaveCrtcRegisters(pScrn, save);
+        if((info->DisplayType == MT_DFP) || 
+           (info->DisplayType == MT_LCD))
+        {
+ 	    R128SaveFPRegisters(pScrn, save);
+        }
+        R128SavePLLRegisters(pScrn, save);
+        R128SaveDDARegisters(pScrn, save);
+        R128SavePalette(pScrn, save);
+    }
 
     R128TRACE(("R128SaveMode returns %p\n", save));
 }
@@ -2805,17 +3346,24 @@
 	fbdevHWSave(pScrn);
 	return;
     }
+
+    if(!info->IsSecondary)
+    {
     vgaHWUnlock(hwp);
     vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_ALL); /* save mode, fonts, cmap */
     vgaHWLock(hwp);
 
-    R128SaveMode(pScrn, save);
+    /*R128SaveMode(pScrn, save);*/
 
     save->dp_datatype      = INREG(R128_DP_DATATYPE);
     save->gen_reset_cntl   = INREG(R128_GEN_RESET_CNTL);
     save->clock_cntl_index = INREG(R128_CLOCK_CNTL_INDEX);
     save->amcgpio_en_reg   = INREG(R128_AMCGPIO_EN_REG);
     save->amcgpio_mask     = INREG(R128_AMCGPIO_MASK);
+    }
+
+    R128SaveMode(pScrn, save);
+
 }
 
 /* Restore the original (text) mode. */
@@ -2833,16 +3381,46 @@
     }
 
     R128Blank(pScrn);
+
+    if (!info->IsSecondary) {
     OUTREG(R128_AMCGPIO_MASK,     restore->amcgpio_mask);
     OUTREG(R128_AMCGPIO_EN_REG,   restore->amcgpio_en_reg);
     OUTREG(R128_CLOCK_CNTL_INDEX, restore->clock_cntl_index);
     OUTREG(R128_GEN_RESET_CNTL,   restore->gen_reset_cntl);
     OUTREG(R128_DP_DATATYPE,      restore->dp_datatype);
+    }
 
     R128RestoreMode(pScrn, restore);
+
+    /* Temp fix to "solve" VT switch problems.  When switching VTs on
+       some systems, the console can either hang or the fonts can be
+       corrupted.  This hack solves the problem 99% of the time.  A
+       correct fix is being worked on. */
+    /* does r128 need this? */
+    usleep(100000);
+
+    if(!info->IsSecondary)
+    {
     vgaHWUnlock(hwp);
     vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_FONTS );
     vgaHWLock(hwp);
+    }
+    else
+    {
+        DevUnion* pPriv;
+        R128EntPtr pR128Ent;
+        pPriv = xf86GetEntityPrivate(pScrn->entityList[0], 
+            gR128EntityIndex);
+        pR128Ent = pPriv->ptr;
+        {
+            ScrnInfoPtr pScrn0 = pR128Ent->pPrimaryScrn;
+            vgaHWPtr      hwp0         = VGAHWPTR(pScrn0);
+            vgaHWUnlock(hwp0);
+            vgaHWRestore(pScrn0, &hwp0->SavedReg, 
+                    VGA_SR_MODE | VGA_SR_FONTS );
+            vgaHWLock(hwp0);
+        }
+    }
 
     R128WaitForVerticalSync(pScrn);
     R128Unblank(pScrn);
@@ -2902,18 +3480,11 @@
 	return FALSE;
     }
 
-    switch (info->BIOSDisplay) {
-    case R128_BIOS_DISPLAY_FP:
+    if ((info->DisplayType == MT_DFP) || 
+        (info->DisplayType == MT_LCD))
 	hsync_fudge = hsync_fudge_fp[format-1];
-	break;
-    case R128_BIOS_DISPLAY_FP_CRT:
-	hsync_fudge = hsync_fudge_fp_crt[format-1];
-	break;
-    case R128_BIOS_DISPLAY_CRT:
-    default:
-	hsync_fudge = hsync_fudge_default[format-1];
-	break;
-    }
+    else               
+        hsync_fudge = hsync_fudge_default[format-1];
 
     save->crtc_gen_cntl = (R128_CRTC_EXT_DISP_EN
 			  | R128_CRTC_EN
@@ -2928,7 +3499,19 @@
 			     ? R128_CRTC_CSYNC_EN
 			     : 0));
 
-    save->crtc_ext_cntl = R128_VGA_ATI_LINEAR | R128_XCRT_CNT_EN;
+    if((info->DisplayType == MT_DFP) || 
+       (info->DisplayType == MT_LCD))
+    {
+        save->crtc_ext_cntl = R128_VGA_ATI_LINEAR | 
+        			  R128_XCRT_CNT_EN;
+        save->crtc_gen_cntl &= ~(R128_CRTC_DBL_SCAN_EN | 
+                                  R128_CRTC_INTERLACE_EN);
+    }
+    else
+        save->crtc_ext_cntl = R128_VGA_ATI_LINEAR | 
+			      R128_XCRT_CNT_EN |
+			      R128_CRTC_CRT_ON;
+
     save->dac_cntl      = (R128_DAC_MASK_ALL
 			   | R128_DAC_VGA_ADR_EN
 			   | (info->dac6bits ? 0 : R128_DAC_8BIT_EN));
@@ -3005,6 +3588,98 @@
     return TRUE;
 }
 
+/* Define CRTC2 registers for requested video mode. */
+static Bool R128InitCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
+				  DisplayModePtr mode, R128InfoPtr info)
+{
+    int    format;
+    int    hsync_start;
+    int    hsync_wid;
+    int    hsync_fudge;
+    int    vsync_wid;
+    int    bytpp;
+    int    hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 };
+
+    switch (info->CurrentLayout.pixel_code) {
+    case 4:  format = 1; bytpp = 0; break;
+    case 8:  format = 2; bytpp = 1; break;
+    case 15: format = 3; bytpp = 2; break;      /*  555 */
+    case 16: format = 4; bytpp = 2; break;      /*  565 */
+    case 24: format = 5; bytpp = 3; break;      /*  RGB */
+    case 32: format = 6; bytpp = 4; break;      /* xRGB */
+    default:
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		   "Unsupported pixel depth (%d)\n", info->CurrentLayout.bitsPerPixel);
+	return FALSE;
+    }
+    R128TRACE(("Format = %d (%d bytes per pixel)\n", format, bytpp));
+
+    hsync_fudge = hsync_fudge_default[format-1];
+
+    save->crtc2_gen_cntl = (R128_CRTC2_EN
+                          /*| R128_CRTC2_CRT2_ON*/
+			  | (format << 8)
+			  | ((mode->Flags & V_DBLSCAN)
+			     ? R128_CRTC2_DBL_SCAN_EN
+			     : 0)
+			  | ((mode->Flags & V_INTERLACE)
+			     ? R128_CRTC2_INTERLACE_EN
+			     : 0));
+#if 0
+    save->dac_cntl      = (R128_DAC_MASK_ALL
+			   | R128_DAC_VGA_ADR_EN
+			   | R128_DAC_CRT_SEL_CRTC2
+			   | (info->dac6bits ? 0 : R128_DAC_8BIT_EN));
+    /*save->dac_cntl       |= R128_DAC_CRT_SEL_CRTC2;*/
+#endif
+    save->crtc2_h_total_disp = ((((mode->CrtcHTotal / 8) - 1) & 0x3ff)
+	   | ((((mode->CrtcHDisplay / 8) - 1) & 0x1ff) << 16));
+
+    hsync_wid = (mode->CrtcHSyncEnd - mode->CrtcHSyncStart) / 8;
+    if (!hsync_wid)       hsync_wid = 1;
+    if (hsync_wid > 0x3f) hsync_wid = 0x3f;
+    hsync_start = mode->CrtcHSyncStart - 8 + hsync_fudge;
+
+    save->crtc2_h_sync_strt_wid = ((hsync_start & 0x1fff)
+				 | (hsync_wid << 16)
+				 | ((mode->Flags & V_NHSYNC)
+				    ? R128_CRTC_H_SYNC_POL
+				    : R128_CRTC_H_SYNC_POL));
+
+#if 1
+				/* This works for double scan mode. */
+    save->crtc2_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff)
+			      | ((mode->CrtcVDisplay - 1) << 16));
+#else
+				/* This is what cce/nbmode.c example code
+				   does -- is this correct? */
+    save->crtc2_v_total_disp = (((mode->CrtcVTotal - 1) & 0xffff)
+			      | ((mode->CrtcVDisplay
+				  * ((mode->Flags & V_DBLSCAN) ? 2 : 1) - 1)
+				 << 16));
+#endif
+
+    vsync_wid = mode->CrtcVSyncEnd - mode->CrtcVSyncStart;
+    if (!vsync_wid)       vsync_wid = 1;
+    if (vsync_wid > 0x1f) vsync_wid = 0x1f;
+
+    save->crtc2_v_sync_strt_wid = (((mode->CrtcVSyncStart - 1) & 0xfff)
+				 | (vsync_wid << 16)
+				 | ((mode->Flags & V_NVSYNC)
+				    ? R128_CRTC2_V_SYNC_POL
+				    : R128_CRTC2_V_SYNC_POL));
+
+    save->crtc2_offset      = 0;
+    save->crtc2_offset_cntl = 0;
+
+    save->crtc2_pitch       = info->CurrentLayout.displayWidth / 8;
+	
+    R128TRACE(("Pitch = %d bytes (virtualX = %d, displayWidth = %d)\n",
+		 save->crtc2_pitch, pScrn->virtualX,
+		 info->CurrentLayout.displayWidth));
+    return TRUE;
+}
+
 /* Define CRTC registers for requested video mode. */
 static void R128InitFPRegisters(R128SavePtr orig, R128SavePtr save,
 				DisplayModePtr mode, R128InfoPtr info)
@@ -3077,6 +3752,7 @@
        the flat panel and external CRT to either simultaneously display
        the same image or display two different images. */
 
+#if 0
     if(!info->isDFP){
         if (info->BIOSDisplay == R128_BIOS_DISPLAY_FP_CRT) {
 		save->crtc_ext_cntl  |= R128_CRTC_CRT_ON;
@@ -3086,6 +3762,11 @@
 		save->crtc2_gen_cntl  = 0;
         }
     }
+#endif
+    if(!info->isDFP){
+        save->crtc_ext_cntl  &= ~R128_CRTC_CRT_ON;
+	save->dac_cntl       |= R128_DAC_CRT_SEL_CRTC2;
+    }
 
     /* WARNING: Be careful about turning on the flat panel */
     if(info->isDFP){
@@ -3165,6 +3846,57 @@
 
 }
 
+/* Define PLL2 registers for requested video mode. */
+static void R128InitPLL2Registers(R128SavePtr save, R128PLLPtr pll,
+				   double dot_clock)
+{
+    unsigned long freq = dot_clock * 100;
+    struct {
+	int divider;
+	int bitvalue;
+    } *post_div,
+      post_divs[]   = {
+				/* From RAGE 128 VR/RAGE 128 GL Register
+				   Reference Manual (Technical Reference
+				   Manual P/N RRG-G04100-C Rev. 0.04), page
+				   3-17 (PLL_DIV_[3:0]).  */
+	{  1, 0 },              /* VCLK_SRC                 */
+	{  2, 1 },              /* VCLK_SRC/2               */
+	{  4, 2 },              /* VCLK_SRC/4               */
+	{  8, 3 },              /* VCLK_SRC/8               */
+	{  3, 4 },              /* VCLK_SRC/3               */
+	{ 16, 5 },              /* VCLK_SRC/16              */
+	{  6, 6 },              /* VCLK_SRC/6               */
+	{ 12, 7 },              /* VCLK_SRC/12              */
+	{  0, 0 }
+    };
+
+    if (freq > pll->max_pll_freq)      freq = pll->max_pll_freq;
+    if (freq * 12 < pll->min_pll_freq) freq = pll->min_pll_freq / 12;
+
+    for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
+	save->pll_output_freq_2 = post_div->divider * freq;
+	if (save->pll_output_freq_2 >= pll->min_pll_freq
+	    && save->pll_output_freq_2 <= pll->max_pll_freq) break;
+    }
+
+    save->dot_clock_freq_2 = freq;
+    save->feedback_div_2   = R128Div(pll->reference_div
+				     * save->pll_output_freq_2,
+				     pll->reference_freq);
+    save->post_div_2       = post_div->divider;
+
+    R128TRACE(("dc=%d, of=%d, fd=%d, pd=%d\n",
+	       save->dot_clock_freq_2,
+	       save->pll_output_freq_2,
+	       save->feedback_div_2,
+	       save->post_div_2));
+
+    save->p2pll_ref_div   = pll->reference_div;
+    save->p2pll_div_0    = (save->feedback_div_2 | (post_div->bitvalue<<16));
+    save->htotal_cntl2    = 0;
+}
+
 /* Define DDA registers for requested video mode. */
 static Bool R128InitDDARegisters(ScrnInfoPtr pScrn, R128SavePtr save,
 				 R128PLLPtr pll, R128InfoPtr info,
@@ -3234,6 +3966,74 @@
     return TRUE;
 }
 
+/* Define DDA2 registers for requested video mode. */
+static Bool R128InitDDA2Registers(ScrnInfoPtr pScrn, R128SavePtr save,
+				 R128PLLPtr pll, R128InfoPtr info,
+                                 DisplayModePtr mode)
+{
+    int         DisplayFifoWidth = 128;
+    int         DisplayFifoDepth = 32;
+    int         XclkFreq;
+    int         VclkFreq;
+    int         XclksPerTransfer;
+    int         XclksPerTransferPrecise;
+    int         UseablePrecision;
+    int         Roff;
+    int         Ron;
+
+    XclkFreq = pll->xclk;
+
+    VclkFreq = R128Div(pll->reference_freq * save->feedback_div_2,
+		       pll->reference_div * save->post_div_2);
+
+    if(info->isDFP && !info->isPro2){
+        if(info->PanelXRes != mode->CrtcHDisplay)
+            VclkFreq = (VclkFreq * mode->CrtcHDisplay)/info->PanelXRes;
+	}
+
+    XclksPerTransfer = R128Div(XclkFreq * DisplayFifoWidth,
+			       VclkFreq * (info->CurrentLayout.pixel_bytes * 8));
+
+    UseablePrecision = R128MinBits(XclksPerTransfer) + 1;
+
+    XclksPerTransferPrecise = R128Div((XclkFreq * DisplayFifoWidth)
+				      << (11 - UseablePrecision),
+				      VclkFreq * (info->CurrentLayout.pixel_bytes * 8));
+
+    Roff  = XclksPerTransferPrecise * (DisplayFifoDepth - 4);
+
+    Ron   = (4 * info->ram->MB
+	     + 3 * MAX(info->ram->Trcd - 2, 0)
+	     + 2 * info->ram->Trp
+	     + info->ram->Twr
+	     + info->ram->CL
+	     + info->ram->Tr2w
+	     + XclksPerTransfer) << (11 - UseablePrecision);
+
+    if (Ron + info->ram->Rloop >= Roff) {
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		   "(Ron = %d) + (Rloop = %d) >= (Roff = %d)\n",
+		   Ron, info->ram->Rloop, Roff);
+	return FALSE;
+    }
+
+    save->dda2_config = (XclksPerTransferPrecise
+			| (UseablePrecision << 16)
+			| (info->ram->Rloop << 20));
+
+    save->dda2_on_off = (Ron << 16) | Roff;
+
+    R128TRACE(("XclkFreq = %d; VclkFreq = %d; per = %d, %d (useable = %d)\n",
+	       XclkFreq,
+	       VclkFreq,
+	       XclksPerTransfer,
+	       XclksPerTransferPrecise,
+	       UseablePrecision));
+    R128TRACE(("Roff = %d, Ron = %d, Rloop = %d\n",
+	       Roff, Ron, info->ram->Rloop));
+
+    return TRUE;
+}
 
 #if 0
 /* Define initial palette for requested video mode.  This doesn't do
@@ -3301,21 +4101,42 @@
 
     info->Flags = mode->Flags;
 
-    R128InitCommonRegisters(save, info);
-    if (!R128InitCrtcRegisters(pScrn, save, mode, info)) return FALSE;
-    if (info->HasPanelRegs || info->isDFP)
-	    R128InitFPRegisters(&info->SavedReg, save, mode, info);
-    if(dot_clock > 0){
-        R128InitPLLRegisters(pScrn, save, &info->pll, dot_clock);
-        if (!R128InitDDARegisters(pScrn, save, &info->pll, info, mode))
-		return FALSE;
+    if(info->IsSecondary)
+    {
+        if (!R128InitCrtc2Registers(pScrn, save, 
+             pScrn->currentMode,info)) 
+            return FALSE;
+        R128InitPLL2Registers(save, &info->pll, dot_clock);
+        if (!R128InitDDA2Registers(pScrn, save, &info->pll, info, mode))
+	    return FALSE;
     }
-    else{
-        save->ppll_ref_div         = info->SavedReg.ppll_ref_div;
-        save->ppll_div_3           = info->SavedReg.ppll_div_3;
-        save->htotal_cntl          = info->SavedReg.htotal_cntl;
-        save->dda_config           = info->SavedReg.dda_config;
-        save->dda_on_off           = info->SavedReg.dda_on_off;
+    else
+    {
+        R128InitCommonRegisters(save, info);
+        if(!R128InitCrtcRegisters(pScrn, save, mode, info)) 
+            return FALSE;
+        if(dot_clock) 
+        {
+            R128InitPLLRegisters(pScrn, save, &info->pll, dot_clock);
+            if (!R128InitDDARegisters(pScrn, save, &info->pll, info, mode))
+	        return FALSE;
+        }
+        else
+        {
+            save->ppll_ref_div         = info->SavedReg.ppll_ref_div;
+            save->ppll_div_3           = info->SavedReg.ppll_div_3;
+            save->htotal_cntl          = info->SavedReg.htotal_cntl;
+            save->dda_config           = info->SavedReg.dda_config;
+            save->dda_on_off           = info->SavedReg.dda_on_off;
+        }
+        /* not used for now */
+        /*if (!info->PaletteSavedOnVT) RADEONInitPalette(save);*/
+    }
+
+    if (((info->DisplayType == MT_DFP) || 
+        (info->DisplayType == MT_LCD)))
+    {
+        R128InitFPRegisters(&info->SavedReg, save, mode, info);
     }
 
     R128TRACE(("R128Init returns %p\n", save));
@@ -3359,7 +4180,19 @@
 
 Bool R128SwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
 {
-    return R128ModeInit(xf86Screens[scrnIndex], mode);
+    ScrnInfoPtr   pScrn       = xf86Screens[scrnIndex];
+    R128InfoPtr info        = R128PTR(pScrn);
+    Bool ret;
+    /* when switch mode in dual-head setup, this function will be called
+       separately for each screen (depending on which screen the cursor is
+       in when user press ctrl-alt-+). Since this function is always
+       called when screen already in extensive mode, the sequence of
+       setting CRTC2 and CRT_EXT regesters doesn't matter any more, 
+       So we set the flag for RADEONRestoreMode here. */
+    info->SwitchingMode = TRUE;
+    ret = R128ModeInit(xf86Screens[scrnIndex], mode);
+    info->SwitchingMode = FALSE;
+    return ret;
 }
 
 /* Used to disallow modes that are not supported by the hardware. */
@@ -3377,13 +4210,12 @@
             return MODE_OK;
     }
 
-    if (info->HasPanelRegs) {
+    if (info->DisplayType == MT_LCD) {
 	if (mode->Flags & V_INTERLACE) return MODE_NO_INTERLACE;
 	if (mode->Flags & V_DBLSCAN)   return MODE_NO_DBLESCAN;
     }
 
-    if (info->HasPanelRegs &&
-	info->BIOSDisplay != R128_BIOS_DISPLAY_CRT &&
+    if (info->DisplayType == MT_LCD &&
 	info->VBIOS) {
 	int i;
 	for (i = info->FPBIOSstart+64; R128_BIOS16(i) != 0; i += 2) {
@@ -3464,6 +4296,12 @@
     if (info->CurrentLayout.pixel_code == 24)
 	Base += 8 * (Base % 3); /* Must be multiple of 8 and 3 */
 
+    if(info->IsSecondary)    
+    {
+        Base += pScrn->fbOffset; 
+        OUTREG(R128_CRTC2_OFFSET, Base);
+    }
+    else
     OUTREG(R128_CRTC_OFFSET, Base);
 }
 
@@ -3591,25 +4429,44 @@
     int           mask      = (R128_CRTC_DISPLAY_DIS
 			       | R128_CRTC_HSYNC_DIS
 			       | R128_CRTC_VSYNC_DIS);
+    int             mask2     = (R128_CRTC2_DISP_DIS |
+    			         R128_CRTC2_VSYNC_DIS |
+		    	         R128_CRTC2_HSYNC_DIS);
 
     switch (PowerManagementMode) {
     case DPMSModeOn:
 	/* Screen: On; HSync: On, VSync: On */
-	OUTREGP(R128_CRTC_EXT_CNTL, 0, ~mask);
+	if (info->IsSecondary)
+		OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~mask2);
+	else
+		OUTREGP(R128_CRTC_EXT_CNTL, 0, ~mask);
 	break;
     case DPMSModeStandby:
 	/* Screen: Off; HSync: Off, VSync: On */
-	OUTREGP(R128_CRTC_EXT_CNTL,
-		R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS, ~mask);
+	if (info->IsSecondary)
+		OUTREGP(R128_CRTC2_GEN_CNTL,
+			R128_CRTC2_DISP_DIS | R128_CRTC2_HSYNC_DIS,
+			~mask2);
+	    else
+		OUTREGP(R128_CRTC_EXT_CNTL,
+			R128_CRTC_DISPLAY_DIS | R128_CRTC_HSYNC_DIS, ~mask);
 	break;
     case DPMSModeSuspend:
 	/* Screen: Off; HSync: On, VSync: Off */
-	OUTREGP(R128_CRTC_EXT_CNTL,
-		R128_CRTC_DISPLAY_DIS | R128_CRTC_VSYNC_DIS, ~mask);
+	if (info->IsSecondary)
+		OUTREGP(R128_CRTC2_GEN_CNTL,
+			R128_CRTC2_DISP_DIS | R128_CRTC2_VSYNC_DIS,
+			~mask2);
+	else 
+		OUTREGP(R128_CRTC_EXT_CNTL,
+			R128_CRTC_DISPLAY_DIS | R128_CRTC_VSYNC_DIS, ~mask);
 	break;
     case DPMSModeOff:
 	/* Screen: Off; HSync: Off, VSync: Off */
-	OUTREGP(R128_CRTC_EXT_CNTL, mask, ~mask);
+	if (info->IsSecondary)
+		OUTREGP(R128_CRTC2_GEN_CNTL, mask2, ~mask2);
+	else
+		OUTREGP(R128_CRTC_EXT_CNTL, mask, ~mask);
 	break;
     }
 }
Index: r128_probe.c
===================================================================
RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/ati/r128_probe.c,v
retrieving revision 1.4
diff -u -r1.4 r128_probe.c
--- r128_probe.c	12 Aug 2004 01:03:06 -0000	1.4
+++ r128_probe.c	10 Oct 2004 03:21:02 -0000
@@ -101,6 +101,8 @@
     { -1,                 -1,                 RES_UNDEFINED }
 };
 
+int gR128EntityIndex = -1;
+
 /* Return the options for supported chipset 'n'; NULL otherwise */
 const OptionInfoRec *
 R128AvailableOptions(int chipid, int busid)
@@ -137,7 +139,6 @@
     int           numDevSections, nATIGDev, nR128GDev;
     int           *usedChips;
     GDevPtr       *devSections, *ATIGDevs, *R128GDevs;
-    EntityInfoPtr pEnt;
     Bool          foundScreen = FALSE;
     int           i;
 
@@ -183,10 +184,13 @@
     if (flags & PROBE_DETECT)
 	foundScreen = TRUE;
     else for (i = 0; i < numUsed; i++) {
-	pEnt = xf86GetEntityInfo(usedChips[i]);
-
-	if (pEnt->active) {
-	    ScrnInfoPtr pScrn = xf86AllocateScreen(drv, 0);
+        ScrnInfoPtr pScrn;
+        EntityInfoPtr pEnt;
+ 
+        pScrn    = NULL;
+        if((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i],
+             R128PciChipsets, 0, 0, 0, 0, 0)))
+	{
 
 #ifdef XFree86LOADER
 
@@ -206,11 +210,43 @@
 
 	    foundScreen          = TRUE;
 
-	    xf86ConfigActivePciEntity(pScrn, usedChips[i], R128PciChipsets,
-				      0, 0, 0, 0, 0);
+        pEnt = xf86GetEntityInfo(usedChips[i]);
+
+        /* mobility cards support Dual-Head, mark the entity as sharable*/
+        if(pEnt->chipset == PCI_CHIP_RAGE128LE ||
+           pEnt->chipset == PCI_CHIP_RAGE128LF ||
+           pEnt->chipset == PCI_CHIP_RAGE128MF ||
+           pEnt->chipset == PCI_CHIP_RAGE128ML)
+        {
+            static int instance = 0;
+            DevUnion* pPriv;
+
+            xf86SetEntitySharable(usedChips[i]);
+            xf86SetEntityInstanceForScreen(pScrn,
+                pScrn->entityList[0], instance);
+
+            if(gR128EntityIndex < 0)
+            {
+                gR128EntityIndex = xf86AllocateEntityPrivateIndex();
+                pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
+                        gR128EntityIndex);
+
+                if (!pPriv->ptr)
+                {
+                    R128EntPtr pR128Ent;
+                    pPriv->ptr = xnfcalloc(sizeof(R128EntRec), 1);
+                    pR128Ent = pPriv->ptr;
+                    pR128Ent->IsDRIEnabled = FALSE;
+                    pR128Ent->BypassSecondary = FALSE;
+                    pR128Ent->HasSecondary = FALSE;
+                    pR128Ent->IsSecondaryRestored = FALSE;                   
+                } 
+            }
+            instance++;
 	}
 	xfree(pEnt);
     }
+    }
 
     xfree(usedChips);
     xfree(devSections);
Index: r128_probe.h
===================================================================
RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/ati/r128_probe.h,v
retrieving revision 1.5
diff -u -r1.5 r128_probe.h
--- r128_probe.h	12 Aug 2004 01:03:06 -0000	1.5
+++ r128_probe.h	10 Oct 2004 03:21:02 -0000
@@ -41,6 +41,21 @@
 
 #include "xf86str.h"
 
+typedef struct
+{
+    Bool IsDRIEnabled;
+
+    Bool HasSecondary;
+    Bool BypassSecondary;
+    /*These two registers are used to make sure the CRTC2 is
+      retored before CRTC_EXT, otherwise it could lead to blank screen.*/
+    Bool IsSecondaryRestored;
+    Bool RestorePrimary;
+
+    ScrnInfoPtr pSecondaryScrn;    
+    ScrnInfoPtr pPrimaryScrn;
+}R128EntRec, *R128EntPtr;
+
 /* r128_probe.c */
 extern const OptionInfoRec * R128AvailableOptions
 			     FunctionPrototype((int, int));
Index: r128_reg.h
===================================================================
RCS file: /cvs/xorg/xc/programs/Xserver/hw/xfree86/drivers/ati/r128_reg.h,v
retrieving revision 1.3
diff -u -r1.3 r128_reg.h
--- r128_reg.h	16 Jun 2004 09:43:58 -0000	1.3
+++ r128_reg.h	10 Oct 2004 03:21:03 -0000
@@ -76,7 +76,7 @@
 
 #define OUTPLL(addr, val)                                                 \
     do {                                                                  \
-	OUTREG8(R128_CLOCK_CNTL_INDEX, ((addr) & 0x1f) | R128_PLL_WR_EN); \
+	OUTREG8(R128_CLOCK_CNTL_INDEX, ((addr) & 0x3f) | R128_PLL_WR_EN); \
 	OUTREG(R128_CLOCK_CNTL_DATA, val);                                \
     } while (0)
 
@@ -284,6 +284,7 @@
 #define R128_CLOCK_CNTL_INDEX             0x0008
 #       define R128_PLL_WR_EN             (1 << 7)
 #       define R128_PLL_DIV_SEL           (3 << 8)
+#       define R128_PLL2_DIV_SEL_MASK     ~(3 << 8)
 #define R128_CLR_CMP_CLR_3D               0x1a24
 #define R128_CLR_CMP_CLR_DST              0x15c8
 #define R128_CLR_CMP_CLR_SRC              0x15c4
@@ -374,15 +375,49 @@
 #define R128_CRTC2_CRNT_FRAME             0x0314
 #define R128_CRTC2_DEBUG                  0x031c
 #define R128_CRTC2_GEN_CNTL               0x03f8
+#       define R128_CRTC2_DBL_SCAN_EN      (1 <<  0)
+#       define R128_CRTC2_INTERLACE_EN     (1 <<  1)
+#       define R128_CRTC2_SYNC_TRISTAT     (1 <<  4)
+#       define R128_CRTC2_HSYNC_TRISTAT    (1 <<  5)
+#       define R128_CRTC2_VSYNC_TRISTAT    (1 <<  6)
+#       define R128_CRTC2_CRT2_ON          (1 <<  7)
+#       define R128_CRTC2_ICON_EN          (1 << 15)
+#       define R128_CRTC2_CUR_EN           (1 << 16)
+#       define R128_CRTC2_CUR_MODE_MASK    (7 << 20)
+#       define R128_CRTC2_DISP_DIS         (1 << 23)
+#       define R128_CRTC2_EN               (1 << 25)
+#       define R128_CRTC2_DISP_REQ_EN_B    (1 << 26)
+#       define R128_CRTC2_HSYNC_DIS        (1 << 28)
+#       define R128_CRTC2_VSYNC_DIS        (1 << 29)
 #define R128_CRTC2_GUI_TRIG_VLINE         0x0318
 #define R128_CRTC2_H_SYNC_STRT_WID        0x0304
+#       define R128_CRTC2_H_SYNC_STRT_PIX        (0x07  <<  0)
+#       define R128_CRTC2_H_SYNC_STRT_CHAR       (0x3ff <<  3)
+#       define R128_CRTC2_H_SYNC_STRT_CHAR_SHIFT 3
+#       define R128_CRTC2_H_SYNC_WID             (0x3f  << 16)
+#       define R128_CRTC2_H_SYNC_WID_SHIFT       16
+#       define R128_CRTC2_H_SYNC_POL             (1     << 23)
 #define R128_CRTC2_H_TOTAL_DISP           0x0300
+#       define R128_CRTC2_H_TOTAL          (0x03ff << 0)
+#       define R128_CRTC2_H_TOTAL_SHIFT    0
+#       define R128_CRTC2_H_DISP           (0x01ff << 16)
+#       define R128_CRTC2_H_DISP_SHIFT     16
 #define R128_CRTC2_OFFSET                 0x0324
 #define R128_CRTC2_OFFSET_CNTL            0x0328
+#	define R128_CRTC2_TILE_EN         (1 << 15)
 #define R128_CRTC2_PITCH                  0x032c
 #define R128_CRTC2_STATUS                 0x03fc
 #define R128_CRTC2_V_SYNC_STRT_WID        0x030c
+#       define R128_CRTC2_V_SYNC_STRT       (0x7ff <<  0)
+#       define R128_CRTC2_V_SYNC_STRT_SHIFT 0
+#       define R128_CRTC2_V_SYNC_WID        (0x1f  << 16)
+#       define R128_CRTC2_V_SYNC_WID_SHIFT  16
+#       define R128_CRTC2_V_SYNC_POL        (1     << 23)
 #define R128_CRTC2_V_TOTAL_DISP           0x0308
+#       define R128_CRTC2_V_TOTAL          (0x07ff << 0)
+#       define R128_CRTC2_V_TOTAL_SHIFT    0
+#       define R128_CRTC2_V_DISP           (0x07ff << 16)
+#       define R128_CRTC2_V_DISP_SHIFT     16
 #define R128_CRTC2_VLINE_CRNT_VLINE       0x0310
 #define R128_CRTC8_DATA                   0x03d5 /* VGA, 0x3b5 */
 #define R128_CRTC8_IDX                    0x03d4 /* VGA, 0x3b4 */
@@ -392,6 +427,12 @@
 #define R128_CUR_HORZ_VERT_POSN           0x0264
 #define R128_CUR_OFFSET                   0x0260
 #       define R128_CUR_LOCK              (1 << 31)
+#define R128_CUR2_CLR0                    0x036c
+#define R128_CUR2_CLR1                    0x0370
+#define R128_CUR2_HORZ_VERT_OFF           0x0368
+#define R128_CUR2_HORZ_VERT_POSN          0x0364
+#define R128_CUR2_OFFSET                  0x0360
+#       define R128_CUR2_LOCK             (1 << 31)
 
 #define R128_DAC_CNTL                     0x0058
 #       define R128_DAC_RANGE_CNTL        (3 <<  0)
@@ -408,9 +449,14 @@
 #define R128_DAC_W_INDEX                  0x03c8 /* VGA */
 #define R128_DDA_CONFIG                   0x02e0
 #define R128_DDA_ON_OFF                   0x02e4
+#define R128_DDA2_CONFIG                  0x03e0
+#define R128_DDA2_ON_OFF                  0x03e4
 #define R128_DEFAULT_OFFSET               0x16e0
 #define R128_DEFAULT_PITCH                0x16e4
 #define R128_DEFAULT_SC_BOTTOM_RIGHT      0x16e8
+#define R128_DEFAULT2_OFFSET               0x16f8
+#define R128_DEFAULT2_PITCH                0x16fc
+#define R128_DEFAULT2_SC_BOTTOM_RIGHT      0x16dc
 #       define R128_DEFAULT_SC_RIGHT_MAX  (0x1fff <<  0)
 #       define R128_DEFAULT_SC_BOTTOM_MAX (0x1fff << 16)
 #define R128_DESTINATION_3D_CLR_CMP_VAL   0x1820
@@ -670,6 +716,7 @@
 #define R128_HOST_DATA_LAST               0x17e0
 #define R128_HOST_PATH_CNTL               0x0130
 #define R128_HTOTAL_CNTL                  0x0009 /* PLL */
+#define R128_HTOTAL2_CNTL                 0x002e /* PLL */
 #define R128_HW_DEBUG                     0x0128
 #define R128_HW_DEBUG2                    0x011c
 
@@ -875,6 +922,19 @@
 #       define R128_PPLL_REF_DIV_MASK     0x03ff
 #       define R128_PPLL_ATOMIC_UPDATE_R  (1 << 15) /* same as _W */
 #       define R128_PPLL_ATOMIC_UPDATE_W  (1 << 15) /* same as _R */
+#define R128_P2PLL_CNTL                    0x002a /* P2PLL */
+#       define R128_P2PLL_RESET               (1 <<  0)
+#       define R128_P2PLL_SLEEP               (1 <<  1)
+#       define R128_P2PLL_ATOMIC_UPDATE_EN    (1 << 16)
+#       define R128_P2PLL_VGA_ATOMIC_UPDATE_EN (1 << 17)
+#       define R128_P2PLL_ATOMIC_UPDATE_VSYNC  (1 << 18)
+#define R128_P2PLL_DIV_0                   0x002c
+#       define R128_P2PLL_FB0_DIV_MASK     0x07ff
+#       define R128_P2PLL_POST0_DIV_MASK   0x00070000
+#define R128_P2PLL_REF_DIV                 0x002B /* PLL */
+#       define R128_P2PLL_REF_DIV_MASK     0x03ff
+#       define R128_P2PLL_ATOMIC_UPDATE_R  (1 << 15) /* same as _W */
+#       define R128_P2PLL_ATOMIC_UPDATE_W  (1 << 15) /* same as _R */
 #define R128_PWR_MNGMT_CNTL_STATUS        0x0f60 /* PCI */
 #define R128_REG_BASE                     0x0f18 /* PCI */
 #define R128_REGPROG_INF                  0x0f09 /* PCI */
@@ -935,7 +995,14 @@
 #define R128_TRAIL_X_SUB                  0x1620
 
 #define R128_VCLK_ECP_CNTL                0x0008 /* PLL */
+#       define R128_VCLK_SRC_SEL_MASK     0x03
+#       define R128_VCLK_SRC_SEL_CPUCLK   0x00
+#       define R128_VCLK_SRC_SEL_PPLLCLK  0x03
 #       define R128_ECP_DIV_MASK          (3 << 8)
+#define R128_V2CLK_VCLKTV_CNTL            0x002d /* PLL */
+#       define R128_V2CLK_SRC_SEL_MASK    0x03
+#       define R128_V2CLK_SRC_SEL_CPUCLK  0x00
+#       define R128_V2CLK_SRC_SEL_P2PLLCLK 0x03
 #define R128_VENDOR_ID                    0x0f00 /* PCI */
 #define R128_VGA_DDA_CONFIG               0x02e8
 #define R128_VGA_DDA_ON_OFF               0x02ec