[Patches] attempted dualhead support for r128

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



THESE PATCHES COULD FRY YOUR CARD
THESE PATCHES COULD FRY YOUR CARD
THESE PATCHES COULD FRY YOUR CARD
I do not have a r128.  I don't even know if these will compile.  Please 
do NOT try them on your card until someone with r128 documentation looks 
them over.

The attached patches provide an attempt at support for dualhead on the 
r128.  They are based on the radeon driver.  I did not however have 
access to any documentation, so much of what was done was based on 
guesses and cross references from the radeon driver.  THESE ARE NOT 
FUNCTIONAL YET.  Dualhead does not appear to work quite the same on the 
r128 as it does on the radeon.  These patches lay out the basic frame 
work.  someone with r128 docs will probably have to fix the register 
poking since I merely guessed for most of that.  Also I'm not sure which 
r128 models support dualhead, so only I enabled it on the mobility 
series since those are the only ones I've seen with dual-head 
capabilities.  These files are diffed against the Xfree 4.2.0 r128 source.

enjoy,

Alex

once again,
THESE PATCHES COULD FRY YOUR CARD

p.s.: CC me on any responses since I'm not subscribed to xpert or dri-devel
--- old/r128.h	Tue Oct  2 15:44:01 2001
+++ new/r128.h	Sat Sep  7 11:26:19 2002
@@ -135,6 +135,17 @@
 				/* CRTC2 registers */
     CARD32     crtc2_gen_cntl;
 
+/* added for dual head */
+    CARD32     dac2_cntl;
+    CARD32     disp_output_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;
     CARD32     fp_crtc_v_total_disp;
@@ -206,6 +217,16 @@
     unsigned long     FbMapSize;    /* Size of frame buffer, in bytes        */
     int               Flags;        /* Saved copy of mode flags              */
 
+    /****** Added for VE/M6 support *******************/
+    RADEONMonitorType DisplayType;  /* Monitor connected on*/
+    RADEONDDCType     DDCType;
+    RADEONConnectorType ConnectorType;
+    BOOL              HasCRTC2;     /* VE/M6/M7 - which ones on R128?*/
+    BOOL              IsSecondary;  /* second Screen */
+    BOOL              UseCRT;       /* force use CRT port as primary */
+    BOOL              SwitchingMode;
+
+
     CARD8             BIOSDisplay;  /* Device the BIOS is set to display to  */
 
     Bool              HasPanelRegs; /* Current chip can connect to a FP      */
--- old/r128_accel.c	Tue Oct  2 15:44:01 2001
+++ new/r128_accel.c	Sat Sep  7 18:55:48 2002
@@ -1540,6 +1540,22 @@
     a->DashedLineFlags                 = (LINE_PATTERN_LSBFIRST_LSBJUSTIFIED
 					  | LINE_PATTERN_POWER_OF_2_ONLY);
 
+/* not sure if this is needed or not */
+    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;
+    }
+
 				/* ImageWrite */
     a->NumScanlineImageWriteBuffers    = 1;
     a->ScanlineImageWriteBuffers       = info->scratch_buffer;
@@ -1554,6 +1570,7 @@
 					  | LEFT_EDGE_CLIPPING
 					  | LEFT_EDGE_CLIPPING_NEGATIVE_X
 					  | SCANLINE_PAD_DWORD;
+
 }
 
 /* Initialize XAA for supported acceleration and also initialize the
--- old/r128_cursor.c	Sat Mar  3 17:26:09 2001
+++ new/r128_cursor.c	Sat Sep  7 18:48:36 2002
@@ -66,14 +66,30 @@
 #endif
 
 
+/************************************************
+
+All of the functions in here are probably broken since I don't have the docs.
+
+*************************************************/
+
+
+
 /* Set cursor foreground and background colors. */
 static void R128SetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
 {
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
-
+    if(info->IsSecondary)
+    {
+    /* what goes here? */
+    OUTREG(R128_CUR_CLR0, bg);
+    OUTREG(R128_CUR_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 +110,23 @@
     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
-				     | ((xorigin ? 0 : x) << 16)
-				     | (yorigin ? 0 : y)));
-    OUTREG(R128_CUR_OFFSET,         info->cursor_start + yorigin * 16);
+    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);
+        }
+        else
+        {
+    	/* what goes here? */
+    	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);
+        }
 }
 
 /* Copy cursor image from `image' to video memory.  R128SetCursorPosition
@@ -112,8 +140,17 @@
     int           y;
     CARD32        save;
 
+    if(!info->IsSecondary)
+    {
     save = INREG(R128_CRTC_GEN_CNTL);
     OUTREG(R128_CRTC_GEN_CNTL, save & (CARD32)~R128_CRTC_CUR_EN);
+    }
+    else
+    { 
+	/* what goes here? */
+        save = INREG(R128_CRTC2_GEN_CNTL);
+        OUTREG(R128_CRTC2_GEN_CNTL, save & (CARD32)~R128_CRTC_CUR_EN);
+    }
 
 #if X_BYTE_ORDER == X_BIG_ENDIAN
     switch(info->CurrentLayout.pixel_bytes) {
@@ -168,8 +205,10 @@
 	*d++ = 0x00000000;
     }
 
