[PATCH] Radeon driver fixes #3

Benjamin Herrenschmidt benh at kernel.crashing.org
Sun Nov 14 20:26:03 PST 2004


Hi !

Here's a new version of my patch. Changes since the previous one are

 - Fix various bugs in RADEONProbePLLParameters() and made it overall more robust.
I'm now probing my PLL parameters on my 3 test machines 100% of the time properly.
This might fix issues with bandwidth calculation

 - Fix a bug in UpdatePanelSize where it could access the detailed DDC timings array
beyond it's limits. I don't fully understand why the code parsing the VESA modes
would try to get the "Flags" from the detailed timings and the code parsing the
detailed timings wouldn't try to get the "Flags" ... This is both fixed now and
it might fix some sync polarity issues with some panels

 - RADEONUpdatePanelSize() is no longer called from RADEONValidateDDCModes() as
suggested by Hui, but instead directly from GetPanelInfo() for MT_DFP and
GetLVDSInfo() for MT_LCD.
However, I still keep the call to RADEONValidateDDCModes() even when UseBIOSDividers
is true, it should be totally harmless now that we get the panel info, the mode data
will not be used for anything but information purpose and/or allowing RMX modes, which
is fine.

 - LVDSProbePLL() is now TRUE by default, thus we do probe the current PLL value
for an LVDS panel by default in absence of a BIOS provided value provided that
PPLL_DIV_n is not equal to the "default" value (0x1bb). This need some testing on
x86 especially but should help on PPC.

 - Fix definition of RADEON_IO_MCLK_DYN_ENABLE to the value in the doc, it was
obviously a typo.

Changes already in the previous one are:

 - Fix once for all the SURFACE_CNTL issues (endian swapper access) by
properly setting the value for the second head. The code got broken by
the new cursor code which would restore the value on both heads, and
thus end up with broken swapper setting whenever the cursor was moved
to head 2

 - Add NoVGA, ReverseDDC and LVDSProbePLL options, see man page for
details.

 - Fix a crasher in RADEONValidateFPModes() where the link pointers
could be dereferenced when NULL under some circumstances

 - Add more stuff to the PLL probing code so it tries to get mclk/sclk
and properly sets the PLL min/max to reasonable defaults (that was missing,
thus breaking CRT mode validation). The code still tend to fail to measure
xtal when the machine isn't perfectly idle, it should be made more robust
by measuring a longer timer and retrying a few times ...


diff -urN xc.orig/programs/Xserver/hw/xfree86/drivers/ati/radeon.h xc/programs/Xserver/hw/xfree86/drivers/ati/radeon.h
--- xc.orig/programs/Xserver/hw/xfree86/drivers/ati/radeon.h	2004-10-04 11:25:21.000000000 +1000
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/radeon.h	2004-11-15 13:48:06.000000000 +1100
@@ -615,6 +615,7 @@
     Bool		AtLeastOneNonClone;
     int			MergedFBXDPI, MergedFBYDPI;
     Bool		NoVirtual;
+    Bool		VGAAccess;
 
     /* special handlings for DELL triple-head server */
     Bool		IsDellServer; 
diff -urN xc.orig/programs/Xserver/hw/xfree86/drivers/ati/radeon.man xc/programs/Xserver/hw/xfree86/drivers/ati/radeon.man
--- xc.orig/programs/Xserver/hw/xfree86/drivers/ati/radeon.man	2004-11-11 11:56:59.000000000 +1100
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/radeon.man	2004-11-15 15:13:10.000000000 +1100
@@ -496,6 +496,34 @@
 with this enabled.  The default is
 .B off.
 .TP
+.BI "Option \*qVGAAccess\*q \*q" boolean \*q
+Tell the driver if it can do legacy VGA IOs to the card. This is
+necessary for properly resuming consoles when in VGA text mode, but
+shouldn't be if the console is using radeonfb or some other graphic
+mode driver. Some platforms like PowerPC have issues with those, and they aren't
+necessary unless you have a real text mode in console. The default is
+.B off 
+on PowerPC and
+.B on 
+on other architectures.
+.TP
+.BI "Option \*qLVDSProbePLL\*q \*q" boolean \*q
+When BIOS panel informations aren't available (like on PowerBooks), it
+may still be necessary to use the firmware provided PLL values for the
+panel or flickering will happen. This option will force probing of
+the current value programmed in the chip when X is launched in that
+case.  This is only useful for LVDS panels (laptop internal panels).
+The default is
+.B on.
+.TP
+.BI "Option \*qReverseDDC\*q \*q" boolean \*q
+When BIOS connector informations aren't available, use this option to
+reverse the mapping of the 2 main DDC ports. Use this if the X serve
+obviously detects the wrong display for each connector. This is
+typically needed on the Radeon 9600 cards bundled with Apple G5s. The
+default is
+.B off.
+.TP
 
 .SH SEE ALSO
 __xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), xorgconfig(__appmansuffix__), Xserver(__appmansuffix__), X(__miscmansuffix__)
