ativalid.c revision 32b578d3
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 "atichip.h"
28#include "atistruct.h"
29#include "ativalid.h"
30
31#include "xf86.h"
32
33/*
34 * ATIValidMode --
35 *
36 * This checks for hardware-related limits on mode timings.
37 */
38ModeStatus
39ATIValidMode
40(
41    int iScreen,
42    DisplayModePtr pMode,
43    Bool Verbose,
44    int flags
45)
46{
47    ScrnInfoPtr pScreenInfo = xf86Screens[iScreen];
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     * The following is done for every mode in the monitor section that
58     * survives the common layer's basic checks.
59     */
60    if (pMode->VScan <= 1)
61        VScan = 1;
62    else
63        VScan = pMode->VScan;
64
65    if (pMode->Flags & V_DBLSCAN)
66        VScan <<= 1;
67
68    if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0))
69    {
70        if ((pMode->CrtcHDisplay > pATI->LCDHorizontal) ||
71            (pMode->CrtcVDisplay > pATI->LCDVertical))
72            return MODE_PANEL;
73
74        if (!pATI->OptionLCDSync || (pMode->type & M_T_BUILTIN))
75        {
76            if ((pMode->HDisplay > pATI->LCDHorizontal) ||
77                (pMode->VDisplay > pATI->LCDVertical))
78                return MODE_PANEL;
79
80            return MODE_OK;
81        }
82
83        /*
84         * Adjust effective timings for monitor checks.  Here the modeline
85         * clock is ignored.  Horizontal timings are scaled by the stretch
86         * ratio used for the displayed area.  The vertical porch is scaled by
87         * the native resolution's aspect ratio.  This seems rather arbitrary,
88         * and it is, but it does make all applicable VESA modes sync on a
89         * panel after stretching.  This has the unfortunate, but necessary,
90         * side-effect of changing the mode's horizontal sync and vertical
91         * refresh rates.  With some exceptions, this tends to increase the
92         * mode's horizontal sync rate, and decrease its vertical refresh rate.
93         */
94        pMode->SynthClock = pATI->LCDClock;
95
96        pMode->CrtcHTotal = pMode->CrtcHBlankEnd =
97            ATIDivide(pMode->CrtcHTotal * pATI->LCDHorizontal,
98                pMode->CrtcHDisplay, -3, 1) << 3;
99        pMode->CrtcHSyncEnd =
100            ATIDivide(pMode->CrtcHSyncEnd * pATI->LCDHorizontal,
101                pMode->CrtcHDisplay, -3, 1) << 3;
102        pMode->CrtcHSyncStart =
103            ATIDivide(pMode->CrtcHSyncStart * pATI->LCDHorizontal,
104                pMode->CrtcHDisplay, -3, -1) << 3;
105        pMode->CrtcHDisplay = pMode->CrtcHBlankStart = pATI->LCDHorizontal;
106
107        pMode->CrtcVTotal = pMode->CrtcVBlankEnd =
108            ATIDivide((pMode->CrtcVTotal - pMode->CrtcVDisplay) *
109                pATI->LCDVertical, pATI->LCDHorizontal, 0, 1) +
110                pATI->LCDVertical;
111        pMode->CrtcVSyncEnd =
112            ATIDivide((pMode->CrtcVSyncEnd - pMode->CrtcVDisplay) *
113                pATI->LCDVertical, pATI->LCDHorizontal, 0, 1) +
114                pATI->LCDVertical;
115        pMode->CrtcVSyncStart =
116            ATIDivide((pMode->CrtcVSyncStart - pMode->CrtcVDisplay) *
117                pATI->LCDVertical, pATI->LCDHorizontal, 0, -1) +
118                pATI->LCDVertical;
119        pMode->CrtcVDisplay = pMode->CrtcVBlankStart = pATI->LCDVertical;
120
121        /*
122         * The CRTC only stretches the mode's displayed area, not its porches.
123         * Reverse-engineer the mode's timings back into the user specified
124         * values so that the stretched mode is produced when the CRTC is
125         * eventually programmed.  The reverse-engineered mode is then checked
126         * against CRTC limits below.
127         */
128        pMode->Clock = pATI->LCDClock;
129
130        HAdjust = pATI->LCDHorizontal - pMode->HDisplay;
131#       define ATIReverseHorizontal(_x) \
132            (pMode->_x - HAdjust)
133
134        pMode->HSyncStart = ATIReverseHorizontal(CrtcHSyncStart);
135        pMode->HSyncEnd = ATIReverseHorizontal(CrtcHSyncEnd);
136        pMode->HTotal = ATIReverseHorizontal(CrtcHTotal);
137
138        VInterlace = GetBits(pMode->Flags, V_INTERLACE) + 1;
139#       define ATIReverseVertical(_y) \
140            ((((pMode->_y - pATI->LCDVertical) * VInterlace) / VScan) + \
141             pMode->VDisplay)
142
143        pMode->VSyncStart = ATIReverseVertical(CrtcVSyncStart);
144        pMode->VSyncEnd = ATIReverseVertical(CrtcVSyncEnd);
145        pMode->VTotal = ATIReverseVertical(CrtcVTotal);
146
147#       undef ATIReverseHorizontal
148#       undef ATIReverseVertical
149    }
150
151    HBlankWidth = (pMode->HTotal >> 3) - (pMode->HDisplay >> 3);
152    if (!HBlankWidth)
153        return MODE_HBLANK_NARROW;
154
155    {
156            if (VScan > 2)
157                return MODE_NO_VSCAN;
158    }
159
160    return MODE_OK;
161}
162