-
+    if(!info->IsSecondary)
     OUTREG(R128_CRTC_GEN_CNTL, save);
+    else
+        OUTREG(R128_CRTC2_GEN_CNTL, save);
 }
 
 /* Hide hardware cursor. */
@@ -177,7 +216,9 @@
 {
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
-
+     if(info->IsSecondary)
+        OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC_CUR_EN);
+     else
     OUTREGP(R128_CRTC_GEN_CNTL, 0, ~R128_CRTC_CUR_EN);
 }
 
@@ -187,7 +228,15 @@
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
 
+    if(info->IsSecondary)
+    {
+         OUTREGP(R128_CRTC2_GEN_CNTL, R128_CRTC_CUR_EN,
+               ~R128_CRTC_CUR_EN);
+    }
+    else
+    {
     OUTREGP(R128_CRTC_GEN_CNTL, R128_CRTC_CUR_EN, ~R128_CRTC_CUR_EN);
+    }
 }
 
 /* Determine if hardware cursor is in use. */
--- old/r128_driver.c	Fri Jan  4 16:22:26 2002
+++ new/r128_driver.c	Sat Sep  7 15:46:04 2002
@@ -468,10 +468,17 @@
 {
     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) /* for DH */
+    {
+    	if(info->isDFP)
+        	OUTREGP(R128_FP_GEN_CNTL, R128_FP_BLANK_DIS, ~R128_FP_BLANK_DIS);
+    	else
+        	OUTREGP(R128_CRTC_EXT_CNTL, R128_CRTC_DISPLAY_DIS, ~R128_CRTC_DISPLAY_DIS);
     else
-        OUTREGP(R128_CRTC_EXT_CNTL, R128_CRTC_DISPLAY_DIS, ~R128_CRTC_DISPLAY_DIS);
+    {
+		/* not sure what's needed here - no docs! this is a guess on my part */
+        	OUTREGP(R128_CRTC2_GEN_CNT, R128_CRTC_DISPLAY_DIS, ~R128_CRTC_DISPLAY_DIS);
+    }
 }
 
 /* Unblank screen. */
@@ -480,10 +487,18 @@
     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)
+    {
+	    if(info->isDFP)
+	        OUTREGP(R128_FP_GEN_CNTL, 0, ~R128_FP_BLANK_DIS);
+	    else
+	        OUTREGP(R128_CRTC_EXT_CNTL, 0, ~R128_CRTC_DISPLAY_DIS);
+    }
     else
-        OUTREGP(R128_CRTC_EXT_CNTL, 0, ~R128_CRTC_DISPLAY_DIS);
+    {
+	    /* not sure what's needed here - no docs! this is a guess on my part */
+	    OUTREGP(R128_CRTC2_GEN_CNTL, 0, ~R128_CRTC_DISPLAY_DIS);
+    }
 }
 
 /* Compute log base 2 of val. */
@@ -623,6 +638,17 @@
 		              Disabling programming of FP registers.\n");
     }
 
+/*  stuff might need to be added to r128.h to deal with this function...
+
+Not even sure what's needed, if anything 
+I guess secondary display would be crt in all cases
+    if(info->HasCRTC2) { }
+       
+         xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s Display == Type %d\n",
+              (info->IsSecondary ? "Secondary" : "Primary"), 
+               info->DisplayType);
+*/
+
     return TRUE;
 }
 