diff -urN xc.orig/programs/Xserver/hw/xfree86/drivers/ati/radeon_accel.c xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_accel.c
--- xc.orig/programs/Xserver/hw/xfree86/drivers/ati/radeon_accel.c	2004-08-12 15:00:22.000000000 +1000
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_accel.c	2004-11-12 11:12:00.000000000 +1100
@@ -291,10 +291,8 @@
     OUTREGP(RADEON_DP_DATATYPE, 0, ~RADEON_HOST_BIG_ENDIAN_EN);
 #endif
 
-    /* Restore SURFACE_CNTL - only the first head contains valid data -ReneR */
-    if (!info->IsSecondary) {
-	OUTREG(RADEON_SURFACE_CNTL, info->ModeReg.surface_cntl);
-    }
+    /* Restore SURFACE_CNTL */
+    OUTREG(RADEON_SURFACE_CNTL, info->ModeReg.surface_cntl);
 
     RADEONWaitForFifo(pScrn, 1);
     OUTREG(RADEON_DEFAULT_SC_BOTTOM_RIGHT, (RADEON_DEFAULT_SC_RIGHT_MAX
diff -urN xc.orig/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c
--- xc.orig/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c	2004-11-11 11:56:59.000000000 +1100
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c	2004-11-15 14:53:11.000000000 +1100
@@ -118,6 +118,7 @@
 static void RADEONGetMergedFBOptions(ScrnInfoPtr pScrn);
 static int RADEONValidateMergeModes(ScrnInfoPtr pScrn);
 static void RADEONSetDynamicClock(ScrnInfoPtr pScrn, int mode);
+static void RADEONUpdatePanelSize(ScrnInfoPtr pScrn);
 
 /* psuedo xinerama support */
 
@@ -171,7 +172,10 @@
     OPTION_SUBPIXEL_ORDER,
 #endif
     OPTION_SHOWCACHE,
-    OPTION_DYNAMIC_CLOCKS
+    OPTION_DYNAMIC_CLOCKS,
+    OPTION_VGA_ACCESS,
+    OPTION_LVDS_PROBE_PLL,
+    OPTION_REVERSE_DDC,
 } RADEONOpts;
 
 static const OptionInfoRec RADEONOptions[] = {
@@ -223,6 +227,9 @@
 #endif
     { OPTION_SHOWCACHE,      "ShowCache",        OPTV_BOOLEAN, {0}, FALSE },
     { OPTION_DYNAMIC_CLOCKS, "DynamicClocks",    OPTV_BOOLEAN, {0}, FALSE },
+    { OPTION_VGA_ACCESS,     "VGAAccess",        OPTV_BOOLEAN, {0}, TRUE  },
+    { OPTION_LVDS_PROBE_PLL, "LVDSProbePLL",     OPTV_BOOLEAN, {0}, FALSE },
+    { OPTION_REVERSE_DDC,    "ReverseDDC",       OPTV_BOOLEAN, {0}, FALSE },
     { -1,                    NULL,               OPTV_NONE,    {0}, FALSE }
 };
 
@@ -891,7 +898,6 @@
 	return MT_NONE;
     }
 
