xf86-video-ati: Branch 'master'

Henry Zhao henryz at kemper.freedesktop.org
Thu Aug 31 12:50:26 PDT 2006


 src/r128_driver.c     |  275 ++++++++++++++++++++++-----------------
 src/radeon_driver.c   |  350 ++++++++++++++++++++++++++++++++++++--------------
 src/radeon_mergedfb.c |   28 +++-
 3 files changed, 437 insertions(+), 216 deletions(-)

New commits:
diff-tree caaed927a07ffbac68b08246185ef93c1e7bb98c (from 6d2028b84ff2b82c849b74776258f8e52c952e36)
Author: Henry Zhao <henryz at localhost.localdomain>
Date:   Thu Aug 31 13:27:45 2006 -0700

    * [ Bug 6966 ] large negative refresh rates reported
    * [ Bug 6309 ] radeon/r128 fails to read hsync/vsync rates when rang
    *              descriptor is missing
    * [ Bug 5473 ] Blank screen with Radeon Mobility X700 (Acer Ferrari 4005)
    * Reboot should not be needed for external CRT to function when connected
      later on Ferrari 4000
    * Modes need to be sorted, and sorted correctly
    * Provide all resolutions (instead only the largest one) in MergedFB clone
      mode without config file
    * Bump up clock rate for ES1000 to allow higher resolution

