2 * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
22 * Except as contained in this notice, the name of the copyright holder(s)
23 * and author(s) shall not be used in advertising or otherwise to promote
24 * the sale, use or other dealings in this Software without prior written
25 * authorization from the copyright holder(s) and author(s).
29 * LCM() and scanLineWidth() are:
31 * Copyright 1997 through 2004 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org
33 * Permission to use, copy, modify, distribute, and sell this software and its
34 * documentation for any purpose is hereby granted without fee, provided that
35 * the above copyright notice appear in all copies and that both that copyright
36 * notice and this permission notice appear in supporting documentation, and
37 * that the name of Marc Aurele La France not be used in advertising or
38 * publicity pertaining to distribution of the software without specific,
39 * written prior permission. Marc Aurele La France makes no representations
40 * about the suitability of this software for any purpose. It is provided
41 * "as-is" without express or implied warranty.
43 * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
44 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
45 * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR
46 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
47 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
48 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
49 * PERFORMANCE OF THIS SOFTWARE.
51 * Copyright 1990,91,92,93 by Thomas Roell, Germany.
52 * Copyright 1991,92,93 by SGCS (Snitily Graphics Consulting Services), USA.
54 * Permission to use, copy, modify, distribute, and sell this software
55 * and its documentation for any purpose is hereby granted without fee,
56 * provided that the above copyright notice appear in all copies and
57 * that both that copyright notice and this permission notice appear
58 * in supporting documentation, and that the name of Thomas Roell nor
59 * SGCS be used in advertising or publicity pertaining to distribution
60 * of the software without specific, written prior permission.
61 * Thomas Roell nor SGCS makes no representations about the suitability
62 * of this software for any purpose. It is provided "as is" without
63 * express or implied warranty.
65 * THOMAS ROELL AND SGCS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
66 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
67 * FITNESS, IN NO EVENT SHALL THOMAS ROELL OR SGCS BE LIABLE FOR ANY
68 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
69 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
70 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
71 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
75 * Authors: Dirk Hohndel <hohndel@XFree86.Org>
76 * David Dawes <dawes@XFree86.Org>
77 * Marc La France <tsi@XFree86.Org>
80 * This file includes helper functions for mode related things.
83 #ifdef HAVE_XORG_CONFIG_H
84 #include <xorg-config.h>
88 #include "xf86Modes.h"
97 printModeRejectMessage(int index
, DisplayModePtr p
, int status
)
101 if (p
->type
& M_T_BUILTIN
)
103 else if (p
->type
& M_T_DEFAULT
)
105 else if (p
->type
& M_T_DRIVER
)
110 xf86DrvMsg(index
, X_INFO
, "Not using %smode \"%s\" (%s)\n", type
, p
->name
,
111 xf86ModeStatusToString(status
));
115 * xf86GetNearestClock --
116 * Find closest clock to given frequency (in kHz). This assumes the
117 * number of clocks is greater than zero.
120 xf86GetNearestClock(ScrnInfoPtr scrp
, int freq
, Bool allowDiv2
,
121 int DivFactor
, int MulFactor
, int *divider
)
123 int nearestClock
= 0, nearestDiv
= 1;
124 int minimumGap
= abs(freq
- scrp
->clock
[0]);
132 /* Must set this here in case the best match is scrp->clock[0] */
136 for (i
= 0; i
< scrp
->numClocks
; i
++) {
137 for (j
= 1; j
<= k
; j
++) {
138 gap
= abs((freq
* j
) - ((scrp
->clock
[i
] * DivFactor
) / MulFactor
));
139 if ((gap
< minimumGap
) || ((gap
== minimumGap
) && (j
< nearestDiv
))) {
144 *divider
= (j
- 1) * V_CLKDIV2
;
152 * xf86ModeStatusToString
154 * Convert a ModeStatus value to a printable message
158 xf86ModeStatusToString(ModeStatus status
)
164 return "hsync out of range";
166 return "vrefresh out of range";
168 return "illegal horizontal timings";
170 return "illegal vertical timings";
172 return "width requires unsupported line pitch";
174 return "no mode of this name";
175 case MODE_NO_INTERLACE
:
176 return "interlace mode not supported";
177 case MODE_NO_DBLESCAN
:
178 return "doublescan mode not supported";
180 return "multiscan mode not supported";
182 return "insufficient memory for mode";
184 return "width too large for virtual size";
186 return "height too large for virtual size";
188 return "insufficient memory given virtual size";
190 return "no clock available for mode";
191 case MODE_CLOCK_HIGH
:
192 return "mode clock too high";
194 return "mode clock too low";
195 case MODE_CLOCK_RANGE
:
196 return "bad mode clock/interlace/doublescan";
197 case MODE_BAD_HVALUE
:
198 return "horizontal timing out of range";
199 case MODE_BAD_VVALUE
:
200 return "vertical timing out of range";
202 return "VScan value out of range";
203 case MODE_HSYNC_NARROW
:
204 return "horizontal sync too narrow";
205 case MODE_HSYNC_WIDE
:
206 return "horizontal sync too wide";
207 case MODE_HBLANK_NARROW
:
208 return "horizontal blanking too narrow";
209 case MODE_HBLANK_WIDE
:
210 return "horizontal blanking too wide";
211 case MODE_VSYNC_NARROW
:
212 return "vertical sync too narrow";
213 case MODE_VSYNC_WIDE
:
214 return "vertical sync too wide";
215 case MODE_VBLANK_NARROW
:
216 return "vertical blanking too narrow";
217 case MODE_VBLANK_WIDE
:
218 return "vertical blanking too wide";
220 return "exceeds panel dimensions";
221 case MODE_INTERLACE_WIDTH
:
222 return "width too large for interlaced mode";
224 return "all modes must have the same width";
225 case MODE_ONE_HEIGHT
:
226 return "all modes must have the same height";
228 return "all modes must have the same resolution";
229 case MODE_NO_REDUCED
:
230 return "monitor doesn't support reduced blanking";
232 return "mode requires too much memory bandwidth";
234 return "unknown reason";
236 return "internal error";
243 * xf86ShowClockRanges() -- Print the clock ranges allowed
244 * and the clock values scaled by ClockMulFactor and ClockDivFactor
247 xf86ShowClockRanges(ScrnInfoPtr scrp
, ClockRangePtr clockRanges
)
255 for (cp
= clockRanges
; cp
!= NULL
; cp
= cp
->next
) {
256 DivFactor
= max(1, cp
->ClockDivFactor
);
257 MulFactor
= max(1, cp
->ClockMulFactor
);
258 if (scrp
->progClock
) {
261 xf86DrvMsg(scrp
->scrnIndex
, X_INFO
,
262 "Clock range: %6.2f to %6.2f MHz\n",
263 (double) cp
->minClock
/ 1000.0,
264 (double) cp
->maxClock
/ 1000.0);
267 xf86DrvMsg(scrp
->scrnIndex
, X_INFO
,
268 "Minimum clock: %6.2f MHz\n",
269 (double) cp
->minClock
/ 1000.0);
274 xf86DrvMsg(scrp
->scrnIndex
, X_INFO
,
275 "Maximum clock: %6.2f MHz\n",
276 (double) cp
->maxClock
/ 1000.0);
280 else if (DivFactor
> 1 || MulFactor
> 1) {
282 for (i
= 0; i
< scrp
->numClocks
; i
++) {
283 scaledClock
= (scrp
->clock
[i
] * DivFactor
) / MulFactor
;
284 if (scaledClock
>= cp
->minClock
&& scaledClock
<= cp
->maxClock
) {
288 xf86DrvMsg(scrp
->scrnIndex
, X_INFO
, "scaled clocks:");
290 xf86ErrorF(" %6.2f", (double) scaledClock
/ 1000.0);
300 modeInClockRange(ClockRangePtr cp
, DisplayModePtr p
)
302 return ((p
->Clock
>= cp
->minClock
) &&
303 (p
->Clock
<= cp
->maxClock
) &&
304 (cp
->interlaceAllowed
|| !(p
->Flags
& V_INTERLACE
)) &&
305 (cp
->doubleScanAllowed
||
306 ((p
->VScan
<= 1) && !(p
->Flags
& V_DBLSCAN
))));
310 * xf86FindClockRangeForMode() [... like the name says ...]
313 xf86FindClockRangeForMode(ClockRangePtr clockRanges
, DisplayModePtr p
)
317 for (cp
= clockRanges
;; cp
= cp
->next
)
318 if (!cp
|| modeInClockRange(cp
, p
))
323 * xf86HandleBuiltinMode() - handles built-in modes
326 xf86HandleBuiltinMode(ScrnInfoPtr scrp
,
328 DisplayModePtr modep
,
329 ClockRangePtr clockRanges
, Bool allowDiv2
)
337 /* Reject previously rejected modes */
338 if (p
->status
!= MODE_OK
)
341 /* Reject previously considered modes */
345 if ((p
->type
& M_T_CLOCK_C
) == M_T_CLOCK_C
) {
346 /* Check clock is in range */
347 cp
= xf86FindClockRangeForMode(clockRanges
, p
);
349 modep
->type
= p
->type
;
350 p
->status
= MODE_CLOCK_RANGE
;
351 return MODE_CLOCK_RANGE
;
353 DivFactor
= cp
->ClockDivFactor
;
354 MulFactor
= cp
->ClockMulFactor
;
355 if (!scrp
->progClock
) {
356 clockIndex
= xf86GetNearestClock(scrp
, p
->Clock
, allowDiv2
,
358 cp
->ClockMulFactor
, &extraFlags
);
359 modep
->Clock
= (scrp
->clock
[clockIndex
] * DivFactor
)
361 modep
->ClockIndex
= clockIndex
;
362 modep
->SynthClock
= scrp
->clock
[clockIndex
];
363 if (extraFlags
& V_CLKDIV2
) {
365 modep
->SynthClock
/= 2;
369 modep
->Clock
= p
->Clock
;
370 modep
->ClockIndex
= -1;
371 modep
->SynthClock
= (modep
->Clock
* MulFactor
)
374 modep
->PrivFlags
= cp
->PrivFlags
;
377 if (!scrp
->progClock
) {
378 modep
->Clock
= p
->Clock
;
379 modep
->ClockIndex
= p
->ClockIndex
;
380 modep
->SynthClock
= p
->SynthClock
;
383 modep
->Clock
= p
->Clock
;
384 modep
->ClockIndex
= -1;
385 modep
->SynthClock
= p
->SynthClock
;
387 modep
->PrivFlags
= p
->PrivFlags
;
389 modep
->type
= p
->type
;
390 modep
->HDisplay
= p
->HDisplay
;
391 modep
->HSyncStart
= p
->HSyncStart
;
392 modep
->HSyncEnd
= p
->HSyncEnd
;
393 modep
->HTotal
= p
->HTotal
;
394 modep
->HSkew
= p
->HSkew
;
395 modep
->VDisplay
= p
->VDisplay
;
396 modep
->VSyncStart
= p
->VSyncStart
;
397 modep
->VSyncEnd
= p
->VSyncEnd
;
398 modep
->VTotal
= p
->VTotal
;
399 modep
->VScan
= p
->VScan
;
400 modep
->Flags
= p
->Flags
| extraFlags
;
401 modep
->CrtcHDisplay
= p
->CrtcHDisplay
;
402 modep
->CrtcHBlankStart
= p
->CrtcHBlankStart
;
403 modep
->CrtcHSyncStart
= p
->CrtcHSyncStart
;
404 modep
->CrtcHSyncEnd
= p
->CrtcHSyncEnd
;
405 modep
->CrtcHBlankEnd
= p
->CrtcHBlankEnd
;
406 modep
->CrtcHTotal
= p
->CrtcHTotal
;
407 modep
->CrtcHSkew
= p
->CrtcHSkew
;
408 modep
->CrtcVDisplay
= p
->CrtcVDisplay
;
409 modep
->CrtcVBlankStart
= p
->CrtcVBlankStart
;
410 modep
->CrtcVSyncStart
= p
->CrtcVSyncStart
;
411 modep
->CrtcVSyncEnd
= p
->CrtcVSyncEnd
;
412 modep
->CrtcVBlankEnd
= p
->CrtcVBlankEnd
;
413 modep
->CrtcVTotal
= p
->CrtcVTotal
;
414 modep
->CrtcHAdjusted
= p
->CrtcHAdjusted
;
415 modep
->CrtcVAdjusted
= p
->CrtcVAdjusted
;
416 modep
->HSync
= p
->HSync
;
417 modep
->VRefresh
= p
->VRefresh
;
418 modep
->Private
= p
->Private
;
419 modep
->PrivSize
= p
->PrivSize
;
429 * This function returns a mode from the given list which matches the
430 * given name. When multiple modes with the same name are available,
431 * the method of picking the matching mode is determined by the
434 * This function takes the following parameters:
436 * modep pointer to the returned mode, which must have the name
438 * clockRanges a list of clock ranges. This is optional when all the
439 * modes are built-in modes.
440 * strategy how to decide which mode to use from multiple modes with
443 * In addition, the following fields from the ScrnInfoRec are used:
444 * modePool the list of monitor modes compatible with the driver
445 * clocks a list of discrete clocks
446 * numClocks number of discrete clocks
447 * progClock clock is programmable
449 * If a mode was found, its values are filled in to the area pointed to
450 * by modep, If a mode was not found the return value indicates the
455 xf86LookupMode(ScrnInfoPtr scrp
, DisplayModePtr modep
,
456 ClockRangePtr clockRanges
, LookupModeFlags strategy
)
458 DisplayModePtr p
, bestMode
= NULL
;
460 int i
, k
, gap
, minimumGap
= CLOCK_TOLERANCE
+ 1;
461 double refresh
, bestRefresh
= 0.0;
467 int ModePrivFlags
= 0;
468 ModeStatus status
= MODE_NOMODE
;
469 Bool allowDiv2
= (strategy
& LOOKUP_CLKDIV2
) != 0;
472 const int types
[] = {
473 M_T_BUILTIN
| M_T_PREFERRED
,
475 M_T_USERDEF
| M_T_PREFERRED
,
477 M_T_DRIVER
| M_T_PREFERRED
,
481 const int ntypes
= sizeof(types
) / sizeof(int);
483 strategy
&= ~(LOOKUP_CLKDIV2
| LOOKUP_OPTIONAL_TOLERANCES
);
485 /* Some sanity checking */
486 if (scrp
== NULL
|| scrp
->modePool
== NULL
||
487 (!scrp
->progClock
&& scrp
->numClocks
== 0)) {
488 ErrorF("xf86LookupMode: called with invalid scrnInfoRec\n");
491 if (modep
== NULL
|| modep
->name
== NULL
) {
492 ErrorF("xf86LookupMode: called with invalid modep\n");
495 for (cp
= clockRanges
; cp
!= NULL
; cp
= cp
->next
) {
496 /* DivFactor and MulFactor must be > 0 */
497 cp
->ClockDivFactor
= max(1, cp
->ClockDivFactor
);
498 cp
->ClockMulFactor
= max(1, cp
->ClockMulFactor
);
501 /* Scan the mode pool for matching names */
502 for (n
= 0; n
< ntypes
; n
++) {
505 for (p
= scrp
->modePool
; p
!= NULL
; p
= p
->next
) {
507 /* scan through the modes in the sort order above */
508 if ((p
->type
& type
) != type
)
511 if (strcmp(p
->name
, modep
->name
) == 0) {
513 /* Skip over previously rejected modes */
514 if (p
->status
!= MODE_OK
) {
520 /* Skip over previously considered modes */
524 if (p
->type
& M_T_BUILTIN
) {
525 return xf86HandleBuiltinMode(scrp
, p
, modep
, clockRanges
,
529 /* Check clock is in range */
530 cp
= xf86FindClockRangeForMode(clockRanges
, p
);
533 * XXX Could do more here to provide a more detailed
534 * reason for not finding a mode.
536 p
->status
= MODE_CLOCK_RANGE
;
538 status
= MODE_CLOCK_RANGE
;
543 * If programmable clock and strategy is not
544 * LOOKUP_BEST_REFRESH, the required mode has been found,
545 * otherwise record the refresh and continue looking.
547 if (scrp
->progClock
) {
549 if (strategy
!= LOOKUP_BEST_REFRESH
) {
551 DivFactor
= cp
->ClockDivFactor
;
552 MulFactor
= cp
->ClockMulFactor
;
553 ModePrivFlags
= cp
->PrivFlags
;
556 refresh
= xf86ModeVRefresh(p
);
557 if (p
->Flags
& V_INTERLACE
)
558 refresh
/= INTERLACE_REFRESH_WEIGHT
;
559 if (refresh
> bestRefresh
) {
561 DivFactor
= cp
->ClockDivFactor
;
562 MulFactor
= cp
->ClockMulFactor
;
563 ModePrivFlags
= cp
->PrivFlags
;
564 bestRefresh
= refresh
;
570 * Clock is in range, so if it is not a programmable clock, find
574 i
= xf86GetNearestClock(scrp
, p
->Clock
, allowDiv2
,
575 cp
->ClockDivFactor
, cp
->ClockMulFactor
,
578 * If the clock is too far from the requested clock, this
582 gap
= abs((p
->Clock
* 2) -
583 ((scrp
->clock
[i
] * cp
->ClockDivFactor
) /
584 cp
->ClockMulFactor
));
587 ((scrp
->clock
[i
] * cp
->ClockDivFactor
) /
588 cp
->ClockMulFactor
));
589 if (gap
> minimumGap
) {
590 p
->status
= MODE_NOCLOCK
;
592 status
= MODE_NOCLOCK
;
597 if (strategy
== LOOKUP_BEST_REFRESH
) {
598 refresh
= xf86ModeVRefresh(p
);
599 if (p
->Flags
& V_INTERLACE
)
600 refresh
/= INTERLACE_REFRESH_WEIGHT
;
601 if (refresh
> bestRefresh
) {
603 DivFactor
= cp
->ClockDivFactor
;
604 MulFactor
= cp
->ClockMulFactor
;
605 ModePrivFlags
= cp
->PrivFlags
;
608 bestRefresh
= refresh
;
612 if (strategy
== LOOKUP_CLOSEST_CLOCK
) {
613 if (gap
< minimumGap
) {
615 DivFactor
= cp
->ClockDivFactor
;
616 MulFactor
= cp
->ClockMulFactor
;
617 ModePrivFlags
= cp
->PrivFlags
;
625 * If strategy is neither LOOKUP_BEST_REFRESH or
626 * LOOKUP_CLOSEST_CLOCK the required mode has been found.
629 DivFactor
= cp
->ClockDivFactor
;
630 MulFactor
= cp
->ClockMulFactor
;
631 ModePrivFlags
= cp
->PrivFlags
;
640 if (!found
|| bestMode
== NULL
)
643 /* Fill in the mode parameters */
644 if (scrp
->progClock
) {
645 modep
->Clock
= bestMode
->Clock
;
646 modep
->ClockIndex
= -1;
647 modep
->SynthClock
= (modep
->Clock
* MulFactor
) / DivFactor
;
650 modep
->Clock
= (scrp
->clock
[clockIndex
] * DivFactor
) / MulFactor
;
651 modep
->ClockIndex
= clockIndex
;
652 modep
->SynthClock
= scrp
->clock
[clockIndex
];
653 if (extraFlags
& V_CLKDIV2
) {
655 modep
->SynthClock
/= 2;
658 modep
->type
= bestMode
->type
;
659 modep
->PrivFlags
= ModePrivFlags
;
660 modep
->HDisplay
= bestMode
->HDisplay
;
661 modep
->HSyncStart
= bestMode
->HSyncStart
;
662 modep
->HSyncEnd
= bestMode
->HSyncEnd
;
663 modep
->HTotal
= bestMode
->HTotal
;
664 modep
->HSkew
= bestMode
->HSkew
;
665 modep
->VDisplay
= bestMode
->VDisplay
;
666 modep
->VSyncStart
= bestMode
->VSyncStart
;
667 modep
->VSyncEnd
= bestMode
->VSyncEnd
;
668 modep
->VTotal
= bestMode
->VTotal
;
669 modep
->VScan
= bestMode
->VScan
;
670 modep
->Flags
= bestMode
->Flags
| extraFlags
;
671 modep
->CrtcHDisplay
= bestMode
->CrtcHDisplay
;
672 modep
->CrtcHBlankStart
= bestMode
->CrtcHBlankStart
;
673 modep
->CrtcHSyncStart
= bestMode
->CrtcHSyncStart
;
674 modep
->CrtcHSyncEnd
= bestMode
->CrtcHSyncEnd
;
675 modep
->CrtcHBlankEnd
= bestMode
->CrtcHBlankEnd
;
676 modep
->CrtcHTotal
= bestMode
->CrtcHTotal
;
677 modep
->CrtcHSkew
= bestMode
->CrtcHSkew
;
678 modep
->CrtcVDisplay
= bestMode
->CrtcVDisplay
;
679 modep
->CrtcVBlankStart
= bestMode
->CrtcVBlankStart
;
680 modep
->CrtcVSyncStart
= bestMode
->CrtcVSyncStart
;
681 modep
->CrtcVSyncEnd
= bestMode
->CrtcVSyncEnd
;
682 modep
->CrtcVBlankEnd
= bestMode
->CrtcVBlankEnd
;
683 modep
->CrtcVTotal
= bestMode
->CrtcVTotal
;
684 modep
->CrtcHAdjusted
= bestMode
->CrtcHAdjusted
;
685 modep
->CrtcVAdjusted
= bestMode
->CrtcVAdjusted
;
686 modep
->HSync
= bestMode
->HSync
;
687 modep
->VRefresh
= bestMode
->VRefresh
;
688 modep
->Private
= bestMode
->Private
;
689 modep
->PrivSize
= bestMode
->PrivSize
;
691 bestMode
->prev
= modep
;
697 * xf86CheckModeForMonitor
699 * This function takes a mode and monitor description, and determines
700 * if the mode is valid for the monitor.
703 xf86CheckModeForMonitor(DisplayModePtr mode
, MonPtr monitor
)
708 if (mode
== NULL
|| monitor
== NULL
) {
709 ErrorF("xf86CheckModeForMonitor: called with invalid parameters\n");
713 DebugF("xf86CheckModeForMonitor(%p %s, %p %s)\n",
714 mode
, mode
->name
, monitor
, monitor
->id
);
716 /* Some basic mode validity checks */
717 if (0 >= mode
->HDisplay
|| mode
->HDisplay
> mode
->HSyncStart
||
718 mode
->HSyncStart
>= mode
->HSyncEnd
|| mode
->HSyncEnd
>= mode
->HTotal
)
719 return MODE_H_ILLEGAL
;
721 if (0 >= mode
->VDisplay
|| mode
->VDisplay
> mode
->VSyncStart
||
722 mode
->VSyncStart
>= mode
->VSyncEnd
|| mode
->VSyncEnd
>= mode
->VTotal
)
723 return MODE_V_ILLEGAL
;
725 if (monitor
->nHsync
> 0) {
726 /* Check hsync against the allowed ranges */
727 float hsync
= xf86ModeHSync(mode
);
729 for (i
= 0; i
< monitor
->nHsync
; i
++)
730 if ((hsync
> monitor
->hsync
[i
].lo
* (1.0 - SYNC_TOLERANCE
)) &&
731 (hsync
< monitor
->hsync
[i
].hi
* (1.0 + SYNC_TOLERANCE
)))
734 /* Now see whether we ran out of sync ranges without finding a match */
735 if (i
== monitor
->nHsync
)
739 if (monitor
->nVrefresh
> 0) {
740 /* Check vrefresh against the allowed ranges */
741 float vrefrsh
= xf86ModeVRefresh(mode
);
743 for (i
= 0; i
< monitor
->nVrefresh
; i
++)
744 if ((vrefrsh
> monitor
->vrefresh
[i
].lo
* (1.0 - SYNC_TOLERANCE
)) &&
745 (vrefrsh
< monitor
->vrefresh
[i
].hi
* (1.0 + SYNC_TOLERANCE
)))
748 /* Now see whether we ran out of refresh ranges without finding a match */
749 if (i
== monitor
->nVrefresh
)
753 /* Force interlaced modes to have an odd VTotal */
754 if (mode
->Flags
& V_INTERLACE
)
755 mode
->CrtcVTotal
= mode
->VTotal
|= 1;
758 * This code stops cvt -r modes, and only cvt -r modes, from hitting 15y+
759 * old CRTs which might, when there is a lot of solar flare activity and
760 * when the celestial bodies are unfavourably aligned, implode trying to
761 * sync to it. It's called "Protecting the user from doing anything stupid".
765 if (xf86ModeIsReduced(mode
)) {
766 if (!monitor
->reducedblanking
&& !(mode
->type
& M_T_DRIVER
))
767 return MODE_NO_REDUCED
;
770 if ((monitor
->maxPixClock
) && (mode
->Clock
> monitor
->maxPixClock
))
771 return MODE_CLOCK_HIGH
;
779 * An internal routine to check if a mode fits in video memory. This tries to
780 * avoid overflows that would otherwise occur when video memory size is greater
784 xf86CheckModeSize(ScrnInfoPtr scrp
, int w
, int x
, int y
)
786 int bpp
= scrp
->fbFormat
.bitsPerPixel
, pad
= scrp
->fbFormat
.scanlinePad
;
787 int lineWidth
, lastWidth
;
789 if (scrp
->depth
== 4)
790 pad
*= 4; /* 4 planes */
793 if ((w
< 0) || (x
< 0) || (y
<= 0))
796 lineWidth
= (((w
* bpp
) + pad
- 1) / pad
) * pad
;
800 * At this point, we need to compare
802 * (lineWidth * (y - 1)) + lastWidth
806 * scrp->videoRam * (1024 * 8)
808 * These are bit quantities. To avoid overflows, do the comparison in
809 * terms of BITMAP_SCANLINE_PAD units. This assumes BITMAP_SCANLINE_PAD
810 * is a power of 2. We currently use 32, which limits us to a video
811 * memory size of 8GB.
814 lineWidth
= (lineWidth
+ (BITMAP_SCANLINE_PAD
- 1)) / BITMAP_SCANLINE_PAD
;
815 lastWidth
= (lastWidth
+ (BITMAP_SCANLINE_PAD
- 1)) / BITMAP_SCANLINE_PAD
;
817 if ((lineWidth
* (y
- 1) + lastWidth
) >
818 (scrp
->videoRam
* ((1024 * 8) / BITMAP_SCANLINE_PAD
)))
825 * xf86InitialCheckModeForDriver
827 * This function checks if a mode satisfies a driver's initial requirements:
828 * - mode size fits within the available pixel area (memory)
829 * - width lies within the range of supported line pitches
830 * - mode size fits within virtual size (if fixed)
831 * - horizontal timings are in range
833 * This function takes the following parameters:
836 * maxPitch (optional) maximum line pitch
837 * virtualX (optional) virtual width requested
838 * virtualY (optional) virtual height requested
840 * In addition, the following fields from the ScrnInfoRec are used:
841 * monitor pointer to structure for monitor section
842 * fbFormat pixel format for the framebuffer
843 * videoRam video memory size (in kB)
844 * maxHValue maximum horizontal timing value
845 * maxVValue maximum vertical timing value
849 xf86InitialCheckModeForDriver(ScrnInfoPtr scrp
, DisplayModePtr mode
,
850 ClockRangePtr clockRanges
,
851 LookupModeFlags strategy
,
852 int maxPitch
, int virtualX
, int virtualY
)
856 Bool allowDiv2
= (strategy
& LOOKUP_CLKDIV2
) != 0;
860 if (!scrp
|| !mode
|| !clockRanges
) {
861 ErrorF("xf86InitialCheckModeForDriver: "
862 "called with invalid parameters\n");
866 DebugF("xf86InitialCheckModeForDriver(%p, %p %s, %p, 0x%x, %d, %d, %d)\n",
867 scrp
, mode
, mode
->name
, clockRanges
, strategy
, maxPitch
, virtualX
,
870 /* Some basic mode validity checks */
871 if (0 >= mode
->HDisplay
|| mode
->HDisplay
> mode
->HSyncStart
||
872 mode
->HSyncStart
>= mode
->HSyncEnd
|| mode
->HSyncEnd
>= mode
->HTotal
)
873 return MODE_H_ILLEGAL
;
875 if (0 >= mode
->VDisplay
|| mode
->VDisplay
> mode
->VSyncStart
||
876 mode
->VSyncStart
>= mode
->VSyncEnd
|| mode
->VSyncEnd
>= mode
->VTotal
)
877 return MODE_V_ILLEGAL
;
879 if (!xf86CheckModeSize(scrp
, mode
->HDisplay
, mode
->HDisplay
,
883 if (maxPitch
> 0 && mode
->HDisplay
> maxPitch
)
884 return MODE_BAD_WIDTH
;
886 if (virtualX
> 0 && mode
->HDisplay
> virtualX
)
887 return MODE_VIRTUAL_X
;
889 if (virtualY
> 0 && mode
->VDisplay
> virtualY
)
890 return MODE_VIRTUAL_Y
;
892 if (scrp
->maxHValue
> 0 && mode
->HTotal
> scrp
->maxHValue
)
893 return MODE_BAD_HVALUE
;
895 if (scrp
->maxVValue
> 0 && mode
->VTotal
> scrp
->maxVValue
)
896 return MODE_BAD_VVALUE
;
899 * The use of the DisplayModeRec's Crtc* and SynthClock elements below is
900 * provisional, in that they are later reused by the driver at mode-set
901 * time. Here, they are temporarily enlisted to contain the mode timings
902 * as seen by the CRT or panel (rather than the CRTC). The driver's
903 * ValidMode() is allowed to modify these so it can deal with such things
904 * as mode stretching and/or centering. The driver should >NOT< modify the
905 * user-supplied values as these are reported back when mode validation is
909 * NOTE: We (ab)use the mode->Crtc* values here to store timing
910 * information for the calculation of Hsync and Vrefresh. Before
911 * these values are calculated the driver is given the opportunity
912 * to either set these HSync and VRefresh itself or modify the timing
914 * The difference to the final calculation is small but imortand:
915 * here we pass the flag INTERLACE_HALVE_V regardless if the driver
916 * sets it or not. This way our calculation of VRefresh has the same
917 * effect as if we do if (flags & V_INTERLACE) refresh *= 2.0
918 * This dual use of the mode->Crtc* values will certainly create
919 * confusion and is bad software design. However since it's part of
920 * the driver API it's hard to change.
923 if (scrp
->ValidMode
) {
925 xf86SetModeCrtc(mode
, INTERLACE_HALVE_V
);
927 cp
= xf86FindClockRangeForMode(clockRanges
, mode
);
929 return MODE_CLOCK_RANGE
;
931 if (cp
->ClockMulFactor
< 1)
932 cp
->ClockMulFactor
= 1;
933 if (cp
->ClockDivFactor
< 1)
934 cp
->ClockDivFactor
= 1;
937 * XXX The effect of clock dividers and multipliers on the monitor's
938 * pixel clock needs to be verified.
940 if (scrp
->progClock
) {
941 mode
->SynthClock
= mode
->Clock
;
944 i
= xf86GetNearestClock(scrp
, mode
->Clock
, allowDiv2
,
945 cp
->ClockDivFactor
, cp
->ClockMulFactor
,
947 mode
->SynthClock
= (scrp
->clock
[i
] * cp
->ClockDivFactor
) /
949 if (needDiv2
& V_CLKDIV2
)
950 mode
->SynthClock
/= 2;
953 status
= (*scrp
->ValidMode
) (scrp
, mode
, FALSE
,
955 if (status
!= MODE_OK
)
958 if (mode
->HSync
<= 0.0)
959 mode
->HSync
= (float) mode
->SynthClock
/ (float) mode
->CrtcHTotal
;
960 if (mode
->VRefresh
<= 0.0)
961 mode
->VRefresh
= (mode
->SynthClock
* 1000.0)
962 / (mode
->CrtcHTotal
* mode
->CrtcVTotal
);
965 mode
->HSync
= xf86ModeHSync(mode
);
966 mode
->VRefresh
= xf86ModeVRefresh(mode
);
968 /* Assume it is OK */
973 * xf86CheckModeForDriver
975 * This function is for checking modes while the server is running (for
976 * use mainly by the VidMode extension).
978 * This function checks if a mode satisfies a driver's requirements:
979 * - width lies within the line pitch
980 * - mode size fits within virtual size
981 * - horizontal/vertical timings are in range
983 * This function takes the following parameters:
986 * flags not (currently) used
988 * In addition, the following fields from the ScrnInfoRec are used:
989 * maxHValue maximum horizontal timing value
990 * maxVValue maximum vertical timing value
991 * virtualX virtual width
992 * virtualY virtual height
993 * clockRanges allowable clock ranges
997 xf86CheckModeForDriver(ScrnInfoPtr scrp
, DisplayModePtr mode
, int flags
)
1000 int i
, k
, gap
, minimumGap
= CLOCK_TOLERANCE
+ 1;
1002 int clockIndex
= -1;
1005 int ModePrivFlags
= 0;
1006 ModeStatus status
= MODE_NOMODE
;
1008 /* Some sanity checking */
1009 if (scrp
== NULL
|| (!scrp
->progClock
&& scrp
->numClocks
== 0)) {
1010 ErrorF("xf86CheckModeForDriver: called with invalid scrnInfoRec\n");
1014 ErrorF("xf86CheckModeForDriver: called with invalid modep\n");
1018 /* Check the mode size */
1019 if (mode
->HDisplay
> scrp
->virtualX
)
1020 return MODE_VIRTUAL_X
;
1022 if (mode
->VDisplay
> scrp
->virtualY
)
1023 return MODE_VIRTUAL_Y
;
1025 if (scrp
->maxHValue
> 0 && mode
->HTotal
> scrp
->maxHValue
)
1026 return MODE_BAD_HVALUE
;
1028 if (scrp
->maxVValue
> 0 && mode
->VTotal
> scrp
->maxVValue
)
1029 return MODE_BAD_VVALUE
;
1031 for (cp
= scrp
->clockRanges
; cp
!= NULL
; cp
= cp
->next
) {
1032 /* DivFactor and MulFactor must be > 0 */
1033 cp
->ClockDivFactor
= max(1, cp
->ClockDivFactor
);
1034 cp
->ClockMulFactor
= max(1, cp
->ClockMulFactor
);
1037 if (scrp
->progClock
) {
1038 /* Check clock is in range */
1039 for (cp
= scrp
->clockRanges
; cp
!= NULL
; cp
= cp
->next
) {
1040 if (modeInClockRange(cp
, mode
))
1044 return MODE_CLOCK_RANGE
;
1047 * If programmable clock the required mode has been found
1049 DivFactor
= cp
->ClockDivFactor
;
1050 MulFactor
= cp
->ClockMulFactor
;
1051 ModePrivFlags
= cp
->PrivFlags
;
1054 status
= MODE_CLOCK_RANGE
;
1055 /* Check clock is in range */
1056 for (cp
= scrp
->clockRanges
; cp
!= NULL
; cp
= cp
->next
) {
1057 if (modeInClockRange(cp
, mode
)) {
1059 * Clock is in range, so if it is not a programmable clock,
1060 * find a matching clock.
1063 i
= xf86GetNearestClock(scrp
, mode
->Clock
, 0,
1064 cp
->ClockDivFactor
, cp
->ClockMulFactor
,
1067 * If the clock is too far from the requested clock, this
1071 gap
= abs((mode
->Clock
* 2) -
1072 ((scrp
->clock
[i
] * cp
->ClockDivFactor
) /
1073 cp
->ClockMulFactor
));
1075 gap
= abs(mode
->Clock
-
1076 ((scrp
->clock
[i
] * cp
->ClockDivFactor
) /
1077 cp
->ClockMulFactor
));
1078 if (gap
> minimumGap
) {
1079 status
= MODE_NOCLOCK
;
1083 DivFactor
= cp
->ClockDivFactor
;
1084 MulFactor
= cp
->ClockMulFactor
;
1085 ModePrivFlags
= cp
->PrivFlags
;
1095 /* Fill in the mode parameters */
1096 if (scrp
->progClock
) {
1097 mode
->ClockIndex
= -1;
1098 mode
->SynthClock
= (mode
->Clock
* MulFactor
) / DivFactor
;
1101 mode
->Clock
= (scrp
->clock
[clockIndex
] * DivFactor
) / MulFactor
;
1102 mode
->ClockIndex
= clockIndex
;
1103 mode
->SynthClock
= scrp
->clock
[clockIndex
];
1104 if (extraFlags
& V_CLKDIV2
) {
1106 mode
->SynthClock
/= 2;
1109 mode
->PrivFlags
= ModePrivFlags
;
1115 inferVirtualSize(ScrnInfoPtr scrp
, DisplayModePtr modes
, int *vx
, int *vy
)
1118 MonPtr mon
= scrp
->monitor
;
1121 DisplayModePtr mode
;
1127 if (DDC
&& DDC
->ver
.revision
>= 4) {
1128 /* For 1.4, we might actually get native pixel format. How novel. */
1129 if (PREFERRED_TIMING_MODE(DDC
->features
.msc
)) {
1130 for (mode
= modes
; mode
; mode
= mode
->next
) {
1131 if (mode
->type
& (M_T_DRIVER
| M_T_PREFERRED
)) {
1139 * Even if we don't, we might get aspect ratio from extra CVT info
1140 * or from the monitor size fields. TODO.
1145 * Technically this triggers if either is zero. That wasn't legal
1146 * before EDID 1.4, but right now we'll get that wrong. TODO.
1149 if (!mon
->widthmm
|| !mon
->heightmm
)
1152 aspect
= (float) mon
->widthmm
/ (float) mon
->heightmm
;
1155 /* find the largest M_T_DRIVER mode with that aspect ratio */
1156 for (mode
= modes
; mode
; mode
= mode
->next
) {
1157 float mode_aspect
, metaspect
;
1159 if (!(mode
->type
& (M_T_DRIVER
| M_T_USERDEF
)))
1161 mode_aspect
= (float) mode
->HDisplay
/ (float) mode
->VDisplay
;
1162 metaspect
= aspect
/ mode_aspect
;
1163 /* 5% slop or so, since we only get size in centimeters */
1164 if (fabs(1.0 - metaspect
) < 0.05) {
1165 if ((mode
->HDisplay
> x
) && (mode
->VDisplay
> y
)) {
1173 xf86DrvMsg(scrp
->scrnIndex
, X_WARNING
,
1174 "Unable to estimate virtual size\n");
1182 xf86DrvMsg(scrp
->scrnIndex
, X_INFO
,
1183 "Estimated virtual size for aspect ratio %.4f is %dx%d\n",
1189 /* Least common multiple */
1191 LCM(unsigned int x
, unsigned int y
)
1193 unsigned int m
= x
, n
= y
, o
;
1195 while ((o
= m
% n
)) {
1204 * Given various screen attributes, determine the minimum scanline width such
1205 * that each scanline is server and DDX padded and any pixels with imbedded
1206 * bank boundaries are off-screen. This function returns -1 if such a width
1210 scanLineWidth(unsigned int xsize
, /* pixels */
1211 unsigned int ysize
, /* pixels */
1212 unsigned int width
, /* pixels */
1213 unsigned long BankSize
, /* char's */
1214 PixmapFormatRec
* pBankFormat
, unsigned int nWidthUnit
/* bits */
1217 unsigned long nBitsPerBank
, nBitsPerScanline
, nBitsPerScanlinePadUnit
;
1218 unsigned long minBitsPerScanline
, maxBitsPerScanline
;
1222 if (!nWidthUnit
|| !pBankFormat
)
1225 nBitsPerBank
= BankSize
* 8;
1226 if (nBitsPerBank
% pBankFormat
->scanlinePad
)
1231 nBitsPerScanlinePadUnit
= LCM(pBankFormat
->scanlinePad
, nWidthUnit
);
1233 (((width
* pBankFormat
->bitsPerPixel
) + nBitsPerScanlinePadUnit
- 1) /
1234 nBitsPerScanlinePadUnit
) * nBitsPerScanlinePadUnit
;
1235 width
= nBitsPerScanline
/ pBankFormat
->bitsPerPixel
;
1237 if (!xsize
|| !(nBitsPerBank
% pBankFormat
->bitsPerPixel
))
1241 * Scanlines will be server-pad aligned at this point. They will also be
1242 * a multiple of nWidthUnit bits long. Ensure that pixels with imbedded
1243 * bank boundaries are off-screen.
1245 * It seems reasonable to limit total frame buffer size to 1/16 of the
1246 * theoretical maximum address space size. On a machine with 32-bit
1247 * addresses (to 8-bit quantities) this turns out to be 256MB. Not only
1248 * does this provide a simple limiting condition for the loops below, but
1249 * it also prevents unsigned long wraparounds.
1254 minBitsPerScanline
= xsize
* pBankFormat
->bitsPerPixel
;
1255 if (minBitsPerScanline
> nBitsPerBank
)
1261 maxBitsPerScanline
=
1262 (((unsigned long) (-1) >> 1) - minBitsPerScanline
) / (ysize
- 1);
1263 while (nBitsPerScanline
<= maxBitsPerScanline
) {
1264 unsigned long BankBase
, BankUnit
;
1266 BankUnit
= ((nBitsPerBank
+ nBitsPerScanline
- 1) / nBitsPerBank
) *
1268 if (!(BankUnit
% nBitsPerScanline
))
1271 for (BankBase
= BankUnit
;; BankBase
+= nBitsPerBank
) {
1274 y
= BankBase
/ nBitsPerScanline
;
1278 x
= BankBase
% nBitsPerScanline
;
1279 if (!(x
% pBankFormat
->bitsPerPixel
))
1282 if (x
< minBitsPerScanline
) {
1284 * Skip ahead certain widths by dividing the excess scanline
1287 y
*= nBitsPerScanlinePadUnit
;
1288 nBitsPerScanline
+= ((x
+ y
- 1) / y
) * nBitsPerScanlinePadUnit
;
1289 width
= nBitsPerScanline
/ pBankFormat
->bitsPerPixel
;
1293 if (BankBase
!= BankUnit
)
1296 if (!(nBitsPerScanline
% x
))
1299 BankBase
= ((nBitsPerScanline
- minBitsPerScanline
) /
1300 (nBitsPerScanline
- x
)) * BankUnit
;
1310 * This function takes a set of mode names, modes and limiting conditions,
1311 * and selects a set of modes and parameters based on those conditions.
1313 * This function takes the following parameters:
1315 * availModes the list of modes available for the monitor
1316 * modeNames (optional) list of mode names that the screen is requesting
1317 * clockRanges a list of clock ranges
1318 * linePitches (optional) a list of line pitches
1319 * minPitch (optional) minimum line pitch (in pixels)
1320 * maxPitch (optional) maximum line pitch (in pixels)
1321 * pitchInc (mandatory) pitch increment (in bits)
1322 * minHeight (optional) minimum virtual height (in pixels)
1323 * maxHeight (optional) maximum virtual height (in pixels)
1324 * virtualX (optional) virtual width requested (in pixels)
1325 * virtualY (optional) virtual height requested (in pixels)
1326 * apertureSize size of video aperture (in bytes)
1327 * strategy how to decide which mode to use from multiple modes with
1330 * In addition, the following fields from the ScrnInfoRec are used:
1331 * clocks a list of discrete clocks
1332 * numClocks number of discrete clocks
1333 * progClock clock is programmable
1334 * monitor pointer to structure for monitor section
1335 * fbFormat format of the framebuffer
1336 * videoRam video memory size
1337 * maxHValue maximum horizontal timing value
1338 * maxVValue maximum vertical timing value
1339 * xInc horizontal timing increment (defaults to 8 pixels)
1341 * The function fills in the following ScrnInfoRec fields:
1342 * modePool A subset of the modes available to the monitor which
1343 * are compatible with the driver.
1344 * modes one mode entry for each of the requested modes, with the
1345 * status field filled in to indicate if the mode has been
1347 * virtualX the resulting virtual width
1348 * virtualY the resulting virtual height
1349 * displayWidth the resulting line pitch
1351 * The function's return value is the number of matching modes found, or -1
1352 * if an unrecoverable error was encountered.
1356 xf86ValidateModes(ScrnInfoPtr scrp
, DisplayModePtr availModes
,
1357 char **modeNames
, ClockRangePtr clockRanges
,
1358 int *linePitches
, int minPitch
, int maxPitch
, int pitchInc
,
1359 int minHeight
, int maxHeight
, int virtualX
, int virtualY
,
1360 int apertureSize
, LookupModeFlags strategy
)
1362 DisplayModePtr p
, q
, r
, new, last
, *endp
;
1363 int i
, numModes
= 0;
1365 int linePitch
= -1, virtX
= 0, virtY
= 0;
1366 int newLinePitch
, newVirtX
, newVirtY
;
1367 int modeSize
; /* in pixels */
1368 Bool validateAllDefaultModes
= FALSE
;
1369 Bool userModes
= FALSE
;
1371 PixmapFormatRec
*BankFormat
;
1374 range hsync
[MAX_HSYNC
];
1375 range vrefresh
[MAX_VREFRESH
];
1376 Bool inferred_virtual
= FALSE
;
1379 ("xf86ValidateModes(%p, %p, %p, %p,\n\t\t %p, %d, %d, %d, %d, %d, %d, %d, %d, 0x%x)\n",
1380 scrp
, availModes
, modeNames
, clockRanges
, linePitches
, minPitch
,
1381 maxPitch
, pitchInc
, minHeight
, maxHeight
, virtualX
, virtualY
,
1382 apertureSize
, strategy
);
1384 /* Some sanity checking */
1385 if (scrp
== NULL
|| scrp
->name
== NULL
|| !scrp
->monitor
||
1386 (!scrp
->progClock
&& scrp
->numClocks
== 0)) {
1387 ErrorF("xf86ValidateModes: called with invalid scrnInfoRec\n");
1390 if (linePitches
!= NULL
&& linePitches
[0] <= 0) {
1391 ErrorF("xf86ValidateModes: called with invalid linePitches\n");
1394 if (pitchInc
<= 0) {
1395 ErrorF("xf86ValidateModes: called with invalid pitchInc\n");
1398 if ((virtualX
> 0) != (virtualY
> 0)) {
1399 ErrorF("xf86ValidateModes: called with invalid virtual resolution\n");
1404 * If requested by the driver, allow missing hsync and/or vrefresh ranges
1405 * in the monitor section.
1407 if (strategy
& LOOKUP_OPTIONAL_TOLERANCES
) {
1408 strategy
&= ~LOOKUP_OPTIONAL_TOLERANCES
;
1411 const char *type
= "";
1412 Bool specified
= FALSE
;
1414 if (scrp
->monitor
->nHsync
<= 0) {
1415 if (numTimings
> 0) {
1416 scrp
->monitor
->nHsync
= numTimings
;
1417 for (i
= 0; i
< numTimings
; i
++) {
1418 scrp
->monitor
->hsync
[i
].lo
= hsync
[i
].lo
;
1419 scrp
->monitor
->hsync
[i
].hi
= hsync
[i
].hi
;
1423 scrp
->monitor
->hsync
[0].lo
= 31.5;
1424 scrp
->monitor
->hsync
[0].hi
= 48.0;
1425 scrp
->monitor
->nHsync
= 1;
1432 for (i
= 0; i
< scrp
->monitor
->nHsync
; i
++) {
1433 if (scrp
->monitor
->hsync
[i
].lo
== scrp
->monitor
->hsync
[i
].hi
)
1434 xf86DrvMsg(scrp
->scrnIndex
, X_INFO
,
1435 "%s: Using %shsync value of %.2f kHz\n",
1436 scrp
->monitor
->id
, type
, scrp
->monitor
->hsync
[i
].lo
);
1438 xf86DrvMsg(scrp
->scrnIndex
, X_INFO
,
1439 "%s: Using %shsync range of %.2f-%.2f kHz\n",
1440 scrp
->monitor
->id
, type
,
1441 scrp
->monitor
->hsync
[i
].lo
,
1442 scrp
->monitor
->hsync
[i
].hi
);
1446 if (scrp
->monitor
->nVrefresh
<= 0) {
1447 if (numTimings
> 0) {
1448 scrp
->monitor
->nVrefresh
= numTimings
;
1449 for (i
= 0; i
< numTimings
; i
++) {
1450 scrp
->monitor
->vrefresh
[i
].lo
= vrefresh
[i
].lo
;
1451 scrp
->monitor
->vrefresh
[i
].hi
= vrefresh
[i
].hi
;
1455 scrp
->monitor
->vrefresh
[0].lo
= 50;
1456 scrp
->monitor
->vrefresh
[0].hi
= 70;
1457 scrp
->monitor
->nVrefresh
= 1;
1464 for (i
= 0; i
< scrp
->monitor
->nVrefresh
; i
++) {
1465 if (scrp
->monitor
->vrefresh
[i
].lo
== scrp
->monitor
->vrefresh
[i
].hi
)
1466 xf86DrvMsg(scrp
->scrnIndex
, X_INFO
,
1467 "%s: Using %svrefresh value of %.2f Hz\n",
1468 scrp
->monitor
->id
, type
,
1469 scrp
->monitor
->vrefresh
[i
].lo
);
1471 xf86DrvMsg(scrp
->scrnIndex
, X_INFO
,
1472 "%s: Using %svrefresh range of %.2f-%.2f Hz\n",
1473 scrp
->monitor
->id
, type
,
1474 scrp
->monitor
->vrefresh
[i
].lo
,
1475 scrp
->monitor
->vrefresh
[i
].hi
);
1479 if (!scrp
->monitor
->maxPixClock
&& !specified
) {
1481 scrp
->monitor
->maxPixClock
= 65000.0;
1483 if (scrp
->monitor
->maxPixClock
) {
1484 xf86DrvMsg(scrp
->scrnIndex
, X_INFO
,
1485 "%s: Using %smaximum pixel clock of %.2f MHz\n",
1486 scrp
->monitor
->id
, type
,
1487 (float) scrp
->monitor
->maxPixClock
/ 1000.0);
1492 * Store the clockRanges for later use by the VidMode extension.
1494 nt_list_for_each_entry(cp
, clockRanges
, next
) {
1495 ClockRangePtr newCR
= xnfalloc(sizeof(ClockRange
));
1496 memcpy(newCR
, cp
, sizeof(ClockRange
));
1498 if (scrp
->clockRanges
== NULL
)
1499 scrp
->clockRanges
= newCR
;
1501 nt_list_append(newCR
, scrp
->clockRanges
, ClockRange
, next
);
1504 /* Determine which pixmap format to pass to scanLineWidth() */
1505 if (scrp
->depth
> 4)
1506 BankFormat
= &scrp
->fbFormat
;
1508 BankFormat
= xf86GetPixFormat(scrp
, 1); /* >not< scrp->depth! */
1510 if (scrp
->xInc
<= 0)
1511 scrp
->xInc
= 8; /* Suitable for VGA and others */
1513 #define _VIRTUALX(x) ((((x) + scrp->xInc - 1) / scrp->xInc) * scrp->xInc)
1516 * Determine maxPitch if it wasn't given explicitly. Note linePitches
1517 * always takes precedence if is non-NULL. In that case the minPitch and
1518 * maxPitch values passed are ignored.
1521 minPitch
= maxPitch
= linePitches
[0];
1522 for (i
= 1; linePitches
[i
] > 0; i
++) {
1523 if (linePitches
[i
] > maxPitch
)
1524 maxPitch
= linePitches
[i
];
1525 if (linePitches
[i
] < minPitch
)
1526 minPitch
= linePitches
[i
];
1530 /* Initial check of virtual size against other constraints */
1531 scrp
->virtualFrom
= X_PROBED
;
1533 * Initialise virtX and virtY if the values are fixed.
1536 if (maxHeight
> 0 && virtualY
> maxHeight
) {
1537 xf86DrvMsg(scrp
->scrnIndex
, X_ERROR
,
1538 "Virtual height (%d) is too large for the hardware "
1539 "(max %d)\n", virtualY
, maxHeight
);
1543 if (minHeight
> 0 && virtualY
< minHeight
) {
1544 xf86DrvMsg(scrp
->scrnIndex
, X_ERROR
,
1545 "Virtual height (%d) is too small for the hardware "
1546 "(min %d)\n", virtualY
, minHeight
);
1550 virtualX
= _VIRTUALX(virtualX
);
1551 if (linePitches
!= NULL
) {
1552 for (i
= 0; linePitches
[i
] != 0; i
++) {
1553 if ((linePitches
[i
] >= virtualX
) &&
1555 scanLineWidth(virtualX
, virtualY
, linePitches
[i
],
1556 apertureSize
, BankFormat
, pitchInc
))) {
1557 linePitch
= linePitches
[i
];
1563 linePitch
= scanLineWidth(virtualX
, virtualY
, minPitch
,
1564 apertureSize
, BankFormat
, pitchInc
);
1567 if ((linePitch
< minPitch
) || (linePitch
> maxPitch
)) {
1568 xf86DrvMsg(scrp
->scrnIndex
, X_ERROR
,
1569 "Virtual width (%d) is too large for the hardware "
1570 "(max %d)\n", virtualX
, maxPitch
);
1574 if (!xf86CheckModeSize(scrp
, linePitch
, virtualX
, virtualY
)) {
1575 xf86DrvMsg(scrp
->scrnIndex
, X_ERROR
,
1576 "Virtual size (%dx%d) (pitch %d) exceeds video memory\n",
1577 virtualX
, virtualY
, linePitch
);
1583 scrp
->virtualFrom
= X_CONFIG
;
1585 else if (!modeNames
|| !*modeNames
) {
1586 /* No virtual size given in the config, try to infer */
1587 /* XXX this doesn't take m{in,ax}Pitch into account; oh well */
1588 inferred_virtual
= inferVirtualSize(scrp
, availModes
, &virtX
, &virtY
);
1589 if (inferred_virtual
)
1590 linePitch
= scanLineWidth(virtX
, virtY
, minPitch
, apertureSize
,
1591 BankFormat
, pitchInc
);
1594 /* Print clock ranges and scaled clocks */
1595 xf86ShowClockRanges(scrp
, clockRanges
);
1598 * If scrp->modePool hasn't been setup yet, set it up now. This allows the
1599 * modes that the driver definitely can't use to be weeded out early. Note
1600 * that a modePool mode's prev field is used to hold a pointer to the
1601 * member of the scrp->modes list for which a match was considered.
1603 if (scrp
->modePool
== NULL
) {
1605 for (p
= availModes
; p
!= NULL
; p
= p
->next
) {
1606 status
= xf86InitialCheckModeForDriver(scrp
, p
, clockRanges
,
1610 if (status
== MODE_OK
) {
1611 status
= xf86CheckModeForMonitor(p
, scrp
->monitor
);
1614 if (status
== MODE_OK
) {
1615 new = xnfalloc(sizeof(DisplayModeRec
));
1619 scrp
->modePool
= new;
1626 q
->name
= xnfstrdup(p
->name
);
1627 q
->status
= MODE_OK
;
1630 printModeRejectMessage(scrp
->scrnIndex
, p
, status
);
1634 if (scrp
->modePool
== NULL
) {
1635 xf86DrvMsg(scrp
->scrnIndex
, X_WARNING
, "Mode pool is empty\n");
1640 for (p
= scrp
->modePool
; p
!= NULL
; p
= p
->next
) {
1642 p
->status
= MODE_OK
;
1647 * Allocate one entry in scrp->modes for each named mode.
1650 xf86DeleteMode(&scrp
->modes
, scrp
->modes
);
1651 endp
= &scrp
->modes
;
1653 if (modeNames
!= NULL
) {
1654 for (i
= 0; modeNames
[i
] != NULL
; i
++) {
1656 new = xnfcalloc(1, sizeof(DisplayModeRec
));
1658 new->type
= M_T_USERDEF
;
1659 new->name
= xnfstrdup(modeNames
[i
]);
1661 new->prev
->next
= new;
1667 /* Lookup each mode */
1669 if (!xf86Info
.disableRandR
1671 && noPanoramiXExtension
1674 validateAllDefaultModes
= TRUE
;
1677 for (p
= scrp
->modes
;; p
= p
->next
) {
1681 * If the supplied mode names don't produce a valid mode, scan through
1682 * unconsidered modePool members until one survives validation. This
1683 * is done in decreasing order by mode pixel area.
1687 if ((numModes
> 0) && !validateAllDefaultModes
)
1690 validateAllDefaultModes
= TRUE
;
1693 for (q
= scrp
->modePool
; q
!= NULL
; q
= q
->next
) {
1694 if ((q
->prev
== NULL
) && (q
->status
== MODE_OK
)) {
1696 * Deal with the case where this mode wasn't considered
1697 * because of a builtin mode of the same name.
1699 for (p
= scrp
->modes
; p
!= NULL
; p
= p
->next
) {
1700 if ((p
->status
!= MODE_OK
) && !strcmp(p
->name
, q
->name
))
1708 * A quick check to not allow default modes with
1709 * horizontal timing parameters that CRTs may have
1712 if (!scrp
->monitor
->reducedblanking
&&
1713 (q
->type
& M_T_DEFAULT
) &&
1714 ((double) q
->HTotal
/ (double) q
->HDisplay
) < 1.15)
1717 if (modeSize
< (q
->HDisplay
* q
->VDisplay
)) {
1719 modeSize
= q
->HDisplay
* q
->VDisplay
;
1728 p
= xnfcalloc(1, sizeof(DisplayModeRec
));
1730 p
->name
= xnfstrdup(r
->name
);
1732 p
->type
= M_T_USERDEF
;
1741 if (repeat
&& ((status
= p
->status
) != MODE_OK
))
1742 printModeRejectMessage(scrp
->scrnIndex
, p
, status
);
1744 status
= xf86LookupMode(scrp
, p
, clockRanges
, strategy
);
1745 if (repeat
&& status
== MODE_NOMODE
)
1747 if (status
!= MODE_OK
)
1748 printModeRejectMessage(scrp
->scrnIndex
, p
, status
);
1749 if (status
== MODE_ERROR
) {
1750 ErrorF("xf86ValidateModes: "
1751 "unexpected result from xf86LookupMode()\n");
1754 if (status
!= MODE_OK
) {
1755 if (p
->status
== MODE_OK
)
1759 p
->type
|= saveType
;
1762 newLinePitch
= linePitch
;
1767 * Don't let non-user defined modes increase the virtual size
1769 if (!(p
->type
& M_T_USERDEF
) && (numModes
> 0)) {
1770 if (p
->HDisplay
> virtX
) {
1771 p
->status
= MODE_VIRTUAL_X
;
1774 if (p
->VDisplay
> virtY
) {
1775 p
->status
= MODE_VIRTUAL_Y
;
1780 * Adjust virtual width and height if the mode is too large for the
1781 * current values and if they are not fixed.
1783 if (virtualX
<= 0 && p
->HDisplay
> newVirtX
)
1784 newVirtX
= _VIRTUALX(p
->HDisplay
);
1785 if (virtualY
<= 0 && p
->VDisplay
> newVirtY
) {
1786 if (maxHeight
> 0 && p
->VDisplay
> maxHeight
) {
1787 p
->status
= MODE_VIRTUAL_Y
; /* ? */
1790 newVirtY
= p
->VDisplay
;
1794 * If virtual resolution is to be increased, revalidate it.
1796 if ((virtX
!= newVirtX
) || (virtY
!= newVirtY
)) {
1797 if (linePitches
!= NULL
) {
1799 for (i
= 0; linePitches
[i
] != 0; i
++) {
1800 if ((linePitches
[i
] >= newVirtX
) &&
1801 (linePitches
[i
] >= linePitch
) &&
1803 scanLineWidth(newVirtX
, newVirtY
, linePitches
[i
],
1804 apertureSize
, BankFormat
, pitchInc
))) {
1805 newLinePitch
= linePitches
[i
];
1811 if (linePitch
< minPitch
)
1812 linePitch
= minPitch
;
1813 newLinePitch
= scanLineWidth(newVirtX
, newVirtY
, linePitch
,
1814 apertureSize
, BankFormat
,
1817 if ((newLinePitch
< minPitch
) || (newLinePitch
> maxPitch
)) {
1818 p
->status
= MODE_BAD_WIDTH
;
1823 * Check that the pixel area required by the new virtual height
1824 * and line pitch isn't too large.
1826 if (!xf86CheckModeSize(scrp
, newLinePitch
, newVirtX
, newVirtY
)) {
1827 p
->status
= MODE_MEM_VIRT
;
1832 if (scrp
->ValidMode
) {
1834 * Give the driver a final say, passing it the proposed virtual
1837 scrp
->virtualX
= newVirtX
;
1838 scrp
->virtualY
= newVirtY
;
1839 scrp
->displayWidth
= newLinePitch
;
1840 p
->status
= (scrp
->ValidMode
) (scrp
, p
, FALSE
,
1843 if (p
->status
!= MODE_OK
) {
1848 /* Mode has passed all the tests */
1851 linePitch
= newLinePitch
;
1852 p
->status
= MODE_OK
;
1857 * If we estimated the virtual size above, we may have filtered away all
1858 * the modes that maximally match that size; scan again to find out and
1861 if (inferred_virtual
) {
1864 for (p
= scrp
->modes
; p
; p
= p
->next
) {
1865 if (p
->HDisplay
> vx
&& p
->VDisplay
> vy
) {
1870 if (vx
< virtX
|| vy
< virtY
) {
1871 const int types
[] = {
1872 M_T_BUILTIN
| M_T_PREFERRED
,
1874 M_T_DRIVER
| M_T_PREFERRED
,
1878 const int ntypes
= sizeof(types
) / sizeof(int);
1882 * We did not find the estimated virtual size. So now we want to
1883 * find the largest mode available, but we want to search in the
1884 * modes in the order of "types" listed above.
1886 for (n
= 0; n
< ntypes
; n
++) {
1887 int type
= types
[n
];
1891 for (p
= scrp
->modes
; p
; p
= p
->next
) {
1892 /* scan through the modes in the sort order above */
1893 if ((p
->type
& type
) != type
)
1895 if (p
->HDisplay
> vx
&& p
->VDisplay
> vy
) {
1904 xf86DrvMsg(scrp
->scrnIndex
, X_WARNING
,
1905 "Shrinking virtual size estimate from %dx%d to %dx%d\n",
1906 virtX
, virtY
, vx
, vy
);
1907 virtX
= _VIRTUALX(vx
);
1909 for (p
= scrp
->modes
; p
; p
= p
->next
) {
1911 if (p
->HDisplay
> virtX
)
1912 p
->status
= MODE_VIRTUAL_X
;
1913 if (p
->VDisplay
> virtY
)
1914 p
->status
= MODE_VIRTUAL_Y
;
1915 if (p
->status
!= MODE_OK
) {
1917 printModeRejectMessage(scrp
->scrnIndex
, p
, p
->status
);
1921 if (linePitches
!= NULL
) {
1922 for (i
= 0; linePitches
[i
] != 0; i
++) {
1923 if ((linePitches
[i
] >= virtX
) &&
1925 scanLineWidth(virtX
, virtY
, linePitches
[i
],
1926 apertureSize
, BankFormat
, pitchInc
))) {
1927 linePitch
= linePitches
[i
];
1933 linePitch
= scanLineWidth(virtX
, virtY
, minPitch
,
1934 apertureSize
, BankFormat
, pitchInc
);
1939 /* Update the ScrnInfoRec parameters */
1941 scrp
->virtualX
= virtX
;
1942 scrp
->virtualY
= virtY
;
1943 scrp
->displayWidth
= linePitch
;
1948 /* Make the mode list into a circular list by joining up the ends */
1950 while (p
->next
!= NULL
)
1952 /* p is now the last mode on the list */
1953 p
->next
= scrp
->modes
;
1954 scrp
->modes
->prev
= p
;
1956 if (minHeight
> 0 && virtY
< minHeight
) {
1957 xf86DrvMsg(scrp
->scrnIndex
, X_ERROR
,
1958 "Virtual height (%d) is too small for the hardware "
1959 "(min %d)\n", virtY
, minHeight
);
1969 * This function removes a mode from a list of modes.
1971 * There are different types of mode lists:
1973 * - singly linked linear lists, ending in NULL
1974 * - doubly linked linear lists, starting and ending in NULL
1975 * - doubly linked circular lists
1980 xf86DeleteMode(DisplayModePtr
* modeList
, DisplayModePtr mode
)
1982 /* Catch the easy/insane cases */
1983 if (modeList
== NULL
|| *modeList
== NULL
|| mode
== NULL
)
1986 /* If the mode is at the start of the list, move the start of the list */
1987 if (*modeList
== mode
)
1988 *modeList
= mode
->next
;
1990 /* If mode is the only one on the list, set the list to NULL */
1991 if ((mode
== mode
->prev
) && (mode
== mode
->next
)) {
1995 if ((mode
->prev
!= NULL
) && (mode
->prev
->next
== mode
))
1996 mode
->prev
->next
= mode
->next
;
1997 if ((mode
->next
!= NULL
) && (mode
->next
->prev
== mode
))
1998 mode
->next
->prev
= mode
->prev
;
2006 * xf86PruneDriverModes
2008 * Remove modes from the driver's mode list which have been marked as
2013 xf86PruneDriverModes(ScrnInfoPtr scrp
)
2015 DisplayModePtr first
, p
, n
;
2022 if (!(first
= scrp
->modes
))
2025 if (p
->status
!= MODE_OK
) {
2026 xf86DeleteMode(&(scrp
->modes
), p
);
2029 } while (p
!= NULL
&& p
!= first
);
2031 /* modePool is no longer needed, turf it */
2032 while (scrp
->modePool
) {
2034 * A modePool mode's prev field is used to hold a pointer to the
2035 * member of the scrp->modes list for which a match was considered.
2036 * Clear that pointer first, otherwise xf86DeleteMode might get
2039 scrp
->modePool
->prev
= NULL
;
2040 xf86DeleteMode(&scrp
->modePool
, scrp
->modePool
);
2045 * xf86SetCrtcForModes
2047 * Goes through the screen's mode list, and initialises the Crtc
2048 * parameters for each mode. The initialisation includes adjustments
2049 * for interlaced and double scan modes.
2052 xf86SetCrtcForModes(ScrnInfoPtr scrp
, int adjustFlags
)
2057 * Store adjustFlags for use with the VidMode extension. There is an
2058 * implicit assumption here that SetCrtcForModes is called once.
2060 scrp
->adjustFlags
= adjustFlags
;
2067 xf86SetModeCrtc(p
, adjustFlags
);
2068 DebugF("%sMode %s: %d (%d) %d %d (%d) %d %d (%d) %d %d (%d) %d\n",
2069 (p
->type
& M_T_DEFAULT
) ? "Default " : "",
2070 p
->name
, p
->CrtcHDisplay
, p
->CrtcHBlankStart
,
2071 p
->CrtcHSyncStart
, p
->CrtcHSyncEnd
, p
->CrtcHBlankEnd
,
2072 p
->CrtcHTotal
, p
->CrtcVDisplay
, p
->CrtcVBlankStart
,
2073 p
->CrtcVSyncStart
, p
->CrtcVSyncEnd
, p
->CrtcVBlankEnd
,
2076 } while (p
!= NULL
&& p
!= scrp
->modes
);
2080 xf86PrintModes(ScrnInfoPtr scrp
)
2083 float hsync
, refresh
= 0;
2084 const char *desc
, *desc2
, *prefix
, *uprefix
;
2089 xf86DrvMsg(scrp
->scrnIndex
, scrp
->virtualFrom
, "Virtual size is %dx%d "
2090 "(pitch %d)\n", scrp
->virtualX
, scrp
->virtualY
,
2091 scrp
->displayWidth
);
2099 hsync
= xf86ModeHSync(p
);
2100 refresh
= xf86ModeVRefresh(p
);
2101 if (p
->Flags
& V_INTERLACE
) {
2104 if (p
->Flags
& V_DBLSCAN
) {
2110 if (p
->type
& M_T_BUILTIN
)
2111 prefix
= "Built-in mode";
2112 else if (p
->type
& M_T_DEFAULT
)
2113 prefix
= "Default mode";
2114 else if (p
->type
& M_T_DRIVER
)
2115 prefix
= "Driver mode";
2118 if (p
->type
& M_T_USERDEF
)
2122 if (hsync
== 0 || refresh
== 0) {
2124 xf86DrvMsg(scrp
->scrnIndex
, X_CONFIG
,
2125 "%s%s \"%s\"\n", uprefix
, prefix
, p
->name
);
2127 xf86DrvMsg(scrp
->scrnIndex
, X_PROBED
,
2128 "%s%s %dx%d (unnamed)\n",
2129 uprefix
, prefix
, p
->HDisplay
, p
->VDisplay
);
2131 else if (p
->Clock
== p
->SynthClock
) {
2132 xf86DrvMsg(scrp
->scrnIndex
, X_CONFIG
,
2133 "%s%s \"%s\": %.1f MHz, %.1f kHz, %.1f Hz%s%s\n",
2134 uprefix
, prefix
, p
->name
, p
->Clock
/ 1000.0,
2135 hsync
, refresh
, desc
, desc2
);
2138 xf86DrvMsg(scrp
->scrnIndex
, X_CONFIG
,
2139 "%s%s \"%s\": %.1f MHz (scaled from %.1f MHz), "
2140 "%.1f kHz, %.1f Hz%s%s\n",
2141 uprefix
, prefix
, p
->name
, p
->Clock
/ 1000.0,
2142 p
->SynthClock
/ 1000.0, hsync
, refresh
, desc
, desc2
);
2144 if (hsync
!= 0 && refresh
!= 0)
2145 xf86PrintModeline(scrp
->scrnIndex
, p
);
2147 } while (p
!= NULL
&& p
!= scrp
->modes
);