-    /* Read and output monitor info using DDC2 over I2C bus */
     if (info->pI2CBus && info->ddc2) {
 	OUTREG(info->DDCReg, INREG(info->DDCReg) &
 	       (CARD32)~(RADEON_GPIO_A_0 | RADEON_GPIO_A_1));
@@ -1204,34 +1210,49 @@
     RADEONPLLPtr  pll  = &info->pll;
     unsigned char *RADEONMMIO = info->MMIO;
     unsigned char ppll_div_sel;
-    unsigned Nx, M;
+    unsigned mpll_fb_div, spll_fb_div, M;
     unsigned xclk, tmp, ref_div;
     int hTotal, vTotal, num, denom, m, n;
-    float hz, vclk, xtal;
+    float hz, prev_xtal, vclk, xtal, mpll, spll;
     long start_secs, start_usecs, stop_secs, stop_usecs, total_usecs;
-    int i;
-
-    for(i=0; i<1000000; i++)
-	if (((INREG(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0)
+    long to1_secs, to1_usecs, to2_secs, to2_usecs;
+    unsigned int f1, f2, f3;
+    int i, tries = 0;
+
+    prev_xtal = 0;
+ again:
+    xtal = 0;
+    if (++tries > 10)
+	    goto failed;
+
+    xf86getsecs(&to1_secs, &to2_usecs);
+    f1 = INREG(RADEON_CRTC_CRNT_FRAME);
+    for (;;) {
+	f2 = INREG(RADEON_CRTC_CRNT_FRAME);
+	if (f1 != f2)
 	    break;
-
+	xf86getsecs(&to2_secs, &to2_usecs);
+	if ((to2_secs - to1_secs) > 1) {
+	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Clock not counting...\n");
+	    goto failed;
+	}
+    }
     xf86getsecs(&start_secs, &start_usecs);
-
-    for(i=0; i<1000000; i++)
-	if (((INREG(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) != 0)
-	    break;
-
-    for(i=0; i<1000000; i++)
-	if (((INREG(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0)
+    for(;;) {
+	f3 = INREG(RADEON_CRTC_CRNT_FRAME);
+	if (f3 != f2)
 	    break;
-
+	xf86getsecs(&to2_secs, &to2_usecs);
+	if ((to2_secs - start_secs) > 1)
+	    goto failed;
+    }
     xf86getsecs(&stop_secs, &stop_usecs);
 
     total_usecs = abs(stop_usecs - start_usecs);
     hz = 1000000/total_usecs;
 
-    hTotal = ((INREG(RADEON_CRTC_H_TOTAL_DISP) & 0x1ff) + 1) * 8;
-    vTotal = ((INREG(RADEON_CRTC_V_TOTAL_DISP) & 0x3ff) + 1);
+    hTotal = ((INREG(RADEON_CRTC_H_TOTAL_DISP) & 0x3ff) + 1) * 8;
+    vTotal = ((INREG(RADEON_CRTC_V_TOTAL_DISP) & 0xfff) + 1);
     vclk = (float)(hTotal * (float)(vTotal * hz));
 
     switch((INPLL(pScrn, RADEON_PPLL_REF_DIV) & 0x30000) >> 16) {
@@ -1293,19 +1314,79 @@
     else if ((xtal > 29400000) && (xtal < 29600000))
         xtal = 2950;
     else
-	return FALSE;
+	goto again;
+ failed:
+    if (xtal == 0) {
+	xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Failed to probe xtal value ! Using default 27Mhz\n");
+	xtal = 2700;
+    } else {
+	if (prev_xtal == 0) {
+	    prev_xtal = xtal;
+	    tries = 0;
+	    goto again;
+	} else if (prev_xtal != xtal) {
+	    prev_xtal = 0;
+	    goto again;
+	}
+    }
 
     tmp = INPLL(pScrn, RADEON_X_MPLL_REF_FB_DIV);
     ref_div = INPLL(pScrn, RADEON_PPLL_REF_DIV) & 0x3ff;
 
-    Nx = (tmp & 0xff00) >> 8;
+    /* Calculate "base" xclk straight from MPLL, though that isn't
+     * really useful (hopefully)
+     */
+    mpll_fb_div = (tmp & 0xff00) >> 8;
+    spll_fb_div = (tmp & 0xff0000) >> 16;
     M = (tmp & 0xff);
-    xclk = RADEONDiv((2 * Nx * xtal), (2 * M));
+    xclk = RADEONDiv((2 * mpll_fb_div * xtal), (2 * M));
+
+    /*
+     * Calculate MCLK based on MCLK-A and SCLK
+     *
+     * NOTE: It is not clear at this point wether we should put in sclk and
+     * mclk the raw SPLL and MPLL output values, or the divided values according
+     * to the source selection iN MCLK_CNTL and SCLK_CNTL. I'm putting the divided
+     * values for now, waiting for a definitive answer from ATI
+     */
+    mpll = ((float)mpll_fb_div * (float)(xtal / 100.0)) / (float)M;
+    spll = ((float)spll_fb_div * (float)(xtal / 100.0)) / (float)M;
+
+    tmp = INPLL(pScrn, RADEON_MCLK_CNTL) & 0x7;
+    switch(tmp) {
+    case 1: info->mclk = mpll; break;
+    case 2: info->mclk = mpll / 2.0; break;
+    case 3: info->mclk = mpll / 4.0; break;
+    case 4: info->mclk = mpll / 8.0; break;
+    case 7: info->mclk = spll; break;
+    default:
+	    info->mclk = 200.00;
+	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unsupported MCLKA source"
+		       " setting %d, can't probe MCLK value !\n", tmp);
+    }
+
+    tmp = INPLL(pScrn, RADEON_SCLK_CNTL) & 0x7;
+    switch(tmp) {
+    case 1: info->sclk = spll; break;
+    case 2: info->sclk = spll / 2.0; break;
+    case 3: info->sclk = spll / 4.0; break;
+    case 4: info->sclk = spll / 8.0; break;
+    case 7: info->sclk = mpll;
+    default:
+	    info->sclk = 200.00;
+	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Unsupported SCLK source"
+		       " setting %d, can't probe SCLK value !\n", tmp);
+    }
 
     /* we're done, hopefully these are sane values */
     pll->reference_div = ref_div;
     pll->xclk = xclk;
     pll->reference_freq = xtal;
+    pll->min_pll_freq = 12500;
+    pll->max_pll_freq = 35000;
+
+    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Probed PLL values: xtal: %f Mhz, "
+	       "sclk: %f Mhz, mclk: %f Mhz\n", xtal/100.0, info->sclk, info->mclk);
 
     return TRUE;
 }
@@ -1334,6 +1415,24 @@
 	info->PanelXRes = 640;
 	info->PanelYRes = 480;
     }
+
+    if (xf86ReturnOptValBool(info->Options, OPTION_LVDS_PROBE_PLL, TRUE)) {
+	    CARD32 ppll_div_sel, ppll_val;
+
+	    OUTREG(RADEON_CLOCK_CNTL_INDEX, 1);
+	    ppll_div_sel = INREG8(RADEON_CLOCK_CNTL_DATA + 1) & 0x3;
+            ppll_val = INPLL(pScrn, RADEON_PPLL_DIV_0 + ppll_div_sel);
+	    if ((ppll_val & 0x000707ff) == 0x1bb)
+		goto noprobe;
+            info->FeedbackDivider = ppll_val & 0x7ff;
+            info->PostDivider = (ppll_val >> 16) & 0x7;
+	    info->RefDivider = info->pll.reference_div;
+            info->UseBiosDividers = TRUE;
+
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		       "Existing panel PLL dividers will be used.\n");
+    }
+ noprobe:
     
     xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 
 	       "Panel size %dx%d is derived, this may not be correct.\n"
@@ -1348,17 +1447,24 @@
     if (!RADEONGetLVDSInfoFromBIOS(pScrn))
         RADEONGetPanelInfoFromReg(pScrn);
 
+    /* The panel size we collected from BIOS may not be the
+     * maximum size supported by the panel.  If not, we update
+     * it now.  These will be used if no matching mode can be
+     * found from EDID data.
+     */
+    RADEONUpdatePanelSize(pScrn);
+
+    /* No timing information for the native mode,
+     * use whatever specified in the Modeline.
+     * If no Modeline specified, we'll just pick
+     * the VESA mode at 60Hz refresh rate which
+     * is likely to be the best for a flat panel.
+     */
     if (info->DotClock == 0) {
         RADEONEntPtr pRADEONEnt   = RADEONEntPriv(pScrn);
         DisplayModePtr  tmp_mode = NULL;
         xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
                    "No valid timing info from BIOS.\n");
-        /* No timing information for the native mode,
-           use whatever specified in the Modeline.
-           If no Modeline specified, we'll just pick
-           the VESA mode at 60Hz refresh rate which
-           is likely to be the best for a flat panel.
-	*/
         tmp_mode = pScrn->monitor->Modes;
         while(tmp_mode) {
             if ((tmp_mode->HDisplay == info->PanelXRes) &&
@@ -1429,6 +1535,8 @@
             RADEONGetTMDSInfo(pScrn);
             if (!pScrn->monitor->DDC)
                 RADEONGetHardCodedEDIDFromBIOS(pScrn);
+	    else if (!info->IsSecondary)
+		RADEONUpdatePanelSize(pScrn);
         }
     }
 }
@@ -1462,7 +1570,8 @@
 		    "Video BIOS not detected, using default clock settings!\n");
 
 #if defined(__powerpc__)
-	if (RADEONProbePLLParameters(pScrn)) return;
+	if (RADEONProbePLLParameters(pScrn))
+            return;
 #endif
 	if (info->IsIGP)
 	    pll->reference_freq = 1432;
@@ -1623,8 +1732,18 @@
 	pRADEONEnt->PortInfo[1].DACType = DAC_PRIMARY;
 	pRADEONEnt->PortInfo[1].TMDSType = TMDS_EXT;
 	pRADEONEnt->PortInfo[1].ConnectorType = CONNECTOR_CRT;
+
+	/* Some cards have the DDC lines swapped and we have no way to
+	 * detect it yet (Mac cards)
+	 */
+	if (xf86ReturnOptValBool(info->Options, OPTION_REVERSE_DDC, FALSE)) {
+	    pRADEONEnt->PortInfo[0].DDCType = DDC_VGA;
+	    pRADEONEnt->PortInfo[1].DDCType = DDC_DVI;
+        }
     }
 
+
+
     /* always make TMDS_INT port first*/
     if (pRADEONEnt->PortInfo[1].TMDSType == TMDS_INT) {
         RADEONConnector connector;
@@ -2596,14 +2715,35 @@
     xf86MonPtr      ddc  = pScrn->monitor->DDC;
     DisplayModePtr  p;
 
+    if (info->UseBiosDividers && info->DotClock != 0)
+	return;
+
     /* Go thru detailed timing table first */
     for (j = 0; j < 4; j++) {
 	if (ddc->det_mon[j].type == 0) {
 	    struct detailed_timings *d_timings =
 		&ddc->det_mon[j].section.d_timings;
+	    int match = 0;
+
+	    /* If we didn't get a panel clock or guessed one, try to match the
+	     * mode with the panel size. We do that because we _need_ a panel
+	     * clock, or ValidateFPModes will fail, even when UseBiosDividers
+	     * is set.
+	     */
+	    if (info->DotClock == 0 &&
+		info->PanelXRes == d_timings->h_active &&
+		info->PanelYRes == d_timings->v_active)
+	        match = 1;
+	    
+	    /* If we don't have a BIOS provided panel data with fixed dividers,
+	     * check for a larger panel size
+	     */
 	    if (info->PanelXRes < d_timings->h_active &&
-		info->PanelYRes < d_timings->v_active) {
+		info->PanelYRes < d_timings->v_active &&
+		!info->UseBiosDividers)
+	        match = 1;
 
+	    if (match) {
 		info->PanelXRes  = d_timings->h_active;
 		info->PanelYRes  = d_timings->v_active;
 		info->DotClock   = d_timings->clock / 1000;
@@ -2613,10 +2753,24 @@
 		info->VOverPlus  = d_timings->v_sync_off;
 		info->VSyncWidth = d_timings->v_sync_width;
 		info->VBlank     = d_timings->v_blanking;
+		info->Flags      = (d_timings->interlaced ? V_INTERLACE : 0);
+		if (d_timings->sync == 3) {
+		    switch (d_timings->misc) {
+		    case 0: info->Flags |= V_NHSYNC | V_NVSYNC; break;
+		    case 1: info->Flags |= V_PHSYNC | V_NVSYNC; break;
+		    case 2: info->Flags |= V_NHSYNC | V_PVSYNC; break;
+		    case 3: info->Flags |= V_PHSYNC | V_PVSYNC; break;
+		    }
+	        }
+		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel infos found from DDC detailed: %dx%d\n",
+			   info->PanelXRes, info->PanelYRes);
 	    }
 	}
     }
 
+    if (info->UseBiosDividers && info->DotClock != 0)
+	return;
+
     /* Search thru standard VESA modes from EDID */
     for (j = 0; j < 8; j++) {
 	if ((info->PanelXRes < ddc->timings2[j].hsize) &&
@@ -2638,28 +2792,16 @@
 			info->VOverPlus  = p->VSyncStart - p->VDisplay;
 			info->VSyncWidth = p->VSyncEnd - p->VSyncStart;
 			info->DotClock   = p->Clock;
-			info->Flags      =
-			    (ddc->det_mon[j].section.d_timings.interlaced
-			     ? V_INTERLACE
-			     : 0);
-			if (ddc->det_mon[j].section.d_timings.sync == 3) {
-			    switch (ddc->det_mon[j].section.d_timings.misc) {
-			    case 0: info->Flags |= V_NHSYNC | V_NVSYNC; break;
-			    case 1: info->Flags |= V_PHSYNC | V_NVSYNC; break;
-			    case 2: info->Flags |= V_NHSYNC | V_PVSYNC; break;
-			    case 3: info->Flags |= V_PHSYNC | V_PVSYNC; break;
-			    }
-			}
+			info->Flags	 = p->Flags;
+			xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel infos found from DDC VESA/EDID: %dx%d\n",
+				   info->PanelXRes, info->PanelYRes);
 		    }
 		}
 	    }
 	}
     }
