ativalid.c revision 32b578d3
132b578d3Smrg/* 232b578d3Smrg * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org 332b578d3Smrg * 432b578d3Smrg * Permission to use, copy, modify, distribute, and sell this software and its 532b578d3Smrg * documentation for any purpose is hereby granted without fee, provided that 632b578d3Smrg * the above copyright notice appear in all copies and that both that copyright 732b578d3Smrg * notice and this permission notice appear in supporting documentation, and 832b578d3Smrg * that the name of Marc Aurele La France not be used in advertising or 932b578d3Smrg * publicity pertaining to distribution of the software without specific, 1032b578d3Smrg * written prior permission. Marc Aurele La France makes no representations 1132b578d3Smrg * about the suitability of this software for any purpose. It is provided 1232b578d3Smrg * "as-is" without express or implied warranty. 1332b578d3Smrg * 1432b578d3Smrg * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 1532b578d3Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO 1632b578d3Smrg * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR 1732b578d3Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 1832b578d3Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 1932b578d3Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 2032b578d3Smrg * PERFORMANCE OF THIS SOFTWARE. 2132b578d3Smrg */ 2232b578d3Smrg 2332b578d3Smrg#ifdef HAVE_CONFIG_H 2432b578d3Smrg#include "config.h" 2532b578d3Smrg#endif 2632b578d3Smrg 2732b578d3Smrg#include "atichip.h" 2832b578d3Smrg#include "atistruct.h" 2932b578d3Smrg#include "ativalid.h" 3032b578d3Smrg 3132b578d3Smrg#include "xf86.h" 3232b578d3Smrg 3332b578d3Smrg/* 3432b578d3Smrg * ATIValidMode -- 3532b578d3Smrg * 3632b578d3Smrg * This checks for hardware-related limits on mode timings. 3732b578d3Smrg */ 3832b578d3SmrgModeStatus 3932b578d3SmrgATIValidMode 4032b578d3Smrg( 4132b578d3Smrg int iScreen, 4232b578d3Smrg DisplayModePtr pMode, 4332b578d3Smrg Bool Verbose, 4432b578d3Smrg int flags 4532b578d3Smrg) 4632b578d3Smrg{ 4732b578d3Smrg ScrnInfoPtr pScreenInfo = xf86Screens[iScreen]; 4832b578d3Smrg ATIPtr pATI = ATIPTR(pScreenInfo); 4932b578d3Smrg int HBlankWidth, HAdjust, VScan, VInterlace; 5032b578d3Smrg 5132b578d3Smrg if (flags & MODECHECK_FINAL) 5232b578d3Smrg { 5332b578d3Smrg return MODE_OK; 5432b578d3Smrg } 5532b578d3Smrg 5632b578d3Smrg /* 5732b578d3Smrg * The following is done for every mode in the monitor section that 5832b578d3Smrg * survives the common layer's basic checks. 5932b578d3Smrg */ 6032b578d3Smrg if (pMode->VScan <= 1) 6132b578d3Smrg VScan = 1; 6232b578d3Smrg else 6332b578d3Smrg VScan = pMode->VScan; 6432b578d3Smrg 6532b578d3Smrg if (pMode->Flags & V_DBLSCAN) 6632b578d3Smrg VScan <<= 1; 6732b578d3Smrg 6832b578d3Smrg if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0)) 6932b578d3Smrg { 7032b578d3Smrg if ((pMode->CrtcHDisplay > pATI->LCDHorizontal) || 7132b578d3Smrg (pMode->CrtcVDisplay > pATI->LCDVertical)) 7232b578d3Smrg return MODE_PANEL; 7332b578d3Smrg 7432b578d3Smrg if (!pATI->OptionLCDSync || (pMode->type & M_T_BUILTIN)) 7532b578d3Smrg { 7632b578d3Smrg if ((pMode->HDisplay > pATI->LCDHorizontal) || 7732b578d3Smrg (pMode->VDisplay > pATI->LCDVertical)) 7832b578d3Smrg return MODE_PANEL; 7932b578d3Smrg 8032b578d3Smrg return MODE_OK; 8132b578d3Smrg } 8232b578d3Smrg 8332b578d3Smrg /* 8432b578d3Smrg * Adjust effective timings for monitor checks. Here the modeline 8532b578d3Smrg * clock is ignored. Horizontal timings are scaled by the stretch 8632b578d3Smrg * ratio used for the displayed area. The vertical porch is scaled by 8732b578d3Smrg * the native resolution's aspect ratio. This seems rather arbitrary, 8832b578d3Smrg * and it is, but it does make all applicable VESA modes sync on a 8932b578d3Smrg * panel after stretching. This has the unfortunate, but necessary, 9032b578d3Smrg * side-effect of changing the mode's horizontal sync and vertical 9132b578d3Smrg * refresh rates. With some exceptions, this tends to increase the 9232b578d3Smrg * mode's horizontal sync rate, and decrease its vertical refresh rate. 9332b578d3Smrg */ 9432b578d3Smrg pMode->SynthClock = pATI->LCDClock; 9532b578d3Smrg 9632b578d3Smrg pMode->CrtcHTotal = pMode->CrtcHBlankEnd = 9732b578d3Smrg ATIDivide(pMode->CrtcHTotal * pATI->LCDHorizontal, 9832b578d3Smrg pMode->CrtcHDisplay, -3, 1) << 3; 9932b578d3Smrg pMode->CrtcHSyncEnd = 10032b578d3Smrg ATIDivide(pMode->CrtcHSyncEnd * pATI->LCDHorizontal, 10132b578d3Smrg pMode->CrtcHDisplay, -3, 1) << 3; 10232b578d3Smrg pMode->CrtcHSyncStart = 10332b578d3Smrg ATIDivide(pMode->CrtcHSyncStart * pATI->LCDHorizontal, 10432b578d3Smrg pMode->CrtcHDisplay, -3, -1) << 3; 10532b578d3Smrg pMode->CrtcHDisplay = pMode->CrtcHBlankStart = pATI->LCDHorizontal; 10632b578d3Smrg 10732b578d3Smrg pMode->CrtcVTotal = pMode->CrtcVBlankEnd = 10832b578d3Smrg ATIDivide((pMode->CrtcVTotal - pMode->CrtcVDisplay) * 10932b578d3Smrg pATI->LCDVertical, pATI->LCDHorizontal, 0, 1) + 11032b578d3Smrg pATI->LCDVertical; 11132b578d3Smrg pMode->CrtcVSyncEnd = 11232b578d3Smrg ATIDivide((pMode->CrtcVSyncEnd - pMode->CrtcVDisplay) * 11332b578d3Smrg pATI->LCDVertical, pATI->LCDHorizontal, 0, 1) + 11432b578d3Smrg pATI->LCDVertical; 11532b578d3Smrg pMode->CrtcVSyncStart = 11632b578d3Smrg ATIDivide((pMode->CrtcVSyncStart - pMode->CrtcVDisplay) * 11732b578d3Smrg pATI->LCDVertical, pATI->LCDHorizontal, 0, -1) + 11832b578d3Smrg pATI->LCDVertical; 11932b578d3Smrg pMode->CrtcVDisplay = pMode->CrtcVBlankStart = pATI->LCDVertical; 12032b578d3Smrg 12132b578d3Smrg /* 12232b578d3Smrg * The CRTC only stretches the mode's displayed area, not its porches. 12332b578d3Smrg * Reverse-engineer the mode's timings back into the user specified 12432b578d3Smrg * values so that the stretched mode is produced when the CRTC is 12532b578d3Smrg * eventually programmed. The reverse-engineered mode is then checked 12632b578d3Smrg * against CRTC limits below. 12732b578d3Smrg */ 12832b578d3Smrg pMode->Clock = pATI->LCDClock; 12932b578d3Smrg 13032b578d3Smrg HAdjust = pATI->LCDHorizontal - pMode->HDisplay; 13132b578d3Smrg# define ATIReverseHorizontal(_x) \ 13232b578d3Smrg (pMode->_x - HAdjust) 13332b578d3Smrg 13432b578d3Smrg pMode->HSyncStart = ATIReverseHorizontal(CrtcHSyncStart); 13532b578d3Smrg pMode->HSyncEnd = ATIReverseHorizontal(CrtcHSyncEnd); 13632b578d3Smrg pMode->HTotal = ATIReverseHorizontal(CrtcHTotal); 13732b578d3Smrg 13832b578d3Smrg VInterlace = GetBits(pMode->Flags, V_INTERLACE) + 1; 13932b578d3Smrg# define ATIReverseVertical(_y) \ 14032b578d3Smrg ((((pMode->_y - pATI->LCDVertical) * VInterlace) / VScan) + \ 14132b578d3Smrg pMode->VDisplay) 14232b578d3Smrg 14332b578d3Smrg pMode->VSyncStart = ATIReverseVertical(CrtcVSyncStart); 14432b578d3Smrg pMode->VSyncEnd = ATIReverseVertical(CrtcVSyncEnd); 14532b578d3Smrg pMode->VTotal = ATIReverseVertical(CrtcVTotal); 14632b578d3Smrg 14732b578d3Smrg# undef ATIReverseHorizontal 14832b578d3Smrg# undef ATIReverseVertical 14932b578d3Smrg } 15032b578d3Smrg 15132b578d3Smrg HBlankWidth = (pMode->HTotal >> 3) - (pMode->HDisplay >> 3); 15232b578d3Smrg if (!HBlankWidth) 15332b578d3Smrg return MODE_HBLANK_NARROW; 15432b578d3Smrg 15532b578d3Smrg { 15632b578d3Smrg if (VScan > 2) 15732b578d3Smrg return MODE_NO_VSCAN; 15832b578d3Smrg } 15932b578d3Smrg 16032b578d3Smrg return MODE_OK; 16132b578d3Smrg} 162