@@ -894,10 +920,13 @@
     } 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.
           M3 can also have DFP, no support for now */	
+
+	/* not sure which have support for dual head */
 	case PCI_CHIP_RAGE128TF: 
 	case PCI_CHIP_RAGE128TL:
 	case PCI_CHIP_RAGE128TR: info->isPro2 = TRUE; 
@@ -909,7 +938,7 @@
 	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; info->HasCRTC2 = TRUE; break;
 	case PCI_CHIP_RAGE128RE:
 	case PCI_CHIP_RAGE128RF:
 	case PCI_CHIP_RAGE128RG:
@@ -967,6 +996,24 @@
     R128MMIO                  = NULL;
     R128UnmapMMIO(pScrn);
 
+    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;
+    }
+
+
 				/* RAM */
     switch (info->MemCntl & 0x3) {
     case 0:                     /* SDR SGRAM 1:1 */
@@ -1777,10 +1824,43 @@
     if (!R128GetRec(pScrn)) return FALSE;
 
     info               = R128PTR(pScrn);
-
+    info->IsSecondary  = FALSE;
     info->pEnt         = xf86GetEntityInfo(pScrn->entityList[0]);
     if (info->pEnt->location.type != BUS_PCI) goto fail;
 
+    R128PreInt10Save(pScrn, &save1, &save2); /* does R128 have this function? */
+
+    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], 
+                    gRADEONEntityIndex);
+            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;
@@ -1913,9 +1993,16 @@
     R128InfoPtr   info      = R128PTR(pScrn);
     unsigned char *R128MMIO = info->MMIO;
     int           i;
-    int           idx;
+    int           idx, j;
     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); /* PAL_SELECT() probably needs to be updated to work here */
+
     /* Select palette 0 (main CRTC) if using FP-enabled chip */
     if (info->HasPanelRegs || info->isDFP) PAL_SELECT(0);
 
@@ -2046,9 +2133,38 @@
 		       (pScrn->displayWidth * pScrn->virtualY *
 			info->CurrentLayout.pixel_bytes * 3 + 1023) / 1024);
 	    info->directRenderingEnabled = FALSE;
-	} else {
-	    info->directRenderingEnabled = R128DRIScreenInit(pScreen);
+	} 
+
+	else {
+            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
 
@@ -2482,6 +2598,35 @@
     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;
+
+/* this function probably needs lots of work...someone with docs...I just guessed */
+
+/*    OUTREG(RADEON_CRTC2_GEN_CNTL,  restore->crtc2_gen_cntl);*/
+    OUTREGP(R128_CRTC2_GEN_CNTL, restore->crtc2_gen_cntl,
+	    RADEON_CRTC2_VSYNC_DIS |
+	    RADEON_CRTC2_HSYNC_DIS |
+	    RADEON_CRTC2_DISP_DIS);
+
+    OUTREG(R128_DAC_CRT_SEL_CRTC2, R128_DAC_CNTL, restore->dac2_cntl);
+/*    OUTREG(RADEON_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)
 {
@@ -2579,6 +2724,53 @@
 	       (restore->ppll_div_3 & R128_PPLL_POST3_DIV_MASK) >> 16));
 }
 
+/* Write PLL2 registers. This function is also broken I just copied it from the PLL function*/
+static void R128RestorePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr restore)
+{
+    R128InfoPtr   info      = R128PTR(pScrn);
+    unsigned char *R128MMIO = info->MMIO;
+
+    OUTREGP(R128_CLOCK_CNTL_INDEX, R128_PLL_DIV_SEL, 0xffff);
+
+    OUTPLLP(pScrn,
+	    R128_PPLL_CNTL,
+	    R128_PPLL_RESET
+	    | R128_PPLL_ATOMIC_UPDATE_EN
+	    | R128_PPLL_VGA_ATOMIC_UPDATE_EN,
+	    0xffff);
+
+    R128PLLWaitForReadUpdateComplete(pScrn);
+    OUTPLLP(pScrn, R128_PPLL_REF_DIV,
+	    restore->p2pll_ref_div, ~R128_PPLL_REF_DIV_MASK);
+    R128PLLWriteUpdate(pScrn);
+
+    R128PLLWaitForReadUpdateComplete(pScrn);
+    OUTPLLP(pScrn, R128_PPLL_DIV_0,
+	    restore->p2pll_div_0, ~R128_PPLL_FB3_DIV_MASK);
+    R128PLLWriteUpdate(pScrn);
+    OUTPLLP(pScrn, R128_PPLL_DIV_0,
+	    restore->p2pll_div_0, ~R128_PPLL_POST3_DIV_MASK);
+    R128PLLWriteUpdate(pScrn);
+
+    R128PLLWaitForReadUpdateComplete(pScrn);
+    OUTPLL(R128_HTOTAL_CNTL, restore->htotal_cntl2);
+    R128PLLWriteUpdate(pScrn);
+
+    OUTPLLP(pScrn, R128_PPLL_CNTL, 0, ~R128_PPLL_RESET);
+
+    R128TRACE(("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
+	       restore->p2pll_ref_div,
+	       restore->ppll_div_0,
+	       restore->htotal_cntl2,
+	       INPLL(pScrn, R128_PPLL_CNTL)));
+    R128TRACE(("Wrote: rd=%d, fd=%d, pd=%d\n",
+	       restore->p2pll_ref_div & R128_PPLL_REF_DIV_MASK,
+	       restore->ppll_div_0 & R128_PPLL_FB3_DIV_MASK,
+	       (restore->ppll_div_0 & R128_PPLL_POST3_DIV_MASK) >> 16));
+}
+
+
+
 /* Write DDA registers. */
 static void R128RestoreDDARegisters(ScrnInfoPtr pScrn, R128SavePtr restore)
 {
@@ -2606,21 +2798,83 @@
 }
 
 /* Write out state to define a new video mode.  */