-
-    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel size found from DDC: %dx%d\n",
-	       info->PanelXRes, info->PanelYRes);
-}
-
+ }
+ 
 /* This function will sort all modes according to their resolution.
  * Highest resolution first.
  */
@@ -2778,6 +2920,8 @@
 
     /* Search thru standard VESA modes from EDID */
     for (j = 0; j < 8; j++) {
+	if (ddc->timings2[j].hsize == 0 || ddc->timings2[j].vsize == 0)
+		continue;
 	for (p = pScrn->monitor->Modes; p && p->next; p = p->next->next) {
 	    /* Ignore all double scan modes */
 	    if ((ddc->timings2[j].hsize == p->HDisplay) &&
@@ -2867,19 +3011,10 @@
     pScrn->virtualX = pScrn1->display->virtualX;
     pScrn->virtualY = pScrn1->display->virtualY;
 
-    if (pScrn->monitor->DDC && !info->UseBiosDividers) {
+    if (pScrn->monitor->DDC) {
 	int  maxVirtX = pScrn->virtualX;
 	int  maxVirtY = pScrn->virtualY;
 
-	if ((DisplayType != MT_CRT) && (!info->IsSecondary) && (!crtc2)) {
-	    /* The panel size we collected from BIOS may not be the
-	     * maximum size supported by the panel.  If not, we update
-	     * it now.  These will be used if no matching mode can be
-	     * found from EDID data.
-	     */
-	    RADEONUpdatePanelSize(pScrn);
-	}
-
 	/* Collect all of the DDC modes */
 	first = last = ddcModes = RADEONDDCModes(pScrn);
 
@@ -3175,8 +3310,9 @@
 		new->next       = NULL;
 		new->prev       = last;
 
-		last->next = new;
+		if (last) last->next = new;
 		last = new;
+		if (!first) first = new;
 	    }
 	}
     }
@@ -3570,7 +3706,8 @@
 		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
 			   "Invalid PanelSize value: %s\n", s);
 	    }
