1/* 2 * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that copyright 7 * notice and this permission notice appear in supporting documentation, and 8 * that the name of Marc Aurele La France not be used in advertising or 9 * publicity pertaining to distribution of the software without specific, 10 * written prior permission. Marc Aurele La France makes no representations 11 * about the suitability of this software for any purpose. It is provided 12 * "as-is" without express or implied warranty. 13 * 14 * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO 16 * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 * PERFORMANCE OF THIS SOFTWARE. 21 */ 22 23#ifdef HAVE_CONFIG_H 24#include "config.h" 25#endif 26 27#include "xf86.h" 28#include "atichip.h" 29#include "atistruct.h" 30#include "ativalid.h" 31 32 33/* 34 * ATIValidMode -- 35 * 36 * This checks for hardware-related limits on mode timings. 37 */ 38ModeStatus 39ATIValidMode 40( 41 SCRN_ARG_TYPE arg, 42 DisplayModePtr pMode, 43 Bool Verbose, 44 int flags 45) 46{ 47 SCRN_INFO_PTR(arg); 48 ATIPtr pATI = ATIPTR(pScreenInfo); 49 int HBlankWidth, HAdjust, VScan, VInterlace; 50 51 if (flags & MODECHECK_FINAL) 52 { 53 return MODE_OK; 54 } 55 56 { 57 int maxHValue, maxVValue; 58 59 maxHValue = (MaxBits(CRTC_H_TOTAL) + 1) << 3; 60 if (pATI->Chip < ATI_CHIP_264VT) 61 { 62 /* CRTC_H_TOTAL is one bit narrower */ 63 maxHValue >>= 1; 64 } 65 if (pMode->HTotal > maxHValue) 66 return MODE_BAD_HVALUE; 67 68 maxVValue = MaxBits(CRTC_V_TOTAL) + 1; 69 if (pMode->VTotal > maxVValue) 70 return MODE_BAD_VVALUE; 71 } 72 73 /* 74 * The following is done for every mode in the monitor section that 75 * survives the common layer's basic checks. 76 */ 77 if (pMode->VScan <= 1) 78 VScan = 1; 79 else 80 VScan = pMode->VScan; 81 82 if (pMode->Flags & V_DBLSCAN) 83 VScan <<= 1; 84 85 if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0)) 86 { 87 if ((pMode->CrtcHDisplay > pATI->LCDHorizontal) || 88 (pMode->CrtcVDisplay > pATI->LCDVertical)) 89 return MODE_PANEL; 90 91 if (!pATI->OptionLCDSync || (pMode->type & M_T_BUILTIN)) 92 { 93 if ((pMode->HDisplay > pATI->LCDHorizontal) || 94 (pMode->VDisplay > pATI->LCDVertical)) 95 return MODE_PANEL; 96 97 return MODE_OK; 98 } 99 100 /* 101 * Adjust effective timings for monitor checks. Here the modeline 102 * clock is ignored. Horizontal timings are scaled by the stretch 103 * ratio used for the displayed area. The vertical porch is scaled by 104 * the native resolution's aspect ratio. This seems rather arbitrary, 105 * and it is, but it does make all applicable VESA modes sync on a 106 * panel after stretching. This has the unfortunate, but necessary, 107 * side-effect of changing the mode's horizontal sync and vertical 108 * refresh rates. With some exceptions, this tends to increase the 109 * mode's horizontal sync rate, and decrease its vertical refresh rate. 110 */ 111 pMode->SynthClock = pATI->LCDClock; 112 113 pMode->CrtcHTotal = pMode->CrtcHBlankEnd = 114 ATIDivide(pMode->CrtcHTotal * pATI->LCDHorizontal, 115 pMode->CrtcHDisplay, -3, 1) << 3; 116 pMode->CrtcHSyncEnd = 117 ATIDivide(pMode->CrtcHSyncEnd * pATI->LCDHorizontal, 118 pMode->CrtcHDisplay, -3, 1) << 3; 119 pMode->CrtcHSyncStart = 120 ATIDivide(pMode->CrtcHSyncStart * pATI->LCDHorizontal, 121 pMode->CrtcHDisplay, -3, -1) << 3; 122 pMode->CrtcHDisplay = pMode->CrtcHBlankStart = pATI->LCDHorizontal; 123 124 pMode->CrtcVTotal = pMode->CrtcVBlankEnd = 125 ATIDivide((pMode->CrtcVTotal - pMode->CrtcVDisplay) * 126 pATI->LCDVertical, pATI->LCDHorizontal, 0, 1) + 127 pATI->LCDVertical; 128 pMode->CrtcVSyncEnd = 129 ATIDivide((pMode->CrtcVSyncEnd - pMode->CrtcVDisplay) * 130 pATI->LCDVertical, pATI->LCDHorizontal, 0, 1) + 131 pATI->LCDVertical; 132 pMode->CrtcVSyncStart = 133 ATIDivide((pMode->CrtcVSyncStart - pMode->CrtcVDisplay) * 134 pATI->LCDVertical, pATI->LCDHorizontal, 0, -1) + 135 pATI->LCDVertical; 136 pMode->CrtcVDisplay = pMode->CrtcVBlankStart = pATI->LCDVertical; 137 138 /* 139 * The CRTC only stretches the mode's displayed area, not its porches. 140 * Reverse-engineer the mode's timings back into the user specified 141 * values so that the stretched mode is produced when the CRTC is 142 * eventually programmed. The reverse-engineered mode is then checked 143 * against CRTC limits below. 144 */ 145 pMode->Clock = pATI->LCDClock; 146 147 HAdjust = pATI->LCDHorizontal - pMode->HDisplay; 148# define ATIReverseHorizontal(_x) \ 149 (pMode->_x - HAdjust) 150 151 pMode->HSyncStart = ATIReverseHorizontal(CrtcHSyncStart); 152 pMode->HSyncEnd = ATIReverseHorizontal(CrtcHSyncEnd); 153 pMode->HTotal = ATIReverseHorizontal(CrtcHTotal); 154 155 VInterlace = GetBits(pMode->Flags, V_INTERLACE) + 1; 156# define ATIReverseVertical(_y) \ 157 ((((pMode->_y - pATI->LCDVertical) * VInterlace) / VScan) + \ 158 pMode->VDisplay) 159 160 pMode->VSyncStart = ATIReverseVertical(CrtcVSyncStart); 161 pMode->VSyncEnd = ATIReverseVertical(CrtcVSyncEnd); 162 pMode->VTotal = ATIReverseVertical(CrtcVTotal); 163 164# undef ATIReverseHorizontal 165# undef ATIReverseVertical 166 } 167 168 HBlankWidth = (pMode->HTotal >> 3) - (pMode->HDisplay >> 3); 169 if (!HBlankWidth) 170 return MODE_HBLANK_NARROW; 171 172 { 173 if (VScan > 2) 174 return MODE_NO_VSCAN; 175 } 176 177 return MODE_OK; 178} 179