+/* this needs work too I suspect... */
 static void R128RestoreMode(ScrnInfoPtr pScrn, R128SavePtr restore)
 {
-    R128InfoPtr info = R128PTR(pScrn);
+    if(!info->HasCRTC2)
+    {
+    	R128InfoPtr info = R128PTR(pScrn);
+
+    	R128TRACE(("R128RestoreMode(%p)\n", restore));
+    	R128RestoreCommonRegisters(pScrn, restore);
+    	R128RestoreCrtcRegisters(pScrn, restore);
+    	if (!(info->HasPanelRegs) || info->BIOSDisplay == R128_BIOS_DISPLAY_CRT){
+    	    R128RestorePLLRegisters(pScrn, restore);
+    	}
+    	R128RestoreDDARegisters(pScrn, restore);
+    	if (info->HasPanelRegs || info->isDFP)
+        	R128RestoreFPRegisters(pScrn, restore);
+
+    	R128RestorePalette(pScrn, restore);
+    }
+
+    /*****
+      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)
+    {
+        R128RestoreCrtc2Registers(pScrn, restore);        
+        R128RestorePLL2Registers(pScrn, restore);
+        
+        if(!info->SwitchingMode)
+        pR128Ent->IsSecondaryRestored = TRUE;
+
+        if(pR128Ent->RestorePrimary)
+        {
+            R128InfoPtr info0 = R128PTR(pR128Ent->pPrimaryScrn); 
+            pR128Ent->RestorePrimary = FALSE;
 
-    R128TRACE(("R128RestoreMode(%p)\n", restore));
-    R128RestoreCommonRegisters(pScrn, restore);
-    R128RestoreCrtcRegisters(pScrn, restore);
-    if (!(info->HasPanelRegs) || info->BIOSDisplay == R128_BIOS_DISPLAY_CRT){
-        R128RestorePLLRegisters(pScrn, restore);
+            R128RestoreCrtcRegisters(pScrn, &restore0);
+            if((info0->HasPanelRegs)
+            {
+                R128RestoreFPRegisters(pScrn, &restore0);
+            }
+            
+            R128RestorePLLRegisters(pScrn, &restore0);   
+            pR128Ent->IsSecondaryRestored = FALSE;
+
+        }
     }
-    R128RestoreDDARegisters(pScrn, restore);
-    if (info->HasPanelRegs || info->isDFP)
-        R128RestoreFPRegisters(pScrn, restore);
+    else
+    {
+        R128RestoreCommonRegisters(pScrn, restore);
+        R128RestoreDDARegisters(pScrn, restore);
+        if(!pR128Ent->HasSecondary || pR128Ent->IsSecondaryRestored
+            || info->SwitchingMode)
+        {
+	    pR128Ent->IsSecondaryRestored = FALSE;
+            R128RestoreCrtcRegisters(pScrn, restore);
+            if((info->HasPanelRegs)
+            {
+               R128RestoreFPRegisters(pScrn, restore);
+            }
+            R128RestorePLLRegisters(pScrn, restore);   
+        }
+        else
+        {
+            memcpy(&restore0, restore, sizeof(restore0));
+            pR128Ent->RestorePrimary = TRUE;
+        }
+    }
+
 
-    R128RestorePalette(pScrn, restore);
 }
 
 /* Read common registers. */
@@ -2663,6 +2917,26 @@
     save->crtc_pitch           = INREG(R128_CRTC_PITCH);
 }
 