-	}
+	} else
+		RADEONGetPanelInfo(pScrn);
     }
 
     if (pScrn->monitor->DDC) {
@@ -4201,15 +4338,6 @@
 	return TRUE;
     }
 
-    if (!xf86LoadSubModule(pScrn, "vgahw")) return FALSE;
-    xf86LoaderReqSymLists(vgahwSymbols, NULL);
-    if (!vgaHWGetHWRec(pScrn)) {
-	RADEONFreeRec(pScrn);
-	goto fail2;
-    }
-
-    vgaHWGetIOBase(VGAHWPTR(pScrn));
-
     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
 	       "PCI bus %d card %d func %d\n",
 	       info->PciInfo->bus,
@@ -4237,6 +4365,32 @@
     memcpy(info->Options, RADEONOptions, sizeof(RADEONOptions));
     xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, info->Options);
 
+    /* By default, don't do VGA IOs on ppc */
+#ifdef __powerpc__
+    info->VGAAccess = FALSE;
+#else
+    info->VGAAccess = TRUE;
+#endif
+
+    xf86GetOptValBool(info->Options, OPTION_VGA_ACCESS, &info->VGAAccess);
+    if (info->VGAAccess) {
+	if (!xf86LoadSubModule(pScrn, "vgahw"))
+	    info->VGAAccess = FALSE;
+        else {
+	    xf86LoaderReqSymLists(vgahwSymbols, NULL);
+            if (!vgaHWGetHWRec(pScrn))
+		info->VGAAccess = FALSE;
+	}
+	if (!info->VGAAccess)
+	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Loading VGA module failed,"
+		       " trying to run without it\n");
+    } else
+	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VGAAccess option set to FALSE,"
+		       " VGA module load skipped\n");
+    if (info->VGAAccess)
+	 vgaHWGetIOBase(VGAHWPTR(pScrn));	    
+
+
     if (!RADEONPreInitWeight(pScrn))
 	goto fail;
 