diff --git a/src/r128_driver.c b/src/r128_driver.c
index 49c0d86..ce2f978 100644
--- a/src/r128_driver.c
+++ b/src/r128_driver.c
@@ -1529,127 +1529,166 @@ static Bool R128GetDFPInfo(ScrnInfoPtr p
 
 static void R128SetSyncRangeFromEdid(ScrnInfoPtr pScrn, int flag)
 {
-    int i;
-    xf86MonPtr ddc = pScrn->monitor->DDC;
-    if(flag)  /*HSync*/
-    {
-        for(i=0; i<4; i++)
-        {
-            if(ddc->det_mon[i].type == DS_RANGES)
-            {
-                pScrn->monitor->nHsync = 1;
-                pScrn->monitor->hsync[0].lo =
-                    ddc->det_mon[i].section.ranges.min_h;
-                pScrn->monitor->hsync[0].hi =
-                    ddc->det_mon[i].section.ranges.max_h;
-                return;
-            }
-        }
-        /*if no sync ranges detected in detailed timing table,
-          let's try to derive them from supported VESA modes
-          Are we doing too much here!!!?
-        **/
-        i = 0;
-        if(ddc->timings1.t1 & 0x02) /*800x600 at 56*/
-        {
-            pScrn->monitor->hsync[i].lo =
-                pScrn->monitor->hsync[i].hi = 35.2;
-            i++;
-        }
-        if(ddc->timings1.t1 & 0x04) /*640x480 at 75*/
-        {
-            pScrn->monitor->hsync[i].lo =
-                pScrn->monitor->hsync[i].hi = 37.5;
-            i++;
-        }
-        if((ddc->timings1.t1 & 0x08) || (ddc->timings1.t1 & 0x01))
-        {
-            pScrn->monitor->hsync[i].lo =
-                pScrn->monitor->hsync[i].hi = 37.9;
-            i++;
-        }
-        if(ddc->timings1.t2 & 0x40)
-        {
-            pScrn->monitor->hsync[i].lo =
-                pScrn->monitor->hsync[i].hi = 46.9;
-            i++;
-        }
-        if((ddc->timings1.t2 & 0x80) || (ddc->timings1.t2 & 0x08))
-        {
-            pScrn->monitor->hsync[i].lo =
-                pScrn->monitor->hsync[i].hi = 48.1;
-            i++;
-        }
-        if(ddc->timings1.t2 & 0x04)
-        {
-            pScrn->monitor->hsync[i].lo =
-                pScrn->monitor->hsync[i].hi = 56.5;
-            i++;
-        }
-        if(ddc->timings1.t2 & 0x02)
-        {
-            pScrn->monitor->hsync[i].lo =
-                pScrn->monitor->hsync[i].hi = 60.0;
-            i++;
-        }
-        if(ddc->timings1.t2 & 0x01)
-        {
-            pScrn->monitor->hsync[i].lo =
-                pScrn->monitor->hsync[i].hi = 64.0;
-            i++;
-        }
-        pScrn->monitor->nHsync = i;
-    }
-    else      /*Vrefresh*/
-    {
-        for(i=0; i<4; i++)
-        {
-            if(ddc->det_mon[i].type == DS_RANGES)
-            {
-                pScrn->monitor->nVrefresh = 1;
-                pScrn->monitor->vrefresh[0].lo =
-                    ddc->det_mon[i].section.ranges.min_v;
-                pScrn->monitor->vrefresh[0].hi =
-                    ddc->det_mon[i].section.ranges.max_v;
-                return;
-            }
-        }
-        i = 0;
-        if(ddc->timings1.t1 & 0x02) /*800x600 at 56*/
-        {
-            pScrn->monitor->vrefresh[i].lo =
-                pScrn->monitor->vrefresh[i].hi = 56;
-            i++;
-        }
-        if((ddc->timings1.t1 & 0x01) || (ddc->timings1.t2 & 0x08))
-        {
-            pScrn->monitor->vrefresh[i].lo =
-                pScrn->monitor->vrefresh[i].hi = 60;
-            i++;
-        }
-        if(ddc->timings1.t2 & 0x04)
-        {
-            pScrn->monitor->vrefresh[i].lo =
-                pScrn->monitor->vrefresh[i].hi = 70;
-            i++;
-        }
-        if((ddc->timings1.t1 & 0x08) || (ddc->timings1.t2 & 0x80))
-        {
-            pScrn->monitor->vrefresh[i].lo =
-                pScrn->monitor->vrefresh[i].hi = 72;
-            i++;
-        }
-        if((ddc->timings1.t1 & 0x04) || (ddc->timings1.t2 & 0x40)
-           || (ddc->timings1.t2 & 0x02) || (ddc->timings1.t2 & 0x01))
-        {
-            pScrn->monitor->vrefresh[i].lo =
-                pScrn->monitor->vrefresh[i].hi = 75;
-            i++;
-        }
-        pScrn->monitor->nVrefresh = i;
+    MonPtr monitor = pScrn->monitor;
+    xf86MonPtr DDC = (xf86MonPtr)(pScrn->monitor->DDC);
+    int i, j;
+    float hmin = 1e6, hmax = 0.0, vmin = 1e6, vmax = 0.0;
+    float h, v;
+    struct std_timings *t;
+    struct detailed_timings *dt;
+    struct monitor_ranges *mon_range = NULL;
+    int numTimings = 0;
+    range hsync[MAX_HSYNC];
+    range vrefresh[MAX_VREFRESH];
+
+    numTimings = 0;
+
+    if (flag) { /* Hsync */
+	for (i = 0; i < DET_TIMINGS; i++) {
+	    switch (DDC->det_mon[i].type) {
+	    case DS_RANGES:
+		mon_range = &DDC->det_mon[i].section.ranges;
+		hsync[numTimings].lo = mon_range->min_h;
+		hsync[numTimings].hi = mon_range->max_h;
+		numTimings++;
+		break;
+
+	    case DS_STD_TIMINGS:
+		t = DDC->det_mon[i].section.std_t;
+		for (j = 0; j < 5; j++) {
+		    if (t[j].hsize > 256) { /* sanity check */
+			h = t[j].refresh * 1.07 * t[j].vsize / 1000.0;
+			if (h < hmin)
+			    hmin = h;
+			if (h > hmax)
+			    hmax = h;
+		    }
+		}
+		break;
+
+	    case DT:
+		dt = &DDC->det_mon[i].section.d_timings;
+		if (dt->clock > 15000000) { /* sanity check */
+		    h = (float)dt->clock / (dt->h_active + dt->h_blanking);
+		    h /= 1000.0;
+		    if (h < hmin)
+			hmin = h;
+		    if (h > hmax)
+			hmax = h;
+		}
+		break;
+	    }
+
+	    if (numTimings > MAX_HSYNC)
+		break;
+	}
+
+	if (numTimings == 0) {
+	    t = DDC->timings2;
+	    for (i = 0; i < STD_TIMINGS; i++) {
+		if (t[i].hsize > 256) { /* sanity check */
+		    h = t[i].refresh * 1.07 * t[i].vsize / 1000.0;
+		    if (h < hmin)
+			hmin = h;
+		    if (h > hmax)
+			hmax = h;
+		}
+	    }
+
+	    if (hmax > 0.0) {
+		hsync[numTimings].lo = hmin;
+		hsync[numTimings].hi = hmax;
+		numTimings++;
+	    }
+	}
+
+	if (numTimings > 0) {
+	    monitor->nHsync = numTimings;
+	    for (i = 0; i < numTimings; i++) {
+	    	monitor->hsync[i].lo = hsync[i].lo;
+	    	monitor->hsync[i].hi = hsync[i].hi;
+	    }
+	} else {
+	    pScrn->monitor->hsync[0].lo = 28;
+            pScrn->monitor->hsync[0].hi = 60;
+            monitor->nHsync = 1;
+	}
+
+    } else {  /* Vrefresh */
+	for (i = 0; i < DET_TIMINGS; i++) {
+	    switch (DDC->det_mon[i].type) {
+	    case DS_RANGES:
+		mon_range = &DDC->det_mon[i].section.ranges;
+		vrefresh[numTimings].lo = mon_range->min_v;
+		vrefresh[numTimings].hi = mon_range->max_v;
+		numTimings++;
+		break;
+
+	    case DS_STD_TIMINGS:
+		t = DDC->det_mon[i].section.std_t;
+		for (j = 0; j < 5; j++) {
+		    if (t[j].hsize > 256) { /* sanity check */
+			if (t[j].refresh < vmin)
+			    vmin = t[i].refresh;
+			if (t[j].refresh > vmax)
+			    vmax = t[i].refresh;
+		    }
+		}
+		break;
+
+	    case DT:
+		dt = &DDC->det_mon[i].section.d_timings;
+		if (dt->clock > 15000000) { /* sanity check */
+		    h = (float)dt->clock / (dt->h_active + dt->h_blanking);
+		    v = h / (dt->v_active + dt->v_blanking);
+		    if (dt->interlaced) 
+			v /= 2.0;
+
+		    if (v < vmin)
+			vmin = v;
+		    if (v > vmax)
+			vmax = v;
+		}
+		break;
+	    }
+
+	    if (numTimings > MAX_HSYNC)
+		break;
+	}
+
+	if (numTimings == 0) {
+	    t = DDC->timings2;
+	    for (i = 0; i < STD_TIMINGS; i++) {
+		if (t[i].hsize > 256) { /* sanity check */
+		    if (t[i].refresh < vmin)
+			vmin = t[i].refresh;
+		    if (t[i].refresh > vmax)
+			vmax = t[i].refresh;
+		}
+	    }
+
+	    if (vmax > 0.0) {
+		vrefresh[numTimings].lo = vmin;
+		vrefresh[numTimings].hi = vmax;
+		numTimings++;
+	    }
+	}
+
+	if (numTimings > 0) {
+	    monitor->nVrefresh = numTimings;
+	    for (i = 0; i < numTimings; i++) {
+		monitor->vrefresh[i].lo = vrefresh[i].lo;
+		monitor->vrefresh[i].hi = vrefresh[i].hi;
+	    }
+	 } else {
+	    pScrn->monitor->vrefresh[0].lo = 43;
+            pScrn->monitor->vrefresh[0].hi = 72;
+            monitor->nVrefresh = 1;
+	}
     }
 }
 
+
 /***********
    xfree's xf86ValidateModes routine deosn't work well with DFPs
    here is our own validation routine. All modes between
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index 7155e42..770bb02 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -136,6 +136,9 @@ static void RADEONSetDynamicClock(ScrnIn
 static void RADEONForceSomeClocks(ScrnInfoPtr pScrn);
 static void RADEONUpdatePanelSize(ScrnInfoPtr pScrn);
 static void RADEONSaveMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save);
+static xf86MonPtr RADEONProbeDDC(ScrnInfoPtr pScrn, int indx);
+static RADEONMonitorType RADEONCrtIsPhysicallyConnected(ScrnInfoPtr pScrn, int IsCrtDac);
+  
 
 #ifdef XF86DRI
 static void RADEONAdjustMemMapRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save);
@@ -958,6 +961,8 @@ static RADEONMonitorType RADEONDisplayDD
     RADEONMonitorType MonType = MT_NONE;
     xf86MonPtr* MonInfo = &port->MonInfo;
     int i, j;
+    RADEONEntPtr pRADEONEnt  = RADEONEntPriv(pScrn);
+    int vbeProbe = FALSE;
 
     DDCReg = info->DDCReg;
     switch(DDCType)
@@ -976,7 +981,9 @@ static RADEONMonitorType RADEONDisplayDD
 	break;
     default:
 	info->DDCReg = DDCReg;
+	/* Fall through, can still try ... 
 	return MT_NONE;
+	*/
     }
 
     /* Read and output monitor info using DDC2 over I2C bus */
@@ -1042,6 +1049,15 @@ static RADEONMonitorType RADEONDisplayDD
     OUTREG(info->DDCReg, INREG(info->DDCReg) &
 	   ~(RADEON_GPIO_EN_0 | RADEON_GPIO_EN_1));
 
+    if ((!*MonInfo) && ((port == &pRADEONEnt->PortInfo[0]) ||
+	(RADEONCrtIsPhysicallyConnected(pScrn, !(pRADEONEnt->PortInfo[1].DACType)) 
+	== MT_CRT))) {
+	vbeProbe = TRUE;
+	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VBE DDC probing on port %d ::: \n", 
+	    (port == &pRADEONEnt->PortInfo[0])? 1:2);
+	*MonInfo = RADEONProbeDDC(pScrn, info->pEnt->index);
+    }
+
     if (*MonInfo) {
 	if ((*MonInfo)->rawData[0x14] & 0x80) {
 	    /* Note some laptops have a DVI output that uses internal TMDS,
@@ -1051,14 +1067,32 @@ static RADEONMonitorType RADEONDisplayDD
 	     * Also for laptop, when X starts with lid closed (no DVI connection)
 	     * both LDVS and TMDS are disable, we still need to treat it as a LVDS panel.
 	     */
-	    if (port->TMDSType == TMDS_EXT) MonType = MT_DFP;
-	    else {
-		if ((INREG(RADEON_FP_GEN_CNTL) & (1<<7)) || !info->IsMobility)
-		    MonType = MT_DFP;
-		else 
-		    MonType = MT_LCD;
+	    if (vbeProbe && 
+		(RADEONCrtIsPhysicallyConnected(pScrn, !(port->DACType)) == MT_CRT)) {
+	    	    MonType = MT_NONE;
+	    	    *MonInfo = NULL;
+		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "VBE probed DDC info nullified on port %d :::\n", (port == &pRADEONEnt->PortInfo[0])? 1:2);
+		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "CRT physically connected but digital device indicated in DDC\n");
+	    } else {
+		if (port->TMDSType == TMDS_EXT) MonType = MT_DFP;
+	    	else {
+		    if ((INREG(RADEON_FP_GEN_CNTL) & (1<<7)) || !info->IsMobility)
+		    	MonType = MT_DFP;
+		    else 
+		    	MonType = MT_LCD;
+		}
 	    }
-	} else MonType = MT_CRT;
+	} else  {
+	    	if ((RADEONCrtIsPhysicallyConnected(pScrn, 
+		    !(pRADEONEnt->PortInfo[1].DACType)) == MT_CRT) && vbeProbe && 
+		    (info->HasCRTC2) && (port == &pRADEONEnt->PortInfo[0])) {
+	    	    MonType = MT_NONE;
+	    	    *MonInfo = NULL;
+		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "DDC info nullified on port 1 :::\n");
+		    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Analog device indicated in DDC but port 2 CRT physically connected\n");
+		} else
+	    	    MonType = MT_CRT;
+	}
     } else MonType = MT_NONE;
 
     info->DDCReg = DDCReg;
