diff options
Diffstat (limited to 'src/radeon_modes.c')
-rw-r--r-- | src/radeon_modes.c | 164 |
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); |