@@ -4352,7 +4506,6 @@
     RADEONGetBIOSInfo(pScrn, pInt10);
     if (!RADEONQueryConnectedMonitors(pScrn))    goto fail;
     RADEONGetClockInfo(pScrn);
-    RADEONGetPanelInfo(pScrn);
 
     /* collect MergedFB options */
     /* only parse mergedfb options on the primary head. 
@@ -4410,7 +4563,8 @@
     if (pInt10)
 	xf86FreeInt10(pInt10);
 
-    vgaHWFreeHWRec(pScrn);
+    if (info->VGAAccess)
+	    vgaHWFreeHWRec(pScrn);
 
  fail2:
     if(info->MMIO) RADEONUnmapMMIO(pScrn);
@@ -4612,10 +4766,15 @@
 
     RADEONSave(pScrn);
 
-    if (xf86ReturnOptValBool(info->Options, OPTION_DYNAMIC_CLOCKS, FALSE)) {
-	RADEONSetDynamicClock(pScrn, 1);
-    } else {
-	RADEONSetDynamicClock(pScrn, 0);
+    /* Only use the value from the primary head or we end up toggling it
+     * for each head which is meaningless
+     */
+    if (!info->IsSecondary) {
+	if (xf86ReturnOptValBool(info->Options, OPTION_DYNAMIC_CLOCKS, FALSE)) {
+	    RADEONSetDynamicClock(pScrn, 1);
+        } else {
+	    RADEONSetDynamicClock(pScrn, 0);
+        }
     }
 
     if (info->FBDev) {
@@ -5846,7 +6005,6 @@
     RADEONInfoPtr  info       = RADEONPTR(pScrn);
     unsigned char *RADEONMMIO = info->MMIO;
     RADEONSavePtr  save       = &info->SavedReg;
-    vgaHWPtr       hwp        = VGAHWPTR(pScrn);
 
     RADEONTRACE(("RADEONSave\n"));
     if (info->FBDev) {
@@ -5855,19 +6013,23 @@
     }
 
     if (!info->IsSecondary) {
-	vgaHWUnlock(hwp);
+        if (info->VGAAccess) {
+    	    vgaHWPtr hwp = VGAHWPTR(pScrn);
+
+            vgaHWUnlock(hwp);
 #if defined(__powerpc__)
-	/* temporary hack to prevent crashing on PowerMacs when trying to
-	 * read VGA fonts and colormap, will find a better solution
-	 * in the future
-	 */
-	vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE); /* Save mode only */
+	    /* temporary hack to prevent crashing on PowerMacs when trying to
+	     * read VGA fonts and colormap, will find a better solution
+	     * in the future. TODO: Check if there's actually some VGA stuff
+	     * setup in the card at all !!
+	     */
+	    vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE); /* Save mode only */
 #else
-	vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_FONTS); /* Save mode
-						       * & fonts & cmap
-						       */
+	    /* Save mode * & fonts & cmap */
+	    vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_FONTS); 
 #endif
