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.c175
1 files changed, 135 insertions, 40 deletions
diff --git a/src/radeon_modes.c b/src/radeon_modes.c
index 50b32a9b..611589ef 100644
--- a/src/radeon_modes.c
+++ b/src/radeon_modes.c
@@ -95,36 +95,19 @@ RADEONTVModes(xf86OutputPtr output)
static DisplayModePtr
RADEONATOMTVModes(xf86OutputPtr output)
{
- RADEONOutputPrivatePtr radeon_output = output->driver_private;
DisplayModePtr last = NULL;
DisplayModePtr new = NULL;
DisplayModePtr first = NULL;
- int max_v, i;
+ int i;
/* Add some common sizes */
int widths[5] = {640, 720, 800, 848, 1024};
-
- if (radeon_output->tvStd == TV_STD_NTSC ||
- radeon_output->tvStd == TV_STD_NTSC_J ||
- radeon_output->tvStd == TV_STD_PAL_M)
- max_v = 480;
- else
- max_v = 600;
+ int heights[5] = {480, 480, 600, 480, 768};
for (i = 0; i < 5; i++) {
- new = xf86CVTMode(widths[i], max_v, 60.0, FALSE, FALSE);
+ new = xf86CVTMode(widths[i], heights[i], 60.0, FALSE, FALSE);
new->type = M_T_DRIVER;
- if (radeon_output->tvStd == TV_STD_NTSC ||
- radeon_output->tvStd == TV_STD_NTSC_J ||
- radeon_output->tvStd == TV_STD_PAL_M) {
- if (widths[i] == 640)
- new->type |= M_T_PREFERRED;
- } else {
- if (widths[i] == 800)
- new->type |= M_T_PREFERRED;
- }
-
new->next = NULL;
new->prev = last;
@@ -148,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) {
@@ -180,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;
@@ -250,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;
@@ -268,7 +253,7 @@ static void RADEONAddScreenModes(xf86OutputPtr output, DisplayModePtr *modeList)
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
@@ -276,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;
}
}
@@ -316,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)
{
@@ -326,8 +421,6 @@ RADEONProbeOutputModes(xf86OutputPtr output)
AtomBiosArgRec atomBiosArg;
AtomBiosResult atomBiosResult;
- ErrorF("in RADEONProbeOutputModes\n");
-
if (output->status == XF86OutputStatusConnected) {
if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
if (IS_AVIVO_VARIANT)
@@ -341,6 +434,8 @@ RADEONProbeOutputModes(xf86OutputPtr output)
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__)