+/* Read CRTC2 registers. */
+/* may be wrong...no docs. */
+static void R128SaveCrtc2Registers(ScrnInfoPtr pScrn, R128SavePtr save)
+{
+    R128InfoPtr   info      = R128PTR(pScrn);
+    unsigned char *R128MMIO = info->MMIO;
+
+    save->crtc2_gen_cntl        = INREG(R128_CRTC2_GEN_CNTL);
+    save->crtc_ext_cntl        = INREG(R128_CRTC_EXT_CNTL);
+    save->dac_cntl             = INREG(R128_DAC_CNTL);
+    save->crtc2_h_total_disp    = INREG(R128_CRTC_H_TOTAL_DISP);
+    save->crtc2_h_sync_strt_wid = INREG(R128_CRTC_H_SYNC_STRT_WID);
+    save->crtc2_v_total_disp    = INREG(R128_CRTC_V_TOTAL_DISP);
+    save->crtc2_v_sync_strt_wid = INREG(R128_CRTC_V_SYNC_STRT_WID);
+    save->crtc2_offset          = INREG(R128_CRTC_OFFSET);
+    save->crtc2_offset_cntl     = INREG(R128_CRTC_OFFSET_CNTL);
+    save->crtc2_pitch           = INREG(R128_CRTC_PITCH);
+}
+
+
 /* Read flat panel registers */
 static void R128SaveFPRegisters(ScrnInfoPtr pScrn, R128SavePtr save)
 {
@@ -2700,6 +2974,25 @@
 	       (save->ppll_div_3 & R128_PPLL_POST3_DIV_MASK) >> 16));
 }
 
+/* Read PLL2 registers. */
+/* needs work too */
+static void R128SavePLL2Registers(ScrnInfoPtr pScrn, R128SavePtr save)
+{
+    save->p2pll_ref_div         = INPLL(pScrn, R128_PPLL_REF_DIV);
+    save->ppll_div_0           = INPLL(pScrn, R128_PPLL_DIV_0);
+    save->htotal_cntl2          = INPLL(pScrn, R128_HTOTAL_CNTL);
+
+    R128TRACE(("Read: 0x%08x 0x%08x 0x%08x\n",
+	       save->ppll_ref_div,
+	       save->ppll_div_0,
+	       save->htotal_cntl));
+    R128TRACE(("Read: rd=%d, fd=%d, pd=%d\n",
+	       save->ppll_ref_div & R128_PPLL_REF_DIV_MASK,
+	       save->ppll_div_0 & R128_PPLL_FB3_DIV_MASK,
+	       (save->ppll_div_0 & R128_PPLL_POST3_DIV_MASK) >> 16));
+}
+
+
 /* Read DDA registers. */
 static void R128SaveDDARegisters(ScrnInfoPtr pScrn, R128SavePtr save)
 {
@@ -2730,15 +3023,23 @@
 {
     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);
+    }
+    else
+    {
+    	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);
+    }
     R128TRACE(("R128SaveMode returns %p\n", save));
+
 }
 
 /* Save everything needed to restore the original VC state. */
@@ -2754,9 +3055,12 @@
 	fbdevHWSave(pScrn);
 	return;
     }
+    if(!info->IsSecondary)
+    {
     vgaHWUnlock(hwp);
     vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_ALL); /* save mode, fonts, cmap */
     vgaHWLock(hwp);
+    }
 
     R128SaveMode(pScrn, save);
 