-	vgaHWLock(hwp);
+	    vgaHWLock(hwp);
+	}
 	save->dp_datatype      = INREG(RADEON_DP_DATATYPE);
 	save->rbbm_soft_reset  = INREG(RADEON_RBBM_SOFT_RESET);
 	save->clock_cntl_index = INREG(RADEON_CLOCK_CNTL_INDEX);
@@ -5883,7 +6045,6 @@
     RADEONInfoPtr  info       = RADEONPTR(pScrn);
     unsigned char *RADEONMMIO = info->MMIO;
     RADEONSavePtr  restore    = &info->SavedReg;
-    vgaHWPtr       hwp        = VGAHWPTR(pScrn);
 
     RADEONTRACE(("RADEONRestore\n"));
 
@@ -5925,27 +6086,36 @@
     usleep(100000);
 #endif
 
-    if (!info->IsSecondary) {
-	vgaHWUnlock(hwp);
+    if (info->VGAAccess) {
+    	vgaHWPtr hwp = VGAHWPTR(pScrn);
+        if (!info->IsSecondary) {
+            vgaHWUnlock(hwp);
 #if defined(__powerpc__)
-	/* Temporary hack to prevent crashing on PowerMacs when trying to
-	 * write VGA fonts, will find a better solution in the future
-	 */
-	vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_MODE );
+	    /* Temporary hack to prevent crashing on PowerMacs when trying to
+	     * write VGA fonts, will find a better solution in the future
+	     */
+	    vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_MODE );
 #else
-	vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_FONTS );
+	    vgaHWRestore(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_FONTS );
 #endif
