summaryrefslogtreecommitdiff
path: root/src/radeon_modes.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/radeon_modes.c')
-rw-r--r--src/radeon_modes.c164
1 files changed, 138 insertions, 26 deletions
diff --git a/src/radeon_modes.c b/src/radeon_modes.c
index ed2fee20..e06f8ddf 100644
--- a/src/radeon_modes.c
+++ b/src/radeon_modes.c
@@ -131,28 +131,29 @@ static DisplayModePtr RADEONFPNativeMode(xf86OutputPtr output)
{
ScrnInfoPtr pScrn = output->scrn;
RADEONOutputPrivatePtr radeon_output = output->driver_private;
+ radeon_native_mode_ptr native_mode = &radeon_output->native_mode;
DisplayModePtr new = NULL;
char stmp[32];
- if (radeon_output->PanelXRes != 0 &&
- radeon_output->PanelYRes != 0 &&
- radeon_output->DotClock != 0) {
+ if (native_mode->PanelXRes != 0 &&
+ native_mode->PanelYRes != 0 &&
+ native_mode->DotClock != 0) {
new = xnfcalloc(1, sizeof (DisplayModeRec));
- sprintf(stmp, "%dx%d", radeon_output->PanelXRes, radeon_output->PanelYRes);
+ sprintf(stmp, "%dx%d", native_mode->PanelXRes, native_mode->PanelYRes);
new->name = xnfalloc(strlen(stmp) + 1);
strcpy(new->name, stmp);
- new->HDisplay = radeon_output->PanelXRes;
- new->VDisplay = radeon_output->PanelYRes;
+ new->HDisplay = native_mode->PanelXRes;
+ new->VDisplay = native_mode->PanelYRes;
- new->HTotal = new->HDisplay + radeon_output->HBlank;
- new->HSyncStart = new->HDisplay + radeon_output->HOverPlus;
- new->HSyncEnd = new->HSyncStart + radeon_output->HSyncWidth;
- new->VTotal = new->VDisplay + radeon_output->VBlank;
- new->VSyncStart = new->VDisplay + radeon_output->VOverPlus;
- new->VSyncEnd = new->VSyncStart + radeon_output->VSyncWidth;
+ new->HTotal = new->HDisplay + native_mode->HBlank;
+ new->HSyncStart = new->HDisplay + native_mode->HOverPlus;
+ new->HSyncEnd = new->HSyncStart + native_mode->HSyncWidth;
+ new->VTotal = new->VDisplay + native_mode->VBlank;
+ new->VSyncStart = new->VDisplay + native_mode->VOverPlus;
+ new->VSyncEnd = new->VSyncStart + native_mode->VSyncWidth;
- new->Clock = radeon_output->DotClock;
+ new->Clock = native_mode->DotClock;
new->Flags = 0;
if (new) {
@@ -163,7 +164,7 @@ static DisplayModePtr RADEONFPNativeMode(xf86OutputPtr output)
}
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Added native panel mode: %dx%d\n",
- radeon_output->PanelXRes, radeon_output->PanelYRes);
+ native_mode->PanelXRes, native_mode->PanelYRes);
}
return new;
@@ -233,6 +234,7 @@ static void RADEONAddScreenModes(xf86OutputPtr output, DisplayModePtr *modeList)
{
ScrnInfoPtr pScrn = output->scrn;
RADEONOutputPrivatePtr radeon_output = output->driver_private;
+ radeon_native_mode_ptr native_mode = &radeon_output->native_mode;
DisplayModePtr last = NULL;
DisplayModePtr new = NULL;
DisplayModePtr first = NULL;
@@ -249,9 +251,9 @@ static void RADEONAddScreenModes(xf86OutputPtr output, DisplayModePtr *modeList)
if (sscanf(ppModeName[i], "%dx%d", &width, &height) != 2) continue;
- if (radeon_output->type == OUTPUT_LVDS) {
+ if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
/* already added the native mode */
- if (width == radeon_output->PanelXRes && height == radeon_output->PanelYRes)
+ if (width == native_mode->PanelXRes && height == native_mode->PanelYRes)
continue;
/* Note: We allow all non-standard modes as long as they do not
@@ -259,13 +261,13 @@ static void RADEONAddScreenModes(xf86OutputPtr output, DisplayModePtr *modeList)
* need the internal RMX unit in the video chips (and there is
* only one per card), this will only apply to the primary head.
*/
- if (width < 320 || width > radeon_output->PanelXRes ||
- height < 200 || height > radeon_output->PanelYRes) {
+ if (width < 320 || width > native_mode->PanelXRes ||
+ height < 200 || height > native_mode->PanelYRes) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Mode %s is out of range.\n", ppModeName[i]);
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Valid FP modes must be between 320x200-%dx%d\n",
- radeon_output->PanelXRes, radeon_output->PanelYRes);
+ native_mode->PanelXRes, native_mode->PanelYRes);
continue;
}
}
@@ -299,6 +301,116 @@ static void RADEONAddScreenModes(xf86OutputPtr output, DisplayModePtr *modeList)
}
+/* BIOS may not have right panel size, we search through all supported
+ * DDC modes looking for the maximum panel size.
+ */
+static void
+RADEONUpdatePanelSize(xf86OutputPtr output)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+ RADEONInfoPtr info = RADEONPTR(pScrn);
+ RADEONOutputPrivatePtr radeon_output = output->driver_private;
+ radeon_native_mode_ptr native_mode = &radeon_output->native_mode;
+ int j;
+ xf86MonPtr ddc = output->MonInfo;
+ DisplayModePtr p;
+
+ // update output's native mode
+ if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
+ radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
+ if (radeon_encoder) {
+ radeon_lvds_ptr lvds = (radeon_lvds_ptr)radeon_encoder->dev_priv;
+ if (lvds)
+ radeon_output->native_mode = lvds->native_mode;
+ }
+ }
+
+ // crtc should handle?
+ if ((info->UseBiosDividers && native_mode->DotClock != 0) || (ddc == NULL))
+ return;
+
+ /* Go thru detailed timing table first */
+ for (j = 0; j < 4; j++) {
+ if (ddc->det_mon[j].type == 0) {
+ struct detailed_timings *d_timings =
+ &ddc->det_mon[j].section.d_timings;
+ int match = 0;
+
+ /* If we didn't get a panel clock or guessed one, try to match the
+ * mode with the panel size. We do that because we _need_ a panel
+ * clock, or ValidateFPModes will fail, even when UseBiosDividers
+ * is set.
+ */
+ if (native_mode->DotClock == 0 &&
+ native_mode->PanelXRes == d_timings->h_active &&
+ native_mode->PanelYRes == d_timings->v_active)
+ match = 1;
+
+ /* If we don't have a BIOS provided panel data with fixed dividers,
+ * check for a larger panel size
+ */
+ if (native_mode->PanelXRes < d_timings->h_active &&
+ native_mode->PanelYRes < d_timings->v_active &&
+ !info->UseBiosDividers)
+ match = 1;
+
+ if (match) {
+ native_mode->PanelXRes = d_timings->h_active;
+ native_mode->PanelYRes = d_timings->v_active;
+ native_mode->DotClock = d_timings->clock / 1000;
+ native_mode->HOverPlus = d_timings->h_sync_off;
+ native_mode->HSyncWidth = d_timings->h_sync_width;
+ native_mode->HBlank = d_timings->h_blanking;
+ native_mode->VOverPlus = d_timings->v_sync_off;
+ native_mode->VSyncWidth = d_timings->v_sync_width;
+ native_mode->VBlank = d_timings->v_blanking;
+ native_mode->Flags = (d_timings->interlaced ? V_INTERLACE : 0);
+ switch (d_timings->misc) {
+ case 0: native_mode->Flags |= V_NHSYNC | V_NVSYNC; break;
+ case 1: native_mode->Flags |= V_PHSYNC | V_NVSYNC; break;
+ case 2: native_mode->Flags |= V_NHSYNC | V_PVSYNC; break;
+ case 3: native_mode->Flags |= V_PHSYNC | V_PVSYNC; break;
+ }
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel infos found from DDC detailed: %dx%d\n",
+ native_mode->PanelXRes, native_mode->PanelYRes);
+ }
+ }
+ }
+
+ if (info->UseBiosDividers && native_mode->DotClock != 0)
+ return;
+
+ /* Search thru standard VESA modes from EDID */
+ for (j = 0; j < 8; j++) {
+ if ((native_mode->PanelXRes < ddc->timings2[j].hsize) &&
+ (native_mode->PanelYRes < ddc->timings2[j].vsize)) {
+ for (p = pScrn->monitor->Modes; p; p = p->next) {
+ if ((ddc->timings2[j].hsize == p->HDisplay) &&
+ (ddc->timings2[j].vsize == p->VDisplay)) {
+ float refresh =
+ (float)p->Clock * 1000.0 / p->HTotal / p->VTotal;
+
+ if (abs((float)ddc->timings2[j].refresh - refresh) < 1.0) {
+ /* Is this good enough? */
+ native_mode->PanelXRes = ddc->timings2[j].hsize;
+ native_mode->PanelYRes = ddc->timings2[j].vsize;
+ native_mode->HBlank = p->HTotal - p->HDisplay;
+ native_mode->HOverPlus = p->HSyncStart - p->HDisplay;
+ native_mode->HSyncWidth = p->HSyncEnd - p->HSyncStart;
+ native_mode->VBlank = p->VTotal - p->VDisplay;
+ native_mode->VOverPlus = p->VSyncStart - p->VDisplay;
+ native_mode->VSyncWidth = p->VSyncEnd - p->VSyncStart;
+ native_mode->DotClock = p->Clock;
+ native_mode->Flags = p->Flags;
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel infos found from DDC VESA/EDID: %dx%d\n",
+ native_mode->PanelXRes, native_mode->PanelYRes);
+ }
+ }
+ }
+ }
+ }
+}
+
DisplayModePtr
RADEONProbeOutputModes(xf86OutputPtr output)
{
@@ -309,31 +421,31 @@ RADEONProbeOutputModes(xf86OutputPtr output)
AtomBiosArgRec atomBiosArg;
AtomBiosResult atomBiosResult;
- ErrorF("in RADEONProbeOutputModes\n");
-
if (output->status == XF86OutputStatusConnected) {
- if (OUTPUT_IS_TV) {
+ if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
if (IS_AVIVO_VARIANT)
modes = RADEONATOMTVModes(output);
else
modes = RADEONTVModes(output);
- } else if (radeon_output->type == OUTPUT_CV) {
+ } else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) {
atomBiosResult = RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS,
ATOMBIOS_GET_CV_MODES, &atomBiosArg);
if (atomBiosResult == ATOM_SUCCESS) {
modes = atomBiosArg.modes;
}
} else {
+ if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT))
+ RADEONUpdatePanelSize(output);
if (output->MonInfo)
modes = xf86OutputGetEDIDModes (output);
#if defined(__powerpc__)
if ((info->MacModel == RADEON_MAC_EMAC) &&
- (radeon_output->DACType == DAC_PRIMARY) &&
+ (radeon_output->active_device & ATOM_DEVICE_CRT1_SUPPORT) &&
(modes == NULL))
modes = RADEONeMacModes(output);
#endif
if (modes == NULL) {
- if ((radeon_output->type == OUTPUT_LVDS) && info->IsAtomBios) {
+ if ((radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) && info->IsAtomBios) {
atomBiosResult = RHDAtomBiosFunc(pScrn->scrnIndex,
info->atomBIOS,
ATOMBIOS_GET_PANEL_EDID, &atomBiosArg);
@@ -344,7 +456,7 @@ RADEONProbeOutputModes(xf86OutputPtr output)
}
}
if (modes == NULL) {
- if (radeon_output->type == OUTPUT_LVDS)
+ if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT))
modes = RADEONFPNativeMode(output);
/* add the screen modes */
RADEONAddScreenModes(output, &modes);