summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/radeon.man7
-rw-r--r--src/radeon.h4
-rw-r--r--src/radeon_bios.c75
-rw-r--r--src/radeon_driver.c96
-rw-r--r--src/radeon_reg.h2
5 files changed, 149 insertions, 35 deletions
diff --git a/man/radeon.man b/man/radeon.man
index 4d66fe3f..eb221171 100644
--- a/man/radeon.man
+++ b/man/radeon.man
@@ -502,6 +502,13 @@ life by reducing power usage. Some users report reduced 3D preformance
with this enabled. The default is
.B off.
.TP
+.BI "Option \*qBIOSHotkeys\*q \*q" boolean \*q
+Enable BIOS hotkey output switching. This allows the BIOS to toggle outputs
+using hotkeys (e.g., fn-f7, etc.). Since the driver does not support ACPI,
+there is no way to validate modes on an output switch and the BIOS can
+potentially change things behind the driver's back. The default is
+.B off.
+.TP
.SH SEE ALSO
__xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), xorgconfig(__appmansuffix__), Xserver(__appmansuffix__), X(__miscmansuffix__)
diff --git a/src/radeon.h b/src/radeon.h
index 098627d4..05637fae 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -620,6 +620,10 @@ typedef struct {
/* special handlings for DELL triple-head server */
Bool IsDellServer;
+
+ /* enable bios hotkey output switching */
+ Bool BiosHotkeys;
+
} RADEONInfoRec, *RADEONInfoPtr;
#define RADEONWaitForFifo(pScrn, entries) \
diff --git a/src/radeon_bios.c b/src/radeon_bios.c
index d54c9b93..37a3e269 100644
--- a/src/radeon_bios.c
+++ b/src/radeon_bios.c
@@ -198,13 +198,28 @@ Bool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn)
return FALSE;
}
} else {
+ /* Some laptops only have one connector (VGA) listed in the connector table,
+ * we need to add LVDS in as a non-DDC display.
+ * Note, we can't assume the listed VGA will be filled in PortInfo[0],
+ * when walking through connector table. connector_found has following meaning:
+ * 0 -- nothing found,
+ * 1 -- only PortInfo[0] filled,
+ * 2 -- only PortInfo[1] filled,
+ * 3 -- both are filled.
+ */
+ int connector_found = 0;
+
if ((tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x50))) {
for (i = 1; i < 4; i++) {
if (!RADEON_BIOS8(tmp + i*2) && i > 1) break; /* end of table */
tmp0 = RADEON_BIOS16(tmp + i*2);
- if (((tmp0 >> 12) & 0x1f) == 0) continue; /* no connector */
+ if (((tmp0 >> 12) & 0x0f) == 0) continue; /* no connector */
+ if (connector_found > 0) {
+ if (pRADEONEnt->PortInfo[tmp1].DDCType == ((tmp0 >> 8) & 0x0f))
+ continue; /* same connector */
+ }
/* internal DDC_DVI port will get assigned to PortInfo[0], or if there is no DDC_DVI (like in some IGPs). */
tmp1 = ((((tmp0 >> 8) & 0xf) == DDC_DVI) || (tmp1 == 1)) ? 0 : 1; /* determine port info index */
@@ -222,9 +237,7 @@ Bool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn)
pRADEONEnt->PortInfo[tmp1].TMDSType == TMDS_INT)
pRADEONEnt->PortInfo[tmp1].TMDSType = TMDS_UNKNOWN;
- xf86DrvMsg(0, X_INFO, "Connector%d: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d\n",
- tmp1, pRADEONEnt->PortInfo[tmp1].DDCType, pRADEONEnt->PortInfo[tmp1].DACType,
- pRADEONEnt->PortInfo[tmp1].TMDSType, pRADEONEnt->PortInfo[tmp1].ConnectorType);
+ connector_found += (tmp1 + 1);
}
} else {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No Connector Info Table found!\n");
@@ -232,14 +245,54 @@ Bool RADEONGetConnectorInfoFromBIOS (ScrnInfoPtr pScrn)
}
if (info->IsMobility) {
- if ((tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x42))) {
- if ((tmp0 = RADEON_BIOS16(tmp + 0x15))) {
- if ((tmp1 = RADEON_BIOS8(tmp0+2) & 0x07)) {
- pRADEONEnt->PortInfo[0].DDCType = tmp1;
- xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "LCD DDC Info Table found!\n");
- }
+ /* For the cases where only one VGA connector is found,
+ we assume LVDS is not listed in the connector table,
+ add it in here as the first port.
+ */
+ if ((connector_found < 3) && (pRADEONEnt->PortInfo[tmp1].ConnectorType == CONNECTOR_CRT)) {
+ if (connector_found == 1) {
+ memcpy (&pRADEONEnt->PortInfo[1], &pRADEONEnt->PortInfo[0],
+ sizeof (pRADEONEnt->PortInfo[0]));
+ }
+ pRADEONEnt->PortInfo[0].DACType = DAC_TVDAC;
+ pRADEONEnt->PortInfo[0].TMDSType = TMDS_UNKNOWN;
+ pRADEONEnt->PortInfo[0].DDCType = DDC_NONE_DETECTED;
+ pRADEONEnt->PortInfo[0].ConnectorType = CONNECTOR_PROPRIETARY;
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "LVDS port is not in connector table, added in.\n");
+ if (connector_found == 0) connector_found = 1;
+ else connector_found = 3;
}
- }
+
+ if ((tmp = RADEON_BIOS16(info->ROMHeaderStart + 0x42))) {
+ if ((tmp0 = RADEON_BIOS16(tmp + 0x15))) {
+ if ((tmp1 = RADEON_BIOS8(tmp0+2) & 0x07)) {
+ pRADEONEnt->PortInfo[0].DDCType = tmp1;
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "LCD DDC Info Table found!\n");
+ }
+ }
+ }
+ } else if (connector_found == 2) {
+ memcpy (&pRADEONEnt->PortInfo[0], &pRADEONEnt->PortInfo[1],
+ sizeof (pRADEONEnt->PortInfo[0]));
+ pRADEONEnt->PortInfo[1].DACType = DAC_UNKNOWN;
+ pRADEONEnt->PortInfo[1].TMDSType = TMDS_UNKNOWN;
+ pRADEONEnt->PortInfo[1].DDCType = DDC_NONE_DETECTED;
+ pRADEONEnt->PortInfo[1].ConnectorType = CONNECTOR_NONE;
+ connector_found = 1;
+ }
+
+ if (connector_found == 0) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "No connector found in Connector Info Table.\n");
+ } else {
+ xf86DrvMsg(0, X_INFO, "Connector0: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d\n",
+ pRADEONEnt->PortInfo[0].DDCType, pRADEONEnt->PortInfo[0].DACType,
+ pRADEONEnt->PortInfo[0].TMDSType, pRADEONEnt->PortInfo[0].ConnectorType);
+ }
+ if (connector_found == 3) {
+ xf86DrvMsg(0, X_INFO, "Connector1: DDCType-%d, DACType-%d, TMDSType-%d, ConnectorType-%d\n",
+ pRADEONEnt->PortInfo[1].DDCType, pRADEONEnt->PortInfo[1].DACType,
+ pRADEONEnt->PortInfo[1].TMDSType, pRADEONEnt->PortInfo[1].ConnectorType);
}
#if 0
diff --git a/src/radeon_driver.c b/src/radeon_driver.c
index 4647d78f..d70ccd7e 100644
--- a/src/radeon_driver.c
+++ b/src/radeon_driver.c
@@ -172,7 +172,8 @@ typedef enum {
OPTION_SUBPIXEL_ORDER,
#endif
OPTION_SHOWCACHE,
- OPTION_DYNAMIC_CLOCKS
+ OPTION_DYNAMIC_CLOCKS,
+ OPTION_BIOS_HOTKEYS
} RADEONOpts;
static const OptionInfoRec RADEONOptions[] = {
@@ -225,6 +226,7 @@ static const OptionInfoRec RADEONOptions[] = {
#endif
{ OPTION_SHOWCACHE, "ShowCache", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_DYNAMIC_CLOCKS, "DynamicClocks", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_BIOS_HOTKEYS, "BIOSHotkeys", OPTV_BOOLEAN, {0}, FALSE },
{ -1, NULL, OPTV_NONE, {0}, FALSE }
};
@@ -1733,6 +1735,13 @@ static BOOL RADEONQueryConnectedMonitors(ScrnInfoPtr pScrn)
break;
}
}
+ for (i = 0; i < max_mt; i++) {
+ if (strcmp(s2, MonTypeName[i]) == 0) {
+ pRADEONEnt->PortInfo[1].MonType = MonTypeID[i];
+ break;
+ }
+ }
+
if (i == max_mt)
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Invalid Monitor type specified for 2nd port \n");
@@ -1765,32 +1774,45 @@ static BOOL RADEONQueryConnectedMonitors(ScrnInfoPtr pScrn)
}
- if (pRADEONEnt->PortInfo[0].MonType == MT_UNKNOWN || pRADEONEnt->PortInfo[1].MonType == MT_UNKNOWN) {
-
- if(((!info->HasCRTC2) || info->IsDellServer) &&
- (pRADEONEnt->PortInfo[0].MonType == MT_UNKNOWN)) {
+ if(((!info->HasCRTC2) || info->IsDellServer)) {
+ if (pRADEONEnt->PortInfo[0].MonType == MT_UNKNOWN) {
if((pRADEONEnt->PortInfo[0].MonType = RADEONDisplayDDCConnected(pScrn, DDC_DVI, &pRADEONEnt->PortInfo[0])));
else if((pRADEONEnt->PortInfo[0].MonType = RADEONDisplayDDCConnected(pScrn, DDC_VGA, &pRADEONEnt->PortInfo[0])));
else if((pRADEONEnt->PortInfo[0].MonType = RADEONDisplayDDCConnected(pScrn, DDC_CRT2, &pRADEONEnt->PortInfo[0])));
else
pRADEONEnt->PortInfo[0].MonType = MT_CRT;
+ }
- if (!ignore_edid) {
- if (pRADEONEnt->PortInfo[0].MonInfo) {
- xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitor1 EDID data ---------------------------\n");
- xf86PrintEDID(pRADEONEnt->PortInfo[0].MonInfo );
- xf86DrvMsg(pScrn->scrnIndex, X_INFO, "End of Monitor1 EDID data --------------------\n");
- }
+ if (!ignore_edid) {
+ if (pRADEONEnt->PortInfo[0].MonInfo) {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Monitor1 EDID data ---------------------------\n");
+ xf86PrintEDID(pRADEONEnt->PortInfo[0].MonInfo );
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "End of Monitor1 EDID data --------------------\n");
}
-
- pRADEONEnt->MonType1 = pRADEONEnt->PortInfo[0].MonType;
- pRADEONEnt->MonInfo1 = pRADEONEnt->PortInfo[0].MonInfo;
- pRADEONEnt->MonType2 = MT_NONE;
- pRADEONEnt->MonInfo2 = NULL;
- info->MergeType = MT_NONE;
- return TRUE;
}
+ pRADEONEnt->MonType1 = pRADEONEnt->PortInfo[0].MonType;
+ pRADEONEnt->MonInfo1 = pRADEONEnt->PortInfo[0].MonInfo;
+ pRADEONEnt->MonType2 = MT_NONE;
+ pRADEONEnt->MonInfo2 = NULL;
+ info->MergeType = MT_NONE;
+ info->DisplayType = pRADEONEnt->MonType1;
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Primary:\n Monitor -- %s\n Connector -- %s\n DAC Type -- %s\n TMDS Type -- %s\n DDC Type -- %s\n",
+ MonTypeName[pRADEONEnt->PortInfo[0].MonType+1],
+ info->IsAtomBios ?
+ ConnectorTypeNameATOM[pRADEONEnt->PortInfo[0].ConnectorType]:
+ ConnectorTypeName[pRADEONEnt->PortInfo[0].ConnectorType],
+ DACTypeName[pRADEONEnt->PortInfo[0].DACType+1],
+ TMDSTypeName[pRADEONEnt->PortInfo[0].TMDSType+1],
+ DDCTypeName[pRADEONEnt->PortInfo[0].DDCType]);
+
+ return TRUE;
+ }
+
+ if (pRADEONEnt->PortInfo[0].MonType == MT_UNKNOWN || pRADEONEnt->PortInfo[1].MonType == MT_UNKNOWN) {
+
/* Primary Head (DVI or Laptop Int. panel)*/
/* A ddc capable display connected on DVI port */
if (pRADEONEnt->PortInfo[0].MonType == MT_UNKNOWN) {
@@ -4623,10 +4645,12 @@ Bool RADEONScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
RADEONSave(pScrn);
- if (xf86ReturnOptValBool(info->Options, OPTION_DYNAMIC_CLOCKS, FALSE)) {
- RADEONSetDynamicClock(pScrn, 1);
- } else {
- RADEONSetDynamicClock(pScrn, 0);
+ if ((!info->IsSecondary) && info->IsMobility) {
+ if (xf86ReturnOptValBool(info->Options, OPTION_DYNAMIC_CLOCKS, FALSE)) {
+ RADEONSetDynamicClock(pScrn, 1);
+ } else {
+ RADEONSetDynamicClock(pScrn, 0);
+ }
}
if (info->FBDev) {
@@ -6817,7 +6841,18 @@ static void RADEONInitFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr orig,
}
}
- if (info->IsMobility) {
+ info->BiosHotkeys = FALSE;
+ /*
+ * Allow the bios to toggle outputs. see below for more.
+ */
+ if (xf86ReturnOptValBool(info->Options, OPTION_BIOS_HOTKEYS, FALSE)) {
+ info->BiosHotkeys = TRUE;
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS HotKeys Enabled\n");
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "BIOS HotKeys Disabled\n");
+ }
+
+ if (info->IsMobility && (!info->BiosHotkeys)) {
RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
/* To work correctly with laptop hotkeys.
@@ -6845,6 +6880,21 @@ static void RADEONInitFPRegisters(ScrnInfoPtr pScrn, RADEONSavePtr orig,
}
save->bios_4_scratch = 0x4;
save->bios_6_scratch = orig->bios_6_scratch | 0x40000000;
+
+ } else if (info->IsMobility && (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->MergedFB || pRADEONEnt->HasSecondary)
+ save->bios_5_scratch = 0x01020201;
+ else
+ save->bios_5_scratch = orig->bios_5_scratch;
+
+ save->bios_4_scratch = orig->bios_4_scratch;
+ save->bios_6_scratch = orig->bios_6_scratch;
+
}
save->fp_crtc_h_total_disp = save->crtc_h_total_disp;
diff --git a/src/radeon_reg.h b/src/radeon_reg.h
index c14b6aec..f6cf3bfd 100644
--- a/src/radeon_reg.h
+++ b/src/radeon_reg.h
@@ -821,7 +821,7 @@
# define RADEON_MC_MCLK_MAX_DYN_STOP_LAT (1<<12)
# define RADEON_IO_MCLK_MAX_DYN_STOP_LAT (1<<13)
# define RADEON_MC_MCLK_DYN_ENABLE (1 << 14)
-# define RADEON_IO_MCLK_DYN_ENABLE (1 << 14)
+# define RADEON_IO_MCLK_DYN_ENABLE (1 << 15)
#define RADEON_MDGPIO_A_REG 0x01ac
#define RADEON_MDGPIO_EN_REG 0x01b0
#define RADEON_MDGPIO_MASK 0x0198