@@ -2789,9 +3093,27 @@
     OUTREG(R128_DP_DATATYPE,      restore->dp_datatype);
 
     R128RestoreMode(pScrn, restore);
+
+    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);
@@ -2952,6 +3274,141 @@
     return TRUE;
 }
 
+
+/* Define CRTC2 registers for requested video mode. */
+/* needs work */
+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 };
+    int    hsync_fudge_fp[]      = { 0x12, 0x11, 0x09, 0x09, 0x05, 0x05 };
+    int    hsync_fudge_fp_crt[]  = { 0x12, 0x10, 0x08, 0x08, 0x04, 0x04 };
+
+    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));
+
+    switch (info->BIOSDisplay) {
+    case R128_BIOS_DISPLAY_FP:
+	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;
+    }
+
+    save->crtc2_gen_cntl = (R128_CRTC_EXT_DISP_EN
+			  | R128_CRTC_EN
+			  | (format << 8)
+			  | ((mode->Flags & V_DBLSCAN)
+			     ? R128_CRTC_DBL_SCAN_EN
+			     : 0)
+			  | ((mode->Flags & V_INTERLACE)
+			     ? R128_CRTC_INTERLACE_EN
+			     : 0)
+			  | ((mode->Flags & V_CSYNC)
+			     ? R128_CRTC_CSYNC_EN
+			     : 0));
+
+    save->crtc_ext_cntl = R128_VGA_ATI_LINEAR | R128_XCRT_CNT_EN;
+    save->dac_cntl      = (R128_DAC_MASK_ALL
+			   | R128_DAC_VGA_ADR_EN
+			   | (info->dac6bits ? 0 : R128_DAC_8BIT_EN));
+
+
+    if(info->isDFP && !info->isPro2)
+    {
+        if(info->PanelXRes < mode->CrtcHDisplay)
+            mode->HDisplay = mode->CrtcHDisplay = info->PanelXRes;
+        if(info->PanelYRes < mode->CrtcVDisplay)
+            mode->VDisplay = mode->CrtcVDisplay = info->PanelYRes;
+        mode->CrtcHTotal = mode->CrtcHDisplay + info->HBlank;
+        mode->CrtcHSyncStart = mode->CrtcHDisplay + info->HOverPlus;
+        mode->CrtcHSyncEnd = mode->CrtcHSyncStart + info->HSyncWidth;
+        mode->CrtcVTotal = mode->CrtcVDisplay + info->VBlank;
+        mode->CrtcVSyncStart = mode->CrtcVDisplay + info->VOverPlus;
+        mode->CrtcVSyncEnd = mode->CrtcVSyncStart + info->VSyncWidth;
+    }
+
+    save->crtc2_h_total_disp = ((((mode->CrtcHTotal / 8) - 1) & 0xffff)
+			      | (((mode->CrtcHDisplay / 8) - 1) << 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 & 0xfff)
+				 | (hsync_wid << 16)
+				 | ((mode->Flags & V_NHSYNC)
+				    ? R128_CRTC_H_SYNC_POL
+				    : 0));
+
+#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_CRTC_V_SYNC_POL
+				    : 0));
+    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->crtc_pitch, pScrn->virtualX, info->CurrentLayout.displayWidth));
+
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+    /* Change the endianness of the aperture */
+    switch (info->CurrentLayout.pixel_code) {
+    case 15:
+    case 16: save->config_cntl |= APER_0_BIG_ENDIAN_16BPP_SWAP; break;
+    case 32: save->config_cntl |= APER_0_BIG_ENDIAN_32BPP_SWAP; break;
+    default: break;
+    }
+#endif
+
+    return TRUE;
+}
+
+
 /* Define CRTC registers for requested video mode. */
 static void R128InitFPRegisters(R128SavePtr orig, R128SavePtr save,
 				DisplayModePtr mode, R128InfoPtr info)
@@ -3023,14 +3480,16 @@
        want to use the dual CRTC capabilities of the R128 to allow both
        the flat panel and external CRT to either simultaneously display
        the same image or display two different images. */
