179 lines
6.2 KiB
C
179 lines
6.2 KiB
C
|
/*
|
||
|
* Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
|
||
|
*
|
||
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
||
|
* documentation for any purpose is hereby granted without fee, provided that
|
||
|
* the above copyright notice appear in all copies and that both that copyright
|
||
|
* notice and this permission notice appear in supporting documentation, and
|
||
|
* that the name of Marc Aurele La France not be used in advertising or
|
||
|
* publicity pertaining to distribution of the software without specific,
|
||
|
* written prior permission. Marc Aurele La France makes no representations
|
||
|
* about the suitability of this software for any purpose. It is provided
|
||
|
* "as-is" without express or implied warranty.
|
||
|
*
|
||
|
* MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
|
||
|
* EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||
|
*/
|
||
|
|
||
|
#ifdef HAVE_CONFIG_H
|
||
|
#include "config.h"
|
||
|
#endif
|
||
|
|
||
|
#include "xf86.h"
|
||
|
#include "atichip.h"
|
||
|
#include "atistruct.h"
|
||
|
#include "ativalid.h"
|
||
|
|
||
|
|
||
|
/*
|
||
|
* ATIValidMode --
|
||
|
*
|
||
|
* This checks for hardware-related limits on mode timings.
|
||
|
*/
|
||
|
ModeStatus
|
||
|
ATIValidMode
|
||
|
(
|
||
|
SCRN_ARG_TYPE arg,
|
||
|
DisplayModePtr pMode,
|
||
|
Bool Verbose,
|
||
|
int flags
|
||
|
)
|
||
|
{
|
||
|
SCRN_INFO_PTR(arg);
|
||
|
ATIPtr pATI = ATIPTR(pScreenInfo);
|
||
|
int HBlankWidth, HAdjust, VScan, VInterlace;
|
||
|
|
||
|
if (flags & MODECHECK_FINAL)
|
||
|
{
|
||
|
return MODE_OK;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
int maxHValue, maxVValue;
|
||
|
|
||
|
maxHValue = (MaxBits(CRTC_H_TOTAL) + 1) << 3;
|
||
|
if (pATI->Chip < ATI_CHIP_264VT)
|
||
|
{
|
||
|
/* CRTC_H_TOTAL is one bit narrower */
|
||
|
maxHValue >>= 1;
|
||
|
}
|
||
|
if (pMode->HTotal > maxHValue)
|
||
|
return MODE_BAD_HVALUE;
|
||
|
|
||
|
maxVValue = MaxBits(CRTC_V_TOTAL) + 1;
|
||
|
if (pMode->VTotal > maxVValue)
|
||
|
return MODE_BAD_VVALUE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* The following is done for every mode in the monitor section that
|
||
|
* survives the common layer's basic checks.
|
||
|
*/
|
||
|
if (pMode->VScan <= 1)
|
||
|
VScan = 1;
|
||
|
else
|
||
|
VScan = pMode->VScan;
|
||
|
|
||
|
if (pMode->Flags & V_DBLSCAN)
|
||
|
VScan <<= 1;
|
||
|
|
||
|
if (pATI->OptionPanelDisplay && (pATI->LCDPanelID >= 0))
|
||
|
{
|
||
|
if ((pMode->CrtcHDisplay > pATI->LCDHorizontal) ||
|
||
|
(pMode->CrtcVDisplay > pATI->LCDVertical))
|
||
|
return MODE_PANEL;
|
||
|
|
||
|
if (!pATI->OptionLCDSync || (pMode->type & M_T_BUILTIN))
|
||
|
{
|
||
|
if ((pMode->HDisplay > pATI->LCDHorizontal) ||
|
||
|
(pMode->VDisplay > pATI->LCDVertical))
|
||
|
return MODE_PANEL;
|
||
|
|
||
|
return MODE_OK;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Adjust effective timings for monitor checks. Here the modeline
|
||
|
* clock is ignored. Horizontal timings are scaled by the stretch
|
||
|
* ratio used for the displayed area. The vertical porch is scaled by
|
||
|
* the native resolution's aspect ratio. This seems rather arbitrary,
|
||
|
* and it is, but it does make all applicable VESA modes sync on a
|
||
|
* panel after stretching. This has the unfortunate, but necessary,
|
||
|
* side-effect of changing the mode's horizontal sync and vertical
|
||
|
* refresh rates. With some exceptions, this tends to increase the
|
||
|
* mode's horizontal sync rate, and decrease its vertical refresh rate.
|
||
|
*/
|
||
|
pMode->SynthClock = pATI->LCDClock;
|
||
|
|
||
|
pMode->CrtcHTotal = pMode->CrtcHBlankEnd =
|
||
|
ATIDivide(pMode->CrtcHTotal * pATI->LCDHorizontal,
|
||
|
pMode->CrtcHDisplay, -3, 1) << 3;
|
||
|
pMode->CrtcHSyncEnd =
|
||
|
ATIDivide(pMode->CrtcHSyncEnd * pATI->LCDHorizontal,
|
||
|
pMode->CrtcHDisplay, -3, 1) << 3;
|
||
|
pMode->CrtcHSyncStart =
|
||
|
ATIDivide(pMode->CrtcHSyncStart * pATI->LCDHorizontal,
|
||
|
pMode->CrtcHDisplay, -3, -1) << 3;
|
||
|
pMode->CrtcHDisplay = pMode->CrtcHBlankStart = pATI->LCDHorizontal;
|
||
|
|
||
|
pMode->CrtcVTotal = pMode->CrtcVBlankEnd =
|
||
|
ATIDivide((pMode->CrtcVTotal - pMode->CrtcVDisplay) *
|
||
|
pATI->LCDVertical, pATI->LCDHorizontal, 0, 1) +
|
||
|
pATI->LCDVertical;
|
||
|
pMode->CrtcVSyncEnd =
|
||
|
ATIDivide((pMode->CrtcVSyncEnd - pMode->CrtcVDisplay) *
|
||
|
pATI->LCDVertical, pATI->LCDHorizontal, 0, 1) +
|
||
|
pATI->LCDVertical;
|
||
|
pMode->CrtcVSyncStart =
|
||
|
ATIDivide((pMode->CrtcVSyncStart - pMode->CrtcVDisplay) *
|
||
|
pATI->LCDVertical, pATI->LCDHorizontal, 0, -1) +
|
||
|
pATI->LCDVertical;
|
||
|
pMode->CrtcVDisplay = pMode->CrtcVBlankStart = pATI->LCDVertical;
|
||
|
|
||
|
/*
|
||
|
* The CRTC only stretches the mode's displayed area, not its porches.
|
||
|
* Reverse-engineer the mode's timings back into the user specified
|
||
|
* values so that the stretched mode is produced when the CRTC is
|
||
|
* eventually programmed. The reverse-engineered mode is then checked
|
||
|
* against CRTC limits below.
|
||
|
*/
|
||
|
pMode->Clock = pATI->LCDClock;
|
||
|
|
||
|
HAdjust = pATI->LCDHorizontal - pMode->HDisplay;
|
||
|
# define ATIReverseHorizontal(_x) \
|
||
|
(pMode->_x - HAdjust)
|
||
|
|
||
|
pMode->HSyncStart = ATIReverseHorizontal(CrtcHSyncStart);
|
||
|
pMode->HSyncEnd = ATIReverseHorizontal(CrtcHSyncEnd);
|
||
|
pMode->HTotal = ATIReverseHorizontal(CrtcHTotal);
|
||
|
|
||
|
VInterlace = GetBits(pMode->Flags, V_INTERLACE) + 1;
|
||
|
# define ATIReverseVertical(_y) \
|
||
|
((((pMode->_y - pATI->LCDVertical) * VInterlace) / VScan) + \
|
||
|
pMode->VDisplay)
|
||
|
|
||
|
pMode->VSyncStart = ATIReverseVertical(CrtcVSyncStart);
|
||
|
pMode->VSyncEnd = ATIReverseVertical(CrtcVSyncEnd);
|
||
|
pMode->VTotal = ATIReverseVertical(CrtcVTotal);
|
||
|
|
||
|
# undef ATIReverseHorizontal
|
||
|
# undef ATIReverseVertical
|
||
|
}
|
||
|
|
||
|
HBlankWidth = (pMode->HTotal >> 3) - (pMode->HDisplay >> 3);
|
||
|
if (!HBlankWidth)
|
||
|
return MODE_HBLANK_NARROW;
|
||
|
|
||
|
{
|
||
|
if (VScan > 2)
|
||
|
return MODE_NO_VSCAN;
|
||
|
}
|
||
|
|
||
|
return MODE_OK;
|
||
|
}
|