@@ -1082,6 +1116,7 @@ RADEONCrtIsPhysicallyConnected(ScrnInfoP
     if(IsCrtDac) {
 	unsigned long ulOrigVCLK_ECP_CNTL;
 	unsigned long ulOrigDAC_CNTL;
+	unsigned long ulOrigDAC_MACRO_CNTL;
 	unsigned long ulOrigDAC_EXT_CNTL;
 	unsigned long ulOrigCRTC_EXT_CNTL;
 	unsigned long ulData;
@@ -1116,11 +1151,21 @@ RADEONCrtIsPhysicallyConnected(ScrnInfoP
 	OUTREG(RADEON_DAC_EXT_CNTL, ulData);
 
 	ulOrigDAC_CNTL     = INREG(RADEON_DAC_CNTL);
+
+	if (ulOrigDAC_CNTL & RADEON_DAC_PDWN) {
+	    /* turn on power so testing can go through */
+	    ulOrigDAC_MACRO_CNTL = INREG(RADEON_DAC_MACRO_CNTL);
+	    ulOrigDAC_MACRO_CNTL &= ~(RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G |
+		RADEON_DAC_PDWN_B);
+	    OUTREG(RADEON_DAC_MACRO_CNTL, ulOrigDAC_MACRO_CNTL);
+	}
+
 	ulData             = ulOrigDAC_CNTL;
 	ulData            |= RADEON_DAC_CMP_EN;
 	ulData            &= ~(RADEON_DAC_RANGE_CNTL_MASK
 			       | RADEON_DAC_PDWN);
 	ulData            |= 0x2;
+
 	OUTREG(RADEON_DAC_CNTL, ulData);
 
 	usleep(10000);
@@ -1135,6 +1180,18 @@ RADEONCrtIsPhysicallyConnected(ScrnInfoP
 	OUTREG(RADEON_DAC_CNTL,      ulOrigDAC_CNTL     );
 	OUTREG(RADEON_DAC_EXT_CNTL,  ulOrigDAC_EXT_CNTL );
 	OUTREG(RADEON_CRTC_EXT_CNTL, ulOrigCRTC_EXT_CNTL);
+
+	if (!bConnected) {
+	    /* Power DAC down if CRT is not connected */
+            ulOrigDAC_MACRO_CNTL = INREG(RADEON_DAC_MACRO_CNTL);
+            ulOrigDAC_MACRO_CNTL |= (RADEON_DAC_PDWN_R | RADEON_DAC_PDWN_G |
+	    	RADEON_DAC_PDWN_B);
+            OUTREG(RADEON_DAC_MACRO_CNTL, ulOrigDAC_MACRO_CNTL);
+
+	    ulData     = INREG(RADEON_DAC_CNTL);
+	    ulData     |= RADEON_DAC_PDWN ;
+	    OUTREG(RADEON_DAC_CNTL, ulData);
+    	}
     } else { /* TV DAC */
 
         /* This doesn't seem to work reliably (maybe worse on some OEM cards),
@@ -1284,7 +1341,6 @@ RADEONCrtIsPhysicallyConnected(ScrnInfoP
 	}
 #endif
     }
-
     return(bConnected ? MT_CRT : MT_NONE);
 }
 
@@ -1694,9 +1750,12 @@ static void RADEONGetClockInfo(ScrnInfoP
     if (info->ChipFamily == CHIP_FAMILY_RV100 && !info->HasCRTC2) {
         /* Avoid RN50 corruption due to memory bandwidth starvation.
          * 18 is an empirical value based on the databook and Windows driver.
-        */
+         *
+         * Empirical value changed to 24 to raise pixel clock limit and
+         * allow higher resolution modes on capable monitors.
+         */
         pll->max_pll_freq = min(pll->max_pll_freq,
-                               18 * info->mclk * 100 / pScrn->bitsPerPixel *
+                               24 * info->mclk * 100 / pScrn->bitsPerPixel *
                                info->RamWidth / 16);
     }
 
@@ -1830,7 +1889,9 @@ static BOOL RADEONQueryConnectedMonitors
 	pRADEONEnt->PortInfo[i].ConnectorType = CONNECTOR_NONE;
     }
 
-    if (!RADEONGetConnectorInfoFromBIOS(pScrn)) {
+    if (!RADEONGetConnectorInfoFromBIOS(pScrn) ||
+	((pRADEONEnt->PortInfo[0].DDCType == 0) &&
+	(pRADEONEnt->PortInfo[1].DDCType == 0))) {
 	/* Below is the most common setting, but may not be true */
 	pRADEONEnt->PortInfo[0].MonType = MT_UNKNOWN;
 	pRADEONEnt->PortInfo[0].MonInfo = NULL;
@@ -3145,7 +3206,8 @@ static void RADEONSortModes(DisplayModeP
 
     p = *last;
     while (p) {
-	if ((((*new)->HDisplay < p->HDisplay) &&
+	if (((*new)->HDisplay < p->HDisplay) ||
+	    (((*new)->HDisplay == p->HDisplay) &&
 	     ((*new)->VDisplay < p->VDisplay)) ||
 	    (((*new)->HDisplay == p->HDisplay) &&
 	     ((*new)->VDisplay == p->VDisplay) &&
@@ -3682,89 +3744,162 @@ static Bool RADEONPreInitGamma(ScrnInfoP
 
 static void RADEONSetSyncRangeFromEdid(ScrnInfoPtr pScrn, int flag)
 {
-    MonPtr      mon = pScrn->monitor;
-    xf86MonPtr  ddc = mon->DDC;
-    int         i;
-
-    if (flag) { /* HSync */
-	for (i = 0; i < 4; i++) {
-	    if (ddc->det_mon[i].type == DS_RANGES) {
-		mon->nHsync = 1;
-		mon->hsync[0].lo = ddc->det_mon[i].section.ranges.min_h;
-		mon->hsync[0].hi = ddc->det_mon[i].section.ranges.max_h;
-		return;
-	    }
-	}
-	/* If no sync ranges detected in detailed timing table, let's
-	 * try to derive them from supported VESA modes.  Are we doing
-	 * too much here!!!?  */
-	i = 0;
-	if (ddc->timings1.t1 & 0x02) { /* 800x600 at 56 */
-	    mon->hsync[i].lo = mon->hsync[i].hi = 35.2;
-	    i++;
-	}
-	if (ddc->timings1.t1 & 0x04) { /* 640x480 at 75 */
-	    mon->hsync[i].lo = mon->hsync[i].hi = 37.5;
-	    i++;
-	}
-	if ((ddc->timings1.t1 & 0x08) || (ddc->timings1.t1 & 0x01)) {
-	    mon->hsync[i].lo = mon->hsync[i].hi = 37.9;
-	    i++;
-	}
-	if (ddc->timings1.t2 & 0x40) {
-	    mon->hsync[i].lo = mon->hsync[i].hi = 46.9;
-	    i++;
-	}
-	if ((ddc->timings1.t2 & 0x80) || (ddc->timings1.t2 & 0x08)) {
-	    mon->hsync[i].lo = mon->hsync[i].hi = 48.1;
-	    i++;
-	}
-	if (ddc->timings1.t2 & 0x04) {
-	    mon->hsync[i].lo = mon->hsync[i].hi = 56.5;
-	    i++;
-	}
-	if (ddc->timings1.t2 & 0x02) {
-	    mon->hsync[i].lo = mon->hsync[i].hi = 60.0;
-	    i++;
-	}
-	if (ddc->timings1.t2 & 0x01) {
-	    mon->hsync[i].lo = mon->hsync[i].hi = 64.0;
-	    i++;
+    MonPtr monitor = pScrn->monitor;
+    xf86MonPtr DDC = (xf86MonPtr)(pScrn->monitor->DDC);
+    int i, j;
+    float hmin = 1e6, hmax = 0.0, vmin = 1e6, vmax = 0.0;
+    float h, v;
+    struct std_timings *t;
+    struct detailed_timings *dt;
+    struct monitor_ranges *mon_range = NULL;
+    int numTimings = 0;
+    range hsync[MAX_HSYNC];
+    range vrefresh[MAX_VREFRESH];
+
+    numTimings = 0;
+
+    if (flag) { /* Hsync */
+	for (i = 0; i < DET_TIMINGS; i++) {
+	    switch (DDC->det_mon[i].type) {
+	    case DS_RANGES:
+		mon_range = &DDC->det_mon[i].section.ranges;
+		hsync[numTimings].lo = mon_range->min_h;
+		hsync[numTimings].hi = mon_range->max_h;
+		numTimings++;
+		break;
+
+	    case DS_STD_TIMINGS:
+		t = DDC->det_mon[i].section.std_t;
+		for (j = 0; j < 5; j++) {
+		    if (t[j].hsize > 256) { /* sanity check */
+			h = t[j].refresh * 1.07 * t[j].vsize / 1000.0;
+			if (h < hmin)
+			    hmin = h;
+			if (h > hmax)
+			    hmax = h;
+		    }
+		}
+		break;
+
+	    case DT:
+		dt = &DDC->det_mon[i].section.d_timings;
+		if (dt->clock > 15000000) { /* sanity check */
+		    h = (float)dt->clock / (dt->h_active + dt->h_blanking);
+		    h /= 1000.0;
+		    if (h < hmin)
+			hmin = h;
+		    if (h > hmax)
+			hmax = h;
+		}
+		break;
+	    }
+
+	    if (numTimings > MAX_HSYNC)
+		break;
+	}
+
+	if (numTimings == 0) {
+	    t = DDC->timings2;
+	    for (i = 0; i < STD_TIMINGS; i++) {
+		if (t[i].hsize > 256) { /* sanity check */
+		    h = t[i].refresh * 1.07 * t[i].vsize / 1000.0;
+		    if (h < hmin)
+			hmin = h;
+		    if (h > hmax)
+			hmax = h;
+		}
+	    }
+
+	    if (hmax > 0.0) {
+		hsync[numTimings].lo = hmin;
+		hsync[numTimings].hi = hmax;
+		numTimings++;
+	    }
 	}
-	mon->nHsync = i;
+
+	if (numTimings > 0) {
+	    monitor->nHsync = numTimings;
+	    for (i = 0; i < numTimings; i++) {
+	    	monitor->hsync[i].lo = hsync[i].lo;
+	    	monitor->hsync[i].hi = hsync[i].hi;
+	    }
+	} else {
+	    pScrn->monitor->hsync[0].lo = 28;
+            pScrn->monitor->hsync[0].hi = 60;
+            monitor->nHsync = 1;
+	}
+
     } else {  /* Vrefresh */
-	for (i = 0; i < 4; i++) {
-	    if (ddc->det_mon[i].type == DS_RANGES) {
-		mon->nVrefresh = 1;
-		mon->vrefresh[0].lo = ddc->det_mon[i].section.ranges.min_v;
-		mon->vrefresh[0].hi = ddc->det_mon[i].section.ranges.max_v;
-		return;
+	for (i = 0; i < DET_TIMINGS; i++) {
+	    switch (DDC->det_mon[i].type) {
+	    case DS_RANGES:
+		mon_range = &DDC->det_mon[i].section.ranges;
+		vrefresh[numTimings].lo = mon_range->min_v;
+		vrefresh[numTimings].hi = mon_range->max_v;
+		numTimings++;
+		break;
+
+	    case DS_STD_TIMINGS:
+		t = DDC->det_mon[i].section.std_t;
+		for (j = 0; j < 5; j++) {
+		    if (t[j].hsize > 256) { /* sanity check */
+			if (t[j].refresh < vmin)
+			    vmin = t[i].refresh;
+			if (t[j].refresh > vmax)
+			    vmax = t[i].refresh;
+		    }
+		}
+		break;
+
+	    case DT:
+		dt = &DDC->det_mon[i].section.d_timings;
+		if (dt->clock > 15000000) { /* sanity check */
+		    h = (float)dt->clock / (dt->h_active + dt->h_blanking);
+		    v = h / (dt->v_active + dt->v_blanking);
+		    if (dt->interlaced) 
+			v /= 2.0;
+
+		    if (v < vmin)
+			vmin = v;
+		    if (v > vmax)
+			vmax = v;
+		}
+		break;
 	    }
+
+	    if (numTimings > MAX_HSYNC)
+		break;
 	}
 
-	i = 0;
-	if (ddc->timings1.t1 & 0x02) { /* 800x600 at 56 */
-	    mon->vrefresh[i].lo = mon->vrefresh[i].hi = 56;
-	    i++;
-	}
-	if ((ddc->timings1.t1 & 0x01) || (ddc->timings1.t2 & 0x08)) {
-	    mon->vrefresh[i].lo = mon->vrefresh[i].hi = 60;
-	    i++;
-	}
-	if (ddc->timings1.t2 & 0x04) {
-	    mon->vrefresh[i].lo = mon->vrefresh[i].hi = 70;
-	    i++;
-	}
-	if ((ddc->timings1.t1 & 0x08) || (ddc->timings1.t2 & 0x80)) {
-	    mon->vrefresh[i].lo = mon->vrefresh[i].hi = 72;
-	    i++;
-	}
-	if ((ddc->timings1.t1 & 0x04) || (ddc->timings1.t2 & 0x40) ||
-	    (ddc->timings1.t2 & 0x02) || (ddc->timings1.t2 & 0x01)) {
-	    mon->vrefresh[i].lo = mon->vrefresh[i].hi = 75;
-	    i++;
+	if (numTimings == 0) {
+	    t = DDC->timings2;
+	    for (i = 0; i < STD_TIMINGS; i++) {
+		if (t[i].hsize > 256) { /* sanity check */
+		    if (t[i].refresh < vmin)
+			vmin = t[i].refresh;
+		    if (t[i].refresh > vmax)
+			vmax = t[i].refresh;
+		}
+	    }
+
+	    if (vmax > 0.0) {
+		vrefresh[numTimings].lo = vmin;
+		vrefresh[numTimings].hi = vmax;
+		numTimings++;
+	    }
+	}
+
+	if (numTimings > 0) {
+	    monitor->nVrefresh = numTimings;
+	    for (i = 0; i < numTimings; i++) {
+		monitor->vrefresh[i].lo = vrefresh[i].lo;
+		monitor->vrefresh[i].hi = vrefresh[i].hi;
+	    }
+	 } else {
+	    pScrn->monitor->vrefresh[0].lo = 43;
+            pScrn->monitor->vrefresh[0].hi = 72;
+            monitor->nVrefresh = 1;
 	}
-	mon->nVrefresh = i;
     }
 }
 
@@ -3940,6 +4075,9 @@ static Bool RADEONPreInitModes(ScrnInfoP
     int            modesFound;
     RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
     char           *s;
+    DisplayModePtr	first = NULL;
+    DisplayModePtr 	last = NULL;
+    DisplayModePtr 	start, mp;
 
     /* This option has two purposes:
      *
@@ -4224,6 +4362,29 @@ static Bool RADEONPreInitModes(ScrnInfoP
 	}
     }
 
+    /* Sort the modes, retain the first */
+    if (pScrn->modes && (start = pScrn->modes->next)) {
+       for (mp = start; mp->next != pScrn->modes; mp = mp->next) {
+           DisplayModePtr 	new = NULL;
+
+           new = xnfcalloc(1, sizeof (DisplayModeRec));
+           memcpy(new, mp, sizeof (DisplayModeRec));
+           new->name = strdup(mp->name);
+           RADEONSortModes(&new, &first, &last);
+       }
+
+       if (last && first) {
+           pScrn->modes->next = first;
+           pScrn->modes->prev = last;
+           first->prev = pScrn->modes;
+           /* Make the list circular */
+           last->next = pScrn->modes;
+
+           for (mp = start; mp->next != pScrn->modes; mp = mp->next) 
+	       xf86DeleteMode(&start, mp);
+       }
+    }
+
     pScrn->currentMode = pScrn->modes;
     if(info->MergedFB) {
        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
@@ -4785,15 +4946,18 @@ static Bool RADEONPreInitXv(ScrnInfoPtr 
     return TRUE;
 }
 
-static void
+static xf86MonPtr
 RADEONProbeDDC(ScrnInfoPtr pScrn, int indx)
 {
     vbeInfoPtr  pVbe;
+    xf86MonPtr monitor;
 
     if (xf86LoadSubModule(pScrn, "vbe")) {
 	pVbe = VBEInit(NULL,indx);
-	ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
-    }
+	monitor = vbeDoEDID(pVbe, NULL);
+	return (monitor);
+    } else
+	return (NULL);
 }
 
 _X_EXPORT Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags)
@@ -4886,7 +5050,7 @@ _X_EXPORT Bool RADEONPreInit(ScrnInfoPtr
     }
 
     if (flags & PROBE_DETECT) {
-	RADEONProbeDDC(pScrn, info->pEnt->index);
+	ConfiguredMonitor = RADEONProbeDDC(pScrn, info->pEnt->index);
 	RADEONPostInt10Check(pScrn, int10_save);
 	if(info->MMIO) RADEONUnmapMMIO(pScrn);
 	return TRUE;
diff --git a/src/radeon_mergedfb.c b/src/radeon_mergedfb.c
index 313dda2..f78c8bb 100644
--- a/src/radeon_mergedfb.c
+++ b/src/radeon_mergedfb.c
@@ -212,6 +212,12 @@ RADEONCopyModeNLink(ScrnInfoPtr pScrn, D
     mode->VSyncEnd += dy;
     mode->VTotal += dy;
 
+    /* This is needed for not generating negative refesh rates in xrandr with the
+       faked DotClock below
+     */
+    if (!(mode->VRefresh))
+        mode->VRefresh = mode->Clock * 1000.0 / mode->HTotal / mode->VTotal;
+
      /* Provide a sophisticated fake DotClock in order to trick the vidmode
       * extension to allow selecting among a number of modes whose merged result
       * looks identical but consists of different modes for CRT1 and CRT2
@@ -531,14 +537,26 @@ RADEONGenerateModeList(ScrnInfoPtr pScrn
    if(str != NULL) {
       return(RADEONGenerateModeListFromMetaModes(pScrn, str, i, j, srel));
    } else {
-      xf86DrvMsg(pScrn->scrnIndex, X_INFO,
-	"No MetaModes given, linking %s modes by default\n",
-	(srel == radeonClone) ? "largest common" :
-	   (info->NonRect ?
+	if (srel == radeonClone ) {
+      	   DisplayModePtr p, q, result = NULL;
+
+      	   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		"Clone mode, list all common modes\n");
+	   for (p = i; p->next != i; p = p->next)
+		for (q = j; q->next != j; q = q->next)
+		   if ((p->HDisplay == q->HDisplay) &&
+			(p->VDisplay == q->VDisplay))
+		   	result = RADEONCopyModeNLink(pScrn, result, p, q, srel);
+	   return result;
+	} else {
+      	   xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+		"No MetaModes given, linking %s modes by default\n",
+	   	(info->NonRect ?
 		(((srel == radeonLeftOf) || (srel == radeonRightOf)) ? "widest" :  "tallest")
 		:
 		(((srel == radeonLeftOf) || (srel == radeonRightOf)) ? "widest common" :  "tallest common")) );
-      return(RADEONGenerateModeListFromLargestModes(pScrn, i, j, srel));
+           return(RADEONGenerateModeListFromLargestModes(pScrn, i, j, srel));
+	}
    }
 }
 



More information about the xorg-commit mailing list