+
+/* something needs to be done here, I suspect, so that dual head is enabled properly */
     
     if(!info->isDFP){
         if (info->BIOSDisplay == R128_BIOS_DISPLAY_FP_CRT) {
 	        save->crtc_ext_cntl  |= R128_CRTC_CRT_ON;
         } else {
-	        save->crtc_ext_cntl  &= ~R128_CRTC_CRT_ON;
+	        save->crtc_ext_cntl  &= R128_CRTC_CRT_ON;
 	        save->dac_cntl       |= R128_DAC_CRT_SEL_CRTC2;
-	        save->crtc2_gen_cntl  = 0;
+	        save->crtc2_gen_cntl  = 1; 
         }
     }
 
@@ -3112,6 +3571,59 @@
 
 }
 
+
+/* Define PLL2 registers for requested video mode. */
+static void R128InitPLL2Registers(ScrnInfoPtr pScrn, 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               */
+				/* bitvalue = 5 is reserved */
+	{  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 = freq;
+    save->feedback_div   = R128Div(pll->reference_div * save->pll_output_freq,
+				   pll->reference_freq);
+    save->post_div       = 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->ppll_div_0     = (save->feedback_div | (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, 
@@ -3246,6 +3758,15 @@
 
     info->Flags = mode->Flags;
 
+    if(info->IsSecondary)
+    {
+        if (!R128InitCrtc2Registers(pScrn, save, 
+             pScrn->currentMode,info)) 
+            return FALSE;
+        R128InitPLL2Registers(save, &info->pll, dot_clock);
+    }
+    else
+    {
     R128InitCommonRegisters(save, info);
     if (!R128InitCrtcRegisters(pScrn, save, mode, info)) return FALSE;
     if (info->HasPanelRegs || info->isDFP)
@@ -3262,6 +3783,7 @@
         save->dda_config           = info->SavedReg.dda_config;
         save->dda_on_off           = info->SavedReg.dda_on_off;
     }
+    }
 
     R128TRACE(("R128Init returns %p\n", save));
     return TRUE;
@@ -3304,7 +3826,18 @@
 
 Bool R128SwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
 {
+    ScrnInfoPtr   pScrn       = xf86Screens[scrnIndex];
+    R128InfoPtr info        = R128PTR(pScrn);
+
+    /* 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;
     return R128ModeInit(xf86Screens[scrnIndex], mode);
+    info->SwitchingMode = FALSE;
 }
 
 /* Used to disallow modes that are not supported by the hardware. */
@@ -3394,7 +3927,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);
 }
 
--- old/r128_probe.c	Mon Nov  5 18:37:50 2001
+++ new/r128_probe.c	Sat Sep  7 11:27:30 2002
@@ -231,12 +231,53 @@
 
 	    foundScreen          = TRUE;
 
+        pEnt = xf86GetEntityInfo(usedChips[i]);
+
+        /* VE/M6 card support Dual-Head, mark the entity as sharable*/
+	/* not sure which r128 cards are dual-head capable, so I chose just the mobilities*/
+        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);
+    }
+
+/* not sure if this is needed 
 	    xf86ConfigActivePciEntity(pScrn, usedChips[i], R128PciChipsets,
 				      0, 0, 0, 0, 0);
 	}
 	xfree(pEnt);
     }
 
+*/
+
     xfree(usedChips);
     xfree(devSections);
 
--- old/r128_reg.h	Tue Oct  2 07:44:16 2001
+++ new/r128_reg.h	Sat Sep  7 14:54:01 2002
@@ -114,6 +114,8 @@
 
 #define INPAL_NEXT() INREG(R128_PALETTE_DATA)
 
+/* does PAL_SELECT need to be changed for dual-head? */
+
 #define PAL_SELECT(idx)                                                   \
     do {                                                                  \
 	CARD32 tmp = INREG(R128_DAC_CNTL);                                \
@@ -382,6 +384,9 @@
 #define R128_CRTC2_V_SYNC_STRT_WID        0x030c
 #define R128_CRTC2_V_TOTAL_DISP           0x0308
 #define R128_CRTC2_VLINE_CRNT_VLINE       0x0310
+
+/* are there some missing CRTC2 regs or is it just different from RADEON? */
+
 #define R128_CRTC8_DATA                   0x03d5 /* VGA, 0x3b5 */
 #define R128_CRTC8_IDX                    0x03d4 /* VGA, 0x3b4 */
 #define R128_CUR_CLR0                     0x026c

[Red Hat General]     [Red Hat Watch]     [Red Hat Development]     [Kernel Development]     [Yosemite Camping]

  Powered by Linux