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 */
38 ModeStatus
ATIValidMode(SCRN_ARG_TYPE arg,DisplayModePtr pMode,Bool Verbose,int flags)39 ATIValidMode
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