-	vgaHWLock(hwp);
-    } else {
-        RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
-	ScrnInfoPtr   pScrn0;
-	vgaHWPtr      hwp0;
-
-	pScrn0 = pRADEONEnt->pPrimaryScrn;
-	hwp0   = VGAHWPTR(pScrn0);
-	vgaHWUnlock(hwp0);
-	vgaHWRestore(pScrn0, &hwp0->SavedReg, VGA_SR_MODE | VGA_SR_FONTS );
-	vgaHWLock(hwp0);
+	    vgaHWLock(hwp);
+        } else {
+            RADEONEntPtr  pRADEONEnt = RADEONEntPriv(pScrn);
+	    ScrnInfoPtr   pScrn0 = pRADEONEnt->pPrimaryScrn;
+            RADEONInfoPtr info0 = RADEONPTR(pScrn0);
+	    vgaHWPtr      hwp0;
+
+	    if (info0->VGAAccess) {
+ 	        hwp0 = VGAHWPTR(pScrn0);
+	        vgaHWUnlock(hwp0);
+#if defined(__powerpc__)
+	        vgaHWRestore(pScrn0, &hwp0->SavedReg, VGA_SR_MODE);
+#else
+	        vgaHWRestore(pScrn0, &hwp0->SavedReg, VGA_SR_MODE | VGA_SR_FONTS );
+#endif
+	        vgaHWLock(hwp0);
+	    }
+	}
     }
     RADEONUnblank(pScrn);
 
@@ -6574,8 +6744,13 @@
 				      ? RADEON_CRTC2_V_SYNC_POL
 				      : 0));
 
+    /* We must make sure Tiling is disabled. It seem all other fancy
+     * options in there can be safely disabled too
+     */
     save->crtc2_offset      = 0;
-    save->crtc2_offset_cntl = INREG(RADEON_CRTC2_OFFSET_CNTL);
+    save->crtc2_offset_cntl = 0;
+    
+
     /* this should be right */
     if (info->MergedFB) {
     save->crtc2_pitch  = (((info->CRT2pScrn->displayWidth * pScrn->bitsPerPixel) +
@@ -6618,6 +6793,23 @@
 
     }
 
+    /* We must set SURFACE_CNTL properly on the second screen too */
+    save->surface_cntl = 0;
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+    /* Alhought we current onlu use aperture 0, also setting aperture 1 should not harm -ReneR */
+    switch (pScrn->bitsPerPixel) {
+    case 16:
+	save->surface_cntl |= RADEON_NONSURF_AP0_SWP_16BPP;
+	save->surface_cntl |= RADEON_NONSURF_AP1_SWP_16BPP;
+	break;
+
+    case 32:
+	save->surface_cntl |= RADEON_NONSURF_AP0_SWP_32BPP;
+	save->surface_cntl |= RADEON_NONSURF_AP1_SWP_32BPP;
+	break;
+    }
+#endif
+
     RADEONTRACE(("Pitch = %d bytes (virtualX = %d, displayWidth = %d)\n",
 		 save->crtc2_pitch, pScrn->virtualX,
 		 info->CurrentLayout.displayWidth));
@@ -7450,7 +7642,7 @@
        }
     }
 
-    if (xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
+    if (info->VGAAccess && xf86LoaderCheckSymbol("vgaHWFreeHWRec"))
 	vgaHWFreeHWRec(pScrn);
     RADEONFreeRec(pScrn);
 }
diff -urN xc.orig/programs/Xserver/hw/xfree86/drivers/ati/radeon_reg.h xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_reg.h
--- xc.orig/programs/Xserver/hw/xfree86/drivers/ati/radeon_reg.h	2004-11-11 11:56:59.000000000 +1100
+++ xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_reg.h	2004-11-15 14:42:19.000000000 +1100
@@ -821,7 +821,7 @@
 #       define RADEON_MC_MCLK_MAX_DYN_STOP_LAT (1<<12)
 #       define RADEON_IO_MCLK_MAX_DYN_STOP_LAT (1<<13)
 #       define RADEON_MC_MCLK_DYN_ENABLE    (1 << 14)
-#       define RADEON_IO_MCLK_DYN_ENABLE    (1 << 14)
+#       define RADEON_IO_MCLK_DYN_ENABLE    (1 << 15)
 #define RADEON_MDGPIO_A_REG                 0x01ac
 #define RADEON_MDGPIO_EN_REG                0x01b0
 #define RADEON_MDGPIO_MASK                  0x0198





More information about the xorg mailing list