summaryrefslogtreecommitdiff
path: root/src/radeon_driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/radeon_driver.c')
-rw-r--r--src/radeon_driver.c3440
1 files changed, 2341 insertions, 1099 deletions
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index ae584332..930ecba6 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -1,4 +1,4 @@
-/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c,v 1.91 2003/02/25 03:50:15 dawes Exp $ */
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c,v 1.116 2003/11/19 02:08:15 martin Exp $ */
/*
* Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
* VA Linux Systems Inc., Fremont, California.
@@ -71,19 +71,7 @@
#include "radeon_sarea.h"
#endif
-#define USE_FB /* not until overlays */
-#ifdef USE_FB
#include "fb.h"
-#else
-
- /* CFB support */
-#define PSZ 8
-#include "cfb.h"
-#undef PSZ
-#include "cfb16.h"
-#include "cfb24.h"
-#include "cfb32.h"
-#endif
/* colormap initialization */
#include "micmap.h"
@@ -105,6 +93,9 @@
#ifndef MAX
#define MAX(a,b) ((a)>(b)?(a):(b))
#endif
+#ifndef MIN
+#define MIN(a,b) ((a)>(b)?(b):(a))
+#endif
/* Forward definitions for driver functions */
static Bool RADEONCloseScreen(int scrnIndex, ScreenPtr pScreen);
@@ -115,6 +106,7 @@ static Bool RADEONModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
static void RADEONDisplayPowerManagementSet(ScrnInfoPtr pScrn,
int PowerManagementMode,
int flags);
+static void RADEONInitDispBandwidth(ScrnInfoPtr pScrn);
typedef enum {
OPTION_NOACCEL,
@@ -123,11 +115,12 @@ typedef enum {
OPTION_DAC_8BIT,
#ifdef XF86DRI
OPTION_IS_PCI,
+ OPTION_BUS_TYPE,
OPTION_CP_PIO,
OPTION_USEC_TIMEOUT,
OPTION_AGP_MODE,
OPTION_AGP_FW,
- OPTION_AGP_SIZE,
+ OPTION_GART_SIZE,
OPTION_RING_SIZE,
OPTION_BUFFER_SIZE,
OPTION_DEPTH_MOVE,
@@ -136,12 +129,17 @@ typedef enum {
#endif
OPTION_PANEL_OFF,
OPTION_DDC_MODE,
- OPTION_CLONE_DISPLAY,
+ OPTION_MONITOR_LAYOUT,
+ OPTION_IGNORE_EDID,
+ OPTION_CRTC2_OVERLAY,
OPTION_CLONE_MODE,
OPTION_CLONE_HSYNC,
OPTION_CLONE_VREFRESH,
OPTION_FBDEV,
- OPTION_VIDEO_KEY
+ OPTION_VIDEO_KEY,
+ OPTION_DISP_PRIORITY,
+ OPTION_PANEL_SIZE,
+ OPTION_MIN_DOTCLOCK
} RADEONOpts;
const OptionInfoRec RADEONOptions[] = {
@@ -151,11 +149,13 @@ const OptionInfoRec RADEONOptions[] = {
{ OPTION_DAC_8BIT, "Dac8Bit", OPTV_BOOLEAN, {0}, TRUE },
#ifdef XF86DRI
{ OPTION_IS_PCI, "ForcePCIMode", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_BUS_TYPE, "BusType", OPTV_ANYSTR, {0}, FALSE },
{ OPTION_CP_PIO, "CPPIOMode", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_USEC_TIMEOUT, "CPusecTimeout", OPTV_INTEGER, {0}, FALSE },
{ OPTION_AGP_MODE, "AGPMode", OPTV_INTEGER, {0}, FALSE },
{ OPTION_AGP_FW, "AGPFastWrite", OPTV_BOOLEAN, {0}, FALSE },
- { OPTION_AGP_SIZE, "AGPSize", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_GART_SIZE, "AGPSize", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_GART_SIZE, "GARTSize", OPTV_INTEGER, {0}, FALSE },
{ OPTION_RING_SIZE, "RingSize", OPTV_INTEGER, {0}, FALSE },
{ OPTION_BUFFER_SIZE, "BufferSize", OPTV_INTEGER, {0}, FALSE },
{ OPTION_DEPTH_MOVE, "EnableDepthMoves", OPTV_BOOLEAN, {0}, FALSE },
@@ -164,21 +164,20 @@ const OptionInfoRec RADEONOptions[] = {
#endif
{ OPTION_PANEL_OFF, "PanelOff", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_DDC_MODE, "DDCMode", OPTV_BOOLEAN, {0}, FALSE },
- { OPTION_CLONE_DISPLAY, "CloneDisplay", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_MONITOR_LAYOUT, "MonitorLayout", OPTV_ANYSTR, {0}, FALSE },
+ { OPTION_IGNORE_EDID, "IgnoreEDID", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_CRTC2_OVERLAY , "OverlayOnCRTC2", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_CLONE_MODE, "CloneMode", OPTV_ANYSTR, {0}, FALSE },
{ OPTION_CLONE_HSYNC, "CloneHSync", OPTV_ANYSTR, {0}, FALSE },
{ OPTION_CLONE_VREFRESH, "CloneVRefresh", OPTV_ANYSTR, {0}, FALSE },
{ OPTION_FBDEV, "UseFBDev", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE },
+ { OPTION_DISP_PRIORITY, "DisplayPriority", OPTV_ANYSTR, {0}, FALSE },
+ { OPTION_PANEL_SIZE, "PanelSize", OPTV_ANYSTR, {0}, FALSE },
+ { OPTION_MIN_DOTCLOCK, "ForceMinDotClock", OPTV_FREQ, {0}, FALSE },
{ -1, NULL, OPTV_NONE, {0}, FALSE }
};
-RADEONRAMRec RADEONRAM[] = { /* Memory Specifications
- From Radeon Manual */
- { 4, 4, 1, 2, 1, 2, 1, 16, 12, "64-bit SDR SDRAM" },
- { 4, 4, 3, 3, 2, 3, 1, 16, 12, "64-bit DDR SDRAM" },
-};
-
static const char *vgahwSymbols[] = {
"vgaHWFreeHWRec",
"vgaHWGetHWRec",
@@ -226,21 +225,11 @@ static const char *ddcSymbols[] = {
NULL
};
-#ifdef USE_FB
static const char *fbSymbols[] = {
"fbScreenInit",
"fbPictureInit",
NULL
};
-#else
-static const char *cfbSymbols[] = {
- "cfbScreenInit",
- "cfb16ScreenInit",
- "cfb24ScreenInit",
- "cfb32ScreenInit",
- NULL
-};
-#endif
static const char *xaaSymbols[] = {
"XAACreateInfoRec",
@@ -355,11 +344,7 @@ void RADEONLoaderRefSymLists(void)
* refer to.
*/
xf86LoaderRefSymLists(vgahwSymbols,
-#ifdef USE_FB
fbSymbols,
-#else
- cfbSymbols,
-#endif
xaaSymbols,
#if 0
xf8_32bppSymbols,
@@ -392,7 +377,7 @@ static struct
{1024, 768, 87},
{832, 624, 75},
{800, 600, 75},
- {800, 600, 72},
+ {800, 600, 72},
{800, 600, 60},
{800, 600, 56},
{640, 480, 75},
@@ -403,6 +388,24 @@ static struct
{720, 400, 70},
};
+static const RADEONTMDSPll default_tmds_pll[CHIP_FAMILY_LAST][4] =
+{
+ {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_UNKNOW*/
+ {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_LEGACY*/
+ {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RADEON*/
+ {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV100*/
+ {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS100*/
+ {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV200*/
+ {{12000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS200*/
+ {{15000, 0xa1b}, {0xffffffff, 0xa3f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R200*/
+ {{15500, 0x81b}, {0xffffffff, 0x83f}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV250*/
+ {{0, 0}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RS300*/
+ {{13000, 0x400f4}, {15000, 0x400f7}, {0xffffffff, 0x400f7/*0x40111*/}, {0, 0}}, /*CHIP_FAMILY_RV280*/
+ {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R300*/
+ {{0xffffffff, 0xb01cb}, {0, 0}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_R350*/
+ {{15000, 0xb0155}, {0xffffffff, 0xb01cb}, {0, 0}, {0, 0}}, /*CHIP_FAMILY_RV350*/
+};
+
extern int gRADEONEntityIndex;
struct RADEONInt10Save {
@@ -414,37 +417,29 @@ struct RADEONInt10Save {
static Bool RADEONMapMMIO(ScrnInfoPtr pScrn);
static Bool RADEONUnmapMMIO(ScrnInfoPtr pScrn);
+static RADEONEntPtr RADEONEntPriv(ScrnInfoPtr pScrn)
+{
+ DevUnion *pPriv;
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ pPriv = xf86GetEntityPrivate(info->pEnt->index,
+ gRADEONEntityIndex);
+ return pPriv->ptr;
+}
+
static void
RADEONPreInt10Save(ScrnInfoPtr pScrn, void **pPtr)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
- unsigned char *RADEONMMIO;
- int mapped = 0;
+ unsigned char *RADEONMMIO = info->MMIO;
CARD32 CardTmp;
static struct RADEONInt10Save SaveStruct = { 0, 0, 0 };
- /*
- * First make sure we have the pci and mmio info and that mmio is mapped
- */
- if (!info->PciInfo)
- info->PciInfo = xf86GetPciInfoForEntity(info->pEnt->index);
- if (!info->PciTag)
- info->PciTag = pciTag(info->PciInfo->bus, info->PciInfo->device,
- info->PciInfo->func);
- if (!info->MMIOAddr)
- info->MMIOAddr = info->PciInfo->memBase[2] & 0xffffff00;
- if (!info->MMIO) {
- RADEONMapMMIO(pScrn);
- mapped = 1;
- }
- RADEONMMIO = info->MMIO;
-
/* Save the values and zap MEM_CNTL */
SaveStruct.MEM_CNTL = INREG(RADEON_MEM_CNTL);
SaveStruct.MEMSIZE = INREG(RADEON_CONFIG_MEMSIZE);
SaveStruct.MPP_TB_CONFIG = INREG(RADEON_MPP_TB_CONFIG);
- /*
+ /*
* Zap MEM_CNTL and set MPP_TB_CONFIG<31:24> to 4
*/
OUTREG(RADEON_MEM_CNTL, 0);
@@ -453,52 +448,40 @@ RADEONPreInt10Save(ScrnInfoPtr pScrn, void **pPtr)
OUTREG(RADEON_MPP_TB_CONFIG, CardTmp);
*pPtr = (void *)&SaveStruct;
-
- /* Unmap mmio space if we mapped it */
- if (mapped)
- RADEONUnmapMMIO(pScrn);
}
static void
RADEONPostInt10Check(ScrnInfoPtr pScrn, void *ptr)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
- unsigned char *RADEONMMIO;
+ unsigned char *RADEONMMIO = info->MMIO;
struct RADEONInt10Save *pSave = ptr;
CARD32 CardTmp;
- int mapped = 0;
/* If we don't have a valid (non-zero) saved MEM_CNTL, get out now */
if (!pSave || !pSave->MEM_CNTL)
return;
- /* First make sure that mmio is mapped */
- if (!info->MMIO) {
- RADEONMapMMIO(pScrn);
- mapped = 1;
- }
- RADEONMMIO = info->MMIO;
-
/*
* If either MEM_CNTL is currently zero or inconistent (configured for
* two channels with the two channels configured differently), restore
* the saved registers.
*/
CardTmp = INREG(RADEON_MEM_CNTL);
- if (!CardTmp ||
- ((CardTmp & 1) &&
+ if (!CardTmp ||
+ ((CardTmp & 1) &&
(((CardTmp >> 8) & 0xff) != ((CardTmp >> 24) & 0xff)))) {
/* Restore the saved registers */
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
- "Restoring MEM_CNTL (%08x), setting to %08x\n",
- CardTmp, pSave->MEM_CNTL);
+ "Restoring MEM_CNTL (%08lx), setting to %08lx\n",
+ (unsigned long)CardTmp, (unsigned long)pSave->MEM_CNTL);
OUTREG(RADEON_MEM_CNTL, pSave->MEM_CNTL);
CardTmp = INREG(RADEON_CONFIG_MEMSIZE);
if (CardTmp != pSave->MEMSIZE) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
- "Restoring CONFIG_MEMSIZE (%08x), setting to %08x\n",
- CardTmp, pSave->MEMSIZE);
+ "Restoring CONFIG_MEMSIZE (%08lx), setting to %08lx\n",
+ (unsigned long)CardTmp, (unsigned long)pSave->MEMSIZE);
OUTREG(RADEON_CONFIG_MEMSIZE, pSave->MEMSIZE);
}
}
@@ -506,16 +489,13 @@ RADEONPostInt10Check(ScrnInfoPtr pScrn, void *ptr)
CardTmp = INREG(RADEON_MPP_TB_CONFIG);
if ((CardTmp & 0xff000000u) != (pSave->MPP_TB_CONFIG & 0xff000000u)) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
- "Restoring MPP_TB_CONFIG<31:24> (%02x), setting to %02x\n",
- CardTmp >> 24, pSave->MPP_TB_CONFIG >> 24);
+ "Restoring MPP_TB_CONFIG<31:24> (%02lx), setting to %02lx\n",
+ (unsigned long)CardTmp >> 24,
+ (unsigned long)pSave->MPP_TB_CONFIG >> 24);
CardTmp &= 0x00ffffffu;
CardTmp |= (pSave->MPP_TB_CONFIG & 0xff000000u);
OUTREG(RADEON_MPP_TB_CONFIG, CardTmp);
}
-
- /* Unmap mmio space if we mapped it */
- if (mapped)
- RADEONUnmapMMIO(pScrn);
}
/* Allocate our private RADEONInfoRec */
@@ -711,12 +691,8 @@ static void RADEONBlank(ScrnInfoPtr pScrn)
case MT_CRT:
case MT_DFP:
OUTREGP(RADEON_CRTC_EXT_CNTL,
- RADEON_CRTC_DISPLAY_DIS |
- RADEON_CRTC_VSYNC_DIS |
- RADEON_CRTC_HSYNC_DIS,
- ~(RADEON_CRTC_DISPLAY_DIS |
- RADEON_CRTC_VSYNC_DIS |
- RADEON_CRTC_HSYNC_DIS));
+ RADEON_CRTC_DISPLAY_DIS,
+ ~(RADEON_CRTC_DISPLAY_DIS));
break;
case MT_NONE:
@@ -725,20 +701,12 @@ static void RADEONBlank(ScrnInfoPtr pScrn)
}
if (info->Clone)
OUTREGP(RADEON_CRTC2_GEN_CNTL,
- RADEON_CRTC2_DISP_DIS |
- RADEON_CRTC2_VSYNC_DIS |
- RADEON_CRTC2_HSYNC_DIS,
- ~(RADEON_CRTC2_DISP_DIS |
- RADEON_CRTC2_VSYNC_DIS |
- RADEON_CRTC2_HSYNC_DIS));
+ RADEON_CRTC2_DISP_DIS,
+ ~(RADEON_CRTC2_DISP_DIS));
} else {
OUTREGP(RADEON_CRTC2_GEN_CNTL,
- RADEON_CRTC2_DISP_DIS |
- RADEON_CRTC2_VSYNC_DIS |
- RADEON_CRTC2_HSYNC_DIS,
- ~(RADEON_CRTC2_DISP_DIS |
- RADEON_CRTC2_VSYNC_DIS |
- RADEON_CRTC2_HSYNC_DIS));
+ RADEON_CRTC2_DISP_DIS,
+ ~(RADEON_CRTC2_DISP_DIS));
}
}
@@ -755,9 +723,7 @@ static void RADEONUnblank(ScrnInfoPtr pScrn)
case MT_DFP:
OUTREGP(RADEON_CRTC_EXT_CNTL,
RADEON_CRTC_CRT_ON,
- ~(RADEON_CRTC_DISPLAY_DIS |
- RADEON_CRTC_VSYNC_DIS |
- RADEON_CRTC_HSYNC_DIS));
+ ~(RADEON_CRTC_DISPLAY_DIS));
break;
case MT_NONE:
@@ -767,9 +733,7 @@ static void RADEONUnblank(ScrnInfoPtr pScrn)
if (info->Clone)
OUTREGP(RADEON_CRTC2_GEN_CNTL,
0,
- ~(RADEON_CRTC2_DISP_DIS |
- RADEON_CRTC2_VSYNC_DIS |
- RADEON_CRTC2_HSYNC_DIS));
+ ~(RADEON_CRTC2_DISP_DIS));
} else {
switch (info->DisplayType) {
case MT_LCD:
@@ -777,9 +741,7 @@ static void RADEONUnblank(ScrnInfoPtr pScrn)
case MT_CRT:
OUTREGP(RADEON_CRTC2_GEN_CNTL,
0,
- ~(RADEON_CRTC2_DISP_DIS |
- RADEON_CRTC2_VSYNC_DIS |
- RADEON_CRTC2_HSYNC_DIS));
+ ~(RADEON_CRTC2_DISP_DIS));
break;
case MT_NONE:
@@ -805,14 +767,338 @@ static int RADEONDiv(int n, int d)
return (n + (d / 2)) / d;
}
-/* Read the Video BIOS block and the FP registers (if applicable) */
-static Bool RADEONGetBIOSParameters(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
+static RADEONMonitorType RADEONDisplayDDCConnected(ScrnInfoPtr pScrn, RADEONDDCType DDCType, xf86MonPtr* MonInfo)
{
- RADEONInfoPtr info = RADEONPTR(pScrn);
- unsigned long tmp, i;
- unsigned char *RADEONMMIO;
- Bool BypassSecondary = FALSE;
- int CloneDispOption;
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ unsigned long DDCReg;
+ RADEONMonitorType MonType = MT_NONE;
+ int i, j;
+
+ DDCReg = info->DDCReg;
+ switch(DDCType)
+ {
+ case DDC_MONID:
+ info->DDCReg = RADEON_GPIO_MONID;
+ break;
+ case DDC_DVI:
+ info->DDCReg = RADEON_GPIO_DVI_DDC;
+ break;
+ case DDC_VGA:
+ info->DDCReg = RADEON_GPIO_VGA_DDC;
+ break;
+ case DDC_CRT2:
+ info->DDCReg = RADEON_GPIO_CRT2_DDC;
+ break;
+ default:
+ info->DDCReg = DDCReg;
+ 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));
+
+ /* For some old monitors (like Compaq Presario FP500), we need
+ * following process to initialize/stop DDC
+ */
+ OUTREG(info->DDCReg, INREG(info->DDCReg) & ~(RADEON_GPIO_EN_1));
+ for (j = 0; j < 3; j++) {
+ OUTREG(info->DDCReg,
+ INREG(info->DDCReg) & ~(RADEON_GPIO_EN_0));
+ usleep(13000);
+
+ OUTREG(info->DDCReg,
+ INREG(info->DDCReg) & ~(RADEON_GPIO_EN_1));
+ for (i = 0; i < 10; i++) {
+ usleep(15000);
+ if (INREG(info->DDCReg) & RADEON_GPIO_Y_1)
+ break;
+ }
+ if (i == 10) continue;
+
+ usleep(15000);
+
+ OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_0);
+ usleep(15000);
+
+ OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_1);
+ usleep(15000);
+ OUTREG(info->DDCReg,
+ INREG(info->DDCReg) & ~(RADEON_GPIO_EN_0));
+ usleep(15000);
+ *MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, info->pI2CBus);
+
+ OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_1);
+ OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_0);
+ usleep(15000);
+ OUTREG(info->DDCReg,
+ INREG(info->DDCReg) & ~(RADEON_GPIO_EN_1));
+ for (i = 0; i < 5; i++) {
+ usleep(15000);
+ if (INREG(info->DDCReg) & RADEON_GPIO_Y_1)
+ break;
+ }
+ usleep(15000);
+ OUTREG(info->DDCReg,
+ INREG(info->DDCReg) & ~(RADEON_GPIO_EN_0));
+ usleep(15000);
+
+ OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_1);
+ OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_0);
+ usleep(15000);
+ if(*MonInfo) break;
+ }
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "DDC2/I2C is not properly initialized\n");
+ MonType = MT_NONE;
+ }
+
+ if (*MonInfo) {
+ if ((*MonInfo)->rawData[0x14] & 0x80) {
+ if (INREG(RADEON_LVDS_GEN_CNTL) & RADEON_LVDS_ON) MonType = MT_LCD;
+ else MonType = MT_DFP;
+ } else MonType = MT_CRT;
+ } else MonType = MT_NONE;
+
+ info->DDCReg = DDCReg;
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "DDC Type: %d, Detected Type: %d\n", DDCType, MonType);
+
+ return MonType;
+}
+
+static RADEONMonitorType
+RADEONCrtIsPhysicallyConnected(ScrnInfoPtr pScrn, int IsCrtDac)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ int bConnected = 0;
+
+ /* the monitor either wasn't connected or it is a non-DDC CRT.
+ * try to probe it
+ */
+ if(IsCrtDac) {
+ unsigned long ulOrigVCLK_ECP_CNTL;
+ unsigned long ulOrigDAC_CNTL;
+ unsigned long ulOrigDAC_EXT_CNTL;
+ unsigned long ulOrigCRTC_EXT_CNTL;
+ unsigned long ulData;
+ unsigned long ulMask;
+
+ ulOrigVCLK_ECP_CNTL = INPLL(pScrn, RADEON_VCLK_ECP_CNTL);
+
+ ulData = ulOrigVCLK_ECP_CNTL;
+ ulData &= ~(RADEON_PIXCLK_ALWAYS_ONb
+ | RADEON_PIXCLK_DAC_ALWAYS_ONb);
+ ulMask = ~(RADEON_PIXCLK_ALWAYS_ONb
+ |RADEON_PIXCLK_DAC_ALWAYS_ONb);
+ OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, ulData, ulMask);
+
+ ulOrigCRTC_EXT_CNTL = INREG(RADEON_CRTC_EXT_CNTL);
+ ulData = ulOrigCRTC_EXT_CNTL;
+ ulData |= RADEON_CRTC_CRT_ON;
+ OUTREG(RADEON_CRTC_EXT_CNTL, ulData);
+
+ ulOrigDAC_EXT_CNTL = INREG(RADEON_DAC_EXT_CNTL);
+ ulData = ulOrigDAC_EXT_CNTL;
+ ulData &= ~RADEON_DAC_FORCE_DATA_MASK;
+ ulData |= (RADEON_DAC_FORCE_BLANK_OFF_EN
+ |RADEON_DAC_FORCE_DATA_EN
+ |RADEON_DAC_FORCE_DATA_SEL_MASK);
+ if ((info->ChipFamily == CHIP_FAMILY_RV250) ||
+ (info->ChipFamily == CHIP_FAMILY_RV280))
+ ulData |= (0x01b6 << RADEON_DAC_FORCE_DATA_SHIFT);
+ else
+ ulData |= (0x01ac << RADEON_DAC_FORCE_DATA_SHIFT);
+
+ OUTREG(RADEON_DAC_EXT_CNTL, ulData);
+
+ ulOrigDAC_CNTL = INREG(RADEON_DAC_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(1000);
+
+ ulData = INREG(RADEON_DAC_CNTL);
+ bConnected = (RADEON_DAC_CMP_OUTPUT & ulData)?1:0;
+
+ ulData = ulOrigVCLK_ECP_CNTL;
+ ulMask = 0xFFFFFFFFL;
+ OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL, ulData, ulMask);
+
+ OUTREG(RADEON_DAC_CNTL, ulOrigDAC_CNTL );
+ OUTREG(RADEON_DAC_EXT_CNTL, ulOrigDAC_EXT_CNTL );
+ OUTREG(RADEON_CRTC_EXT_CNTL, ulOrigCRTC_EXT_CNTL);
+ } else { /* TV DAC */
+
+ /* This doesn't seem to work reliably (maybe worse on some OEM cards),
+ for now we always return false. If one wants to connected a
+ non-DDC monitor on the DVI port when CRT port is also connected,
+ he will need to explicitly tell the driver in the config file
+ with Option MonitorLayout.
+ */
+ bConnected = FALSE;
+
+#if 0
+ if (info->ChipFamily == CHIP_FAMILY_R200) {
+
+ unsigned long ulOrigGPIO_MONID;
+ unsigned long ulOrigFP2_GEN_CNTL;
+ unsigned long ulOrigDISP_OUTPUT_CNTL;
+ unsigned long ulOrigCRTC2_GEN_CNTL;
+ unsigned long ulOrigDISP_LIN_TRANS_GRPH_A;
+ unsigned long ulOrigDISP_LIN_TRANS_GRPH_B;
+ unsigned long ulOrigDISP_LIN_TRANS_GRPH_C;
+ unsigned long ulOrigDISP_LIN_TRANS_GRPH_D;
+ unsigned long ulOrigDISP_LIN_TRANS_GRPH_E;
+ unsigned long ulOrigDISP_LIN_TRANS_GRPH_F;
+ unsigned long ulOrigCRTC2_H_TOTAL_DISP;
+ unsigned long ulOrigCRTC2_V_TOTAL_DISP;
+ unsigned long ulOrigCRTC2_H_SYNC_STRT_WID;
+ unsigned long ulOrigCRTC2_V_SYNC_STRT_WID;
+ unsigned long ulData, i;
+
+ ulOrigGPIO_MONID = INREG(RADEON_GPIO_MONID);
+ ulOrigFP2_GEN_CNTL = INREG(RADEON_FP2_GEN_CNTL);
+ ulOrigDISP_OUTPUT_CNTL = INREG(RADEON_DISP_OUTPUT_CNTL);
+ ulOrigCRTC2_GEN_CNTL = INREG(RADEON_CRTC2_GEN_CNTL);
+ ulOrigDISP_LIN_TRANS_GRPH_A = INREG(RADEON_DISP_LIN_TRANS_GRPH_A);
+ ulOrigDISP_LIN_TRANS_GRPH_B = INREG(RADEON_DISP_LIN_TRANS_GRPH_B);
+ ulOrigDISP_LIN_TRANS_GRPH_C = INREG(RADEON_DISP_LIN_TRANS_GRPH_C);
+ ulOrigDISP_LIN_TRANS_GRPH_D = INREG(RADEON_DISP_LIN_TRANS_GRPH_D);
+ ulOrigDISP_LIN_TRANS_GRPH_E = INREG(RADEON_DISP_LIN_TRANS_GRPH_E);
+ ulOrigDISP_LIN_TRANS_GRPH_F = INREG(RADEON_DISP_LIN_TRANS_GRPH_F);
+
+ ulOrigCRTC2_H_TOTAL_DISP = INREG(RADEON_CRTC2_H_TOTAL_DISP);
+ ulOrigCRTC2_V_TOTAL_DISP = INREG(RADEON_CRTC2_V_TOTAL_DISP);
+ ulOrigCRTC2_H_SYNC_STRT_WID = INREG(RADEON_CRTC2_H_SYNC_STRT_WID);
+ ulOrigCRTC2_V_SYNC_STRT_WID = INREG(RADEON_CRTC2_V_SYNC_STRT_WID);
+
+ ulData = INREG(RADEON_GPIO_MONID);
+ ulData &= ~RADEON_GPIO_A_0;
+ OUTREG(RADEON_GPIO_MONID, ulData);
+
+ OUTREG(RADEON_FP2_GEN_CNTL, 0x0a000c0c);
+
+ OUTREG(RADEON_DISP_OUTPUT_CNTL, 0x00000012);
+
+ OUTREG(RADEON_CRTC2_GEN_CNTL, 0x06000000);
+ OUTREG(RADEON_DISP_LIN_TRANS_GRPH_A, 0x00000000);
+ OUTREG(RADEON_DISP_LIN_TRANS_GRPH_B, 0x000003f0);
+ OUTREG(RADEON_DISP_LIN_TRANS_GRPH_C, 0x00000000);
+ OUTREG(RADEON_DISP_LIN_TRANS_GRPH_D, 0x000003f0);
+ OUTREG(RADEON_DISP_LIN_TRANS_GRPH_E, 0x00000000);
+ OUTREG(RADEON_DISP_LIN_TRANS_GRPH_F, 0x000003f0);
+ OUTREG(RADEON_CRTC2_H_TOTAL_DISP, 0x01000008);
+ OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, 0x00000800);
+ OUTREG(RADEON_CRTC2_V_TOTAL_DISP, 0x00080001);
+ OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, 0x00000080);
+
+ for (i = 0; i < 200; i++) {
+ ulData = INREG(RADEON_GPIO_MONID);
+ bConnected = (ulData & RADEON_GPIO_Y_0)?1:0;
+ if (!bConnected) break;
+
+ usleep(1000);
+ }
+
+ OUTREG(RADEON_DISP_LIN_TRANS_GRPH_A, ulOrigDISP_LIN_TRANS_GRPH_A);
+ OUTREG(RADEON_DISP_LIN_TRANS_GRPH_B, ulOrigDISP_LIN_TRANS_GRPH_B);
+ OUTREG(RADEON_DISP_LIN_TRANS_GRPH_C, ulOrigDISP_LIN_TRANS_GRPH_C);
+ OUTREG(RADEON_DISP_LIN_TRANS_GRPH_D, ulOrigDISP_LIN_TRANS_GRPH_D);
+ OUTREG(RADEON_DISP_LIN_TRANS_GRPH_E, ulOrigDISP_LIN_TRANS_GRPH_E);
+ OUTREG(RADEON_DISP_LIN_TRANS_GRPH_F, ulOrigDISP_LIN_TRANS_GRPH_F);
+ OUTREG(RADEON_CRTC2_H_TOTAL_DISP, ulOrigCRTC2_H_TOTAL_DISP);
+ OUTREG(RADEON_CRTC2_V_TOTAL_DISP, ulOrigCRTC2_V_TOTAL_DISP);
+ OUTREG(RADEON_CRTC2_H_SYNC_STRT_WID, ulOrigCRTC2_H_SYNC_STRT_WID);
+ OUTREG(RADEON_CRTC2_V_SYNC_STRT_WID, ulOrigCRTC2_V_SYNC_STRT_WID);
+ OUTREG(RADEON_CRTC2_GEN_CNTL, ulOrigCRTC2_GEN_CNTL);
+ OUTREG(RADEON_DISP_OUTPUT_CNTL, ulOrigDISP_OUTPUT_CNTL);
+ OUTREG(RADEON_FP2_GEN_CNTL, ulOrigFP2_GEN_CNTL);
+ OUTREG(RADEON_GPIO_MONID, ulOrigGPIO_MONID);
+ } else {
+ unsigned long ulOrigPIXCLKSDATA;
+ unsigned long ulOrigTV_MASTER_CNTL;
+ unsigned long ulOrigTV_DAC_CNTL;
+ unsigned long ulOrigTV_PRE_DAC_MUX_CNTL;
+ unsigned long ulOrigDAC_CNTL2;
+ unsigned long ulData;
+ unsigned long ulMask;
+
+ ulOrigPIXCLKSDATA = INPLL(pScrn, RADEON_PIXCLKS_CNTL);
+
+ ulData = ulOrigPIXCLKSDATA;
+ ulData &= ~(RADEON_PIX2CLK_ALWAYS_ONb
+ | RADEON_PIX2CLK_DAC_ALWAYS_ONb);
+ ulMask = ~(RADEON_PIX2CLK_ALWAYS_ONb
+ | RADEON_PIX2CLK_DAC_ALWAYS_ONb);
+ OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, ulData, ulMask);
+
+ ulOrigTV_MASTER_CNTL = INREG(RADEON_TV_MASTER_CNTL);
+ ulData = ulOrigTV_MASTER_CNTL;
+ ulData &= ~RADEON_TVCLK_ALWAYS_ONb;
+ OUTREG(RADEON_TV_MASTER_CNTL, ulData);
+
+ ulOrigDAC_CNTL2 = INREG(RADEON_DAC_CNTL2);
+ ulData = ulOrigDAC_CNTL2;
+ ulData &= ~RADEON_DAC2_DAC2_CLK_SEL;
+ OUTREG(RADEON_DAC_CNTL2, ulData);
+
+ ulOrigTV_DAC_CNTL = INREG(RADEON_TV_DAC_CNTL);
+
+ ulData = 0x00880213;
+ OUTREG(RADEON_TV_DAC_CNTL, ulData);
+
+ ulOrigTV_PRE_DAC_MUX_CNTL = INREG(RADEON_TV_PRE_DAC_MUX_CNTL);
+
+ ulData = (RADEON_Y_RED_EN
+ | RADEON_C_GRN_EN
+ | RADEON_CMP_BLU_EN
+ | RADEON_RED_MX_FORCE_DAC_DATA
+ | RADEON_GRN_MX_FORCE_DAC_DATA
+ | RADEON_BLU_MX_FORCE_DAC_DATA);
+ if ((info->ChipFamily == CHIP_FAMILY_R300) ||
+ (info->ChipFamily == CHIP_FAMILY_R350) ||
+ (info->ChipFamily == CHIP_FAMILY_RV350))
+ ulData |= 0x180 << RADEON_TV_FORCE_DAC_DATA_SHIFT;
+ else
+ ulData |= 0x1f5 << RADEON_TV_FORCE_DAC_DATA_SHIFT;
+ OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, ulData);
+
+ usleep(1000);
+
+ ulData = INREG(RADEON_TV_DAC_CNTL);
+ bConnected = (ulData & RADEON_TV_DAC_CMPOUT)?1:0;
+
+ ulData = ulOrigPIXCLKSDATA;
+ ulMask = 0xFFFFFFFFL;
+ OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, ulData, ulMask);
+
+ OUTREG(RADEON_TV_MASTER_CNTL, ulOrigTV_MASTER_CNTL);
+ OUTREG(RADEON_DAC_CNTL2, ulOrigDAC_CNTL2);
+ OUTREG(RADEON_TV_DAC_CNTL, ulOrigTV_DAC_CNTL);
+ OUTREG(RADEON_TV_PRE_DAC_MUX_CNTL, ulOrigTV_PRE_DAC_MUX_CNTL);
+ }
+#endif
+ }
+
+ return(bConnected ? MT_CRT : MT_NONE);
+}
+
+static void RADEONQueryConnectedDisplays(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ const char *s;
+ Bool ignore_edid = FALSE, ddc_crt2_used = FALSE;
#define RADEON_BIOS8(v) (info->VBIOS[v])
#define RADEON_BIOS16(v) (info->VBIOS[v] | \
@@ -822,6 +1108,303 @@ static Bool RADEONGetBIOSParameters(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
(info->VBIOS[(v) + 2] << 16) | \
(info->VBIOS[(v) + 3] << 24))
+ pRADEONEnt->MonType1 = MT_NONE;
+ pRADEONEnt->MonType2 = MT_NONE;
+ pRADEONEnt->MonInfo1 = NULL;
+ pRADEONEnt->MonInfo2 = NULL;
+ pRADEONEnt->ReversedDAC = FALSE;
+ pRADEONEnt->ReversedTMDS = FALSE;
+
+ /* IgnoreEDID option is different from NoDDC options used by DDC module
+ * When IgnoreEDID is used, monitor detection will still use DDC
+ * detection, but all EDID data will not be used in mode validation.
+ */
+ if (xf86GetOptValBool(info->Options, OPTION_IGNORE_EDID, &ignore_edid)) {
+ if (ignore_edid)
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+ "IgnoreEDID is specified, EDID data will be ignored\n");
+ }
+
+ /*
+ * MonitorLayout option takes a string for two monitors connected in following format:
+ * Option "MonitorLayout" "primary-port-display, secondary-port-display"
+ * primary and secondary port displays can have one of following:
+ * NONE, CRT, LVDS, TMDS
+ * With this option, driver will bring up monitors as specified,
+ * not using auto-detection routines to probe monitors.
+ */
+
+ /* current monitor mapping scheme:
+ * Two displays connected:
+ * Primary Port:
+ * CRTC1 -> FP/TMDS -> DVI port -> TMDS panel --> Primary or
+ * CRTC1 -> FP/LVDS -> Int. LCD -> LVDS panel --> Primary or
+ * CRTC1 -> TV DAC -> DVI port -> CRT monitor --> Primary
+ *
+ * Secondary Port
+ * CRTC2 -> CRT DAC -> VGA port -> CRT monitor --> Secondary or
+ * CRTC2 -> FP2/Ext. -> DVI port -> TMDS panel --> Secondary
+ *
+ * Only DVI (or Int. LDC) conneced:
+ * CRTC1 -> FP/TMDS -> DVI port -> TMDS panel --> Primary or
+ * CRTC1 -> FP/LVDS -> Int. LCD -> LVDS panel --> Primary or
+ * CRTC1 -> TV DAC -> DVI port -> CRT monitor --> Primary
+ *
+ * Only VGA (can be DVI on some dual-DVI boards) connected:
+ * CRTC1 -> CRT DAC -> VGA port -> CRT monitor --> Primary or
+ * CRTC1 -> FP2/Ext. -> DVI port -> TMDS panel --> Primary (not supported)
+ *
+ * Note, this is different from Windows scheme where
+ * if a digital panel is connected to DVI port, DVI will be the 1st port
+ * otherwise, VGA port will be treated as 1st port
+ *
+ * Here we always treat DVI port as primary if both ports are connected.
+ * When only one port is connected, it will be treated as
+ * primary regardless which port or what type of display is involved.
+ */
+
+ if ((s = xf86GetOptValString(info->Options, OPTION_MONITOR_LAYOUT))) {
+ char s1[5], s2[5];
+ int i = 0, second = 0;
+
+ /* When using user specified monitor types, we will not do DDC detection
+ *
+ */
+ do {
+ switch(*s)
+ {
+ case ',':
+ s1[i] = '\0';
+ i = 0;
+ second = 1;
+ break;
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ break;
+ default:
+ if (second)
+ s2[i] = *s;
+ else
+ s1[i] = *s;
+ i++;
+ if (i == 4) break;
+ }
+ } while(*s++);
+ s2[i] = '\0';
+
+ if (strcmp(s1, "NONE") == 0)
+ pRADEONEnt->MonType1 = MT_NONE;
+ else if (strcmp(s1, "CRT") == 0)
+ pRADEONEnt->MonType1 = MT_CRT;
+ else if (strcmp(s1, "TMDS") == 0)
+ pRADEONEnt->MonType1 = MT_DFP;
+ else if (strcmp(s1, "LVDS") == 0)
+ pRADEONEnt->MonType1 = MT_LCD;
+ else
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "Invalid Monitor type specified for 1st port \n");
+ if (strcmp(s2, "NONE") == 0)
+ pRADEONEnt->MonType2 = MT_NONE;
+ else if (strcmp(s2, "CRT") == 0)
+ pRADEONEnt->MonType2 = MT_CRT;
+ else if (strcmp(s2, "TMDS") == 0)
+ pRADEONEnt->MonType2 = MT_DFP;
+ else if (strcmp(s2, "LVDS") == 0)
+ pRADEONEnt->MonType2 = MT_LCD;
+ else
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "Invalid Monitor type specified for 2nd port \n");
+
+ if (!ignore_edid) {
+ if (pRADEONEnt->MonType1) /* assuming the first port using DDC_DVI */
+ if(!RADEONDisplayDDCConnected(pScrn, DDC_DVI, &pRADEONEnt->MonInfo1)) {
+ RADEONDisplayDDCConnected(pScrn, DDC_CRT2, &pRADEONEnt->MonInfo1);
+ ddc_crt2_used = TRUE;
+ }
+ if (pRADEONEnt->MonType2) { /* assuming the second port using DDC_VGA/DDC_CRT2 */
+ if(!RADEONDisplayDDCConnected(pScrn, DDC_VGA, &pRADEONEnt->MonInfo2))
+ if (!ddc_crt2_used)
+ RADEONDisplayDDCConnected(pScrn, DDC_CRT2, &pRADEONEnt->MonInfo2);
+ }
+ }
+
+ if (!pRADEONEnt->MonType1) {
+ if (pRADEONEnt->MonType2) {
+ pRADEONEnt->MonType1 = pRADEONEnt->MonType2;
+ pRADEONEnt->MonInfo1 = pRADEONEnt->MonInfo2;
+ } else {
+ pRADEONEnt->MonType1 = MT_CRT;
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "No valid monitor specified, force to CRT on 1st port\n");
+ }
+ pRADEONEnt->MonType2 = MT_NONE;
+ pRADEONEnt->MonInfo2 = NULL;
+ }
+ } else {
+ /* Auto detection */
+ int i;
+ CARD32 tmp;
+
+ /* Old single head radeon cards */
+ if(!info->HasCRTC2) {
+ if((pRADEONEnt->MonType1 = RADEONDisplayDDCConnected(pScrn, DDC_DVI, &pRADEONEnt->MonInfo1)));
+ else if((pRADEONEnt->MonType1 = RADEONDisplayDDCConnected(pScrn, DDC_VGA, &pRADEONEnt->MonInfo1)));
+ else if((pRADEONEnt->MonType1 = RADEONDisplayDDCConnected(pScrn, DDC_CRT2, &pRADEONEnt->MonInfo1)));
+ else if (pInt10) {
+ if (xf86LoadSubModule(pScrn, "vbe")) {
+ vbeInfoPtr pVbe;
+ pVbe = VBEInit(pInt10, info->pEnt->index);
+ if (pVbe) {
+ for (i = 0; i < 5; i++) {
+ pRADEONEnt->MonInfo1 = vbeDoEDID(pVbe, NULL);
+ }
+ if (pRADEONEnt->MonInfo1->rawData[0x14] & 0x80)
+ pRADEONEnt->MonType1 = MT_DFP;
+ else pRADEONEnt->MonType1 = MT_CRT;
+ }
+ }
+ } else
+ pRADEONEnt->MonType1 = MT_CRT;
+
+ pRADEONEnt->HasSecondary = FALSE;
+ if (!ignore_edid) {
+ if (pRADEONEnt->MonInfo1) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitor1 EDID data ---------------------------\n");
+ xf86PrintEDID( pRADEONEnt->MonInfo1 );
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "End of Monitor1 EDID data --------------------\n");
+ }
+ }
+ return;
+ }
+
+ /* Normally the port uses DDC_DVI connected with TVDAC,
+ * But this is not true for OEM cards which have TVDAC and CRT DAC reversed.
+ * If that's the case, we need also reverse the port arrangement.
+ * BIOS settings are supposed report this correctly, work fine for all cards tested.
+ * But there may be some exceptions, in that case, user can reverse their monitor
+ * definition in config file to correct the problem.
+ */
+ if (info->VBIOS && (tmp = RADEON_BIOS16(info->FPBIOSstart + 0x50))) {
+ for (i = 1; i < 4; i++) {
+ unsigned int tmp0;
+ if (!RADEON_BIOS8(tmp + i*2) && i > 1) break;
+ tmp0 = RADEON_BIOS16(tmp + i*2);
+ if ((!(tmp0 & 0x01)) && (((tmp0 >> 8) & 0xf) == DDC_DVI)) {
+ pRADEONEnt->ReversedDAC = TRUE;
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Reversed DACs detected\n");
+ }
+ if ((((tmp0 >> 8) & 0x0f) == DDC_DVI ) && ((tmp0 >> 4) & 0x1)) {
+ pRADEONEnt->ReversedTMDS = TRUE;
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Reversed TMDS detected\n");
+ }
+ }
+ }
+
+ /* Primary Head (DVI or Laptop Int. panel)*/
+ /* A ddc capable display connected on DVI port */
+ if((pRADEONEnt->MonType1 = RADEONDisplayDDCConnected(pScrn, DDC_DVI, &pRADEONEnt->MonInfo1)));
+ else if((pRADEONEnt->MonType1 =
+ RADEONDisplayDDCConnected(pScrn, DDC_CRT2, &pRADEONEnt->MonInfo1))) {
+ ddc_crt2_used = TRUE;
+ } else if ((info->IsMobility) &&
+ (info->VBIOS && (INREG(RADEON_BIOS_4_SCRATCH) & 4))) {
+ /* non-DDC laptop panel connected on primary */
+ pRADEONEnt->MonType1 = MT_LCD;
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Non-DDC laptop panel detected\n");
+ } else {
+ /* CRT on DVI, TODO: not reliable, make it always return false for now*/
+ pRADEONEnt->MonType1 = RADEONCrtIsPhysicallyConnected(pScrn, pRADEONEnt->ReversedDAC);
+ }
+
+ /* Secondary Head (mostly VGA, can be DVI on some OEM boards)*/
+ if((pRADEONEnt->MonType2 =
+ RADEONDisplayDDCConnected(pScrn, DDC_VGA, &pRADEONEnt->MonInfo2)));
+ else if(!ddc_crt2_used)
+ pRADEONEnt->MonType2 =
+ RADEONDisplayDDCConnected(pScrn, DDC_CRT2, &pRADEONEnt->MonInfo2);
+ if (!pRADEONEnt->MonType2)
+ pRADEONEnt->MonType2 = RADEONCrtIsPhysicallyConnected(pScrn, !pRADEONEnt->ReversedDAC);
+
+ if(pRADEONEnt->ReversedTMDS) {
+ /* always keep internal TMDS as primary head */
+ if (pRADEONEnt->MonType1 == MT_DFP ||
+ pRADEONEnt->MonType2 == MT_DFP) {
+ int tmp1 = pRADEONEnt->MonType1;
+ xf86MonPtr MonInfo = pRADEONEnt->MonInfo1;
+ pRADEONEnt->MonInfo1 = pRADEONEnt->MonInfo2;
+ pRADEONEnt->MonInfo2 = MonInfo;
+ pRADEONEnt->MonType1 = pRADEONEnt->MonType2;
+ pRADEONEnt->MonType2 = tmp1;
+ if ((pRADEONEnt->MonType1 == MT_CRT) ||
+ (pRADEONEnt->MonType2 == MT_CRT)) {
+ pRADEONEnt->ReversedDAC ^= 1;
+ }
+ }
+ }
+
+ /* no display detected on DVI port*/
+ if (pRADEONEnt->MonType1 == MT_NONE) {
+ if (pRADEONEnt->MonType2 != MT_NONE) {
+ /* Only one detected on VGA, let it to be primary */
+ pRADEONEnt->MonType1 = pRADEONEnt->MonType2;
+ pRADEONEnt->MonInfo1 = pRADEONEnt->MonInfo2;
+ pRADEONEnt->MonType2 = MT_NONE;
+ pRADEONEnt->MonInfo2 = NULL;
+ } else {
+ /* Non detected, Default to a CRT connected */
+ pRADEONEnt->MonType1 = MT_CRT;
+ }
+ }
+ }
+
+ if(s) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Displays Configured by MonitorLayout: \n\tMonitor1--Type %d, Monitor2--Type %d\n\n",
+ pRADEONEnt->MonType1, pRADEONEnt->MonType2);
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Displays Detected: Monitor1--Type %d, Monitor2--Type %d\n\n",
+ pRADEONEnt->MonType1, pRADEONEnt->MonType2);
+ }
+
+ if(ignore_edid) {
+ pRADEONEnt->MonInfo1 = NULL;
+ pRADEONEnt->MonInfo2 = NULL;
+ }
+
+ if (!ignore_edid) {
+ if (pRADEONEnt->MonInfo1) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitor1 EDID data ---------------------------\n");
+ xf86PrintEDID( pRADEONEnt->MonInfo1 );
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "End of Monitor1 EDID data --------------------\n");
+ }
+ if (pRADEONEnt->MonInfo2) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitor2 EDID data ---------------------------\n");
+ xf86PrintEDID( pRADEONEnt->MonInfo2 );
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "End of Monitor2 EDID data --------------------\n");
+ }
+ }
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "\n");
+
+ info->OverlayOnCRTC2 = FALSE;
+ if (xf86ReturnOptValBool(info->Options, OPTION_CRTC2_OVERLAY, FALSE)) {
+ info->OverlayOnCRTC2 = TRUE;
+ }
+
+ if (pRADEONEnt->MonType2 == MT_NONE)
+ pRADEONEnt->HasSecondary = FALSE;
+}
+
+
+/* Read the Video BIOS block and the FP registers (if applicable). */
+static Bool RADEONGetBIOSParameters(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned long tmp, i;
+
if (!(info->VBIOS = xalloc(RADEON_VBIOS_SIZE))) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Cannot allocate space for hold Video BIOS!\n");
@@ -848,334 +1431,338 @@ static Bool RADEONGetBIOSParameters(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
if (info->VBIOS[0] != 0x55 || info->VBIOS[1] != 0xaa) {
xfree(info->VBIOS);
+ info->FPBIOSstart = 0;
info->VBIOS = NULL;
info->BIOSAddr = 0x00000000;
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Video BIOS not found!\n");
- return TRUE;
- }
-
- info->FPBIOSstart = RADEON_BIOS16(0x48);
+ } else
+ info->FPBIOSstart = RADEON_BIOS16(0x48);
info->OverlayOnCRTC2 = FALSE;
- RADEONMapMMIO(pScrn);
- RADEONMMIO = info->MMIO;
+ if (!info->IsSecondary)
+ RADEONQueryConnectedDisplays(pScrn, pInt10);
- /* FIXME: using BIOS scratch registers to detect connected monitors
- * may not be a reliable way.... should use EDID data. Also it only
- * works with for VE/M6, no such registers in regular RADEON!!!
- */
-
- /* VE and M6 have both DVI and CRT ports (for M6 DVI port can be
- * switch to DFP port). The DVI port can also be conneted to a CRT
- * with an adapter. Here is the definition of ports for this
- * driver:
- *
- * (1) If both port are connected, DVI port will be treated as the
- * Primary port (first screen in XF86Config, uses CRTC1) and CRT
- * port will be treated as the Secondary port (second screen in
- * XF86Config, uses CRTC2)
- *
- * (2) If only one screen specified in XF86Config, it will be used
- * for DVI port if a monitor is connected to DVI port, otherwise
- * (only one monitor is connected the CRT port) it will be used for
- * CRT port.
- */
+ {
+ RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
- if (info->HasCRTC2) {
- /* FIXME: this may not be reliable */
- tmp = INREG(RADEON_BIOS_4_SCRATCH);
+ info->Clone = FALSE;
+ info->CloneType = MT_NONE;
- if (info->IsSecondary) {
- /* Check Port2 (CRT port) -- for the existing boards (VE &
- * M6), this port can only be connected to a CRT
- */
- if (tmp & 0x02) info->DisplayType = MT_CRT;
- else if (tmp & 0x800) info->DisplayType = MT_DFP;
- else if (tmp & 0x400) info->DisplayType = MT_LCD;
- else if (tmp & 0x1000) info->DisplayType = MT_CTV;
- else if (tmp & 0x2000) info->DisplayType = MT_STV;
- else info->DisplayType = MT_CRT;
+ if(info->HasCRTC2) {
+ if(info->IsSecondary) {
+ info->DisplayType = (RADEONMonitorType)pRADEONEnt->MonType2;
+ if(info->DisplayType == MT_NONE) return FALSE;
+ } else {
+ info->DisplayType = (RADEONMonitorType)pRADEONEnt->MonType1;
+ if(!pRADEONEnt->HasSecondary) {
+ info->CloneType = (RADEONMonitorType)pRADEONEnt->MonType2;
+ if (info->CloneType != MT_NONE)
+ info->Clone = TRUE;
+ }
+ }
} else {
- info->Clone = FALSE;
- info->CloneType = MT_NONE;
-
- /* Check Primary (DVI/DFP port) */
- if (tmp & 0x08) info->DisplayType = MT_DFP;
- else if (tmp & 0x04) info->DisplayType = MT_LCD;
- else if (tmp & 0x0200) info->DisplayType = MT_CRT;
- else if (tmp & 0x10) info->DisplayType = MT_CTV;
- else if (tmp & 0x20) info->DisplayType = MT_STV;
- else info->DisplayType = MT_NONE;
-
- if (info->DisplayType == MT_NONE) {
- /* DVI port has no monitor connected, try CRT port.
- * If something on CRT port, treat it as primary
+ info->DisplayType = (RADEONMonitorType)pRADEONEnt->MonType1;
+ }
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s Display == Type %d\n",
+ (info->IsSecondary ? "Secondary" : "Primary"),
+ info->DisplayType);
+
+ if (info->Clone)
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Clone Display == Type %d\n",
+ info->CloneType);
+
+ info->HBlank = 0;
+ info->HOverPlus = 0;
+ info->HSyncWidth = 0;
+ info->VBlank = 0;
+ info->VOverPlus = 0;
+ info->VSyncWidth = 0;
+ info->DotClock = 0;
+ info->UseBiosDividers = FALSE;
+
+ if (info->DisplayType == MT_LCD && info->VBIOS &&
+ !(xf86GetOptValString(info->Options, OPTION_PANEL_SIZE))) {
+ tmp = RADEON_BIOS16(info->FPBIOSstart + 0x40);
+ if (!tmp) {
+ info->PanelPwrDly = 200;
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "No Panel Info Table found in BIOS!\n");
+ } else {
+ char stmp[30];
+ int tmp0;
+
+ for (i = 0; i < 24; i++)
+ stmp[i] = RADEON_BIOS8(tmp+i+1);
+ stmp[24] = 0;
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Panel ID string: %s\n", stmp);
+
+ info->PanelXRes = RADEON_BIOS16(tmp+25);
+ info->PanelYRes = RADEON_BIOS16(tmp+27);
+ xf86DrvMsg(0, X_INFO, "Panel Size from BIOS: %dx%d\n",
+ info->PanelXRes, info->PanelYRes);
+
+ info->PanelPwrDly = RADEON_BIOS16(tmp+44);
+ if (info->PanelPwrDly > 2000 || info->PanelPwrDly < 0)
+ info->PanelPwrDly = 2000;
+
+ /* some panels only work well with certain divider combinations.
*/
- if (xf86IsEntityShared(pScrn->entityList[0])) {
- DevUnion *pPriv;
- RADEONEntPtr pRADEONEnt;
-
- pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
- gRADEONEntityIndex);
- pRADEONEnt = pPriv->ptr;
- pRADEONEnt->BypassSecondary = TRUE;
+ info->RefDivider = RADEON_BIOS16(tmp+46);
+ info->PostDivider = RADEON_BIOS8(tmp+48);
+ info->FeedbackDivider = RADEON_BIOS16(tmp+49);
+ if ((info->RefDivider != 0) &&
+ (info->FeedbackDivider > 3)) {
+ info->UseBiosDividers = TRUE;
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "BIOS provided dividers will be used.\n");
}
- if (tmp & 0x02) info->DisplayType = MT_CRT;
- else if (tmp & 0x800) info->DisplayType = MT_DFP;
- else if (tmp & 0x400) info->DisplayType = MT_LCD;
- else if (tmp & 0x1000) info->DisplayType = MT_CTV;
- else if (tmp & 0x2000) info->DisplayType = MT_STV;
- else {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "No monitor detected!!!\n");
- return FALSE;
+ /* We don't use a while loop here just in case we have a corrupted BIOS image.
+ The max number of table entries is 23 at present, but may grow in future.
+ To ensure it works with future revisions we loop it to 32.
+ */
+ for (i = 0; i < 32; i++) {
+ tmp0 = RADEON_BIOS16(tmp+64+i*2);
+ if (tmp0 == 0) break;
+ if ((RADEON_BIOS16(tmp0) == info->PanelXRes) &&
+ (RADEON_BIOS16(tmp0+2) == info->PanelYRes)) {
+ info->HBlank = (RADEON_BIOS16(tmp0+17) -
+ RADEON_BIOS16(tmp0+19)) * 8;
+ info->HOverPlus = (RADEON_BIOS16(tmp0+21) -
+ RADEON_BIOS16(tmp0+19) - 1) * 8;
+ info->HSyncWidth = RADEON_BIOS8(tmp0+23) * 8;
+ info->VBlank = (RADEON_BIOS16(tmp0+24) -
+ RADEON_BIOS16(tmp0+26));
+ info->VOverPlus = ((RADEON_BIOS16(tmp0+28) & 0x7ff) -
+ RADEON_BIOS16(tmp0+26));
+ info->VSyncWidth = ((RADEON_BIOS16(tmp0+28) & 0xf800) >> 11);
+ info->DotClock = RADEON_BIOS16(tmp0+9) * 10;
+ info->Flags = 0;
+ }
}
- BypassSecondary = TRUE;
- } else {
- if (tmp & 0x02) {
- info->CloneType = MT_CRT;
- info->Clone = TRUE;
- } else if (tmp & 0x800) {
- info->CloneType = MT_DFP;
- info->Clone = TRUE;
+
+ if (info->DotClock == 0) {
+ 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) &&
+ (tmp_mode->VDisplay == info->PanelYRes)) {
+
+ float refresh =
+ (float)tmp_mode->Clock * 1000.0 / tmp_mode->HTotal / tmp_mode->VTotal;
+ if ((abs(60.0 - refresh) < 1.0) ||
+ (tmp_mode->type == 0)) {
+ info->HBlank = tmp_mode->HTotal - tmp_mode->HDisplay;
+ info->HOverPlus = tmp_mode->HSyncStart - tmp_mode->HDisplay;
+ info->HSyncWidth = tmp_mode->HSyncEnd - tmp_mode->HSyncStart;
+ info->VBlank = tmp_mode->VTotal - tmp_mode->VDisplay;
+ info->VOverPlus = tmp_mode->VSyncStart - tmp_mode->VDisplay;
+ info->VSyncWidth = tmp_mode->VSyncEnd - tmp_mode->VSyncStart;
+ info->DotClock = tmp_mode->Clock;
+ info->Flags = 0;
+ break;
+ }
+ tmp_mode = tmp_mode->next;
+ }
+ }
+ if ((info->DotClock == 0) && !pRADEONEnt->MonInfo1) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Panel size is not correctly detected.\n"
+ "Please try to use PanelSize option for correct settings.\n");
+ return FALSE;
+ }
}
}
+ }
+ }
- /* FIXME: This option is too complicated. We need to
- * find a better way to handle all cases.
- *
- * CloneDisplay options:
- * 0 -- disable
- * 1 -- auto-detect (default)
- * 2 -- force on
- * 3 -- auto-detect + 2nd head overlay.
- * 4 -- force on + 2nd head overlay.
- * others -- auto-detect
- *
- * Force on: it will force the clone mode on even no display
- * is detected. With this option together with the proper
- * CloneHSync and CloneVRefresh options, we can turn on the
- * CRT ouput on the 2nd head regardless if a monitor is
- * connected there. This way, we can plug in a CRT to the
- * second head later after X server has started.
- *
- * 2nd head overlay: it will force the hardware overlay on
- * CRTC2 (used by 2nd head). Since we only have one overlay,
- * we have to decide which head to use it (the overlay space
- * on the other head will be blank). 2nd head overlay is on
- * automatically when PanelOff option is effective.
- */
- if (xf86GetOptValInteger(info->Options, OPTION_CLONE_DISPLAY,
- &(CloneDispOption))) {
- char *s = NULL;
+ if (info->VBIOS) {
+ tmp = RADEON_BIOS16(info->FPBIOSstart + 0x30);
+ info->sclk = RADEON_BIOS16(tmp + 8) / 100.0;
+ info->mclk = RADEON_BIOS16(tmp + 10) / 100.0;
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No valid info for SCLK/MCLK for display bandwidth calculation.\n");
+ info->sclk = 200.00;
+ info->mclk = 200.00;
+ }
- if (CloneDispOption < 0 || CloneDispOption > 4) {
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "Illegal CloneDisplay Option set, "
- "using default\n");
- CloneDispOption = 1;
- }
+ return TRUE;
+}
- switch (CloneDispOption) {
- case 0: s = "Disable"; break;
- case 1: s = "Auto-detect"; break;
- case 2: s = "Force On"; break;
- case 3: s = "Auto-detect -- use 2nd head overlay"; break;
- case 4: s = "Force On -- use 2nd head overlay"; break;
- }
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "CloneDisplay option: %s (%d)\n",
- s, CloneDispOption);
- } else {
- /* Default to auto-detect */
- CloneDispOption = 1;
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "CloneDisplay option not set -- "
- "defaulting to auto-detect\n");
- }
+static Bool RADEONProbePLLParameters(ScrnInfoPtr pScrn)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ RADEONPLLPtr pll = &info->pll;
+ unsigned char *RADEONMMIO = info->MMIO;
+ unsigned char ppll_div_sel;
+ unsigned Nx, M;
+ unsigned xclk, tmp, ref_div;
+ int hTotal, vTotal, num, denom, m, n;
+ float hz, vclk, xtal;
+ 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)
+ break;
- if (CloneDispOption == 0) {
- info->Clone = FALSE;
- } else if ((CloneDispOption == 2 || CloneDispOption == 4)
- && !info->Clone) {
- info->CloneType = MT_CRT;
- info->Clone = TRUE;
- }
+ xf86getsecs(&start_secs, &start_usecs);
- /* This will be used to set OV0_SCALAR_CNTL */
- if (info->Clone && (CloneDispOption == 3 || CloneDispOption == 4))
- info->OverlayOnCRTC2 = TRUE;
- }
- } else {
- /* Regular Radeon ASIC, only one CRTC, but it could be used for
- * DFP with a DVI output, like AIW board
- */
- tmp = INREG(RADEON_FP_GEN_CNTL);
- if (tmp & RADEON_FP_EN_TMDS) 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);
-
- RADEONMMIO = NULL;
- RADEONUnmapMMIO(pScrn);
-
- info->HBlank = 0;
- info->HOverPlus = 0;
- info->HSyncWidth = 0;
- info->VBlank = 0;
- info->VOverPlus = 0;
- info->VSyncWidth = 0;
- info->DotClock = 0;
-
- if (info->DisplayType == MT_LCD) {
- tmp = RADEON_BIOS16(info->FPBIOSstart + 0x40);
- if (!tmp) {
- info->PanelPwrDly = 200;
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "No Panel Info Table found in BIOS!\n");
- } else {
- char stmp[30];
- int tmp0;
+ for(i=0; i<1000000; i++)
+ if (((INREG(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) != 0)
+ break;
- for (i = 0; i < 24; i++)
- stmp[i] = RADEON_BIOS8(tmp+i+1);
- stmp[24] = 0;
+ for(i=0; i<1000000; i++)
+ if (((INREG(RADEON_CRTC_VLINE_CRNT_VLINE) >> 16) & 0x3ff) == 0)
+ break;
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "Panel ID string: %s\n", stmp);
+ xf86getsecs(&stop_secs, &stop_usecs);
- info->PanelXRes = RADEON_BIOS16(tmp+25);
- info->PanelYRes = RADEON_BIOS16(tmp+27);
- xf86DrvMsg(0, X_INFO, "Panel Size from BIOS: %dx%d\n",
- info->PanelXRes, info->PanelYRes);
+ total_usecs = abs(stop_usecs - start_usecs);
+ hz = 1000000/total_usecs;
- info->PanelPwrDly = RADEON_BIOS16(tmp+44);
- if (info->PanelPwrDly > 2000 || info->PanelPwrDly < 0)
- info->PanelPwrDly = 2000;
- for (i = 0; i < 20; i++) {
- tmp0 = RADEON_BIOS16(tmp+64+i*2);
- if (tmp0 == 0) break;
- if ((RADEON_BIOS16(tmp0) == info->PanelXRes) &&
- (RADEON_BIOS16(tmp0+2) == info->PanelYRes)) {
- info->HBlank = (RADEON_BIOS16(tmp0+17) -
- RADEON_BIOS16(tmp0+19)) * 8;
- info->HOverPlus = (RADEON_BIOS16(tmp0+21) -
- RADEON_BIOS16(tmp0+19) - 1) * 8;
- info->HSyncWidth = RADEON_BIOS8(tmp0+23) * 8;
- info->VBlank = (RADEON_BIOS16(tmp0+24) -
- RADEON_BIOS16(tmp0+26));
- info->VOverPlus = ((RADEON_BIOS16(tmp0+28) & 0x7ff) -
- RADEON_BIOS16(tmp0+26));
- info->VSyncWidth = ((RADEON_BIOS16(tmp0+28) & 0xf800)
- >> 11);
- info->DotClock = RADEON_BIOS16(tmp0+9) * 10;
- info->Flags = 0;
- }
- }
- }
- } else if ((info->DisplayType == MT_DFP) && info->HasCRTC2) {
+ hTotal = ((INREG(RADEON_CRTC_H_TOTAL_DISP) & 0x1ff) + 1) * 8;
+ vTotal = ((INREG(RADEON_CRTC_V_TOTAL_DISP) & 0x3ff) + 1);
+ vclk = (float)(hTotal * (float)(vTotal * hz));
+
+ switch((INPLL(pScrn, RADEON_PPLL_REF_DIV) & 0x30000) >> 16) {
+ case 0:
+ default:
+ num = 1;
+ denom = 1;
+ break;
+ case 1:
+ n = ((INPLL(pScrn, RADEON_X_MPLL_REF_FB_DIV) >> 16) & 0xff);
+ m = (INPLL(pScrn, RADEON_X_MPLL_REF_FB_DIV) & 0xff);
+ num = 2*n;
+ denom = 2*m;
+ break;
+ case 2:
+ n = ((INPLL(pScrn, RADEON_X_MPLL_REF_FB_DIV) >> 8) & 0xff);
+ m = (INPLL(pScrn, RADEON_X_MPLL_REF_FB_DIV) & 0xff);
+ num = 2*n;
+ denom = 2*m;
+ break;
+ }
+
+ OUTREG(RADEON_CLOCK_CNTL_INDEX, 1);
+ ppll_div_sel = INREG8(RADEON_CLOCK_CNTL_DATA + 1) & 0x3;
+
+ n = (INPLL(pScrn, RADEON_PPLL_DIV_0 + ppll_div_sel) & 0x7ff);
+ m = (INPLL(pScrn, RADEON_PPLL_REF_DIV) & 0x3ff);
+
+ num *= n;
+ denom *= m;
+
+ switch ((INPLL(pScrn, RADEON_PPLL_DIV_0 + ppll_div_sel) >> 16) & 0x7) {
+ case 1:
+ denom *= 2;
+ break;
+ case 2:
+ denom *= 4;
+ break;
+ case 3:
+ denom *= 8;
+ break;
+ case 4:
+ denom *= 3;
+ break;
+ case 6:
+ denom *= 6;
+ break;
+ case 7:
+ denom *= 12;
+ break;
+ }
+
+ xtal = (int)(vclk *(float)denom/(float)num);
+
+ if ((xtal > 26900000) && (xtal < 27100000))
+ xtal = 2700;
+ else if ((xtal > 14200000) && (xtal < 14400000))
+ xtal = 1432;
+ else if ((xtal > 29400000) && (xtal < 29600000))
+ xtal = 2950;
+ else
+ return FALSE;
+
+ tmp = INPLL(pScrn, RADEON_X_MPLL_REF_FB_DIV);
+ ref_div = INPLL(pScrn, RADEON_PPLL_REF_DIV) & 0x3ff;
+
+ Nx = (tmp & 0xff00) >> 8;
+ M = (tmp & 0xff);
+ xclk = RADEONDiv((2 * Nx * xtal), (2 * M));
+
+ /* we're done, hopefully these are sane values */
+ pll->reference_div = ref_div;
+ pll->xclk = xclk;
+ pll->reference_freq = xtal;
+
+ return TRUE;
+}
+
+static void RADEONGetTMDSInfo(ScrnInfoPtr pScrn)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ CARD32 tmp;
+ int i, n;
+
+ for (i=0; i<4; i++) {
+ info->tmds_pll[i].value = 0;
+ info->tmds_pll[i].freq = 0;
+ }
+
+ if (info->VBIOS) {
tmp = RADEON_BIOS16(info->FPBIOSstart + 0x34);
- if (tmp != 0) {
- tmp = RADEON_BIOS16(tmp + 2);
- if (tmp != 0) {
- /* 18 bytes of EDID data should be here */
- info->DotClock = RADEON_BIOS16(tmp) * 10;
- info->PanelXRes =
- ((RADEON_BIOS8(tmp + 4) & 0xf0) << 4) +
- RADEON_BIOS8(tmp + 2);
- info->HBlank =
- ((RADEON_BIOS8(tmp + 4) & 0x0f) << 8) +
- RADEON_BIOS8(tmp + 3);
- info->PanelYRes =
- ((RADEON_BIOS8(tmp + 7) & 0xf0) << 4) +
- RADEON_BIOS8(tmp + 5);
- info->VBlank =
- ((RADEON_BIOS8(tmp + 7) & 0x0f) << 8) +
- RADEON_BIOS8(tmp + 6);
- info->HOverPlus =
- ((RADEON_BIOS8(tmp + 11) & 0xc0) << 2) +
- RADEON_BIOS8(tmp + 8);
- info->HSyncWidth =
- ((RADEON_BIOS8(tmp + 11) & 0x30) << 4) +
- RADEON_BIOS8(tmp + 9);
- info->VOverPlus =
- ((RADEON_BIOS8(tmp + 11) & 0x0c) << 2) +
- ((RADEON_BIOS8(tmp + 10) & 0xf0) >> 4);
- info->VSyncWidth =
- ((RADEON_BIOS8(tmp + 11) & 0x03) << 4) +
- (RADEON_BIOS8(tmp + 10) & 0x0f);
- info->Flags = 0;
- } else {
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "No DFP timing table detected\n");
+ if (tmp) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "DFP table revision: %d\n", RADEON_BIOS8(tmp));
+ if (RADEON_BIOS8(tmp) == 3) {
+ n = RADEON_BIOS8(tmp + 5) + 1;
+ if (n > 4) n = 4;
+ for (i=0; i<n; i++) {
+ info->tmds_pll[i].value = RADEON_BIOS32(tmp+i*10+0x08);
+ info->tmds_pll[i].freq = RADEON_BIOS16(tmp+i*10+0x10);
+ }
+ return;
}
- }
- RADEONTRACE(("DFP Info: ----------------------\n"
- "pixel clock: %d KHz\n"
- "panel size: %dx%d\n"
- "H. Blanking: %d\n"
- "H. Sync. Offset: %d\n"
- "H. Sync. Width: %d\n"
- "V. Blanking: %d\n"
- "V. Sync. Offset: %d\n"
- "V. Sync. Width: %d\n",
- info->DotClock,
- info->PanelXRes, info->PanelYRes,
- info->HBlank,
- info->HOverPlus,
- info->HSyncWidth,
- info->VBlank, info->VOverPlus, info->VSyncWidth));
- }
-
- /* Detect connector type from BIOS, used for I2C/DDC qeurying EDID,
- * Only available for VE or newer cards */
-
- /* DELL OEM card doesn't seem to follow the conviention for BIOS's
- * DDC type, we have to make a special case. Following hard coded
- * type works with both CRT+CRT and DVI+DVI cases
- */
- if (info->IsDell && info->DellType == 2) {
- if (info->IsSecondary)
- info->DDCType = DDC_CRT2;
- else
- info->DDCType = DDC_DVI;
- info->CloneDDCType = DDC_CRT2;
- } else if ((tmp = RADEON_BIOS16(info->FPBIOSstart + 0x50))) {
- for (i = 1; i < 4; i++) {
- unsigned int tmp0;
- if (!RADEON_BIOS8(tmp + i*2) && i > 1) break;
-
- /* Note: Secondary port (CRT port) actually uses primary DAC */
- tmp0 = RADEON_BIOS16(tmp + i*2);
- if (tmp0 & 0x01) {
- if (!info->IsSecondary && !BypassSecondary)
- info->DDCType = (tmp0 & 0x0f00) >> 8;
- } else { /* Primary DAC */
- if (info->Clone)
- info->CloneDDCType = (tmp0 & 0x0f00) >> 8;
- else if (info->IsSecondary ||
- BypassSecondary ||
- !info->HasCRTC2) {
- info->DDCType = (tmp0 & 0x0f00) >> 8;
+ /* revision 4 has some problem as it appears in RV280,
+ comment it off for new, use default instead */
+ /*
+ else if (RADEON_BIOS8(tmp) == 4) {
+ int stride = 0;
+ n = RADEON_BIOS8(tmp + 5) + 1;
+ if (n > 4) n = 4;
+ for (i=0; i<n; i++) {
+ info->tmds_pll[i].value = RADEON_BIOS32(tmp+stride+0x08);
+ info->tmds_pll[i].freq = RADEON_BIOS16(tmp+stride+0x10);
+ if (i == 0) stride += 10;
+ else stride += 6;
}
+ return;
}
+ */
}
- } else {
- /* Orignal radeon cards, set it to DDC_VGA, this will not work
- * with AIW, it should be DDC_DVI, let it fall back to VBE calls
- * for AIW
- */
- info->DDCType = DDC_VGA;
}
- return TRUE;
+ for (i=0; i<4; i++) {
+ info->tmds_pll[i].value = default_tmds_pll[info->ChipFamily][i].value;
+ info->tmds_pll[i].freq = default_tmds_pll[info->ChipFamily][i].freq;
+ }
}
/* Read PLL parameters from BIOS block. Default to typical values if
@@ -1187,23 +1774,47 @@ static Bool RADEONGetPLLParameters(ScrnInfoPtr pScrn)
RADEONPLLPtr pll = &info->pll;
CARD16 bios_header;
CARD16 pll_info_block;
+ double min_dotclock;
if (!info->VBIOS) {
- xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
- "Video BIOS not detected, using default PLL parameters!\n");
- /* These probably aren't going to work for
- the card you are using. Specifically,
- reference freq can be 29.50MHz,
- 28.63MHz, or 14.32MHz. YMMV. */
-
- /* These are somewhat sane defaults for Mac boards, we will need
- * to find a good way of getting these from OpenFirmware
- */
- pll->reference_freq = 2700;
- pll->reference_div = 67;
+
pll->min_pll_freq = 12500;
pll->max_pll_freq = 35000;
- pll->xclk = 16615;
+
+
+ if (!RADEONProbePLLParameters(pScrn)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "Video BIOS not detected, using default PLL parameters!\n");
+
+ switch (info->Chipset) {
+ case PCI_CHIP_R200_QL:
+ case PCI_CHIP_R200_QN:
+ case PCI_CHIP_R200_QO:
+ case PCI_CHIP_R200_BB:
+ pll->reference_freq = 2700;
+ pll->reference_div = 12;
+ pll->xclk = 27500;
+ break;
+ case PCI_CHIP_RV250_Id:
+ case PCI_CHIP_RV250_Ie:
+ case PCI_CHIP_RV250_If:
+ case PCI_CHIP_RV250_Ig:
+ pll->reference_freq = 2700;
+ pll->reference_div = 12;
+ pll->xclk = 24975;
+ break;
+ case PCI_CHIP_RV200_QW:
+ pll->reference_freq = 2700;
+ pll->reference_div = 12;
+ pll->xclk = 23000;
+ break;
+ default:
+ pll->reference_freq = 2700;
+ pll->reference_div = 67;
+ pll->xclk = 16615;
+ break;
+ }
+ }
} else {
bios_header = RADEON_BIOS16(0x48);
pll_info_block = RADEON_BIOS16(bios_header + 0x30);
@@ -1217,13 +1828,25 @@ static Bool RADEONGetPLLParameters(ScrnInfoPtr pScrn)
pll->xclk = RADEON_BIOS16(pll_info_block + 0x08);
}
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "PLL parameters: rf=%d rd=%d min=%d max=%d; xclk=%d\n",
- pll->reference_freq,
- pll->reference_div,
- pll->min_pll_freq,
- pll->max_pll_freq,
- pll->xclk);
+ /* (Some?) Radeon BIOSes seem too lie about their minimum dot
+ * clocks. Allow users to override the detected minimum dot clock
+ * value (e.g., and allow it to be suitable for TV sets).
+ */
+ if (xf86GetOptValFreq(info->Options, OPTION_MIN_DOTCLOCK,
+ OPTUNITS_MHZ, &min_dotclock)) {
+ if (min_dotclock < 12 || min_dotclock*100 >= pll->max_pll_freq) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Illegal minimum dotclock specified %.2f MHz "
+ "(option ignored)\n",
+ min_dotclock);
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Forced minimum dotclock to %.2f MHz "
+ "(instead of detected %.2f MHz)\n",
+ min_dotclock, ((double)pll->min_pll_freq/1000));
+ pll->min_pll_freq = min_dotclock * 1000;
+ }
+ }
return TRUE;
}
@@ -1233,7 +1856,7 @@ static Bool RADEONPreInitVisual(ScrnInfoPtr pScrn)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
- if (!xf86SetDepthBpp(pScrn, 8, 8, 8, Support32bppFb))
+ if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb))
return FALSE;
switch (pScrn->depth) {
@@ -1317,6 +1940,44 @@ static Bool RADEONPreInitWeight(ScrnInfoPtr pScrn)
return TRUE;
}
+static void RADEONGetVRamType(ScrnInfoPtr pScrn)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ CARD32 tmp;
+
+ if (info->IsIGP || (info->ChipFamily >= CHIP_FAMILY_R300) ||
+ (INREG(RADEON_MEM_SDRAM_MODE_REG) & (1<<30)))
+ info->IsDDR = TRUE;
+ else
+ info->IsDDR = FALSE;
+
+ tmp = INREG(RADEON_MEM_CNTL);
+ if ((info->ChipFamily == CHIP_FAMILY_R300) ||
+ (info->ChipFamily == CHIP_FAMILY_R350) ||
+ (info->ChipFamily == CHIP_FAMILY_RV350)) {
+ tmp &= R300_MEM_NUM_CHANNELS_MASK;
+ switch (tmp) {
+ case 0: info->RamWidth = 64; break;
+ case 1: info->RamWidth = 128; break;
+ case 2: info->RamWidth = 256; break;
+ default: info->RamWidth = 128; break;
+ }
+ } else if ((info->ChipFamily == CHIP_FAMILY_RV100) ||
+ (info->ChipFamily == CHIP_FAMILY_RS100) ||
+ (info->ChipFamily == CHIP_FAMILY_RS200)){
+ if (tmp & RV100_HALF_MODE) info->RamWidth = 32;
+ else info->RamWidth = 64;
+ } else {
+ if (tmp & RADEON_MEM_NUM_CHANNELS_MASK) info->RamWidth = 128;
+ else info->RamWidth = 64;
+ }
+
+ /* This may not be correct, as some cards can have half of channel disabled
+ * ToDo: identify these cases
+ */
+}
+
/* This is called by RADEONPreInit to handle config file overrides for
* things like chipset and memory regions. Also determine memory size
* and type. If memory type ever needs an override, put it in this
@@ -1327,9 +1988,12 @@ static Bool RADEONPreInitConfig(ScrnInfoPtr pScrn)
RADEONInfoPtr info = RADEONPTR(pScrn);
EntityInfoPtr pEnt = info->pEnt;
GDevPtr dev = pEnt->device;
- int offset = 0; /* RAM Type */
MessageType from;
- unsigned char *RADEONMMIO;
+ unsigned char *RADEONMMIO = info->MMIO;
+#ifdef XF86DRI
+ const char *s;
+ CARD32 agpCommand;
+#endif
/* Chipset */
from = X_PROBED;
@@ -1360,56 +2024,81 @@ static Bool RADEONPreInitConfig(ScrnInfoPtr pScrn)
info->Chipset);
info->HasCRTC2 = TRUE;
+ info->IsMobility = FALSE;
+ info->IsIGP = FALSE;
switch (info->Chipset) {
case PCI_CHIP_RADEON_LY:
case PCI_CHIP_RADEON_LZ:
- info->ChipFamily = CHIP_FAMILY_M6;
+ info->IsMobility = TRUE;
+ info->ChipFamily = CHIP_FAMILY_RV100;
break;
case PCI_CHIP_RV100_QY:
case PCI_CHIP_RV100_QZ:
- info->ChipFamily = CHIP_FAMILY_VE;
+ info->ChipFamily = CHIP_FAMILY_RV100;
+ break;
+
+ case PCI_CHIP_RS100_4336:
+ info->IsMobility = TRUE;
+ case PCI_CHIP_RS100_4136:
+ info->ChipFamily = CHIP_FAMILY_RS100;
+ info->IsIGP = TRUE;
+ break;
+
+ case PCI_CHIP_RS200_4337:
+ info->IsMobility = TRUE;
+ case PCI_CHIP_RS200_4137:
+ info->ChipFamily = CHIP_FAMILY_RS200;
+ info->IsIGP = TRUE;
+ break;
+
+ case PCI_CHIP_RS250_4437:
+ info->IsMobility = TRUE;
+ case PCI_CHIP_RS250_4237:
+ info->ChipFamily = CHIP_FAMILY_RS200;
+ info->IsIGP = TRUE;
break;
case PCI_CHIP_R200_BB:
+ case PCI_CHIP_R200_BC:
case PCI_CHIP_R200_QH:
- case PCI_CHIP_R200_QI:
- case PCI_CHIP_R200_QJ:
- case PCI_CHIP_R200_QK:
case PCI_CHIP_R200_QL:
case PCI_CHIP_R200_QM:
- case PCI_CHIP_R200_QN:
- case PCI_CHIP_R200_QO:
- case PCI_CHIP_R200_Qh:
- case PCI_CHIP_R200_Qi:
- case PCI_CHIP_R200_Qj:
- case PCI_CHIP_R200_Qk:
- case PCI_CHIP_R200_Ql:
info->ChipFamily = CHIP_FAMILY_R200;
break;
+ case PCI_CHIP_RADEON_LW:
+ case PCI_CHIP_RADEON_LX:
+ info->IsMobility = TRUE;
case PCI_CHIP_RV200_QW: /* RV200 desktop */
case PCI_CHIP_RV200_QX:
info->ChipFamily = CHIP_FAMILY_RV200;
break;
- case PCI_CHIP_RADEON_LW:
- case PCI_CHIP_RADEON_LX:
- info->ChipFamily = CHIP_FAMILY_M7;
- break;
-
- case PCI_CHIP_RV250_Id:
- case PCI_CHIP_RV250_Ie:
+ case PCI_CHIP_RV250_Ld:
+ case PCI_CHIP_RV250_Lf:
+ case PCI_CHIP_RV250_Lg:
+ info->IsMobility = TRUE;
case PCI_CHIP_RV250_If:
case PCI_CHIP_RV250_Ig:
info->ChipFamily = CHIP_FAMILY_RV250;
break;
- case PCI_CHIP_RV250_Ld:
- case PCI_CHIP_RV250_Le:
- case PCI_CHIP_RV250_Lf:
- case PCI_CHIP_RV250_Lg:
- info->ChipFamily = CHIP_FAMILY_M9;
+ case PCI_CHIP_RS300_5835:
+ info->IsMobility = TRUE;
+ case PCI_CHIP_RS300_5834:
+ info->ChipFamily = CHIP_FAMILY_RS300;
+ info->IsIGP = TRUE;
+ break;
+
+ case PCI_CHIP_RV280_5C61:
+ case PCI_CHIP_RV280_5C63:
+ info->IsMobility = TRUE;
+ case PCI_CHIP_RV280_5960:
+ case PCI_CHIP_RV280_5961:
+ case PCI_CHIP_RV280_5962:
+ case PCI_CHIP_RV280_5964:
+ info->ChipFamily = CHIP_FAMILY_RV280;
break;
case PCI_CHIP_R300_AD:
@@ -1423,47 +2112,47 @@ static Bool RADEONPreInitConfig(ScrnInfoPtr pScrn)
info->ChipFamily = CHIP_FAMILY_R300;
break;
+ case PCI_CHIP_RV350_NP:
+ case PCI_CHIP_RV350_NQ:
+ case PCI_CHIP_RV350_NR:
+ case PCI_CHIP_RV350_NS:
+ case PCI_CHIP_RV350_NT:
+ case PCI_CHIP_RV350_NV:
+ info->IsMobility = TRUE;
+ case PCI_CHIP_RV350_AP:
+ case PCI_CHIP_RV350_AQ:
+ case PCI_CHIP_RV360_AR:
+ case PCI_CHIP_RV350_AS:
+ case PCI_CHIP_RV350_AT:
+ case PCI_CHIP_RV350_AV:
+ info->ChipFamily = CHIP_FAMILY_RV350;
+ break;
+
+ case PCI_CHIP_R350_AH:
+ case PCI_CHIP_R350_AI:
+ case PCI_CHIP_R350_AJ:
+ case PCI_CHIP_R350_AK:
+ case PCI_CHIP_R350_NH:
+ case PCI_CHIP_R350_NI:
+ case PCI_CHIP_R350_NK:
+ case PCI_CHIP_R360_NJ:
+ info->ChipFamily = CHIP_FAMILY_R350;
+ break;
+
default:
/* Original Radeon/7200 */
info->ChipFamily = CHIP_FAMILY_RADEON;
info->HasCRTC2 = FALSE;
}
- /* Here is the special case for DELL's VE card.
- * It needs some special handlings for it's 2nd head to work.
- */
- info->IsDell = FALSE;
- if (info->ChipFamily == CHIP_FAMILY_VE &&
- info->PciInfo->subsysVendor == PCI_VENDOR_ATI &&
- info->PciInfo->subsysCard & (1 << 12)) { /* DELL's signature */
- if (info->PciInfo->subsysCard & 0xb00) {
- info->IsDell = TRUE;
- info->DellType = 2; /* DVI+DVI config, this seems to be the
- * only known type for now, can be
- * connected to both DVI+DVI and VGA+VGA
- * dongles.
- */
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "DELL OEM Card detected with %s (type %d)\n",
- (info->DellType == 2) ? "DVI+DVI / VGA+VGA" : "VGA+VGA",
- info->DellType);
- } else {
- info->DellType = 0; /* Unknown */
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "Unknown type of DELL's Card (SSCID %x), "
- "treated as normal type\n",
- info->PciInfo->subsysCard);
- }
- }
-
/* Framebuffer */
from = X_PROBED;
- info->LinearAddr = info->PciInfo->memBase[0] & 0xfc000000;
+ info->LinearAddr = info->PciInfo->memBase[0] & 0xfe000000;
pScrn->memPhysBase = info->LinearAddr;
if (dev->MemBase) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "Linear address override, using 0x%08x instead of 0x%08x\n",
+ "Linear address override, using 0x%08lx instead of 0x%08lx\n",
dev->MemBase,
info->LinearAddr);
info->LinearAddr = dev->MemBase;
@@ -1476,29 +2165,12 @@ static Bool RADEONPreInitConfig(ScrnInfoPtr pScrn)
xf86DrvMsg(pScrn->scrnIndex, from,
"Linear framebuffer at 0x%08lx\n", info->LinearAddr);
- /* MMIO registers */
- from = X_PROBED;
- info->MMIOAddr = info->PciInfo->memBase[2] & 0xffffff00;
- if (dev->IOBase) {
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "MMIO address override, using 0x%08x instead of 0x%08x\n",
- dev->IOBase,
- info->MMIOAddr);
- info->MMIOAddr = dev->IOBase;
- from = X_CONFIG;
- } else if (!info->MMIOAddr) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid MMIO address\n");
- return FALSE;
- }
- xf86DrvMsg(pScrn->scrnIndex, from,
- "MMIO registers at 0x%08lx\n", info->MMIOAddr);
-
/* BIOS */
from = X_PROBED;
info->BIOSAddr = info->PciInfo->biosBase & 0xfffe0000;
if (dev->BiosBase) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "BIOS address override, using 0x%08x instead of 0x%08x\n",
+ "BIOS address override, using 0x%08lx instead of 0x%08lx\n",
dev->BiosBase,
info->BIOSAddr);
info->BIOSAddr = dev->BiosBase;
@@ -1509,13 +2181,36 @@ static Bool RADEONPreInitConfig(ScrnInfoPtr pScrn)
"BIOS at 0x%08lx\n", info->BIOSAddr);
}
- RADEONMapMMIO(pScrn);
- RADEONMMIO = info->MMIO;
-
/* Read registers used to determine options */
from = X_PROBED;
if (info->FBDev)
pScrn->videoRam = fbdevHWGetVidmem(pScrn) / 1024;
+ else if ((info->ChipFamily == CHIP_FAMILY_RS100) ||
+ (info->ChipFamily == CHIP_FAMILY_RS200) ||
+ (info->ChipFamily == CHIP_FAMILY_RS300)) {
+ CARD32 tom = INREG(RADEON_NB_TOM);
+ pScrn->videoRam = (((tom >> 16) -
+ (tom & 0xffff) + 1) << 6);
+ OUTREG(RADEON_MC_FB_LOCATION, tom);
+ OUTREG(RADEON_DISPLAY_BASE_ADDR, (tom & 0xffff) << 16);
+ OUTREG(RADEON_DISPLAY2_BASE_ADDR, (tom & 0xffff) << 16);
+ OUTREG(RADEON_OV0_BASE_ADDR, (tom & 0xffff) << 16);
+
+ /* This is supposed to fix the crtc2 noise problem.
+ */
+ OUTREG(RADEON_GRPH2_BUFFER_CNTL,
+ INREG(RADEON_GRPH2_BUFFER_CNTL) & ~0x7f0000);
+
+ if ((info->ChipFamily == CHIP_FAMILY_RS100) ||
+ (info->ChipFamily == CHIP_FAMILY_RS200)) {
+ /* This is to workaround the asic bug for RMX, some versions
+ of BIOS dosen't have this register initialized correctly.
+ */
+ OUTREGP(RADEON_CRTC_MORE_CNTL, RADEON_CRTC_H_CUTOFF_ACTIVE_EN,
+ ~RADEON_CRTC_H_CUTOFF_ACTIVE_EN);
+ }
+
+ }
else
pScrn->videoRam = INREG(RADEON_CONFIG_MEMSIZE) / 1024;
@@ -1525,12 +2220,9 @@ static Bool RADEONPreInitConfig(ScrnInfoPtr 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;
- RADEONEntPtr pRADEONEnt;
+ RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
RADEONInfoPtr info1;
- pPriv = xf86GetEntityPrivate(pScrn->entityList[0], gRADEONEntityIndex);
- pRADEONEnt = pPriv->ptr;
pScrn->videoRam /= 2;
pRADEONEnt->pPrimaryScrn->videoRam = pScrn->videoRam;
@@ -1548,16 +2240,8 @@ static Bool RADEONPreInitConfig(ScrnInfoPtr pScrn)
info->MemCntl = INREG(RADEON_SDRAM_MODE_REG);
info->BusCntl = INREG(RADEON_BUS_CNTL);
- RADEONMMIO = NULL;
- RADEONUnmapMMIO(pScrn);
- /* RAM */
- switch (info->MemCntl >> 30) {
- case 0: offset = 0; break; /* 64-bit SDR SDRAM */
- case 1: offset = 1; break; /* 64-bit DDR SDRAM */
- default: offset = 0;
- }
- info->ram = &RADEONRAM[offset];
+ RADEONGetVRamType(pScrn);
if (dev->videoRam) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
@@ -1570,62 +2254,53 @@ static Bool RADEONPreInitConfig(ScrnInfoPtr pScrn)
pScrn->videoRam &= ~1023;
info->FbMapSize = pScrn->videoRam * 1024;
xf86DrvMsg(pScrn->scrnIndex, from,
- "VideoRAM: %d kByte (%s)\n", pScrn->videoRam, info->ram->name);
+ "VideoRAM: %d kByte (%d bit %s SDRAM)\n", pScrn->videoRam, info->RamWidth, info->IsDDR?"DDR":"SDR");
#ifdef XF86DRI
/* AGP/PCI */
- if (xf86ReturnOptValBool(info->Options, OPTION_IS_PCI, FALSE)) {
- info->IsPCI = TRUE;
- xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forced into PCI-only mode\n");
+
+ /* There are signatures in BIOS and PCI-SSID for a PCI card, but
+ * they are not very reliable. Following detection method works for
+ * all cards tested so far. Note, checking AGP_ENABLE bit after
+ * drmAgpEnable call can also give the correct result. However,
+ * calling drmAgpEnable on a PCI card can cause some strange lockup
+ * when the server restarts next time.
+ */
+
+ agpCommand = pciReadLong(info->PciTag, RADEON_AGP_COMMAND_PCI_CONFIG);
+ pciWriteLong(info->PciTag, RADEON_AGP_COMMAND_PCI_CONFIG,
+ agpCommand | RADEON_AGP_ENABLE);
+ if (pciReadLong(info->PciTag, RADEON_AGP_COMMAND_PCI_CONFIG)
+ & RADEON_AGP_ENABLE) {
+ info->IsPCI = FALSE;
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "AGP card detected\n");
} else {
- switch (info->Chipset) {
-#if 0
- case PCI_CHIP_RADEON_XX: info->IsPCI = TRUE; break;
-#endif
- case PCI_CHIP_RV100_QY:
- case PCI_CHIP_RV100_QZ:
- case PCI_CHIP_RADEON_LW:
- case PCI_CHIP_RADEON_LX:
- case PCI_CHIP_RADEON_LY:
- case PCI_CHIP_RADEON_LZ:
- case PCI_CHIP_RADEON_QD:
- case PCI_CHIP_RADEON_QE:
- case PCI_CHIP_RADEON_QF:
- case PCI_CHIP_RADEON_QG:
- case PCI_CHIP_R200_BB:
- case PCI_CHIP_R200_QH:
- case PCI_CHIP_R200_QI:
- case PCI_CHIP_R200_QJ:
- case PCI_CHIP_R200_QK:
- case PCI_CHIP_R200_QL:
- case PCI_CHIP_R200_QM:
- case PCI_CHIP_R200_QN:
- case PCI_CHIP_R200_QO:
- case PCI_CHIP_R200_Qh:
- case PCI_CHIP_R200_Qi:
- case PCI_CHIP_R200_Qj:
- case PCI_CHIP_R200_Qk:
- case PCI_CHIP_R200_Ql:
- case PCI_CHIP_RV200_QW:
- case PCI_CHIP_RV200_QX:
- case PCI_CHIP_RV250_Id:
- case PCI_CHIP_RV250_Ie:
- case PCI_CHIP_RV250_If:
- case PCI_CHIP_RV250_Ig:
- case PCI_CHIP_RV250_Ld:
- case PCI_CHIP_RV250_Le:
- case PCI_CHIP_RV250_Lf:
- case PCI_CHIP_RV250_Lg:
- case PCI_CHIP_R300_AD:
- case PCI_CHIP_R300_AE:
- case PCI_CHIP_R300_AF:
- case PCI_CHIP_R300_AG:
- case PCI_CHIP_R300_ND:
- case PCI_CHIP_R300_NE:
- case PCI_CHIP_R300_NF:
- case PCI_CHIP_R300_NG:
- default: info->IsPCI = FALSE; break;
+ info->IsPCI = TRUE;
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "PCI card detected\n");
+ }
+ pciWriteLong(info->PciTag, RADEON_AGP_COMMAND_PCI_CONFIG, agpCommand);
+
+ if ((s = xf86GetOptValString(info->Options, OPTION_BUS_TYPE))) {
+ if (strcmp(s, "AGP") == 0) {
+ info->IsPCI = FALSE;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forced into AGP mode\n");
+ } else if (strcmp(s, "PCI") == 0) {
+ info->IsPCI = TRUE;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forced into PCI mode\n");
+ } else if (strcmp(s, "PCIE") == 0) {
+ info->IsPCI = TRUE;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+ "PCI Express not supported yet, using PCI mode\n");
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+ "Invalid BusType option, using detected type\n");
}
+ } else if (xf86ReturnOptValBool(info->Options, OPTION_IS_PCI, FALSE)) {
+ info->IsPCI = TRUE;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Forced into PCI mode\n");
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "ForcePCIMode is deprecated -- "
+ "use BusType option instead\n");
}
#endif
@@ -1657,6 +2332,9 @@ static void RADEONI2CPutBits(I2CBusPtr b, int Clock, int data)
val |= (Clock ? 0:RADEON_GPIO_EN_1);
val |= (data ? 0:RADEON_GPIO_EN_0);
OUTREG(info->DDCReg, val);
+
+ /* read back to improve reliability on some cards. */
+ val = INREG(info->DDCReg);
}
static Bool RADEONI2cInit(ScrnInfoPtr pScrn)
@@ -1672,23 +2350,6 @@ static Bool RADEONI2cInit(ScrnInfoPtr pScrn)
info->pI2CBus->I2CGetBits = RADEONI2CGetBits;
info->pI2CBus->AcknTimeout = 5;
- switch (info->DDCType) {
- case DDC_MONID:
- info->DDCReg = RADEON_GPIO_MONID;
- break;
- case DDC_DVI:
- info->DDCReg = RADEON_GPIO_DVI_DDC;
- break;
- case DDC_VGA:
- info->DDCReg = RADEON_GPIO_VGA_DDC;
- break;
- case DDC_CRT2:
- info->DDCReg = RADEON_GPIO_CRT2_DDC;
- break;
- default:
- return FALSE;
- }
-
if (!xf86I2CBusInit(info->pI2CBus)) return FALSE;
return TRUE;
}
@@ -1718,113 +2379,6 @@ static void RADEONPreInitDDC(ScrnInfoPtr pScrn)
}
}
-static xf86MonPtr RADEONDoDDC(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
-{
- RADEONInfoPtr info = RADEONPTR(pScrn);
- xf86MonPtr MonInfo = NULL;
- unsigned char *RADEONMMIO;
- int i;
-
- /* We'll use DDC2, BIOS EDID can only detect the monitor connected
- * to one port. For VE, BIOS EDID detects the monitor connected to
- * DVI port by default. If no monitor their, it will try CRT port
- */
-
- /* Read and output monitor info using DDC2 over I2C bus */
- if (info->pI2CBus && info->ddc2) {
- int j;
-
- if (!RADEONMapMMIO(pScrn)) return NULL;
- RADEONMMIO = info->MMIO;
- OUTREG(info->DDCReg, INREG(info->DDCReg) &
- (CARD32)~(RADEON_GPIO_A_0 | RADEON_GPIO_A_1));
-
- /* For some old monitors (like Compaq Presario FP500), we need
- * following process to initialize/stop DDC
- */
- OUTREG(info->DDCReg, INREG(info->DDCReg) & ~(RADEON_GPIO_EN_1));
- for (j = 0; j < 3; j++) {
- OUTREG(info->DDCReg,
- INREG(info->DDCReg) & ~(RADEON_GPIO_EN_0));
- usleep(13000);
-
- OUTREG(info->DDCReg,
- INREG(info->DDCReg) & ~(RADEON_GPIO_EN_1));
- for (i = 0; i < 10; i++) {
- usleep(15000);
- if (INREG(info->DDCReg) & RADEON_GPIO_Y_1)
- break;
- }
- if (i == 10) continue;
-
- usleep(15000);
-
- OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_0);
- usleep(15000);
-
- OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_1);
- usleep(15000);
- OUTREG(info->DDCReg,
- INREG(info->DDCReg) & ~(RADEON_GPIO_EN_0));
- usleep(15000);
- MonInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, info->pI2CBus);
-
- OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_1);
- OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_0);
- usleep(15000);
- OUTREG(info->DDCReg,
- INREG(info->DDCReg) & ~(RADEON_GPIO_EN_1));
- for (i = 0; i < 50; i++) {
- usleep(15000);
- if (INREG(info->DDCReg) & RADEON_GPIO_Y_1)
- break;
- }
- usleep(15000);
- OUTREG(info->DDCReg,
- INREG(info->DDCReg) & ~(RADEON_GPIO_EN_0));
- usleep(15000);
-
- OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_1);
- OUTREG(info->DDCReg, INREG(info->DDCReg) | RADEON_GPIO_EN_0);
- usleep(15000);
- if (MonInfo)
- break;
- }
-
- RADEONUnmapMMIO(pScrn);
- }
-
- if (!MonInfo && pInt10 && (info->DDCReg == RADEON_GPIO_VGA_DDC)) {
- if (xf86LoadSubModule(pScrn, "vbe")) {
- vbeInfoPtr pVbe;
- pVbe = VBEInit(pInt10, info->pEnt->index);
- if (pVbe) {
- for (i = 0; i < 5; i++) {
- MonInfo = vbeDoEDID(pVbe, NULL);
- info->ddc_bios = TRUE;
- if (MonInfo)
- break;
- }
- } else
- info->ddc_bios = FALSE;
- }
- }
-
- if (MonInfo) {
- if (info->ddc2)
- xf86DrvMsg(pScrn->scrnIndex, X_INFO, "I2C EDID Info:\n");
- else if (info->ddc_bios)
- xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS EDID Info:\n");
- else return NULL;
-
- xf86PrintEDID(MonInfo);
- xf86DrvMsg(pScrn->scrnIndex, X_INFO, "End of DDC Monitor info\n\n");
-
- xf86SetDDCproperties(pScrn, MonInfo);
- return MonInfo;
- }
- else return NULL;
-}
/* BIOS may not have right panel size, we search through all supported
* DDC modes looking for the maximum panel size.
@@ -1910,7 +2464,7 @@ static void RADEONSortModes(DisplayModePtr *new, DisplayModePtr *first,
p = *last;
while (p) {
- if ((((*new)->HDisplay < p->HDisplay) &&
+ if ((((*new)->HDisplay < p->HDisplay) &&
((*new)->VDisplay < p->VDisplay)) ||
(((*new)->HDisplay == p->HDisplay) &&
((*new)->VDisplay == p->VDisplay) &&
@@ -1929,7 +2483,7 @@ static void RADEONSortModes(DisplayModePtr *new, DisplayModePtr *first,
p->prev = *new;
*first = *new;
break;
- }
+ }
p = p->prev;
}
@@ -1955,7 +2509,7 @@ static void RADEONSetPitch (ScrnInfoPtr pScrn)
pScrn->displayWidth = dummy;
}
-/* When no mode provided in config file, this will add all modes supported in
+/* When no mode provided in config file, this will add all modes supported in
* DDC date the pScrn->modes list
*/
static DisplayModePtr RADEONDDCModes(ScrnInfoPtr pScrn)
@@ -2065,7 +2619,7 @@ static DisplayModePtr RADEONDDCModes(ScrnInfoPtr pScrn)
strcpy(new->name, p->name);
new->status = MODE_OK;
new->type = M_T_DEFAULT;
-
+
count++;
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
@@ -2103,11 +2657,11 @@ static int RADEONValidateDDCModes(ScrnInfoPtr pScrn, char **ppModeName,
pScrn->virtualX = pScrn->display->virtualX;
pScrn->virtualY = pScrn->display->virtualY;
- if (pScrn->monitor->DDC) {
+ if (pScrn->monitor->DDC && !info->UseBiosDividers) {
int maxVirtX = pScrn->virtualX;
int maxVirtY = pScrn->virtualY;
- if (DisplayType != MT_CRT) {
+ if ((DisplayType != MT_CRT) && !info->IsSecondary) {
/* 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
@@ -2193,7 +2747,7 @@ static int RADEONValidateDDCModes(ScrnInfoPtr pScrn, char **ppModeName,
}
}
- /*
+ /*
* Add remaining DDC modes if they're smaller than the user
* specified modes
*/
@@ -2295,8 +2849,7 @@ static DisplayModePtr RADEONFPNativeMode(ScrnInfoPtr pScrn)
return new;
}
-/* XFree86's xf86ValidateModes routine doesn't work well with DFPs, so
- * here is our own validation routine.
+/* FP mode initialization routine for using on-chip RMX to scale
*/
static int RADEONValidateFPModes(ScrnInfoPtr pScrn, char **ppModeName)
{
@@ -2304,6 +2857,7 @@ static int RADEONValidateFPModes(ScrnInfoPtr pScrn, char **ppModeName)
DisplayModePtr last = NULL;
DisplayModePtr new = NULL;
DisplayModePtr first = NULL;
+ DisplayModePtr p, tmp;
int count = 0;
int i, width, height;
@@ -2314,7 +2868,7 @@ static int RADEONValidateFPModes(ScrnInfoPtr pScrn, char **ppModeName)
* don't have any DDC info.
*/
for (i = 0; ppModeName[i] != NULL; i++) {
- /* FIXME: Use HDisplay and VDisplay instead of mode string */
+
if (sscanf(ppModeName[i], "%dx%d", &width, &height) != 2) continue;
/* Note: We allow all non-standard modes as long as they do not
@@ -2346,7 +2900,7 @@ static int RADEONValidateFPModes(ScrnInfoPtr pScrn, char **ppModeName)
new->HSyncEnd = new->HSyncStart + info->HSyncWidth;
new->VTotal = info->PanelYRes + info->VBlank;
new->VSyncStart = info->PanelYRes + info->VOverPlus;
- new->VSyncEnd = new->VSyncStart + info->VSyncWidth;
+ new->VSyncEnd = new->VSyncStart + info->VSyncWidth;
new->Clock = info->DotClock;
new->Flags |= RADEON_USE_RMX;
@@ -2374,6 +2928,44 @@ static int RADEONValidateFPModes(ScrnInfoPtr pScrn, char **ppModeName)
if (first) count = 1;
}
+ /* add in all default vesa modes smaller than panel size, used for randr*/
+ for (p = pScrn->monitor->Modes; p && p->next; p = p->next->next) {
+ if ((p->HDisplay <= info->PanelXRes) && (p->VDisplay <= info->PanelYRes)) {
+ tmp = first;
+ while (tmp) {
+ if ((p->HDisplay == tmp->HDisplay) && (p->VDisplay == tmp->VDisplay)) break;
+ tmp = tmp->next;
+ }
+ if (!tmp) {
+ new = xnfcalloc(1, sizeof(DisplayModeRec));
+ new->name = xnfalloc(strlen(p->name) + 1);
+ strcpy(new->name, p->name);
+ new->HDisplay = p->HDisplay;
+ new->VDisplay = p->VDisplay;
+
+ /* These values are effective values after expansion They are
+ * not really used to set CRTC registers.
+ */
+ new->HTotal = info->PanelXRes + info->HBlank;
+ new->HSyncStart = info->PanelXRes + info->HOverPlus;
+ new->HSyncEnd = new->HSyncStart + info->HSyncWidth;
+ new->VTotal = info->PanelYRes + info->VBlank;
+ new->VSyncStart = info->PanelYRes + info->VOverPlus;
+ new->VSyncEnd = new->VSyncStart + info->VSyncWidth;
+ new->Clock = info->DotClock;
+ new->Flags |= RADEON_USE_RMX;
+
+ new->type |= M_T_DEFAULT;
+
+ new->next = NULL;
+ new->prev = last;
+
+ last->next = new;
+ last = new;
+ }
+ }
+ }
+
/* Close the doubly-linked mode list, if we found any usable modes */
if (last) {
last->next = first;
@@ -2497,9 +3089,10 @@ static int RADEONValidateCloneModes(ScrnInfoPtr pScrn)
int tmp_vdisplay = 0;
int i, save_n_hsync, save_n_vrefresh;
range save_hsync, save_vrefresh;
- char *s;
- char **clone_mode_names = NULL;
+ char *s;
+ char **clone_mode_names = NULL;
Bool ddc_mode = info->ddc_mode;
+ RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
/* Save all infomations that will be changed by clone mode validateion */
save_mode = pScrn->modes;
@@ -2524,8 +3117,8 @@ static int RADEONValidateCloneModes(ScrnInfoPtr pScrn)
clockRanges->minClock = info->pll.min_pll_freq;
clockRanges->maxClock = info->pll.max_pll_freq * 10;
clockRanges->clockIndex = -1;
- clockRanges->interlaceAllowed = FALSE;
- clockRanges->doubleScanAllowed = FALSE;
+ clockRanges->interlaceAllowed = (info->CloneType == MT_CRT);
+ clockRanges->doubleScanAllowed = (info->CloneType == MT_CRT);
/* Only take one clone mode from config file for now, rest of clone
* modes will copy from primary head.
@@ -2536,14 +3129,19 @@ static int RADEONValidateCloneModes(ScrnInfoPtr pScrn)
else count++;
clone_mode_names[0] = xnfalloc(strlen(s)+1);
sprintf(clone_mode_names[0], "%dx%d", tmp_hdisplay, tmp_vdisplay);
- xf86DrvMsg(0, X_INFO, "Clone mode %s in config file is used\n");
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Clone mode %s in config file is used\n", clone_mode_names[0]);
}
}
- if (pScrn->display->virtualX < tmp_hdisplay)
- pScrn->display->virtualX = tmp_hdisplay;
- if (pScrn->display->virtualY < tmp_vdisplay)
- pScrn->display->virtualY = tmp_vdisplay;
+ for (i = 0; i < count; i++) {
+ if (sscanf(clone_mode_names[i], "%dx%d",
+ &tmp_hdisplay, &tmp_vdisplay) == 2) {
+ if (pScrn->display->virtualX < tmp_hdisplay)
+ pScrn->display->virtualX = tmp_hdisplay;
+ if (pScrn->display->virtualY < tmp_vdisplay)
+ pScrn->display->virtualY = tmp_vdisplay;
+ }
+ }
save_hsync = pScrn->monitor->hsync[0];
save_vrefresh = pScrn->monitor->vrefresh[0];
@@ -2576,48 +3174,25 @@ static int RADEONValidateCloneModes(ScrnInfoPtr pScrn)
}
}
- if ((pScrn->monitor->nVrefresh == 0) || (pScrn->monitor->nHsync == 0) ||
- (info->CloneType != MT_CRT) || info->ddc_mode) {
- unsigned int save_ddc_reg;
- save_ddc_reg = info->DDCReg;
- switch (info->CloneDDCType) {
- case DDC_MONID: info->DDCReg = RADEON_GPIO_MONID; break;
- case DDC_DVI: info->DDCReg = RADEON_GPIO_DVI_DDC; break;
- case DDC_VGA: info->DDCReg = RADEON_GPIO_VGA_DDC; break;
- case DDC_CRT2: info->DDCReg = RADEON_GPIO_CRT2_DDC; break;
- default: info->DDCReg = 0; break;
- }
-
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "DDC detection (type %d) for clone modes\n",
- info->CloneDDCType);
-
- /* When primary head has an invalid DDC type, I2C is not
- * initialized, so we do it here.
- */
- if (!info->ddc2) info->ddc2 = xf86I2CBusInit(info->pI2CBus);
-
- pScrn->monitor->DDC = RADEONDoDDC(pScrn, NULL);
- if (pScrn->monitor->DDC) {
- if (info->CloneType == MT_CRT) {
- if (pScrn->monitor->nHsync == 0)
- RADEONSetSyncRangeFromEdid(pScrn, 1);
- if (pScrn->monitor->nVrefresh == 0)
- RADEONSetSyncRangeFromEdid(pScrn, 0);
- }
- } else if (info->ddc_mode) {
- ddc_mode = FALSE;
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "No DDC data available for clone mode, "
- "DDCMode option is dismissed\n");
- }
- info->DDCReg = save_ddc_reg;
+ pScrn->monitor->DDC = pRADEONEnt->MonInfo2;
+ if (pScrn->monitor->DDC) {
+ if ((pScrn->monitor->nVrefresh == 0) || (pScrn->monitor->nHsync == 0)) {
+ if (pScrn->monitor->nHsync == 0)
+ RADEONSetSyncRangeFromEdid(pScrn, 1);
+ if (pScrn->monitor->nVrefresh == 0)
+ RADEONSetSyncRangeFromEdid(pScrn, 0);
+ }
+ } else if (info->ddc_mode) {
+ ddc_mode = FALSE;
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "No DDC data available for clone mode, "
+ "DDCMode option is dismissed\n");
}
if (info->CloneType == MT_CRT && !ddc_mode) {
modesFound =
- xf86ValidateModes(pScrn, pScrn->monitor->Modes,
- clone_mode_names,
+ xf86ValidateModes(pScrn, pScrn->monitor->Modes,
+ clone_mode_names,
clockRanges,
NULL, /* linePitches */
8 * 64, /* minPitch */
@@ -2627,51 +3202,84 @@ static int RADEONValidateCloneModes(ScrnInfoPtr pScrn)
2048, /* maxHeight */
pScrn->display->virtualX,
pScrn->display->virtualY,
- info->FbMapSize,
+ info->FbMapSize,
LOOKUP_BEST_REFRESH);
} else {
/* Try to add DDC modes */
- info->IsSecondary = TRUE; /* Fake it */
+ info->IsSecondary = TRUE; /*fake secondary head*/
modesFound = RADEONValidateDDCModes(pScrn, clone_mode_names,
info->CloneType);
- info->IsSecondary = FALSE; /* Restore it!!! */
+ info->IsSecondary = FALSE;
/* If that fails and we're connect to a flat panel, then try to
* add the flat panel modes
*/
- if (modesFound < 1 && info->DisplayType != MT_CRT)
- modesFound = RADEONValidateFPModes(pScrn, clone_mode_names);
+ if (modesFound < 1 && info->CloneType != MT_CRT) {
+ modesFound =
+ xf86ValidateModes(pScrn, pScrn->monitor->Modes,
+ clone_mode_names,
+ clockRanges,
+ NULL, /* linePitches */
+ 8 * 64, /* minPitch */
+ 8 * 1024, /* maxPitch */
+ 64 * pScrn->bitsPerPixel, /* pitchInc */
+ 128, /* minHeight */
+ 2048, /* maxHeight */
+ pScrn->display->virtualX,
+ pScrn->display->virtualY,
+ info->FbMapSize,
+ LOOKUP_BEST_REFRESH);
+ }
}
if (modesFound > 0) {
+ int valid = 0;
+ save_mode = pScrn->modes;
xf86SetCrtcForModes(pScrn, 0);
xf86PrintModes(pScrn);
for (i = 0; i < modesFound; i++) {
+
while (pScrn->modes->status != MODE_OK) {
pScrn->modes = pScrn->modes->next;
}
if (!pScrn->modes) break;
- clone_mode = xnfcalloc (1, sizeof (DisplayModeRec));
- if (!clone_mode || !pScrn->modes) break;
- memcpy(clone_mode, pScrn->modes, sizeof(DisplayModeRec));
- clone_mode->name = xnfalloc(strlen(pScrn->modes->name) + 1);
- strcpy(clone_mode->name, pScrn->modes->name);
+ if (pScrn->modes->Clock != 0.0) {
- if (i == 0) {
- info->CloneModes = clone_mode;
- info->CurCloneMode = clone_mode;
- } else {
- clone_mode->prev = tmp_mode;
- clone_mode->prev->next = clone_mode;
- }
+ clone_mode = xnfcalloc (1, sizeof (DisplayModeRec));
+ if (!clone_mode) break;
+ memcpy(clone_mode, pScrn->modes, sizeof(DisplayModeRec));
+ clone_mode->name = xnfalloc(strlen(pScrn->modes->name) + 1);
+ strcpy(clone_mode->name, pScrn->modes->name);
+
+ if (!info->CurCloneMode) {
+ info->CloneModes = clone_mode;
+ info->CurCloneMode = clone_mode;
+ clone_mode->prev = NULL;
+ } else {
+ clone_mode->prev = tmp_mode;
+ clone_mode->prev->next = clone_mode;
+ }
+ valid++;
- tmp_mode = clone_mode;
- clone_mode->next = NULL;
+ tmp_mode = clone_mode;
+ clone_mode->next = NULL;
+ }
pScrn->modes = pScrn->modes->next;
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "Valid Clone Mode: %s\n", clone_mode->name);
}
+
+ /* no longer needed, free it */
+ pScrn->modes = save_mode;
+ while (pScrn->modes)
+ xf86DeleteMode(&pScrn->modes, pScrn->modes);
+ pScrn->modes = NULL;
+
+ /* modepool is no longer needed, free it */
+ while (pScrn->modePool)
+ xf86DeleteMode(&pScrn->modePool, pScrn->modePool);
+ pScrn->modePool = NULL;
+
+ modesFound = valid;
}
/* Clone_mode_names list is no longer needed, free it. */
@@ -2686,7 +3294,6 @@ static int RADEONValidateCloneModes(ScrnInfoPtr pScrn)
}
/* We need to restore all changed info for the primary head */
- pScrn->modes = save_mode;
pScrn->monitor->hsync[0] = save_hsync;
pScrn->monitor->vrefresh[0] = save_vrefresh;
@@ -2703,10 +3310,6 @@ static int RADEONValidateCloneModes(ScrnInfoPtr pScrn)
xfree(CRtmp);
}
- /* modePool is no longer needed, free it */
- while (pScrn->modePool)
- xf86DeleteMode(&pScrn->modePool, pScrn->modePool);
- pScrn->modePool = NULL;
return modesFound;
}
@@ -2719,10 +3322,8 @@ static Bool RADEONPreInitModes(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
RADEONInfoPtr info = RADEONPTR(pScrn);
ClockRangePtr clockRanges;
int modesFound;
- char *mod = NULL;
-#ifndef USE_FB
- const char *Sym = NULL;
-#endif
+ RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
+ char *s;
/* This option has two purposes:
*
@@ -2754,6 +3355,10 @@ static Bool RADEONPreInitModes(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
info->ddc_mode =
xf86ReturnOptValBool(info->Options, OPTION_DDC_MODE, FALSE);
+ /* don't use RMX if we have a dual-tdms panels */
+ if (pRADEONEnt->MonType2 == MT_DFP)
+ info->ddc_mode = TRUE;
+
/* Here is a hack for cloning first display on the second head. If
* we don't do this, when both heads are connected, the same CRTC
* will be used to drive them according to the capability of the
@@ -2767,11 +3372,6 @@ static Bool RADEONPreInitModes(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
*/
if (info->HasCRTC2) {
if (info->Clone) {
- DevUnion *pPriv;
- RADEONEntPtr pRADEONEnt;
- pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
- gRADEONEntityIndex);
- pRADEONEnt = pPriv->ptr;
/* If we have 2 screens from the config file, we don't need
* to do clone thing, let each screen handles one head.
@@ -2795,34 +3395,90 @@ static Bool RADEONPreInitModes(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
}
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "Validating modes on %s head (DDCType: %d) ---------\n",
- info->IsSecondary ? "Secondary" : "Primary",
- info->DDCType);
+ "Validating modes on %s head ---------\n",
+ info->IsSecondary ? "Secondary" : "Primary");
+
+ if (info->IsSecondary)
+ pScrn->monitor->DDC = pRADEONEnt->MonInfo2;
+ else
+ pScrn->monitor->DDC = pRADEONEnt->MonInfo1;
- pScrn->monitor->DDC = RADEONDoDDC(pScrn, pInt10);
if (!pScrn->monitor->DDC && info->ddc_mode) {
info->ddc_mode = FALSE;
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"No DDC data available, DDCMode option is dismissed\n");
}
- if (pScrn->monitor->DDC) {
- /* If we still don't know sync range yet, let's try EDID.
- *
- * Note that, since we can have dual heads, Xconfigurator
- * may not be able to probe both monitors correctly through
- * vbe probe function (RADEONProbeDDC). Here we provide an
- * additional way to auto-detect sync ranges if they haven't
- * been added to XF86Config manually.
- */
- if (pScrn->monitor->nHsync <= 0)
- RADEONSetSyncRangeFromEdid(pScrn, 1);
- if (pScrn->monitor->nVrefresh <= 0)
- RADEONSetSyncRangeFromEdid(pScrn, 0);
+ if ((info->DisplayType == MT_DFP) ||
+ (info->DisplayType == MT_LCD)) {
+ if ((s = xf86GetOptValString(info->Options, OPTION_PANEL_SIZE))) {
+ int PanelX, PanelY;
+ DisplayModePtr tmp_mode = NULL;
+ if (sscanf(s, "%dx%d", &PanelX, &PanelY) == 2) {
+ info->PanelXRes = PanelX;
+ info->PanelYRes = PanelY;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+ "Panel size is forced to: %s\n", s);
+
+ /* We can't trust BIOS or DDC timings anymore,
+ 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.
+ */
+ info->ddc_mode = FALSE;
+ pScrn->monitor->DDC = NULL;
+ tmp_mode = pScrn->monitor->Modes;
+ while(tmp_mode) {
+ if ((tmp_mode->HDisplay == PanelX) &&
+ (tmp_mode->VDisplay == PanelY)) {
+
+ float refresh =
+ (float)tmp_mode->Clock * 1000.0 / tmp_mode->HTotal / tmp_mode->VTotal;
+ if ((abs(60.0 - refresh) < 1.0) ||
+ (tmp_mode->type == 0)) {
+ info->HBlank = tmp_mode->HTotal - tmp_mode->HDisplay;
+ info->HOverPlus = tmp_mode->HSyncStart - tmp_mode->HDisplay;
+ info->HSyncWidth = tmp_mode->HSyncEnd - tmp_mode->HSyncStart;
+ info->VBlank = tmp_mode->VTotal - tmp_mode->VDisplay;
+ info->VOverPlus = tmp_mode->VSyncStart - tmp_mode->VDisplay;
+ info->VSyncWidth = tmp_mode->VSyncEnd - tmp_mode->VSyncStart;
+ info->DotClock = tmp_mode->Clock;
+ info->Flags = 0;
+ break;
+ }
+ }
+ tmp_mode = tmp_mode->next;
+ }
+ if (info->DotClock == 0) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "No valid timing info for specified panel size.\n"
+ "Please specify the Modeline for this panel\n");
+ return FALSE;
+ }
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+ "Invalid PanelSize value: %s\n", s);
+ }
+ }
}
+ if (pScrn->monitor->DDC) {
+ /* If we still don't know sync range yet, let's try EDID.
+ *
+ * Note that, since we can have dual heads, Xconfigurator
+ * may not be able to probe both monitors correctly through
+ * vbe probe function (RADEONProbeDDC). Here we provide an
+ * additional way to auto-detect sync ranges if they haven't
+ * been added to XF86Config manually.
+ */
+ if (pScrn->monitor->nHsync <= 0)
+ RADEONSetSyncRangeFromEdid(pScrn, 1);
+ if (pScrn->monitor->nVrefresh <= 0)
+ RADEONSetSyncRangeFromEdid(pScrn, 0);
+ }
+
+ /* Get mode information */
pScrn->progClock = TRUE;
-
clockRanges = xnfcalloc(sizeof(*clockRanges), 1);
clockRanges->next = NULL;
clockRanges->minClock = info->pll.min_pll_freq;
@@ -2836,6 +3492,7 @@ static Bool RADEONPreInitModes(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
* 'stretched' from their native mode.
*/
if (info->DisplayType == MT_CRT && !info->ddc_mode) {
+
modesFound =
xf86ValidateModes(pScrn,
pScrn->monitor->Modes,
@@ -2865,6 +3522,7 @@ static Bool RADEONPreInitModes(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
return FALSE;
}
+
} else {
/* First, free any allocated modes during configuration, since
* we don't need them
@@ -2881,8 +3539,54 @@ static Bool RADEONPreInitModes(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
/* If that fails and we're connect to a flat panel, then try to
* add the flat panel modes
*/
- if (modesFound < 1 && info->DisplayType != MT_CRT)
- modesFound = RADEONValidateFPModes(pScrn, pScrn->display->modes);
+ if (info->DisplayType != MT_CRT) {
+
+ /* some panels have DDC, but don't have internal scaler.
+ * in this case, we need to validate additional modes
+ * by using on-chip RMX.
+ */
+ int user_modes_asked = 0, user_modes_found = 0, i;
+ DisplayModePtr tmp_mode = pScrn->modes;
+ while (pScrn->display->modes[user_modes_asked]) user_modes_asked++;
+ if (tmp_mode) {
+ for (i = 0; i < modesFound; i++) {
+ if (tmp_mode->type & M_T_USERDEF) user_modes_found++;
+ tmp_mode = tmp_mode->next;
+ }
+ }
+
+ if ((modesFound <= 1) || (user_modes_found < user_modes_asked)) {
+ /* when panel size is not valid, try to validate
+ * mode using xf86ValidateModes routine
+ * This can happen when DDC is disabled.
+ */
+ if (info->PanelXRes < 320 || info->PanelYRes < 200)
+ modesFound =
+ xf86ValidateModes(pScrn,
+ pScrn->monitor->Modes,
+ pScrn->display->modes,
+ clockRanges,
+ NULL, /* linePitches */
+ 8 * 64, /* minPitch */
+ 8 * 1024, /* maxPitch */
+ 64 * pScrn->bitsPerPixel, /* pitchInc */
+ 128, /* minHeight */
+ 2048, /* maxHeight */
+ pScrn->display->virtualX,
+ pScrn->display->virtualY,
+ info->FbMapSize,
+ LOOKUP_BEST_REFRESH);
+ else if (!info->IsSecondary)
+ modesFound = RADEONValidateFPModes(pScrn, pScrn->display->modes);
+ }
+ }
+
+ /* Setup the screen's clockRanges for the VidMode extension */
+ if (!pScrn->clockRanges) {
+ pScrn->clockRanges = xnfcalloc(sizeof(*(pScrn->clockRanges)), 1);
+ memcpy(pScrn->clockRanges, clockRanges, sizeof(*clockRanges));
+ pScrn->clockRanges->strategy = LOOKUP_BEST_REFRESH;
+ }
/* Fail if we still don't have any valid modes */
if (modesFound < 1) {
@@ -2897,11 +3601,6 @@ static Bool RADEONPreInitModes(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
}
return FALSE;
}
-
- /* Setup the screen's clockRanges for the VidMode extension */
- pScrn->clockRanges = xnfcalloc(sizeof(*(pScrn->clockRanges)), 1);
- memcpy(pScrn->clockRanges, clockRanges, sizeof(*clockRanges));
- pScrn->clockRanges->strategy = LOOKUP_BEST_REFRESH;
}
xf86SetCrtcForModes(pScrn, 0);
@@ -2915,9 +3614,9 @@ static Bool RADEONPreInitModes(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
if ((clone_mode->HDisplay > pScrn->virtualX) ||
(clone_mode->VDisplay > pScrn->virtualY)) {
pScrn->virtualX =
- pScrn->display->virtualX = clone_mode->HDisplay;
+ pScrn->display->virtualX = clone_mode->HDisplay;
pScrn->virtualY =
- pScrn->display->virtualY = clone_mode->VDisplay;
+ pScrn->display->virtualY = clone_mode->VDisplay;
RADEONSetPitch(pScrn);
}
if (!clone_mode->next) break;
@@ -2932,23 +3631,9 @@ static Bool RADEONPreInitModes(ScrnInfoPtr pScrn, xf86Int10InfoPtr pInt10)
xf86SetDpi(pScrn, 0, 0);
/* Get ScreenInit function */
-#ifdef USE_FB
- mod = "fb";
-#else
- switch (pScrn->bitsPerPixel) {
- case 8: mod = "cfb"; Sym = "cfbScreenInit"; break;
- case 16: mod = "cfb16"; Sym = "cfb16ScreenInit"; break;
- case 32: mod = "cfb32"; Sym = "cfb32ScreenInit"; break;
- }
-#endif
-
- if (mod && !xf86LoadSubModule(pScrn, mod)) return FALSE;
+ if (!xf86LoadSubModule(pScrn, "fb")) return FALSE;
-#ifdef USE_FB
xf86LoaderReqSymLists(fbSymbols, NULL);
-#else
- xf86LoaderReqSymbols(Sym, NULL);
-#endif
info->CurrentLayout.displayWidth = pScrn->displayWidth;
info->CurrentLayout.mode = pScrn->currentMode;
@@ -3024,10 +3709,10 @@ static Bool RADEONPreInitDRI(ScrnInfoPtr pScrn)
}
info->agpMode = RADEON_DEFAULT_AGP_MODE;
- info->agpSize = RADEON_DEFAULT_AGP_SIZE;
+ info->gartSize = RADEON_DEFAULT_GART_SIZE;
info->ringSize = RADEON_DEFAULT_RING_SIZE;
info->bufSize = RADEON_DEFAULT_BUFFER_SIZE;
- info->agpTexSize = RADEON_DEFAULT_AGP_TEX_SIZE;
+ info->gartTexSize = RADEON_DEFAULT_GART_TEX_SIZE;
info->agpFastWrite = RADEON_DEFAULT_AGP_FAST_WRITE;
info->CPusecTimeout = RADEON_DEFAULT_CP_TIMEOUT;
@@ -3050,67 +3735,67 @@ static Bool RADEONPreInitDRI(ScrnInfoPtr pScrn)
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
"Enabling AGP Fast Write\n");
} else {
- xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"AGP Fast Write disabled by default\n");
}
+ }
- if (xf86GetOptValInteger(info->Options,
- OPTION_AGP_SIZE, (int *)&(info->agpSize))) {
- switch (info->agpSize) {
- case 4:
- case 8:
- case 16:
- case 32:
- case 64:
- case 128:
- case 256:
- break;
-
- default:
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "Illegal AGP size: %d MB\n", info->agpSize);
- return FALSE;
- }
- }
+ if (xf86GetOptValInteger(info->Options,
+ OPTION_GART_SIZE, (int *)&(info->gartSize))) {
+ switch (info->gartSize) {
+ case 4:
+ case 8:
+ case 16:
+ case 32:
+ case 64:
+ case 128:
+ case 256:
+ break;
- if (xf86GetOptValInteger(info->Options,
- OPTION_RING_SIZE, &(info->ringSize))) {
- if (info->ringSize < 1 || info->ringSize >= (int)info->agpSize) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "Illegal ring buffer size: %d MB\n",
- info->ringSize);
- return FALSE;
- }
+ default:
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Illegal GART size: %d MB\n", info->gartSize);
+ return FALSE;
}
+ }
- if (xf86GetOptValInteger(info->Options,
- OPTION_BUFFER_SIZE, &(info->bufSize))) {
- if (info->bufSize < 1 || info->bufSize >= (int)info->agpSize) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "Illegal vertex/indirect buffers size: %d MB\n",
- info->bufSize);
- return FALSE;
- }
- if (info->bufSize > 2) {
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "Illegal vertex/indirect buffers size: %d MB\n",
- info->bufSize);
- xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "Clamping vertex/indirect buffers size to 2 MB\n");
- info->bufSize = 2;
- }
+ if (xf86GetOptValInteger(info->Options,
+ OPTION_RING_SIZE, &(info->ringSize))) {
+ if (info->ringSize < 1 || info->ringSize >= (int)info->gartSize) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Illegal ring buffer size: %d MB\n",
+ info->ringSize);
+ return FALSE;
}
+ }
- if (info->ringSize + info->bufSize + info->agpTexSize >
- (int)info->agpSize) {
+ if (xf86GetOptValInteger(info->Options,
+ OPTION_BUFFER_SIZE, &(info->bufSize))) {
+ if (info->bufSize < 1 || info->bufSize >= (int)info->gartSize) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
- "Buffers are too big for requested AGP space\n");
+ "Illegal vertex/indirect buffers size: %d MB\n",
+ info->bufSize);
return FALSE;
}
+ if (info->bufSize > 2) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Illegal vertex/indirect buffers size: %d MB\n",
+ info->bufSize);
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Clamping vertex/indirect buffers size to 2 MB\n");
+ info->bufSize = 2;
+ }
+ }
- info->agpTexSize = info->agpSize - (info->ringSize + info->bufSize);
+ if (info->ringSize + info->bufSize + info->gartTexSize >
+ (int)info->gartSize) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Buffers are too big for requested GART space\n");
+ return FALSE;
}
+ info->gartTexSize = info->gartSize - (info->ringSize + info->bufSize);
+
if (xf86GetOptValInteger(info->Options, OPTION_USEC_TIMEOUT,
&(info->CPusecTimeout))) {
/* This option checked by the RADEON DRM kernel module */
@@ -3129,7 +3814,7 @@ static Bool RADEONPreInitDRI(ScrnInfoPtr pScrn)
* for dedicated 3d rendering boxes
*/
info->noBackBuffer = xf86ReturnOptValBool(info->Options,
- OPTION_NO_BACKBUFFER,
+ OPTION_NO_BACKBUFFER,
FALSE);
if (info->noBackBuffer) {
@@ -3170,7 +3855,8 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags)
RADEONInfoPtr info;
xf86Int10InfoPtr pInt10 = NULL;
void *int10_save = NULL;
-
+ const char *s;
+
RADEONTRACE(("RADEONPreInit\n"));
if (pScrn->numEntities != 1) return FALSE;
@@ -3182,14 +3868,34 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags)
info->CurCloneMode = NULL;
info->CloneModes = NULL;
info->IsSwitching = FALSE;
+ info->MMIO = NULL;
- info->pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
+ info->pEnt = xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]);
if (info->pEnt->location.type != BUS_PCI) goto fail;
info->PciInfo = xf86GetPciInfoForEntity(info->pEnt->index);
info->PciTag = pciTag(info->PciInfo->bus,
info->PciInfo->device,
info->PciInfo->func);
+ info->MMIOAddr = info->PciInfo->memBase[2] & 0xffffff00;
+ if (info->pEnt->device->IOBase) {
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+ "MMIO address override, using 0x%08lx instead of 0x%08lx\n",
+ info->pEnt->device->IOBase,
+ info->MMIOAddr);
+ info->MMIOAddr = info->pEnt->device->IOBase;
+ } else if (!info->MMIOAddr) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid MMIO address\n");
+ goto fail1;
+ }
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "MMIO registers at 0x%08lx\n", info->MMIOAddr);
+
+ if(!RADEONMapMMIO(pScrn)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Memory map the MMIO region failed\n");
+ goto fail1;
+ }
#if !defined(__alpha__)
if (xf86GetPciDomain(info->PciTag) ||
@@ -3200,39 +3906,29 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags)
* going to run it again - so make sure to "fix up" the card
* so that (1) we can read the BIOS ROM and (2) the BIOS will
* get the memory config right.
- */
+ */
RADEONPreInt10Save(pScrn, &int10_save);
#endif
- if (xf86IsEntityShared(pScrn->entityList[0])) {
- if (xf86IsPrimInitDone(pScrn->entityList[0])) {
- DevUnion *pPriv;
- RADEONEntPtr pRADEONEnt;
+ if (xf86IsEntityShared(info->pEnt->index)) {
+ if (xf86IsPrimInitDone(info->pEnt->index)) {
+
+ RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
info->IsSecondary = TRUE;
- pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
- gRADEONEntityIndex);
- pRADEONEnt = pPriv->ptr;
- if (pRADEONEnt->BypassSecondary) {
- pRADEONEnt->HasSecondary = FALSE;
+ if (!pRADEONEnt->HasSecondary) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Only one monitor detected, Second screen "
"will NOT be created\n");
- return FALSE;
+ goto fail2;
}
pRADEONEnt->pSecondaryScrn = pScrn;
} else {
- DevUnion *pPriv;
- RADEONEntPtr pRADEONEnt;
+ RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
- xf86SetPrimInitDone(pScrn->entityList[0]);
- pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
- gRADEONEntityIndex);
+ xf86SetPrimInitDone(info->pEnt->index);
- pRADEONEnt = pPriv->ptr;
pRADEONEnt->pPrimaryScrn = pScrn;
- pRADEONEnt->IsDRIEnabled = FALSE;
- pRADEONEnt->BypassSecondary = FALSE;
pRADEONEnt->RestorePrimary = FALSE;
pRADEONEnt->IsSecondaryRestored = FALSE;
}
@@ -3241,6 +3937,7 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags)
if (flags & PROBE_DETECT) {
RADEONProbeDDC(pScrn, info->pEnt->index);
RADEONPostInt10Check(pScrn, int10_save);
+ if(info->MMIO) RADEONUnmapMMIO(pScrn);
return TRUE;
}
@@ -3248,7 +3945,7 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags)
xf86LoaderReqSymLists(vgahwSymbols, NULL);
if (!vgaHWGetHWRec(pScrn)) {
RADEONFreeRec(pScrn);
- return FALSE;
+ goto fail2;
}
vgaHWGetIOBase(VGAHWPTR(pScrn));
@@ -3291,6 +3988,18 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags)
info->videoKey = 0x1E;
}
+ info->DispPriority = 1;
+ if ((s = xf86GetOptValString(info->Options, OPTION_DISP_PRIORITY))) {
+ if (strcmp(s, "AUTO") == 0) {
+ info->DispPriority = 1;
+ } else if (strcmp(s, "BIOS") == 0) {
+ info->DispPriority = 0;
+ } else if (strcmp(s, "HIGH") == 0) {
+ info->DispPriority = 2;
+ } else
+ info->DispPriority = 1;
+ }
+
if (xf86ReturnOptValBool(info->Options, OPTION_FBDEV, FALSE)) {
/* check for Linux framebuffer device */
@@ -3321,17 +4030,13 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags)
if (!RADEONPreInitConfig(pScrn))
goto fail;
-#if !defined(__powerpc__)
+ RADEONPreInitDDC(pScrn);
+
if (!RADEONGetBIOSParameters(pScrn, pInt10))
goto fail;
-#else
- /* Force type to CRT since we currently can't read BIOS to tell us
- * what kind of heads we have.
- */
- info->DisplayType = MT_CRT;
-#endif
- RADEONPreInitDDC(pScrn);
+ if (info->DisplayType == MT_DFP)
+ RADEONGetTMDSInfo(pScrn);
if (!RADEONGetPLLParameters(pScrn)) goto fail;
@@ -3357,6 +4062,9 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags)
if (pInt10)
xf86FreeInt10(pInt10);
+ if(info->MMIO) RADEONUnmapMMIO(pScrn);
+ info->MMIO = NULL;
+
xf86DrvMsg(pScrn->scrnIndex, X_NOTICE,
"For information on using the multimedia capabilities\n of this"
" adapter, please see http://gatos.sf.net.\n");
@@ -3365,7 +4073,10 @@ Bool RADEONPreInit(ScrnInfoPtr pScrn, int flags)
fail:
/* Pre-init failed. */
-
+ if (info->IsSecondary) {
+ RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
+ pRADEONEnt->HasSecondary = FALSE;
+ }
/* Free the video bios (if applicable) */
if (info->VBIOS) {
xfree(info->VBIOS);
@@ -3377,7 +4088,13 @@ fail:
xf86FreeInt10(pInt10);
vgaHWFreeHWRec(pScrn);
+
+ fail2:
+ if(info->MMIO) RADEONUnmapMMIO(pScrn);
+ info->MMIO = NULL;
+ fail1:
RADEONFreeRec(pScrn);
+
return FALSE;
}
@@ -3480,7 +4197,7 @@ static void RADEONLoadPalette(ScrnInfoPtr pScrn, int numColors,
g = colors[idx].green;
b = colors[idx / 2].blue;
OUTPAL(idx * 4, r, g, b);
-
+
/* AH - Added to write extra green data - How come
* this isn't needed on R128? We didn't load the
* extra green data in the other routine.
@@ -3591,8 +4308,8 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
#ifdef XF86DRI
/* Setup DRI after visuals have been
- established, but before cfbScreenInit is
- called. cfbScreenInit will eventually
+ established, but before fbScreenInit is
+ called. fbScreenInit will eventually
call the driver's InitGLXVisuals call
back. */
{
@@ -3615,7 +4332,16 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
(pScrn->displayWidth * pScrn->virtualY *
info->CurrentLayout.pixel_bytes * 3 + 1023) / 1024);
info->directRenderingEnabled = FALSE;
- } else if (info->ChipFamily >= CHIP_FAMILY_R300) {
+ } else if ((info->ChipFamily == CHIP_FAMILY_RS100) ||
+ (info->ChipFamily == CHIP_FAMILY_RS200) ||
+ (info->ChipFamily == CHIP_FAMILY_RS300)) {
+ info->directRenderingEnabled = FALSE;
+ xf86DrvMsg(scrnIndex, X_WARNING,
+ "Direct rendering not yet supported on "
+ "IGP320/330/340/350, 7000, 9000 integrated chips\n");
+ } else if ((info->ChipFamily == CHIP_FAMILY_R300) ||
+ (info->ChipFamily == CHIP_FAMILY_R350) ||
+ (info->ChipFamily == CHIP_FAMILY_RV350)) {
info->directRenderingEnabled = FALSE;
xf86DrvMsg(scrnIndex, X_WARNING,
"Direct rendering not yet supported on "
@@ -3625,9 +4351,9 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
info->directRenderingEnabled = FALSE;
else {
/* Xinerama has sync problem with DRI, disable it for now */
- if (xf86IsEntityShared(pScrn->entityList[0])) {
+ if (xf86IsEntityShared(info->pEnt->index)) {
info->directRenderingEnabled = FALSE;
- xf86DrvMsg(scrnIndex, X_WARNING,
+ xf86DrvMsg(scrnIndex, X_WARNING,
"Direct Rendering Disabled -- "
"Dual-head configuration is not working with "
"DRI at present.\n"
@@ -3637,53 +4363,16 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
info->directRenderingEnabled =
RADEONDRIScreenInit(pScreen);
}
-
- if (xf86IsEntityShared(pScrn->entityList[0])) {
- DevUnion *pPriv;
- RADEONEntPtr pRADEONEnt;
-
- pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
- gRADEONEntityIndex);
- pRADEONEnt = pPriv->ptr;
- pRADEONEnt->IsDRIEnabled = info->directRenderingEnabled;
- }
}
}
}
#endif
-#ifdef USE_FB
if (!fbScreenInit(pScreen, info->FB,
pScrn->virtualX, pScrn->virtualY,
pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth,
pScrn->bitsPerPixel))
return FALSE;
-#else
- switch (pScrn->bitsPerPixel) {
- case 8:
- if (!cfbScreenInit(pScreen, info->FB,
- pScrn->virtualX, pScrn->virtualY,
- pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth))
- return FALSE;
- break;
- case 16:
- if (!cfb16ScreenInit(pScreen, info->FB,
- pScrn->virtualX, pScrn->virtualY,
- pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth))
- return FALSE;
- break;
- case 32:
- if (!cfb32ScreenInit(pScreen, info->FB,
- pScrn->virtualX, pScrn->virtualY,
- pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth))
- return FALSE;
- break;
- default:
- xf86DrvMsg(scrnIndex, X_ERROR,
- "Invalid bpp (%d)\n", pScrn->bitsPerPixel);
- return FALSE;
- }
-#endif
xf86SetBlackWhitePixels(pScreen);
@@ -3703,10 +4392,8 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
}
}
-#ifdef USE_FB
/* Must be after RGB order fixed */
fbPictureInit (pScreen, 0, 0);
-#endif
#ifdef RENDER
if (PictureGetSubpixelOrder (pScreen) == SubPixelUnknown)
@@ -3754,13 +4441,13 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
}
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "Using %d MB AGP aperture\n", info->agpSize);
+ "Using %d MB GART aperture\n", info->gartSize);
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Using %d MB for the ring buffer\n", info->ringSize);
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Using %d MB for vertex/indirect buffers\n", info->bufSize);
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "Using %d MB for AGP textures\n", info->agpTexSize);
+ "Using %d MB for GART textures\n", info->gartTexSize);
/* Try for front, back, depth, and three framebuffers worth of
* pixmap cache. Should be enough for a fullscreen background
@@ -3777,7 +4464,7 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
info->textureSize = info->FbMapSize - 4 * bufferSize - depthSize;
}
if (info->textureSize < (int)info->FbMapSize / 2) {
- info->textureSize = info->FbMapSize - 3 * bufferSize - depthSize;
+ info->textureSize = info->FbMapSize - 3 * bufferSize - depthSize;
}
/* If there's still no space for textures, try without pixmap cache */
if (info->textureSize < 0) {
@@ -4008,7 +4695,7 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
int width, height;
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
- "Using hardware cursor (scanline %d)\n",
+ "Using hardware cursor (scanline %ld)\n",
info->cursor_start / pScrn->displayWidth
/ info->CurrentLayout.pixel_bytes);
if (xf86QueryLargestOffscreenArea(pScreen, &width, &height,
@@ -4038,9 +4725,7 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
| CMAP_RELOAD_ON_MODE_SWITCH)) return FALSE;
/* DPMS setup */
-#ifdef DPMSExtension
xf86DPMSInit(pScreen, RADEONDisplayPowerManagementSet, 0);
-#endif
RADEONInitVideo(pScreen);
@@ -4058,12 +4743,16 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
#ifdef XF86DRI
/* DRI finalization */
if (info->directRenderingEnabled) {
- /* Now that mi, cfb, drm and others have
+ /* Now that mi, fb, drm and others have
done their thing, complete the DRI
setup. */
info->directRenderingEnabled = RADEONDRIFinishScreenInit(pScreen);
}
if (info->directRenderingEnabled) {
+ if ((info->DispPriority == 1) && (!info->IsPCI)) {
+ /* we need to re-calculate bandwidth because of AGPMode difference. */
+ RADEONInitDispBandwidth(pScrn);
+ }
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering enabled\n");
} else {
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering disabled\n");
@@ -4103,13 +4792,11 @@ static void RADEONRestoreCommonRegisters(ScrnInfoPtr pScrn,
if (info->HasCRTC2 &&
!info->IsSwitching &&
info->ChipFamily != CHIP_FAMILY_R200 &&
- info->ChipFamily != CHIP_FAMILY_R300) {
- DevUnion *pPriv;
- RADEONEntPtr pRADEONEnt;
+ info->ChipFamily != CHIP_FAMILY_R300 &&
+ info->ChipFamily != CHIP_FAMILY_R350 &&
+ info->ChipFamily != CHIP_FAMILY_RV350) {
CARD32 tmp;
-
- pPriv = xf86GetEntityPrivate(pScrn->entityList[0], gRADEONEntityIndex);
- pRADEONEnt = pPriv->ptr;
+ RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
if (pRADEONEnt->HasSecondary || info->Clone) {
tmp = INREG(RADEON_DAC_CNTL2);
@@ -4171,6 +4858,8 @@ static void RADEONRestoreCrtcRegisters(ScrnInfoPtr pScrn,
OUTREG(RADEON_CRTC_OFFSET, restore->crtc_offset);
OUTREG(RADEON_CRTC_OFFSET_CNTL, restore->crtc_offset_cntl);
OUTREG(RADEON_CRTC_PITCH, restore->crtc_pitch);
+ OUTREG(RADEON_DISP_MERGE_CNTL, restore->disp_merge_cntl);
+ OUTREG(RADEON_CRTC_MORE_CNTL, restore->crtc_more_cntl);
}
/* Write CRTC2 registers */
@@ -4188,18 +4877,14 @@ static void RADEONRestoreCrtc2Registers(ScrnInfoPtr pScrn,
OUTREG(RADEON_DAC_CNTL2, restore->dac2_cntl);
- if (info->ChipFamily == CHIP_FAMILY_R200 ||
- info->ChipFamily == CHIP_FAMILY_R300) {
+ OUTREG(RADEON_TV_DAC_CNTL, 0x00280203);
+ if ((info->ChipFamily == CHIP_FAMILY_R200) ||
+ (info->ChipFamily == CHIP_FAMILY_R300) ||
+ (info->ChipFamily == CHIP_FAMILY_R350) ||
+ (info->ChipFamily == CHIP_FAMILY_RV350)) {
OUTREG(RADEON_DISP_OUTPUT_CNTL, restore->disp_output_cntl);
} else {
OUTREG(RADEON_DISP_HW_DEBUG, restore->disp_hw_debug);
- if (info->IsDell) {
- /* Workaround for DELL card. BIOS doesn't initialize
- * TV_DAC_CNTL to a correct value which causes too high
- * contrast for the second CRT (using TV_DAC).
- */
- OUTREG(RADEON_TV_DAC_CNTL, 0x00280203);
- }
}
OUTREG(RADEON_CRTC2_H_TOTAL_DISP, restore->crtc2_h_total_disp);
@@ -4209,13 +4894,14 @@ static void RADEONRestoreCrtc2Registers(ScrnInfoPtr pScrn,
OUTREG(RADEON_CRTC2_OFFSET, restore->crtc2_offset);
OUTREG(RADEON_CRTC2_OFFSET_CNTL, restore->crtc2_offset_cntl);
OUTREG(RADEON_CRTC2_PITCH, restore->crtc2_pitch);
+ OUTREG(RADEON_DISP2_MERGE_CNTL, restore->disp2_merge_cntl);
- if (info->DisplayType == MT_DFP || info->CloneType == MT_DFP) {
+ if ((info->DisplayType == MT_DFP && info->IsSecondary) ||
+ info->CloneType == MT_DFP) {
OUTREG(RADEON_FP_H2_SYNC_STRT_WID, restore->fp2_h_sync_strt_wid);
OUTREG(RADEON_FP_V2_SYNC_STRT_WID, restore->fp2_v_sync_strt_wid);
OUTREG(RADEON_FP2_GEN_CNTL, restore->fp2_gen_cntl);
}
-
#if 0
/* Hack for restoring text mode -- fixed elsewhere */
usleep(100000);
@@ -4234,11 +4920,31 @@ static void RADEONRestoreFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
OUTREG(RADEON_FP_H_SYNC_STRT_WID, restore->fp_h_sync_strt_wid);
OUTREG(RADEON_FP_V_SYNC_STRT_WID, restore->fp_v_sync_strt_wid);
OUTREG(RADEON_TMDS_PLL_CNTL, restore->tmds_pll_cntl);
+ OUTREG(RADEON_TMDS_TRANSMITTER_CNTL,restore->tmds_transmitter_cntl);
OUTREG(RADEON_FP_HORZ_STRETCH, restore->fp_horz_stretch);
OUTREG(RADEON_FP_VERT_STRETCH, restore->fp_vert_stretch);
OUTREG(RADEON_FP_GEN_CNTL, restore->fp_gen_cntl);
- if (info->DisplayType == MT_LCD) {
+ /* old AIW Radeon has some BIOS initialization problem
+ * with display buffer underflow, only occurs to DFP
+ */
+ if (!info->HasCRTC2)
+ OUTREG(RADEON_GRPH_BUFFER_CNTL,
+ INREG(RADEON_GRPH_BUFFER_CNTL) & ~0x7f0000);
+
+ if (info->DisplayType != MT_DFP) {
+ unsigned long tmpPixclksCntl = INPLL(pScrn, RADEON_PIXCLKS_CNTL);
+ OUTREG(RADEON_BIOS_5_SCRATCH, restore->bios_5_scratch);
+
+ if (info->IsMobility || info->IsIGP) {
+ /* Asic bug, when turning off LVDS_ON, we have to make sure
+ RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
+ */
+ if (!(restore->lvds_gen_cntl & RADEON_LVDS_ON)) {
+ OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb);
+ }
+ }
+
tmp = INREG(RADEON_LVDS_GEN_CNTL);
if ((tmp & (RADEON_LVDS_ON | RADEON_LVDS_BLON)) ==
(restore->lvds_gen_cntl & (RADEON_LVDS_ON | RADEON_LVDS_BLON))) {
@@ -4254,6 +4960,12 @@ static void RADEONRestoreFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr restore)
OUTREG(RADEON_LVDS_GEN_CNTL, restore->lvds_gen_cntl);
}
}
+
+ if (info->IsMobility || info->IsIGP) {
+ if (!(restore->lvds_gen_cntl & RADEON_LVDS_ON)) {
+ OUTPLL(RADEON_PIXCLKS_CNTL, tmpPixclksCntl);
+ }
+ }
}
}
@@ -4316,6 +5028,18 @@ static void RADEONRestorePLLRegisters(ScrnInfoPtr pScrn,
RADEONInfoPtr info = RADEONPTR(pScrn);
unsigned char *RADEONMMIO = info->MMIO;
+ if (info->IsMobility) {
+ /* A temporal workaround for the occational blanking on certain laptop panels.
+ This appears to related to the PLL divider registers (fail to lock?).
+ It occurs even when all dividers are the same with their old settings.
+ In this case we really don't need to fiddle with PLL registers.
+ By doing this we can avoid the blanking problem with some panels.
+ */
+ if ((restore->ppll_ref_div == (INPLL(pScrn, RADEON_PPLL_REF_DIV) & RADEON_PPLL_REF_DIV_MASK)) &&
+ (restore->ppll_div_3 == (INPLL(pScrn, RADEON_PPLL_DIV_3) & (RADEON_PPLL_POST3_DIV_MASK | RADEON_PPLL_FB3_DIV_MASK))))
+ return;
+ }
+
OUTPLLP(pScrn, RADEON_VCLK_ECP_CNTL,
RADEON_VCLK_SRC_SEL_CPUCLK,
~(RADEON_VCLK_SRC_SEL_MASK));
@@ -4333,7 +5057,9 @@ static void RADEONRestorePLLRegisters(ScrnInfoPtr pScrn,
RADEON_PLL_DIV_SEL,
~(RADEON_PLL_DIV_SEL));
- if (info->ChipFamily == CHIP_FAMILY_R300) {
+ if ((info->ChipFamily == CHIP_FAMILY_R300) ||
+ (info->ChipFamily == CHIP_FAMILY_R350) ||
+ (info->ChipFamily == CHIP_FAMILY_RV350)) {
if (restore->ppll_ref_div & R300_PPLL_REF_DIV_ACC_MASK) {
/* When restoring console mode, use saved PPLL_REF_DIV
* setting.
@@ -4344,7 +5070,7 @@ static void RADEONRestorePLLRegisters(ScrnInfoPtr pScrn,
} else {
/* R300 uses ref_div_acc field as real ref divider */
OUTPLLP(pScrn, RADEON_PPLL_REF_DIV,
- (restore->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT),
+ (restore->ppll_ref_div << R300_PPLL_REF_DIV_ACC_SHIFT),
~R300_PPLL_REF_DIV_ACC_MASK);
}
} else {
@@ -4373,6 +5099,11 @@ static void RADEONRestorePLLRegisters(ScrnInfoPtr pScrn,
| RADEON_PPLL_ATOMIC_UPDATE_EN
| RADEON_PPLL_VGA_ATOMIC_UPDATE_EN));
+ xf86DrvMsg(0, X_INFO, "Wrote: rd=%d, fd=%d, pd=%d\n",
+ restore->ppll_ref_div & RADEON_PPLL_REF_DIV_MASK,
+ restore->ppll_div_3 & RADEON_PPLL_FB3_DIV_MASK,
+ (restore->ppll_div_3 & RADEON_PPLL_POST3_DIV_MASK) >> 16);
+
RADEONTRACE(("Wrote: 0x%08x 0x%08x 0x%08x (0x%08x)\n",
restore->ppll_ref_div,
restore->ppll_div_3,
@@ -4481,26 +5212,19 @@ static void RADEONRestorePalette(ScrnInfoPtr pScrn, RADEONSavePtr restore)
/* Write out state to define a new video mode */
static void RADEONRestoreMode(ScrnInfoPtr pScrn, RADEONSavePtr restore)
{
- RADEONInfoPtr info = RADEONPTR(pScrn);
- DevUnion *pPriv;
- RADEONEntPtr pRADEONEnt;
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
static RADEONSaveRec restore0;
/* For Non-dual head card, we don't have private field in the Entity */
if (!info->HasCRTC2) {
RADEONRestoreCommonRegisters(pScrn, restore);
RADEONRestoreCrtcRegisters(pScrn, restore);
- if ((info->DisplayType == MT_DFP) ||
- (info->DisplayType == MT_LCD)) {
- RADEONRestoreFPRegisters(pScrn, restore);
- }
+ RADEONRestoreFPRegisters(pScrn, restore);
RADEONRestorePLLRegisters(pScrn, restore);
return;
}
- pPriv = xf86GetEntityPrivate(pScrn->entityList[0], gRADEONEntityIndex);
- pRADEONEnt = pPriv->ptr;
-
RADEONTRACE(("RADEONRestoreMode(%p)\n", restore));
/* When changing mode with Dual-head card, care must be taken for
@@ -4513,7 +5237,7 @@ static void RADEONRestoreMode(ScrnInfoPtr pScrn, RADEONSavePtr restore)
* we may get a blank screen.
*/
if (info->IsSecondary) {
- if (!pRADEONEnt->RestorePrimary)
+ if (!pRADEONEnt->RestorePrimary && !info->IsSwitching)
RADEONRestoreCommonRegisters(pScrn, restore);
RADEONRestoreCrtc2Registers(pScrn, restore);
RADEONRestorePLL2Registers(pScrn, restore);
@@ -4523,15 +5247,10 @@ static void RADEONRestoreMode(ScrnInfoPtr pScrn, RADEONSavePtr restore)
pRADEONEnt->IsSecondaryRestored = TRUE;
if (pRADEONEnt->RestorePrimary) {
- RADEONInfoPtr info0 = RADEONPTR(pRADEONEnt->pPrimaryScrn);
pRADEONEnt->RestorePrimary = FALSE;
RADEONRestoreCrtcRegisters(pScrn, &restore0);
- if ((info0->DisplayType == MT_DFP) ||
- (info0->DisplayType == MT_LCD)) {
- RADEONRestoreFPRegisters(pScrn, &restore0);
- }
-
+ RADEONRestoreFPRegisters(pScrn, &restore0);
RADEONRestorePLLRegisters(pScrn, &restore0);
pRADEONEnt->IsSecondaryRestored = FALSE;
}
@@ -4549,10 +5268,7 @@ static void RADEONRestoreMode(ScrnInfoPtr pScrn, RADEONSavePtr restore)
pRADEONEnt->IsSecondaryRestored = FALSE;
RADEONRestoreCrtcRegisters(pScrn, restore);
- if ((info->DisplayType == MT_DFP) ||
- (info->DisplayType == MT_LCD)) {
- RADEONRestoreFPRegisters(pScrn, restore);
- }
+ RADEONRestoreFPRegisters(pScrn, restore);
RADEONRestorePLLRegisters(pScrn, restore);
} else {
memcpy(&restore0, restore, sizeof(restore0));
@@ -4583,6 +5299,8 @@ static void RADEONSaveCommonRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save)
save->cap1_trig_cntl = INREG(RADEON_CAP1_TRIG_CNTL);
save->bus_cntl = INREG(RADEON_BUS_CNTL);
save->surface_cntl = INREG(RADEON_SURFACE_CNTL);
+ save->grph_buffer_cntl = INREG(RADEON_GRPH_BUFFER_CNTL);
+ save->grph2_buffer_cntl = INREG(RADEON_GRPH2_BUFFER_CNTL);
}
/* Read miscellaneous registers which might be destroyed by an fbdevHW call */
@@ -4623,6 +5341,8 @@ static void RADEONSaveCrtcRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save)
save->crtc_offset = INREG(RADEON_CRTC_OFFSET);
save->crtc_offset_cntl = INREG(RADEON_CRTC_OFFSET_CNTL);
save->crtc_pitch = INREG(RADEON_CRTC_PITCH);
+ save->disp_merge_cntl = INREG(RADEON_DISP_MERGE_CNTL);
+ save->crtc_more_cntl = INREG(RADEON_CRTC_MORE_CNTL);
}
/* Read flat panel registers */
@@ -4641,6 +5361,13 @@ static void RADEONSaveFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save)
save->lvds_gen_cntl = INREG(RADEON_LVDS_GEN_CNTL);
save->lvds_pll_cntl = INREG(RADEON_LVDS_PLL_CNTL);
save->tmds_pll_cntl = INREG(RADEON_TMDS_PLL_CNTL);
+ save->tmds_transmitter_cntl= INREG(RADEON_TMDS_TRANSMITTER_CNTL);
+ save->bios_5_scratch = INREG(RADEON_BIOS_5_SCRATCH);
+
+ if (info->ChipFamily == CHIP_FAMILY_RV280) {
+ /* bit 22 of TMDS_PLL_CNTL is read-back inverted */
+ save->tmds_pll_cntl ^= (1 << 22);
+ }
}
/* Read CRTC2 registers */
@@ -4665,7 +5392,7 @@ static void RADEONSaveCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save)
save->fp2_h_sync_strt_wid = INREG (RADEON_FP_H2_SYNC_STRT_WID);
save->fp2_v_sync_strt_wid = INREG (RADEON_FP_V2_SYNC_STRT_WID);
save->fp2_gen_cntl = INREG (RADEON_FP2_GEN_CNTL);
-
+ save->disp2_merge_cntl = INREG(RADEON_DISP2_MERGE_CNTL);
}
/* Read PLL registers */
@@ -4735,11 +5462,7 @@ static void RADEONSaveMode(ScrnInfoPtr pScrn, RADEONSavePtr save)
RADEONSavePLLRegisters(pScrn, save);
RADEONSaveCommonRegisters(pScrn, save);
RADEONSaveCrtcRegisters(pScrn, save);
-
- if ((info->DisplayType == MT_DFP) ||
- (info->DisplayType == MT_LCD)) {
- RADEONSaveFPRegisters(pScrn, save);
- }
+ RADEONSaveFPRegisters(pScrn, save);
if (info->Clone) {
RADEONSaveCrtc2Registers(pScrn, save);
@@ -4774,7 +5497,7 @@ static void RADEONSave(ScrnInfoPtr pScrn)
*/
vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE); /* Save mode only */
#else
- vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_ALL); /* Save mode
+ vgaHWSave(pScrn, &hwp->SavedReg, VGA_SR_MODE | VGA_SR_FONTS); /* Save mode
* & fonts & cmap
*/
#endif
@@ -4813,12 +5536,14 @@ static void RADEONRestore(ScrnInfoPtr pScrn)
if (info->R300CGWorkaround) R300CGWorkaround(pScrn);
OUTREG(RADEON_RBBM_SOFT_RESET, restore->rbbm_soft_reset);
OUTREG(RADEON_DP_DATATYPE, restore->dp_datatype);
+ OUTREG(RADEON_GRPH_BUFFER_CNTL, restore->grph_buffer_cntl);
+ OUTREG(RADEON_GRPH2_BUFFER_CNTL, restore->grph2_buffer_cntl);
#if 0
/* M6 card has trouble restoring text mode for its CRT.
* This is fixed elsewhere and will be removed in the future.
*/
- if ((xf86IsEntityShared(pScrn->entityList[0]) || info->Clone)
+ if ((xf86IsEntityShared(info->pEnt->index) || info->Clone)
&& info->IsM6)
OUTREG(RADEON_DAC_CNTL2, restore->dac2_cntl);
#endif
@@ -4846,15 +5571,10 @@ static void RADEONRestore(ScrnInfoPtr pScrn)
#endif
vgaHWLock(hwp);
} else {
- DevUnion *pPriv;
- RADEONEntPtr pRADEONEnt;
+ RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
ScrnInfoPtr pScrn0;
vgaHWPtr hwp0;
- pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
- gRADEONEntityIndex);
- pRADEONEnt = pPriv->ptr;
-
pScrn0 = pRADEONEnt->pPrimaryScrn;
hwp0 = VGAHWPTR(pScrn0);
vgaHWUnlock(hwp0);
@@ -4890,6 +5610,322 @@ static void RADEONInitCommonRegisters(RADEONSavePtr save, RADEONInfoPtr info)
save->bus_cntl |= RADEON_BUS_RD_DISCARD_EN;
}
+/* Calculate display buffer watermark to prevent buffer underflow */
+static void RADEONInitDispBandwidth(ScrnInfoPtr pScrn)
+{
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
+ unsigned char *RADEONMMIO = info->MMIO;
+ RADEONInfoPtr info2 = NULL;
+
+ DisplayModePtr mode1, mode2;
+
+ CARD32 temp, data, mem_trcd, mem_trp, mem_tras, mem_trbs=0;
+ float mem_tcas;
+ int k1, c;
+ CARD32 MemTrcdExtMemCntl[4] = {1, 2, 3, 4};
+ CARD32 MemTrpExtMemCntl[4] = {1, 2, 3, 4};
+ CARD32 MemTrasExtMemCntl[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+ CARD32 MemTrcdMemTimingCntl[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+ CARD32 MemTrpMemTimingCntl[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+ CARD32 MemTrasMemTimingCntl[16] = {4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
+
+ float MemTcas[8] = {0, 1, 2, 3, 0, 1.5, 2.5, 0};
+ float MemTcas2[8] = {0, 1, 2, 3, 4, 5, 6, 7};
+ float MemTrbs[8] = {1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5};
+
+ float mem_bw, peak_disp_bw;
+ float min_mem_eff = 0.8;
+ float sclk_eff, sclk_delay;
+ float mc_latency_mclk, mc_latency_sclk, cur_latency_mclk, cur_latency_sclk;
+ float disp_latency, disp_latency_overhead, disp_drain_rate, disp_drain_rate2;
+ float pix_clk, pix_clk2; /* in MHz */
+ int cur_size = 16; /* in octawords */
+ int critical_point, critical_point2;
+ int stop_req, max_stop_req;
+ float read_return_rate, time_disp1_drop_priority;
+
+ if (pRADEONEnt->pSecondaryScrn) {
+ if (info->IsSecondary) return;
+ info2 = RADEONPTR(pRADEONEnt->pSecondaryScrn);
+ } else if (info->Clone) info2 = info;
+
+ /*
+ * Determine if there is enough bandwidth for current display mode
+ */
+ mem_bw = info->mclk * (info->RamWidth / 8) * (info->IsDDR ? 2 : 1);
+
+ mode1 = info->CurrentLayout.mode;
+ if (info->Clone)
+ mode2 = info->CurCloneMode;
+ else if ((pRADEONEnt->HasSecondary) && info2)
+ mode2 = info2->CurrentLayout.mode;
+ else
+ mode2 = NULL;
+
+ pix_clk = mode1->Clock/1000.0;
+ if (mode2)
+ pix_clk2 = mode2->Clock/1000.0;
+ else
+ pix_clk2 = 0;
+
+ peak_disp_bw = (pix_clk * info->CurrentLayout.pixel_bytes);
+ if (info2)
+ peak_disp_bw += (pix_clk2 * info2->CurrentLayout.pixel_bytes);
+
+ if (peak_disp_bw >= mem_bw * min_mem_eff) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "You may not have enough display bandwidth for current mode\n"
+ "If you have flickering problem, try to lower resolution, refresh rate, or color depth\n");
+ }
+
+ /* CRTC1
+ Set GRPH_BUFFER_CNTL register using h/w defined optimal values.
+ GRPH_STOP_REQ <= MIN[ 0x7C, (CRTC_H_DISP + 1) * (bit depth) / 0x10 ]
+ */
+ stop_req = mode1->HDisplay * info->CurrentLayout.pixel_bytes / 16;
+
+ /* setup Max GRPH_STOP_REQ default value */
+ if ((info->ChipFamily == CHIP_FAMILY_RV100) ||
+ (info->ChipFamily == CHIP_FAMILY_RV200) ||
+ (info->ChipFamily == CHIP_FAMILY_RV250) ||
+ (info->ChipFamily == CHIP_FAMILY_RV280) ||
+ (info->ChipFamily == CHIP_FAMILY_RS100) ||
+ (info->ChipFamily == CHIP_FAMILY_RS200) ||
+ (info->ChipFamily == CHIP_FAMILY_RS300))
+ max_stop_req = 0x5c;
+ else
+ max_stop_req = 0x7c;
+ if (stop_req > max_stop_req)
+ stop_req = max_stop_req;
+
+ /* Get values from the EXT_MEM_CNTL register...converting its contents. */
+ temp = INREG(RADEON_MEM_TIMING_CNTL);
+ if ((info->ChipFamily == CHIP_FAMILY_RV100) || info->IsIGP) { /* RV100, M6, IGPs */
+ mem_trcd = MemTrcdExtMemCntl[(temp & 0x0c) >> 2];
+ mem_trp = MemTrpExtMemCntl[ (temp & 0x03) >> 0];
+ mem_tras = MemTrasExtMemCntl[(temp & 0x70) >> 4];
+ } else { /* RV200 and later */
+ mem_trcd = MemTrcdMemTimingCntl[(temp & 0x07) >> 0];
+ mem_trp = MemTrpMemTimingCntl[ (temp & 0x700) >> 8];
+ mem_tras = MemTrasMemTimingCntl[(temp & 0xf000) >> 12];
+ }
+
+ /* Get values from the MEM_SDRAM_MODE_REG register...converting its */
+ temp = INREG(RADEON_MEM_SDRAM_MODE_REG);
+ data = (temp & (7<<20)) >> 20;
+ if ((info->ChipFamily == CHIP_FAMILY_RV100) || info->IsIGP) { /* RV100, M6, IGPs */
+ mem_tcas = MemTcas [data];
+ } else {
+ mem_tcas = MemTcas2 [data];
+ }
+
+ if ((info->ChipFamily == CHIP_FAMILY_R300) ||
+ (info->ChipFamily == CHIP_FAMILY_R350) ||
+ (info->ChipFamily == CHIP_FAMILY_RV350)) {
+
+ /* on the R300, Tcas is included in Trbs.
+ */
+ temp = INREG(RADEON_MEM_CNTL);
+ data = (R300_MEM_NUM_CHANNELS_MASK & temp);
+ if (data == 2) {
+ if (R300_MEM_USE_CD_CH_ONLY & temp) {
+ temp = INREG(R300_MC_IND_INDEX);
+ temp &= ~R300_MC_IND_ADDR_MASK;
+ temp |= R300_MC_READ_CNTL_CD_mcind;
+ OUTREG(R300_MC_IND_INDEX, temp);
+ temp = INREG(R300_MC_IND_DATA);
+ data = (R300_MEM_RBS_POSITION_C_MASK & temp);
+ } else {
+ temp = INREG(R300_MC_READ_CNTL_AB);
+ data = (R300_MEM_RBS_POSITION_A_MASK & temp);
+ }
+ } else {
+ temp = INREG(R300_MC_READ_CNTL_AB);
+ data = (R300_MEM_RBS_POSITION_A_MASK & temp);
+ }
+
+ mem_trbs = MemTrbs[data];
+ mem_tcas += mem_trbs;
+ }
+
+ if ((info->ChipFamily == CHIP_FAMILY_RV100) || info->IsIGP) { /* RV100, M6, IGPs */
+ /* DDR64 SCLK_EFF = SCLK for analysis */
+ sclk_eff = info->sclk;
+ } else {
+#ifdef XF86DRI
+ if (info->directRenderingEnabled)
+ sclk_eff = info->sclk - (info->agpMode * 50.0 / 3.0);
+ else
+#endif
+ sclk_eff = info->sclk;
+ }
+
+ /* Find the memory controller latency for the display client.
+ */
+ if ((info->ChipFamily == CHIP_FAMILY_R300) ||
+ (info->ChipFamily == CHIP_FAMILY_R350) ||
+ (info->ChipFamily == CHIP_FAMILY_RV350)) {
+ /*not enough for R350 ???*/
+ /*
+ if (!mode2) sclk_delay = 150;
+ else {
+ if (info->RamWidth == 256) sclk_delay = 87;
+ else sclk_delay = 97;
+ }
+ */
+ sclk_delay = 250;
+ } else {
+ if ((info->ChipFamily == CHIP_FAMILY_RV100) ||
+ info->IsIGP) {
+ if (info->IsDDR) sclk_delay = 41;
+ else sclk_delay = 33;
+ } else {
+ if (info->RamWidth == 128) sclk_delay = 57;
+ else sclk_delay = 41;
+ }
+ }
+
+ mc_latency_sclk = sclk_delay / sclk_eff;
+
+ if (info->IsDDR) {
+ if (info->RamWidth == 32) {
+ k1 = 40;
+ c = 3;
+ } else {
+ k1 = 20;
+ c = 1;
+ }
+ } else {
+ k1 = 40;
+ c = 3;
+ }
+ mc_latency_mclk = ((2.0*mem_trcd + mem_tcas*c + 4.0*mem_tras + 4.0*mem_trp + k1) /
+ info->mclk) + (4.0 / sclk_eff);
+
+ /*
+ HW cursor time assuming worst case of full size colour cursor.
+ */
+ cur_latency_mclk = (mem_trp + MAX(mem_tras, (mem_trcd + 2*(cur_size - (info->IsDDR+1))))) / info->mclk;
+ cur_latency_sclk = cur_size / sclk_eff;
+
+ /*
+ Find the total latency for the display data.
+ */
+ disp_latency_overhead = 8.0 / info->sclk;
+ mc_latency_mclk = mc_latency_mclk + disp_latency_overhead + cur_latency_mclk;
+ mc_latency_sclk = mc_latency_sclk + disp_latency_overhead + cur_latency_sclk;
+ disp_latency = MAX(mc_latency_mclk, mc_latency_sclk);
+
+ /*
+ Find the drain rate of the display buffer.
+ */
+ disp_drain_rate = pix_clk / (16.0/info->CurrentLayout.pixel_bytes);
+ if (info2)
+ disp_drain_rate2 = pix_clk2 / (16.0/info2->CurrentLayout.pixel_bytes);
+ else
+ disp_drain_rate2 = 0;
+
+ /*
+ Find the critical point of the display buffer.
+ */
+ critical_point= (CARD32)(disp_drain_rate * disp_latency + 0.5);
+
+ /* ???? */
+ /*
+ temp = (info->SavedReg.grph_buffer_cntl & RADEON_GRPH_CRITICAL_POINT_MASK) >> RADEON_GRPH_CRITICAL_POINT_SHIFT;
+ if (critical_point < temp) critical_point = temp;
+ */
+ if (info->DispPriority == 2) {
+ if (mode2) {
+ /*??some R300 cards have problem with this set to 0, when CRTC2 is enabled.*/
+ if (info->ChipFamily == CHIP_FAMILY_R300)
+ critical_point += 0x10;
+ else
+ critical_point = 0;
+ }
+ else
+ critical_point = 0;
+ }
+
+ /*
+ The critical point should never be above max_stop_req-4. Setting
+ GRPH_CRITICAL_CNTL = 0 will thus force high priority all the time.
+ */
+ if (max_stop_req - critical_point < 4) critical_point = 0;
+
+ temp = info->SavedReg.grph_buffer_cntl;
+ temp &= ~(RADEON_GRPH_STOP_REQ_MASK);
+ temp |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT);
+ temp &= ~(RADEON_GRPH_START_REQ_MASK);
+ if ((info->ChipFamily == CHIP_FAMILY_R350) &&
+ (stop_req > 0x15)) {
+ stop_req -= 0x10;
+ }
+ temp |= (stop_req << RADEON_GRPH_START_REQ_SHIFT);
+
+ temp |= RADEON_GRPH_BUFFER_SIZE;
+ temp &= ~(RADEON_GRPH_CRITICAL_CNTL |
+ RADEON_GRPH_CRITICAL_AT_SOF |
+ RADEON_GRPH_STOP_CNTL);
+ /*
+ Write the result into the register.
+ */
+ OUTREG(RADEON_GRPH_BUFFER_CNTL, ((temp & ~RADEON_GRPH_CRITICAL_POINT_MASK) |
+ (critical_point << RADEON_GRPH_CRITICAL_POINT_SHIFT)));
+
+ RADEONTRACE(("GRPH_BUFFER_CNTL from %x to %x\n",
+ info->SavedReg.grph_buffer_cntl, INREG(RADEON_GRPH_BUFFER_CNTL)));
+
+ if (mode2) {
+ stop_req = mode2->HDisplay * info2->CurrentLayout.pixel_bytes / 16;
+
+ if (stop_req > max_stop_req) stop_req = max_stop_req;
+
+ temp = info->SavedReg.grph2_buffer_cntl;
+ temp &= ~(RADEON_GRPH_STOP_REQ_MASK);
+ temp |= (stop_req << RADEON_GRPH_STOP_REQ_SHIFT);
+ temp &= ~(RADEON_GRPH_START_REQ_MASK);
+ if ((info->ChipFamily == CHIP_FAMILY_R350) &&
+ (stop_req > 0x15)) {
+ stop_req -= 0x10;
+ }
+ temp |= (stop_req << RADEON_GRPH_START_REQ_SHIFT);
+ temp |= RADEON_GRPH_BUFFER_SIZE;
+ temp &= ~(RADEON_GRPH_CRITICAL_CNTL |
+ RADEON_GRPH_CRITICAL_AT_SOF |
+ RADEON_GRPH_STOP_CNTL);
+
+ if ((info->ChipFamily == CHIP_FAMILY_RS100) ||
+ (info->ChipFamily == CHIP_FAMILY_RS200))
+ critical_point2 = 0;
+ else {
+ read_return_rate = MIN(info->sclk, info->mclk*(info->RamWidth*(info->IsDDR+1)/128));
+ time_disp1_drop_priority = critical_point / (read_return_rate - disp_drain_rate);
+
+ critical_point2 = (CARD32)((disp_latency + time_disp1_drop_priority +
+ disp_latency) * disp_drain_rate2 + 0.5);
+
+ if (info->DispPriority == 2) {
+ if (info->ChipFamily == CHIP_FAMILY_R300)
+ critical_point2 += 0x10;
+ else
+ critical_point2 = 0;
+ }
+
+ if (max_stop_req - critical_point2 < 4) critical_point2 = 0;
+
+ }
+
+ OUTREG(RADEON_GRPH2_BUFFER_CNTL, ((temp & ~RADEON_GRPH_CRITICAL_POINT_MASK) |
+ (critical_point2 << RADEON_GRPH_CRITICAL_POINT_SHIFT)));
+
+ RADEONTRACE(("GRPH2_BUFFER_CNTL from %x to %x\n",
+ info->SavedReg.grph2_buffer_cntl, INREG(RADEON_GRPH2_BUFFER_CNTL)));
+ }
+}
+
/* Define CRTC registers for requested video mode */
static Bool RADEONInitCrtcRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save,
DisplayModePtr mode, RADEONInfoPtr info)
@@ -4901,24 +5937,22 @@ static Bool RADEONInitCrtcRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save,
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[] = { 0x02, 0x02, 0x00, 0x00, 0x05, 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 */
+ case 4: format = 1; break;
+ case 8: format = 2; break;
+ case 15: format = 3; break; /* 555 */
+ case 16: format = 4; break; /* 565 */
+ case 24: format = 5; break; /* RGB */
+ case 32: format = 6; break; /* xRGB */
default:
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Unsupported pixel depth (%d)\n",
info->CurrentLayout.bitsPerPixel);
return FALSE;
}
- RADEONTRACE(("Format = %d (%d bytes per pixel)\n", format, bytpp));
if ((info->DisplayType == MT_DFP) ||
(info->DisplayType == MT_LCD)) {
@@ -5015,7 +6049,19 @@ static Bool RADEONInitCrtcRegisters(ScrnInfoPtr pScrn, RADEONSavePtr save,
(pScrn->bitsPerPixel * 8));
save->crtc_pitch |= save->crtc_pitch << 16;
+ /* Some versions of BIOS setup CRTC_MORE_CNTL for a DFP, if we
+ have a CRT here, it should be cleared to avoild a blank screen.
+ */
+ if (info->DisplayType == MT_CRT)
+ save->crtc_more_cntl = (info->SavedReg.crtc_more_cntl &
+ ~(RADEON_CRTC_H_CUTOFF_ACTIVE_EN |
+ RADEON_CRTC_V_CUTOFF_ACTIVE_EN));
+ else
+ save->crtc_more_cntl = info->SavedReg.crtc_more_cntl;
+
save->surface_cntl = 0;
+ save->disp_merge_cntl = info->SavedReg.disp_merge_cntl;
+ save->disp_merge_cntl &= ~RADEON_DISP_RGB_OFFSET_EN;
#if X_BYTE_ORDER == X_BIG_ENDIAN
switch (pScrn->bitsPerPixel) {
@@ -5040,29 +6086,28 @@ static Bool RADEONInitCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save,
DisplayModePtr mode, RADEONInfoPtr info)
{
unsigned char *RADEONMMIO = info->MMIO;
+ RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
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 */
+ case 4: format = 1; break;
+ case 8: format = 2; break;
+ case 15: format = 3; break; /* 555 */
+ case 16: format = 4; break; /* 565 */
+ case 24: format = 5; break; /* RGB */
+ case 32: format = 6; break; /* xRGB */
default:
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Unsupported pixel depth (%d)\n",
info->CurrentLayout.bitsPerPixel);
return FALSE;
}
- RADEONTRACE(("Format = %d (%d bytes per pixel)\n", format, bytpp));
hsync_fudge = hsync_fudge_default[format-1];
@@ -5082,27 +6127,45 @@ static Bool RADEONInitCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save,
/* Turn CRT on in case the first head is a DFP */
save->crtc_ext_cntl |= RADEON_CRTC_CRT_ON;
save->dac2_cntl = info->SavedReg.dac2_cntl;
+ /* always let TVDAC drive CRT2, we don't support tvout yet */
+ save->dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL;
+ save->disp_output_cntl = info->SavedReg.disp_output_cntl;
if (info->ChipFamily == CHIP_FAMILY_R200 ||
- info->ChipFamily == CHIP_FAMILY_R300) {
- save->disp_output_cntl =
- ((info->SavedReg.disp_output_cntl
- & ~(CARD32)RADEON_DISP_DAC_SOURCE_MASK)
- | RADEON_DISP_DAC_SOURCE_CRTC2);
+ info->ChipFamily == CHIP_FAMILY_R300 ||
+ info->ChipFamily == CHIP_FAMILY_R350 ||
+ info->ChipFamily == CHIP_FAMILY_RV350) {
+ save->disp_output_cntl &= ~(RADEON_DISP_DAC_SOURCE_MASK |
+ RADEON_DISP_DAC2_SOURCE_MASK);
+ if (pRADEONEnt->MonType1 != MT_CRT) {
+ save->disp_output_cntl |= (RADEON_DISP_DAC_SOURCE_CRTC2 |
+ RADEON_DISP_DAC2_SOURCE_CRTC2);
+ } else {
+ if (pRADEONEnt->ReversedDAC) {
+ save->disp_output_cntl |= RADEON_DISP_DAC2_SOURCE_CRTC2;
+ } else {
+ save->disp_output_cntl |= RADEON_DISP_DAC_SOURCE_CRTC2;
+ }
+ }
} else {
save->disp_hw_debug = info->SavedReg.disp_hw_debug;
- if (info->IsDell && info->DellType == 2) {
- if (info->DisplayType == MT_CRT || info->CloneType == MT_CRT) {
- /* Turn on 2nd CRT */
+ /* Turn on 2nd CRT */
+ if (pRADEONEnt->MonType1 != MT_CRT) {
+ /* This is for some sample boards with the VGA port
+ connected to the TVDAC, but BIOS doesn't reflect this.
+ Here we configure both DACs to use CRTC2.
+ Not sure if this happens in any retail board.
+ */
+ save->disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL;
+ save->dac2_cntl |= RADEON_DAC2_DAC_CLK_SEL;
+ } else {
+ if (pRADEONEnt->ReversedDAC) {
+ save->disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL;
save->dac2_cntl &= ~RADEON_DAC2_DAC_CLK_SEL;
- save->dac2_cntl |= RADEON_DAC2_DAC2_CLK_SEL;
- save->disp_hw_debug &= ~RADEON_CRT2_DISP1_SEL;
-
- /* This will make 2nd CRT stay on in console */
- info->SavedReg.dac2_cntl = save->dac2_cntl;
- info->SavedReg.disp_hw_debug |= RADEON_CRT2_DISP1_SEL;
- info->SavedReg.crtc2_gen_cntl |= RADEON_CRTC2_CRT2_ON;
+ } else {
+ save->disp_hw_debug |= RADEON_CRT2_DISP1_SEL;
+ save->dac2_cntl |= RADEON_DAC2_DAC_CLK_SEL;
}
- } else save->dac2_cntl |= RADEON_DAC2_DAC_CLK_SEL;
+ }
}
save->crtc2_h_total_disp =
@@ -5149,32 +6212,40 @@ static Bool RADEONInitCrtc2Registers(ScrnInfoPtr pScrn, RADEONSavePtr save,
((pScrn->bitsPerPixel * 8) -1)) /
(pScrn->bitsPerPixel * 8));
save->crtc2_pitch |= save->crtc2_pitch << 16;
+ save->disp2_merge_cntl = info->SavedReg.disp2_merge_cntl;
+ save->disp2_merge_cntl &= ~(RADEON_DISP2_RGB_OFFSET_EN);
- if (info->DisplayType == MT_DFP || info->CloneType == MT_DFP) {
+ if ((info->DisplayType == MT_DFP && info->IsSecondary) ||
+ info->CloneType == MT_DFP) {
save->crtc2_gen_cntl = (RADEON_CRTC2_EN | (format << 8));
save->fp2_h_sync_strt_wid = save->crtc2_h_sync_strt_wid;
save->fp2_v_sync_strt_wid = save->crtc2_v_sync_strt_wid;
- save->fp2_gen_cntl = (RADEON_FP2_SEL_CRTC2 |
- RADEON_FP2_PANEL_FORMAT |
+ save->fp2_gen_cntl = (RADEON_FP2_PANEL_FORMAT |
RADEON_FP2_ON);
+ if (info->ChipFamily >= CHIP_FAMILY_R200) {
+ save->fp2_gen_cntl |= RADEON_FP2_DV0_EN;
+ }
- if (pScrn->rgbBits == 8)
+ if (info->ChipFamily == CHIP_FAMILY_R200 ||
+ info->ChipFamily == CHIP_FAMILY_R300 ||
+ info->ChipFamily == CHIP_FAMILY_R350 ||
+ info->ChipFamily == CHIP_FAMILY_RV350) {
+ save->fp2_gen_cntl &= ~RADEON_FP2_SOURCE_SEL_MASK;
+ save->fp2_gen_cntl |= RADEON_FP2_SOURCE_SEL_CRTC2;
+ } else {
+ save->fp2_gen_cntl &= ~RADEON_FP2_SRC_SEL_MASK;
+ save->fp2_gen_cntl |= RADEON_FP2_SRC_SEL_CRTC2;
+ }
+
+ if (pScrn->rgbBits == 8)
save->fp2_gen_cntl |= RADEON_FP2_PANEL_FORMAT; /* 24 bit format */
else
save->fp2_gen_cntl &= ~RADEON_FP2_PANEL_FORMAT;/* 18 bit format */
/* FIXME: When there are two DFPs, the 2nd DFP is driven by the
* external TMDS transmitter. It may have a problem at
- * high dot clock for certain panels. Since we don't
- * know how to control the external TMDS transmitter, not
- * much we can do here.
+ * high dot clock for certain panels.
*/
-#if 0
- if (save->dot_clock_freq > 15000)
- save->tmds_pll_cntl = 0xA3F;
- else if(save->tmds_pll_cntl != 0xA3F)
- save->tmds_pll_cntl = info->SavedReg.tmds_pll_cntl;
-#endif
/* If BIOS has not turned it on, we'll keep it on so that we'll
* have a valid VGA screen even after X quits or VT is switched
@@ -5199,6 +6270,31 @@ static void RADEONInitFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr orig,
int yres = mode->VDisplay;
float Hratio, Vratio;
+ /* If the FP registers have been initialized before for a panel,
+ * but the primary port is a CRT, we need to reinitialize
+ * FP registers in order for CRT to work properly
+ */
+
+ if ((info->DisplayType != MT_DFP) && (info->DisplayType != MT_LCD)) {
+ save->fp_crtc_h_total_disp = orig->fp_crtc_h_total_disp;
+ save->fp_crtc_v_total_disp = orig->fp_crtc_v_total_disp;
+ save->fp_gen_cntl = 0;
+ save->fp_h_sync_strt_wid = orig->fp_h_sync_strt_wid;
+ save->fp_horz_stretch = 0;
+ save->fp_v_sync_strt_wid = orig->fp_v_sync_strt_wid;
+ save->fp_vert_stretch = 0;
+ save->lvds_gen_cntl = orig->lvds_gen_cntl;
+ save->lvds_pll_cntl = orig->lvds_pll_cntl;
+ save->tmds_pll_cntl = orig->tmds_pll_cntl;
+ save->tmds_transmitter_cntl= orig->tmds_transmitter_cntl;
+
+ save->lvds_gen_cntl |= ( RADEON_LVDS_DISPLAY_DIS | (1 << 23));
+ save->lvds_gen_cntl &= ~(RADEON_LVDS_BLON | RADEON_LVDS_ON);
+ save->fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN);
+
+ return;
+ }
+
if (info->PanelXRes == 0 || info->PanelYRes == 0) {
Hratio = 1.0;
Vratio = 1.0;
@@ -5213,7 +6309,7 @@ static void RADEONInitFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr orig,
if (Hratio == 1.0 || !(mode->Flags & RADEON_USE_RMX)) {
save->fp_horz_stretch = orig->fp_horz_stretch;
save->fp_horz_stretch &= ~(RADEON_HORZ_STRETCH_BLEND |
- RADEON_HORZ_STRETCH_ENABLE);
+ RADEON_HORZ_STRETCH_ENABLE);
save->fp_horz_stretch &= ~(RADEON_HORZ_AUTO_RATIO |
RADEON_HORZ_PANEL_SIZE);
save->fp_horz_stretch |= ((xres/8-1)<<16);
@@ -5268,7 +6364,7 @@ static void RADEONInitFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr orig,
save->fp_gen_cntl |= (RADEON_FP_CRTC_DONT_SHADOW_VPAR |
RADEON_FP_CRTC_DONT_SHADOW_HEND );
- if (pScrn->rgbBits == 8)
+ if (pScrn->rgbBits == 8)
save->fp_gen_cntl |= RADEON_FP_PANEL_FORMAT; /* 24 bit format */
else
save->fp_gen_cntl &= ~RADEON_FP_PANEL_FORMAT;/* 18 bit format */
@@ -5276,14 +6372,6 @@ static void RADEONInitFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr orig,
save->lvds_gen_cntl = orig->lvds_gen_cntl;
save->lvds_pll_cntl = orig->lvds_pll_cntl;
- /* This is needed for some panel at high resolution (>=1600x1200)
- */
- if ((save->dot_clock_freq > 15000) &&
- (info->ChipFamily != CHIP_FAMILY_R300))
- save->tmds_pll_cntl = 0xA3F;
- else
- save->tmds_pll_cntl = orig->tmds_pll_cntl;
-
info->PanelOff = FALSE;
/* This option is used to force the ONLY DEVICE in XFConfig to use
* CRT port, instead of default DVI port.
@@ -5292,23 +6380,69 @@ static void RADEONInitFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr orig,
info->PanelOff = TRUE;
}
+ save->tmds_pll_cntl = orig->tmds_pll_cntl;
+ save->tmds_transmitter_cntl= orig->tmds_transmitter_cntl;
if (info->PanelOff && info->Clone) {
info->OverlayOnCRTC2 = TRUE;
if (info->DisplayType == MT_LCD) {
/* Turning off LVDS_ON seems to make panel white blooming.
* For now we just turn off display data ???
*/
- save->lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_DISPLAY_DIS);
- save->lvds_gen_cntl &= ~(RADEON_LVDS_BLON);
+ save->lvds_gen_cntl |= (RADEON_LVDS_DISPLAY_DIS);
+ save->lvds_gen_cntl &= ~(RADEON_LVDS_BLON | RADEON_LVDS_ON);
} else if (info->DisplayType == MT_DFP)
save->fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN);
} else {
if (info->DisplayType == MT_LCD) {
+ RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
+
+ /* BIOS will use this setting to reset displays upon lid close/open.
+ * Here we let BIOS controls LCD, but the driver will control the external CRT.
+ */
+ if (info->Clone || pRADEONEnt->HasSecondary)
+ save->bios_5_scratch = 0x01020201;
+ else
+ save->bios_5_scratch = orig->bios_5_scratch;
+
save->lvds_gen_cntl |= (RADEON_LVDS_ON | RADEON_LVDS_BLON);
save->fp_gen_cntl &= ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN);
- } else if (info->DisplayType == MT_DFP)
+
+ } else if (info->DisplayType == MT_DFP) {
+ int i;
+ CARD32 tmp = orig->tmds_pll_cntl & 0xfffff;
+ for (i=0; i<4; i++) {
+ if (info->tmds_pll[i].freq == 0) break;
+ if (save->dot_clock_freq < info->tmds_pll[i].freq) {
+ tmp = info->tmds_pll[i].value ;
+ break;
+ }
+ }
+ if ((info->ChipFamily == CHIP_FAMILY_R300) ||
+ (info->ChipFamily == CHIP_FAMILY_R350) ||
+ (info->ChipFamily == CHIP_FAMILY_RV350) ||
+ (info->ChipFamily == CHIP_FAMILY_RV280)) {
+ if (tmp & 0xfff00000)
+ save->tmds_pll_cntl = tmp;
+ else
+ save->tmds_pll_cntl = (orig->tmds_pll_cntl & 0xfff00000) | tmp;
+ } else save->tmds_pll_cntl = tmp;
+
+ RADEONTRACE(("TMDS_PLL from %x to %x\n",
+ orig->tmds_pll_cntl,
+ save->tmds_pll_cntl));
+
+ save->tmds_transmitter_cntl &= ~(RADEON_TMDS_TRANSMITTER_PLLRST);
+ if ((info->ChipFamily == CHIP_FAMILY_R300) ||
+ (info->ChipFamily == CHIP_FAMILY_R350) ||
+ (info->ChipFamily == CHIP_FAMILY_RV350) ||
+ (info->ChipFamily == CHIP_FAMILY_R200) || !info->HasCRTC2)
+ save->tmds_transmitter_cntl &= ~(RADEON_TMDS_TRANSMITTER_PLLEN);
+ else /* weird, RV chips got this bit reversed? */
+ save->tmds_transmitter_cntl |= (RADEON_TMDS_TRANSMITTER_PLLEN);
+
save->fp_gen_cntl |= (RADEON_FP_FPON | RADEON_FP_TMDS_EN);
+ }
}
save->fp_crtc_h_total_disp = save->crtc_h_total_disp;
@@ -5348,10 +6482,16 @@ static void RADEONInitPLLRegisters(RADEONSavePtr save, RADEONPLLPtr pll,
for (post_div = &post_divs[0]; post_div->divider; ++post_div) {
save->pll_output_freq = post_div->divider * freq;
+
if (save->pll_output_freq >= pll->min_pll_freq
&& save->pll_output_freq <= pll->max_pll_freq) break;
}
+ if (!post_div->divider) {
+ save->pll_output_freq = freq;
+ post_div = &post_divs[0];
+ }
+
save->dot_clock_freq = freq;
save->feedback_div = RADEONDiv(pll->reference_div
* save->pll_output_freq,
@@ -5403,6 +6543,11 @@ static void RADEONInitPLL2Registers(RADEONSavePtr save, RADEONPLLPtr pll,
&& save->pll_output_freq_2 <= pll->max_pll_freq) break;
}
+ if (!post_div->divider) {
+ save->pll_output_freq_2 = freq;
+ post_div = &post_divs[0];
+ }
+
save->dot_clock_freq_2 = freq;
save->feedback_div_2 = RADEONDiv(pll->reference_div
* save->pll_output_freq_2,
@@ -5499,7 +6644,13 @@ static Bool RADEONInit(ScrnInfoPtr pScrn, DisplayModePtr mode,
return FALSE;
dot_clock = mode->Clock/1000.0;
if (dot_clock) {
- RADEONInitPLLRegisters(save, &info->pll, dot_clock);
+ if (info->UseBiosDividers) {
+ save->ppll_ref_div = info->RefDivider;
+ save->ppll_div_3 = info->FeedbackDivider | (info->PostDivider << 16);
+ save->htotal_cntl = 0;
+ }
+ else
+ RADEONInitPLLRegisters(save, &info->pll, dot_clock);
} else {
save->ppll_ref_div = info->SavedReg.ppll_ref_div;
save->ppll_div_3 = info->SavedReg.ppll_div_3;
@@ -5515,10 +6666,7 @@ static Bool RADEONInit(ScrnInfoPtr pScrn, DisplayModePtr mode,
/* if (!info->PaletteSavedOnVT) RADEONInitPalette(save); */
}
- if (((info->DisplayType == MT_DFP) ||
- (info->DisplayType == MT_LCD))) {
- RADEONInitFPRegisters(pScrn, &info->SavedReg, save, mode, info);
- }
+ RADEONInitFPRegisters(pScrn, &info->SavedReg, save, mode, info);
RADEONTRACE(("RADEONInit returns %p\n", save));
return TRUE;
@@ -5537,6 +6685,10 @@ static Bool RADEONModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
RADEONUnblank(pScrn);
info->CurrentLayout.mode = mode;
+
+ if (info->DispPriority)
+ RADEONInitDispBandwidth(pScrn);
+
return TRUE;
}
@@ -5582,7 +6734,7 @@ Bool RADEONSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
if (info->Clone && info->CloneModes) {
DisplayModePtr clone_mode = info->CloneModes;
- /* Try to match a mode on primary head
+ /* Try to match a mode on primary head
* FIXME: This may not be good if both heads don't have
* exactly the same list of mode.
*/
@@ -5647,14 +6799,29 @@ Bool RADEONSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
return ret;
}
+#ifdef X_XF86MiscPassMessage
+Bool RADEONHandleMessage(int scrnIndex, const char* msgtype,
+ const char* msgval, char** retmsg)
+{
+ ErrorF("RADEONHandleMessage(%d, \"%s\", \"%s\", retmsg)\n", scrnIndex,
+ msgtype, msgval);
+ *retmsg = "";
+ return 0;
+}
+#endif
+
/* Used to disallow modes that are not supported by the hardware */
-int RADEONValidMode(int scrnIndex, DisplayModePtr mode,
- Bool verbose, int flag)
+ModeStatus RADEONValidMode(int scrnIndex, DisplayModePtr mode,
+ Bool verbose, int flag)
{
- /* Searching for native mode timing table embedded in BIOS image.
- * Not working yet. Currently we calculate from FP registers
+ /* There are problems with double scan mode at high clocks
+ * They're likely related PLL and display buffer settings.
+ * Disable these modes for now.
*/
-
+ if (mode->Flags & V_DBLSCAN) {
+ if ((mode->CrtcHDisplay >= 1024) || (mode->CrtcVDisplay >= 768))
+ return MODE_CLOCK_RANGE;
+ }
return MODE_OK;
}
@@ -5689,15 +6856,15 @@ void RADEONDoAdjustFrame(ScrnInfoPtr pScrn, int x, int y, int clone)
#ifdef XF86DRI
if (info->directRenderingEnabled) {
- pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen);
-
- if (pSAREAPriv->pfCurrentPage == 1) {
- Base += info->backOffset;
- }
+ pSAREAPriv = DRIGetSAREAPrivate(pScrn->pScreen);
if (clone || info->IsSecondary) {
pSAREAPriv->crtc2_base = Base;
}
+
+ if (pSAREAPriv->pfCurrentPage == 1) {
+ Base += info->backOffset;
+ }
}
#endif
@@ -5746,6 +6913,17 @@ Bool RADEONEnterVT(int scrnIndex, int flags)
} else
if (!RADEONModeInit(pScrn, pScrn->currentMode)) return FALSE;
+#ifdef XF86DRI
+ if (info->directRenderingEnabled) {
+ /* get the Radeon back into shape after resume */
+ RADEONDRIResume(pScrn->pScreen);
+ }
+#endif
+ /* this will get XVideo going again, but only if XVideo was initialised
+ during server startup (hence the info->adaptor if). */
+ if (info->adaptor)
+ RADEONResetVideo(pScrn);
+
if (info->accelOn)
RADEONEngineRestore(pScrn);
@@ -5814,8 +6992,8 @@ static Bool RADEONCloseScreen(int scrnIndex, ScreenPtr pScreen)
if (pScrn->vtSema) {
RADEONRestore(pScrn);
- RADEONUnmapMem(pScrn);
}
+ RADEONUnmapMem(pScrn);
if (info->accel) XAADestroyInfoRec(info->accel);
info->accel = NULL;
@@ -5829,13 +7007,9 @@ static Bool RADEONCloseScreen(int scrnIndex, ScreenPtr pScreen)
if (info->DGAModes) xfree(info->DGAModes);
info->DGAModes = NULL;
- if (info->CloneModes)
- while (info->CloneModes)
- xf86DeleteMode(&info->CloneModes, info->CloneModes);
-
pScrn->vtSema = FALSE;
- xf86ClearPrimInitDone(pScrn->entityList[0]);
+ xf86ClearPrimInitDone(info->pEnt->index);
pScreen->BlockHandler = info->BlockHandler;
pScreen->CloseScreen = info->CloseScreen;
@@ -5936,6 +7110,74 @@ static void RADEONDisplayPowerManagementSet(ScrnInfoPtr pScrn,
}
break;
}
+
+ if (PowerManagementMode == DPMSModeOn) {
+ if (info->IsSecondary) {
+ if (info->DisplayType == MT_DFP) {
+ OUTREGP (RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_BLANK_EN);
+ OUTREGP (RADEON_FP2_GEN_CNTL, RADEON_FP2_ON, ~RADEON_FP2_ON);
+ if (info->ChipFamily >= CHIP_FAMILY_R200) {
+ OUTREGP (RADEON_FP2_GEN_CNTL, RADEON_FP2_DV0_EN, ~RADEON_FP2_DV0_EN);
+ }
+ }
+ } else {
+ if ((info->Clone) && (info->CloneType == MT_DFP)) {
+ OUTREGP (RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_BLANK_EN);
+ OUTREGP (RADEON_FP2_GEN_CNTL, RADEON_FP2_ON, ~RADEON_FP2_ON);
+ if (info->ChipFamily >= CHIP_FAMILY_R200) {
+ OUTREGP (RADEON_FP2_GEN_CNTL, RADEON_FP2_DV0_EN, ~RADEON_FP2_DV0_EN);
+ }
+ }
+ if (info->DisplayType == MT_DFP) {
+ OUTREGP (RADEON_FP_GEN_CNTL, (RADEON_FP_FPON | RADEON_FP_TMDS_EN),
+ ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN));
+ } else if (info->DisplayType == MT_LCD) {
+
+ OUTREGP (RADEON_LVDS_GEN_CNTL, RADEON_LVDS_BLON, ~RADEON_LVDS_BLON);
+ usleep (info->PanelPwrDly * 1000);
+ OUTREGP (RADEON_LVDS_GEN_CNTL, RADEON_LVDS_ON, ~RADEON_LVDS_ON);
+ }
+ }
+ } else if ((PowerManagementMode == DPMSModeOff) ||
+ (PowerManagementMode == DPMSModeSuspend) ||
+ (PowerManagementMode == DPMSModeStandby)) {
+ if (info->IsSecondary) {
+ if (info->DisplayType == MT_DFP) {
+ OUTREGP (RADEON_FP2_GEN_CNTL, RADEON_FP2_BLANK_EN, ~RADEON_FP2_BLANK_EN);
+ OUTREGP (RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_ON);
+ if (info->ChipFamily >= CHIP_FAMILY_R200) {
+ OUTREGP (RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_DV0_EN);
+ }
+ }
+ } else {
+ if ((info->Clone) && (info->CloneType == MT_DFP)) {
+ OUTREGP (RADEON_FP2_GEN_CNTL, RADEON_FP2_BLANK_EN, ~RADEON_FP2_BLANK_EN);
+ OUTREGP (RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_ON);
+ if (info->ChipFamily >= CHIP_FAMILY_R200) {
+ OUTREGP (RADEON_FP2_GEN_CNTL, 0, ~RADEON_FP2_DV0_EN);
+ }
+ }
+ if (info->DisplayType == MT_DFP) {
+ OUTREGP (RADEON_FP_GEN_CNTL, 0, ~(RADEON_FP_FPON | RADEON_FP_TMDS_EN));
+ } else if (info->DisplayType == MT_LCD) {
+ unsigned long tmpPixclksCntl = INPLL(pScrn, RADEON_PIXCLKS_CNTL);
+
+ if (info->IsMobility || info->IsIGP) {
+ /* Asic bug, when turning off LVDS_ON, we have to make sure
+ RADEON_PIXCLK_LVDS_ALWAYS_ON bit is off
+ */
+ OUTPLLP(pScrn, RADEON_PIXCLKS_CNTL, 0, ~RADEON_PIXCLK_LVDS_ALWAYS_ONb);
+ }
+
+ OUTREGP (RADEON_LVDS_GEN_CNTL, 0,
+ ~(RADEON_LVDS_BLON | RADEON_LVDS_ON));
+
+ if (info->IsMobility || info->IsIGP) {
+ OUTPLL(RADEON_PIXCLKS_CNTL, tmpPixclksCntl);
+ }
+ }
+ }
+ }
}
#ifdef XF86DRI