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 27e35d4d8eSmrg#include "xf86.h" 2832b578d3Smrg#include "atichip.h" 2932b578d3Smrg#include "atistruct.h" 3032b578d3Smrg#include "ativalid.h" 3132b578d3Smrg 3232b578d3Smrg 3332b578d3Smrg/* 3432b578d3Smrg * ATIValidMode -- 3532b578d3Smrg * 3632b578d3Smrg * This checks for hardware-related limits on mode timings. 3732b578d3Smrg */ 3832b578d3SmrgModeStatus 3932b578d3SmrgATIValidMode 4032b578d3Smrg( 41e35d4d8eSmrg SCRN_ARG_TYPE arg, 4232b578d3Smrg DisplayModePtr pMode, 4332b578d3Smrg Bool Verbose, 4432b578d3Smrg int flags 4532b578d3Smrg) 4632b578d3Smrg{ 47e35d4d8eSmrg SCRN_INFO_PTR(arg); 4832b578d3Smrg ATIPtr pATI = ATIPTR(pScreenInfo); 4932b578d3Smrg int HBlankWidth, HAdjust, VScan, VInterlace; 5032b578d3Smrg 5132b578d3Smrg if (flags & MODECHECK_FINAL) 5232b578d3Smrg { 5332b578d3Smrg return MODE_OK; 5432b578d3Smrg } 5532b578d3Smrg 56d2b10af6Smrg { 57d2b10af6Smrg int maxHValue, maxVValue; 58d2b10af6Smrg 59d2b10af6Smrg maxHValue = (MaxBits(CRTC_H_TOTAL) + 1) << 3; 60d2b10af6Smrg if (pATI->Chip < ATI_CHIP_264VT) 61d2b10af6Smrg { 62d2b10af6Smrg /* CRTC_H_TOTAL is one bit narrower */ 63d2b10af6Smrg maxHValue >>= 1; 64d2b10af6Smrg } 65d2b10af6Smrg if (pMode->HTotal > maxHValue) 66d2b10af6Smrg return MODE_BAD_HVALUE; 67d2b10af6Smrg 68d2b10af6Smrg maxVValue = MaxBits(CRTC_V_TOTAL) + 1; 69d2b10af6Smrg if (pMode->VTotal > maxVValue) 70d2b10af6Smrg return MODE_BAD_VVALUE; 71d2b10af6Smrg } 72d2b10af6Smrg 7332b578d3Smrg /* 7432b578d3Smrg * The following is done for every mode in the monitor section that 7532b578d3Smrg * survives the common layer's basic checks. 7632b578d3Smrg */ 7732b578d3Smrg if (pMode->VScan <= 1) 7832b578d3Smrg VScan = 1; 7932b578d3Smrg else 8032b578d3Smrg VScan = pMode->VScan; 8132b578d3Smrg 8232b578d3Smrg if (pMode->Flags & V_DBLSCAN) 8332b578d3Smrg VScan <<= 1; 8432b578d3Smrg 8532b578d3Smrg if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0)) 8632b578d3Smrg { 8732b578d3Smrg if ((pMode->CrtcHDisplay > pATI->LCDHorizontal) || 8832b578d3Smrg (pMode->CrtcVDisplay > pATI->LCDVertical)) 8932b578d3Smrg return MODE_PANEL; 9032b578d3Smrg 9132b578d3Smrg if (!pATI->OptionLCDSync || (pMode->type & M_T_BUILTIN)) 9232b578d3Smrg { 9332b578d3Smrg if ((pMode->HDisplay > pATI->LCDHorizontal) || 9432b578d3Smrg (pMode->VDisplay > pATI->LCDVertical)) 9532b578d3Smrg return MODE_PANEL; 9632b578d3Smrg 9732b578d3Smrg return MODE_OK; 9832b578d3Smrg } 9932b578d3Smrg 10032b578d3Smrg /* 10132b578d3Smrg * Adjust effective timings for monitor checks. Here the modeline 10232b578d3Smrg * clock is ignored. Horizontal timings are scaled by the stretch 10332b578d3Smrg * ratio used for the displayed area. The vertical porch is scaled by 10432b578d3Smrg * the native resolution's aspect ratio. This seems rather arbitrary, 10532b578d3Smrg * and it is, but it does make all applicable VESA modes sync on a 10632b578d3Smrg * panel after stretching. This has the unfortunate, but necessary, 10732b578d3Smrg * side-effect of changing the mode's horizontal sync and vertical 10832b578d3Smrg * refresh rates. With some exceptions, this tends to increase the 10932b578d3Smrg * mode's horizontal sync rate, and decrease its vertical refresh rate. 11032b578d3Smrg */ 11132b578d3Smrg pMode->SynthClock = pATI->LCDClock; 11232b578d3Smrg 11332b578d3Smrg pMode->CrtcHTotal = pMode->CrtcHBlankEnd = 11432b578d3Smrg ATIDivide(pMode->CrtcHTotal * pATI->LCDHorizontal, 11532b578d3Smrg pMode->CrtcHDisplay, -3, 1) << 3; 11632b578d3Smrg pMode->CrtcHSyncEnd = 11732b578d3Smrg ATIDivide(pMode->CrtcHSyncEnd * pATI->LCDHorizontal, 11832b578d3Smrg pMode->CrtcHDisplay, -3, 1) << 3; 11932b578d3Smrg pMode->CrtcHSyncStart = 12032b578d3Smrg ATIDivide(pMode->CrtcHSyncStart * pATI->LCDHorizontal, 12132b578d3Smrg pMode->CrtcHDisplay, -3, -1) << 3; 12232b578d3Smrg pMode->CrtcHDisplay = pMode->CrtcHBlankStart = pATI->LCDHorizontal; 12332b578d3Smrg 12432b578d3Smrg pMode->CrtcVTotal = pMode->CrtcVBlankEnd = 12532b578d3Smrg ATIDivide((pMode->CrtcVTotal - pMode->CrtcVDisplay) * 12632b578d3Smrg pATI->LCDVertical, pATI->LCDHorizontal, 0, 1) + 12732b578d3Smrg pATI->LCDVertical; 12832b578d3Smrg pMode->CrtcVSyncEnd = 12932b578d3Smrg ATIDivide((pMode->CrtcVSyncEnd - pMode->CrtcVDisplay) * 13032b578d3Smrg pATI->LCDVertical, pATI->LCDHorizontal, 0, 1) + 13132b578d3Smrg pATI->LCDVertical; 13232b578d3Smrg pMode->CrtcVSyncStart = 13332b578d3Smrg ATIDivide((pMode->CrtcVSyncStart - pMode->CrtcVDisplay) * 13432b578d3Smrg pATI->LCDVertical, pATI->LCDHorizontal, 0, -1) + 13532b578d3Smrg pATI->LCDVertical; 13632b578d3Smrg pMode->CrtcVDisplay = pMode->CrtcVBlankStart = pATI->LCDVertical; 13732b578d3Smrg 13832b578d3Smrg /* 13932b578d3Smrg * The CRTC only stretches the mode's displayed area, not its porches. 14032b578d3Smrg * Reverse-engineer the mode's timings back into the user specified 14132b578d3Smrg * values so that the stretched mode is produced when the CRTC is 14232b578d3Smrg * eventually programmed. The reverse-engineered mode is then checked 14332b578d3Smrg * against CRTC limits below. 14432b578d3Smrg */ 14532b578d3Smrg pMode->Clock = pATI->LCDClock; 14632b578d3Smrg 14732b578d3Smrg HAdjust = pATI->LCDHorizontal - pMode->HDisplay; 14832b578d3Smrg# define ATIReverseHorizontal(_x) \ 14932b578d3Smrg (pMode->_x - HAdjust) 15032b578d3Smrg 15132b578d3Smrg pMode->HSyncStart = ATIReverseHorizontal(CrtcHSyncStart); 15232b578d3Smrg pMode->HSyncEnd = ATIReverseHorizontal(CrtcHSyncEnd); 15332b578d3Smrg pMode->HTotal = ATIReverseHorizontal(CrtcHTotal); 15432b578d3Smrg 15532b578d3Smrg VInterlace = GetBits(pMode->Flags, V_INTERLACE) + 1; 15632b578d3Smrg# define ATIReverseVertical(_y) \ 15732b578d3Smrg ((((pMode->_y - pATI->LCDVertical) * VInterlace) / VScan) + \ 15832b578d3Smrg pMode->VDisplay) 15932b578d3Smrg 16032b578d3Smrg pMode->VSyncStart = ATIReverseVertical(CrtcVSyncStart); 16132b578d3Smrg pMode->VSyncEnd = ATIReverseVertical(CrtcVSyncEnd); 16232b578d3Smrg pMode->VTotal = ATIReverseVertical(CrtcVTotal); 16332b578d3Smrg 16432b578d3Smrg# undef ATIReverseHorizontal 16532b578d3Smrg# undef ATIReverseVertical 16632b578d3Smrg } 16732b578d3Smrg 16832b578d3Smrg HBlankWidth = (pMode->HTotal >> 3) - (pMode->HDisplay >> 3); 16932b578d3Smrg if (!HBlankWidth) 17032b578d3Smrg return MODE_HBLANK_NARROW; 17132b578d3Smrg 17232b578d3Smrg { 17332b578d3Smrg if (VScan > 2) 17432b578d3Smrg return MODE_NO_VSCAN; 17532b578d3Smrg } 17632b578d3Smrg 17732b578d3Smrg return MODE_OK; 17832b578d3Smrg} 179