--- xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c.panel_size_orig 2003-10-02 12:47:59.000000000 -0400 +++ xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_driver.c 2003-10-02 12:46:07.000000000 -0400 @@ -136,7 +136,8 @@ OPTION_CLONE_VREFRESH, OPTION_FBDEV, OPTION_VIDEO_KEY, - OPTION_DISP_PRIORITY + OPTION_DISP_PRIORITY, + OPTION_PANEL_SIZE } RADEONOpts; const OptionInfoRec RADEONOptions[] = { @@ -169,6 +170,7 @@ { 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 }, { -1, NULL, OPTV_NONE, {0}, FALSE } }; @@ -1476,7 +1478,8 @@ info->DotClock = 0; info->UseBiosDividers = FALSE; - if (info->DisplayType == MT_LCD && info->VBIOS) { + if (info->DisplayType == MT_LCD && info->VBIOS && + !(xf86GetOptValString(info->Options, OPTION_PANEL_SIZE))) { tmp = RADEON_BIOS16(info->FPBIOSstart + 0x40); if (!tmp) { info->PanelPwrDly = 200; @@ -1514,7 +1517,11 @@ "BIOS provided dividers will be used."); } - for (i = 0; i < 20; i++) { + /* 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) && @@ -1533,6 +1540,46 @@ info->Flags = 0; } } + + 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; + } + } } } } @@ -3237,6 +3284,7 @@ ClockRangePtr clockRanges; int modesFound; RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); + char *s; /* This option has two purposes: * @@ -3322,6 +3370,59 @@ "No DDC data available, DDCMode option is dismissed\n"); } + 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. * --- xc/programs/Xserver/hw/xfree86/drivers/ati/radeon.man.panel_size_orig 2003-10-02 12:52:40.000000000 -0400 +++ xc/programs/Xserver/hw/xfree86/drivers/ati/radeon.man 2003-10-02 13:05:41.000000000 -0400 @@ -268,6 +268,19 @@ The default value is .B off. .TP +.BI "Option \*qPanelSize\*q \*q" "string" \*q +Should only be used when driver cannot detect the correct panel size. +Apply to both desktop (TMDS) and laptop (LVDS) digital panels. +When a valid panel size is specified, the timings collected from +DDC and BIOS will not be used. If you have a panel with timings +different from that of a standard VESA mode, you have to provide +this information through the Modeline. +.br +For example, Option "PanelSize" "1400x1050" +.br +The default value is +.B none. +.TP .BI "Option \*qPanelOff\*q \*q" boolean \*q Disable panel output. Only used when clone is enabled. .br