Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1029 serge 1
/*
2
 * Copyright 2004-2008  Luc Verhaegen 
3
 * Copyright 2007, 2008 Matthias Hopf 
4
 * Copyright 2007, 2008 Egbert Eich   
5
 * Copyright 2007, 2008 Advanced Micro Devices, Inc.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a
8
 * copy of this software and associated documentation files (the "Software"),
9
 * to deal in the Software without restriction, including without limitation
10
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11
 * and/or sell copies of the Software, and to permit persons to whom the
12
 * Software is furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20
 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
21
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23
 * OTHER DEALINGS IN THE SOFTWARE.
24
 */
25
 
26
#ifdef HAVE_CONFIG_H
27
#include "config.h"
28
#endif
29
 
30
#include "xf86.h"
31
#if HAVE_XF86_ANSIC_H
32
# include "xf86_ansic.h"
33
#else
34
# include 
35
# include 
36
#endif
37
 
38
 
39
#include "rhd.h"
40
 
41
#include "edid.h"
42
#include "xf86DDC.h"
43
 
44
#include "rhd_crtc.h"
45
#include "rhd_pll.h"
46
#include "rhd_connector.h"
47
#include "rhd_output.h"
48
#include "rhd_modes.h"
49
#include "rhd_monitor.h"
50
 
51
/* For Acceleration FB validation */
52
//#include "r5xx_accel.h"
53
 
54
/*
55
 * Define a set of own mode errors.
56
 */
57
#define RHD_MODE_STATUS 0x51B00
58
#ifndef MONREC_HAS_REDUCED
59
#define MODE_NO_REDUCED     0x01 + RHD_MODE_STATUS
60
#endif
61
#define MODE_MEM_BW         0x02 + RHD_MODE_STATUS
62
#define MODE_OUTPUT_UNDEF   0x03 + RHD_MODE_STATUS
63
#define MODE_NOT_PAL        0x04 + RHD_MODE_STATUS
64
#define MODE_NOT_NTSC       0x05 + RHD_MODE_STATUS
65
#define MODE_HTOTAL_WIDE    0x06 + RHD_MODE_STATUS
66
#define MODE_HDISPLAY_WIDE  0x07 + RHD_MODE_STATUS
67
#define MODE_HSYNC_RANGE    0x08 + RHD_MODE_STATUS
68
#define MODE_HBLANK_RANGE   0x09 + RHD_MODE_STATUS
69
#define MODE_VTOTAL_WIDE    0x0A + RHD_MODE_STATUS
70
#define MODE_VDISPLAY_WIDE  0x0B + RHD_MODE_STATUS
71
#define MODE_VSYNC_RANGE    0x0C + RHD_MODE_STATUS
72
#define MODE_VBLANK_RANGE   0x0D + RHD_MODE_STATUS
73
#define MODE_PITCH          0x0E + RHD_MODE_STATUS
74
#define MODE_OFFSET         0x0F + RHD_MODE_STATUS
75
#define MODE_MINHEIGHT      0x10 + RHD_MODE_STATUS
76
#define MODE_FIXED          0x11 + RHD_MODE_STATUS
77
#define MODE_SCALE          0x12 + RHD_MODE_STATUS
78
 
79
/*
80
 * Don't bother with checking whether X offers this. Just use the internal one
81
 * I'm the author of the X side one anyway.
82
 */
83
 
84
/*
85
 * Generate a CVT standard mode from HDisplay, VDisplay and VRefresh.
86
 *
87
 * These calculations are stolen from the CVT calculation spreadsheet written
88
 * by Graham Loveridge. He seems to be claiming no copyright and there seems to
89
 * be no license attached to this. He apparently just wants to see his name
90
 * mentioned.
91
 *
92
 * This file can be found at http://www.vesa.org/Public/CVT/CVTd6r1.xls
93
 *
94
 * Comments and structure corresponds to the comments and structure of the xls.
95
 * This should ease importing of future changes to the standard (not very
96
 * likely though).
97
 *
98
 * About margins; i'm sure that they are to be the bit between HDisplay and
99
 * HBlankStart, HBlankEnd and HTotal, VDisplay and VBlankStart, VBlankEnd and
100
 * VTotal, where the overscan colour is shown. FB seems to call _all_ blanking
101
 * outside sync "margin" for some reason. Since we prefer seeing proper
102
 * blanking instead of the overscan colour, and since the Crtc* values will
103
 * probably get altered after us, we will disable margins altogether. With
104
 * these calculations, Margins will plainly expand H/VDisplay, and we don't
105
 * want that. -- libv
106
 *
107
 */
108
DisplayModePtr
109
RHDCVTMode(int HDisplay, int VDisplay, float VRefresh, Bool Reduced,
110
           Bool Interlaced)
111
{
112
    DisplayModeRec  *Mode = xnfalloc(sizeof(DisplayModeRec));
113
 
114
    /* 1) top/bottom margin size (% of height) - default: 1.8 */
115
#define CVT_MARGIN_PERCENTAGE 1.8
116
 
117
    /* 2) character cell horizontal granularity (pixels) - default 8 */
118
#define CVT_H_GRANULARITY 1
119
 
120
    /* 4) Minimum vertical porch (lines) - default 3 */
121
#define CVT_MIN_V_PORCH 3
122
 
123
    /* 4) Minimum number of vertical back porch lines - default 6 */
124
#define CVT_MIN_V_BPORCH 6
125
 
126
    /* Pixel Clock step (kHz) */
127
#define CVT_CLOCK_STEP 250
128
 
129
    Bool Margins = FALSE;
130
    float  VFieldRate, HPeriod;
131
    int  HDisplayRnd, HMargin;
132
    int  VDisplayRnd, VMargin, VSync;
133
    float  Interlace; /* Please rename this */
134
 
135
    memset(Mode, 0, sizeof(DisplayModeRec));
136
 
137
    /* CVT default is 60.0Hz */
138
    if (!VRefresh)
139
        VRefresh = 60.0;
140
 
141
    /* 1. Required field rate */
142
    if (Interlaced)
143
        VFieldRate = VRefresh * 2;
144
    else
145
        VFieldRate = VRefresh;
146
 
147
    /* 2. Horizontal pixels */
148
    HDisplayRnd = HDisplay - (HDisplay % CVT_H_GRANULARITY);
149
 
150
    /* 3. Determine left and right borders */
151
    if (Margins) {
152
        /* right margin is actually exactly the same as left */
153
        HMargin = (((float) HDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0);
154
        HMargin -= HMargin % CVT_H_GRANULARITY;
155
    } else
156
        HMargin = 0;
157
 
158
    /* 4. Find total active pixels */
159
    Mode->HDisplay = HDisplayRnd + 2*HMargin;
160
 
161
    /* 5. Find number of lines per field */
162
    if (Interlaced)
163
        VDisplayRnd = VDisplay / 2;
164
    else
165
        VDisplayRnd = VDisplay;
166
 
167
    /* 6. Find top and bottom margins */
168
    /* nope. */
169
    if (Margins)
170
        /* top and bottom margins are equal again. */
171
        VMargin = (((float) VDisplayRnd) * CVT_MARGIN_PERCENTAGE / 100.0);
172
    else
173
        VMargin = 0;
174
 
175
    Mode->VDisplay = VDisplay + 2*VMargin;
176
 
177
    /* 7. Interlace */
178
    if (Interlaced)
179
        Interlace = 0.5;
180
    else
181
        Interlace = 0.0;
182
 
183
    /* Determine VSync Width from aspect ratio */
184
    if (!(VDisplay % 3) && ((VDisplay * 4 / 3) == HDisplay))
185
        VSync = 4;
186
    else if (!(VDisplay % 9) && ((VDisplay * 16 / 9) == HDisplay))
187
        VSync = 5;
188
    else if (!(VDisplay % 10) && ((VDisplay * 16 / 10) == HDisplay))
189
        VSync = 6;
190
    else if (!(VDisplay % 4) && ((VDisplay * 5 / 4) == HDisplay))
191
        VSync = 7;
192
    else if (!(VDisplay % 9) && ((VDisplay * 15 / 9) == HDisplay))
193
        VSync = 7;
194
    else /* Custom */
195
        VSync = 10;
196
 
197
    if (!Reduced) { /* simplified GTF calculation */
198
 
199
        /* 4) Minimum time of vertical sync + back porch interval (µs)
200
         * default 550.0 */
201
#define CVT_MIN_VSYNC_BP 550.0
202
 
203
        /* 3) Nominal HSync width (% of line period) - default 8 */
204
#define CVT_HSYNC_PERCENTAGE 8
205
 
206
        float  HBlankPercentage;
207
        int  VSyncAndBackPorch, VBackPorch;
208
        int  HBlank;
209
 
210
        /* 8. Estimated Horizontal period */
211
        HPeriod = ((float) (1000000.0 / VFieldRate - CVT_MIN_VSYNC_BP)) /
212
            (VDisplayRnd + 2 * VMargin + CVT_MIN_V_PORCH + Interlace);
213
 
214
        /* 9. Find number of lines in sync + backporch */
215
        if (((int)(CVT_MIN_VSYNC_BP / HPeriod) + 1) < (VSync + CVT_MIN_V_PORCH))
216
            VSyncAndBackPorch = VSync + CVT_MIN_V_PORCH;
217
        else
218
            VSyncAndBackPorch = (int)(CVT_MIN_VSYNC_BP / HPeriod) + 1;
219
 
220
        /* 10. Find number of lines in back porch */
221
        VBackPorch = VSyncAndBackPorch - VSync;
222
 
223
        /* 11. Find total number of lines in vertical field */
224
        Mode->VTotal = VDisplayRnd + 2 * VMargin + VSyncAndBackPorch + Interlace
225
            + CVT_MIN_V_PORCH;
226
 
227
        /* 5) Definition of Horizontal blanking time limitation */
228
        /* Gradient (%/kHz) - default 600 */
229
#define CVT_M_FACTOR 600
230
 
231
        /* Offset (%) - default 40 */
232
#define CVT_C_FACTOR 40
233
 
234
        /* Blanking time scaling factor - default 128 */
235
#define CVT_K_FACTOR 128
236
 
237
        /* Scaling factor weighting - default 20 */
238
#define CVT_J_FACTOR 20
239
 
240
#define CVT_M_PRIME CVT_M_FACTOR * CVT_K_FACTOR / 256
241
#define CVT_C_PRIME (CVT_C_FACTOR - CVT_J_FACTOR) * CVT_K_FACTOR / 256 + \
242
        CVT_J_FACTOR
243
 
244
        /* 12. Find ideal blanking duty cycle from formula */
245
        HBlankPercentage = CVT_C_PRIME - CVT_M_PRIME * HPeriod/1000.0;
246
 
247
        /* 13. Blanking time */
248
        if (HBlankPercentage < 20)
249
            HBlankPercentage = 20;
250
 
251
        HBlank = Mode->HDisplay * HBlankPercentage/(100.0 - HBlankPercentage);
252
        HBlank -= HBlank % (2*CVT_H_GRANULARITY);
253
 
254
        /* 14. Find total number of pixels in a line. */
255
        Mode->HTotal = Mode->HDisplay + HBlank;
256
 
257
        /* Fill in HSync values */
258
        Mode->HSyncEnd = Mode->HDisplay + HBlank / 2;
259
 
260
        Mode->HSyncStart = Mode->HSyncEnd -
261
            (Mode->HTotal * CVT_HSYNC_PERCENTAGE) / 100;
262
        Mode->HSyncStart += CVT_H_GRANULARITY -
263
            Mode->HSyncStart % CVT_H_GRANULARITY;
264
 
265
        /* Fill in VSync values */
266
        Mode->VSyncStart = Mode->VDisplay + CVT_MIN_V_PORCH;
267
        Mode->VSyncEnd = Mode->VSyncStart + VSync;
268
 
269
    } else { /* Reduced blanking */
270
        /* Minimum vertical blanking interval time (µs) - default 460 */
271
#define CVT_RB_MIN_VBLANK 460.0
272
 
273
        /* Fixed number of clocks for horizontal sync */
274
#define CVT_RB_H_SYNC 32.0
275
 
276
        /* Fixed number of clocks for horizontal blanking */
277
#define CVT_RB_H_BLANK 160.0
278
 
279
        /* Fixed number of lines for vertical front porch - default 3 */
280
#define CVT_RB_VFPORCH 3
281
 
282
        int  VBILines;
283
 
284
        /* 8. Estimate Horizontal period. */
285
        HPeriod = ((float) (1000000.0 / VFieldRate - CVT_RB_MIN_VBLANK)) /
286
            (VDisplayRnd + 2*VMargin);
287
 
288
        /* 9. Find number of lines in vertical blanking */
289
        VBILines = ((float) CVT_RB_MIN_VBLANK) / HPeriod + 1;
290
 
291
        /* 10. Check if vertical blanking is sufficient */
292
        if (VBILines < (CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH))
293
            VBILines = CVT_RB_VFPORCH + VSync + CVT_MIN_V_BPORCH;
294
 
295
        /* 11. Find total number of lines in vertical field */
296
        Mode->VTotal = VDisplayRnd + 2 * VMargin + Interlace + VBILines;
297
 
298
        /* 12. Find total number of pixels in a line */
299
        Mode->HTotal = Mode->HDisplay + CVT_RB_H_BLANK;
300
 
301
        /* Fill in HSync values */
302
        Mode->HSyncEnd = Mode->HDisplay + CVT_RB_H_BLANK / 2;
303
        Mode->HSyncStart = Mode->HSyncEnd - CVT_RB_H_SYNC;
304
 
305
        /* Fill in VSync values */
306
        Mode->VSyncStart = Mode->VDisplay + CVT_RB_VFPORCH;
307
        Mode->VSyncEnd = Mode->VSyncStart + VSync;
308
    }
309
 
310
    /* 15/13. Find pixel clock frequency (kHz for xf86) */
311
    Mode->Clock = Mode->HTotal * 1000.0 / HPeriod;
312
    Mode->Clock -= Mode->Clock % CVT_CLOCK_STEP;
313
 
314
    /* 16/14. Find actual Horizontal Frequency (kHz) */
315
    Mode->HSync = ((float) Mode->Clock) / ((float) Mode->HTotal);
316
 
317
    /* 17/15. Find actual Field rate */
318
    Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) /
319
        ((float) (Mode->HTotal * Mode->VTotal));
320
 
321
    /* 18/16. Find actual vertical frame frequency */
322
    /* ignore - just set the mode flag for interlaced */
323
    if (Interlaced)
324
        Mode->VTotal *= 2;
325
 
326
    {
327
        char  Name[256];
328
        Name[0] = 0;
329
 
330
        snprintf(Name, 256, "%dx%d", HDisplay, VDisplay);
331
        Mode->name = strdup(Name);
332
    }
333
 
334
    if (Reduced)
335
        Mode->Flags |= V_PHSYNC | V_NVSYNC;
336
    else
337
        Mode->Flags |= V_NHSYNC | V_PVSYNC;
338
 
339
    if (Interlaced)
340
        Mode->Flags |= V_INTERLACE;
341
 
342
    return Mode;
343
}
344
 
345
/*
346
 * Temporary.
347
 */
348
static void
349
add(char **p, char *new)
350
{
351
//  char *tmp = kmalloc(strlen(*p) + strlen(new) + 2);
352
 
353
  *p = (char*)realloc(*p, strlen(*p) + strlen(new) + 2);
354
  strcat(*p, " ");
355
  strcat(*p, new);
356
}
357
 
358
/*
359
 *
360
 */
361
Bool
362
rhdModesEqual(DisplayModePtr mode1, DisplayModePtr mode2)
363
{
364
    if (mode1->Clock == mode2->Clock
365
	&& mode1->HDisplay == mode2->HDisplay
366
	&& mode1->HSyncStart == mode2->HSyncStart
367
	&& mode1->HSyncEnd == mode2->HSyncEnd
368
	&& mode1->HTotal == mode2->HTotal
369
	&& mode1->HSkew == mode2->HSkew
370
	&& mode1->VDisplay == mode2->VDisplay
371
	&& mode1->VSyncStart == mode2->VSyncStart
372
	&& mode1->VSyncEnd == mode2->VSyncEnd
373
	&& mode1->VTotal == mode2->VTotal
374
	&& mode1->VScan == mode2->VScan
375
	&& mode1->Flags == mode2->Flags)
376
	return TRUE;
377
 
378
    return FALSE;
379
}
380
 
381
/*
382
 *
383
 */
384
void
385
RHDPrintModeline(DisplayModePtr mode)
386
{
387
    char tmp[256];
388
    char *flags = xnfcalloc(1, 1);
389
 
390
    if (mode->HSkew) {
391
	snprintf(tmp, 256, "hskew %i", mode->HSkew);
392
	add(&flags, tmp);
393
    }
394
    if (mode->VScan) {
395
	snprintf(tmp, 256, "vscan %i", mode->VScan);
396
	add(&flags, tmp);
397
    }
398
    if (mode->Flags & V_INTERLACE) add(&flags, "interlace");
399
    if (mode->Flags & V_CSYNC) add(&flags, "composite");
400
    if (mode->Flags & V_DBLSCAN) add(&flags, "doublescan");
401
    if (mode->Flags & V_BCAST) add(&flags, "bcast");
402
    if (mode->Flags & V_PHSYNC) add(&flags, "+hsync");
403
    if (mode->Flags & V_NHSYNC) add(&flags, "-hsync");
404
    if (mode->Flags & V_PVSYNC) add(&flags, "+vsync");
405
    if (mode->Flags & V_NVSYNC) add(&flags, "-vsync");
406
    if (mode->Flags & V_PCSYNC) add(&flags, "+csync");
407
    if (mode->Flags & V_NCSYNC) add(&flags, "-csync");
408
#if 0
409
    if (mode->Flags & V_CLKDIV2) add(&flags, "vclk/2");
410
#endif
411
    xf86Msg(X_NONE, "Modeline \"%s\"  %6.2f  %i %i %i %i  %i %i %i %i%s\n",
412
	    mode->name, mode->Clock/1000.,
413
	    mode->HDisplay, mode->HSyncStart, mode->HSyncEnd, mode->HTotal,
414
	    mode->VDisplay, mode->VSyncStart, mode->VSyncEnd, mode->VTotal,
415
	    flags);
416
    xfree(flags);
417
}
418
 
419
/*
420
 * xf86Mode.c should have a some more DisplayModePtr list handling.
421
 */
422
DisplayModePtr
423
RHDModesAdd(DisplayModePtr Modes, DisplayModePtr Additions)
424
{
425
    if (!Modes) {
426
        if (Additions)
427
            return Additions;
428
        else
429
            return NULL;
430
    }
431
 
432
    if (Additions) {
433
        DisplayModePtr Mode = Modes;
434
 
435
        while (Mode->next)
436
            Mode = Mode->next;
437
 
438
        Mode->next = Additions;
439
        Additions->prev = Mode;
440
    }
441
 
442
    return Modes;
443
}
444
 
445
/*
446
 *
447
 */
448
static DisplayModePtr
449
rhdModeDelete(DisplayModePtr Modes, DisplayModePtr Delete)
450
{
451
    DisplayModePtr Next, Previous;
452
 
453
    if (!Delete)
454
	return Modes;
455
 
456
    if (Modes == Delete)
457
	Modes = NULL;
458
 
459
    if (Delete->next == Delete)
460
	Delete->next = NULL;
461
 
462
    if (Delete->prev == Delete)
463
	Delete->next = NULL;
464
 
465
    Next = Delete->next;
466
    Previous = Delete->prev;
467
 
468
    if (Next)
469
	Next->prev = Previous;
470
 
471
    if (Previous)
472
	Previous->next = Next;
473
 
474
    xfree(Delete->name);
475
    xfree(Delete);
476
 
477
    if (Modes)
478
	return Modes;
479
 
480
    if (Next)
481
	return Next;
482
 
483
    if (Previous)
484
	while (Previous->prev)
485
	    Previous = Previous->prev;
486
 
487
    return Previous;
488
}
489
 
490
/*
491
 *
492
 */
493
DisplayModePtr
494
RHDModeCopy(DisplayModePtr Mode)
495
{
496
    DisplayModePtr New;
497
 
498
    if (!Mode)
499
        return NULL;
500
 
501
    New = xnfalloc(sizeof(DisplayModeRec));
502
    memcpy(New, Mode, sizeof(DisplayModeRec)); /* re-use private */
503
    New->name = strdup(Mode->name);
504
    New->prev = NULL;
505
    New->next = NULL;
506
    New->Private = Mode->Private;
507
    New->PrivSize = Mode->PrivSize;
508
 
509
    return New;
510
}
511
 
512
/*
513
 *
514
 */
515
static void
516
rhdModesDestroy(DisplayModePtr Modes)
517
{
518
    DisplayModePtr mode = Modes, next;
519
 
520
    while (mode) {
521
        next = mode->next;
522
        xfree(mode->name);
523
        xfree(mode);
524
        mode = next;
525
    }
526
}
527
 
528
/*
529
 * Basic sanity checks.
530
 */
531
static int
532
rhdModeSanity(RHDPtr rhdPtr, DisplayModePtr Mode)
533
{
534
    /* do we need to bother at all? */
535
    if (Mode->status != MODE_OK)
536
        return Mode->status;
537
 
538
    if (!Mode->name) {
539
	xf86DrvMsg(rhdPtr->scrnIndex, X_ERROR,
540
		   "Validation found mode without name.\n");
541
        return MODE_ERROR;
542
    }
543
 
544
    if (Mode->Clock <= 0)
545
        return MODE_NOCLOCK;
546
 
547
    if ((Mode->HDisplay <= 0) || (Mode->HSyncStart <= 0) ||
548
        (Mode->HSyncEnd <= 0) || (Mode->HTotal <= 0))
549
        return MODE_H_ILLEGAL;
550
 
551
    if ((Mode->HTotal <= Mode->HSyncEnd) ||
552
        (Mode->HSyncEnd <= Mode->HSyncStart) ||
553
        (Mode->HSyncStart < Mode->HDisplay))
554
        return MODE_H_ILLEGAL;
555
 
556
    /* HSkew? */
557
 
558
    if ((Mode->VDisplay <= 0) || (Mode->VSyncStart <= 0) ||
559
        (Mode->VSyncEnd <= 0) || (Mode->VTotal <= 0))
560
        return MODE_V_ILLEGAL;
561
 
562
    if ((Mode->VTotal <= Mode->VSyncEnd) ||
563
        (Mode->VSyncEnd <= Mode->VSyncStart) ||
564
        (Mode->VSyncStart < Mode->VDisplay))
565
        return MODE_V_ILLEGAL;
566
 
567
    if ((Mode->VScan != 0) && (Mode->VScan != 1))
568
        return MODE_NO_VSCAN;
569
 
570
    if (Mode->Flags & V_DBLSCAN)
571
        return MODE_NO_DBLESCAN;
572
 
573
    /* Flags */
574
    return MODE_OK;
575
}
576
 
577
/*
578
 * After we passed the initial sanity check, we need to fill out the CRTC
579
 * values.
580
 */
581
static void
582
rhdModeFillOutCrtcValues(DisplayModePtr Mode)
583
{
584
    /* do we need to bother at all? */
585
    if (Mode->status != MODE_OK)
586
        return;
587
 
588
    Mode->ClockIndex = -1; /* Always! direct non-programmable support must die. */
589
 
590
    if (!Mode->SynthClock)
591
        Mode->SynthClock = Mode->Clock;
592
 
593
    if (!Mode->CrtcHDisplay)
594
        Mode->CrtcHDisplay = Mode->HDisplay;
595
 
596
    if (!Mode->CrtcHBlankStart)
597
        Mode->CrtcHBlankStart = Mode->HDisplay;
598
 
599
    if (!Mode->CrtcHSyncStart)
600
        Mode->CrtcHSyncStart = Mode->HSyncStart;
601
 
602
    if (!Mode->CrtcHSyncEnd)
603
        Mode->CrtcHSyncEnd = Mode->HSyncEnd;
604
 
605
    if (!Mode->CrtcHBlankEnd)
606
        Mode->CrtcHBlankEnd = Mode->HTotal;
607
 
608
    if (!Mode->CrtcHTotal)
609
        Mode->CrtcHTotal = Mode->HTotal;
610
 
611
    if (!Mode->CrtcHSkew)
612
        Mode->CrtcHSkew = Mode->HSkew;
613
 
614
    if (!Mode->CrtcVDisplay)
615
        Mode->CrtcVDisplay = Mode->VDisplay;
616
 
617
    if (!Mode->CrtcVBlankStart)
618
        Mode->CrtcVBlankStart = Mode->VDisplay;
619
 
620
    if (!Mode->CrtcVSyncStart)
621
        Mode->CrtcVSyncStart = Mode->VSyncStart;
622
 
623
    if (!Mode->CrtcVSyncEnd)
624
        Mode->CrtcVSyncEnd = Mode->VSyncEnd;
625
 
626
    if (!Mode->CrtcVBlankEnd)
627
        Mode->CrtcVBlankEnd = Mode->VTotal;
628
 
629
    if (!Mode->CrtcVTotal)
630
        Mode->CrtcVTotal = Mode->VTotal;
631
 
632
    /* Always change these */
633
    Mode->HSync = ((float) Mode->SynthClock) / Mode->CrtcHTotal;
634
    Mode->VRefresh = (Mode->SynthClock * 1000.0) /
635
        (Mode->CrtcHTotal * Mode->CrtcVTotal);
636
    if (Mode->Flags & V_INTERLACE)
637
	Mode->VRefresh *= 2.0;
638
    if (Mode->Flags & V_DBLSCAN)
639
	Mode->VRefresh /= 2.0;
640
 
641
    /* We're usually first in the chain, right after rhdModeSanity. */
642
    Mode->CrtcHAdjusted = FALSE;
643
    Mode->CrtcVAdjusted = FALSE;
644
 
645
    /* Steer clear of PrivSize, Private and PrivFlags */
646
}
647
 
648
/*
649
 * Basic sanity checks.
650
 */
651
static int
652
rhdModeCrtcSanity(DisplayModePtr Mode)
653
{
654
    if (Mode->SynthClock <= 0)
655
        return MODE_NOCLOCK;
656
 
657
    if ((Mode->CrtcHDisplay <= 0) || (Mode->CrtcHBlankStart <= 0) ||
658
        (Mode->CrtcHSyncStart <= 0) || (Mode->CrtcHSyncEnd <= 0) ||
659
        (Mode->CrtcHBlankEnd <= 0) || (Mode->CrtcHTotal <= 0))
660
        return MODE_H_ILLEGAL;
661
 
662
    /* there seem to be no alignment constraints on horizontal timing on our
663
       hardware here */
664
 
665
    if ((Mode->CrtcHTotal < Mode->CrtcHBlankEnd) ||
666
        (Mode->CrtcHBlankEnd <= Mode->CrtcHSyncEnd) ||
667
        (Mode->CrtcHSyncEnd <= Mode->CrtcHSyncStart) ||
668
        (Mode->CrtcHSyncStart < Mode->CrtcHBlankStart) ||
669
        (Mode->CrtcHBlankStart < Mode->CrtcHDisplay))
670
        return MODE_H_ILLEGAL;
671
 
672
    /* CrtcHSkew? */
673
 
674
    if ((Mode->CrtcVDisplay <= 0) || (Mode->CrtcVBlankStart <= 0) ||
675
        (Mode->CrtcVSyncStart <= 0) || (Mode->CrtcVSyncEnd <= 0) ||
676
        (Mode->CrtcVBlankEnd <= 0) || (Mode->CrtcVTotal <= 0))
677
        return MODE_V_ILLEGAL;
678
 
679
    if ((Mode->CrtcVTotal < Mode->CrtcVBlankEnd) ||
680
        (Mode->CrtcVBlankEnd <= Mode->CrtcVSyncEnd) ||
681
        (Mode->CrtcVSyncEnd <= Mode->CrtcVSyncStart) ||
682
        (Mode->CrtcVSyncStart < Mode->CrtcVBlankStart) ||
683
        (Mode->CrtcVBlankStart < Mode->CrtcVDisplay))
684
        return MODE_V_ILLEGAL;
685
 
686
    return MODE_OK;
687
}
688
 
689
/*
690
 *
691
 */
692
static Bool
693
rhdMonitorFixedValid(struct rhdMonitor *Monitor, DisplayModePtr Mode)
694
{
695
    DisplayModePtr Fixed;
696
 
697
    for (Fixed = Monitor->Modes; Fixed; Fixed = Fixed->next) {
698
	if ((Mode->Flags != Fixed->Flags) ||
699
	    (Mode->Clock != Fixed->Clock) ||
700
	    (Mode->SynthClock != Fixed->Clock))
701
	    continue;
702
 
703
	if ((Mode->HDisplay > Fixed->HDisplay) ||
704
	    (Mode->VDisplay > Fixed->VDisplay))
705
	    continue;
706
 
707
	if ((Mode->HSyncStart != Fixed->HSyncStart) ||
708
	    (Mode->HSyncEnd != Fixed->HSyncEnd))
709
	    continue;
710
 
711
	if ((Mode->VSyncStart != Fixed->VSyncStart) ||
712
	    (Mode->VSyncEnd != Fixed->VSyncEnd))
713
	    continue;
714
 
715
	if ((Mode->CrtcHDisplay > Fixed->HDisplay) ||
716
	    (Mode->CrtcVDisplay > Fixed->VDisplay))
717
	    continue;
718
 
719
	if ((Mode->CrtcHBlankStart != Fixed->HDisplay) ||
720
	    (Mode->CrtcHSyncStart != Fixed->HSyncStart) ||
721
	    (Mode->CrtcHSyncEnd != Fixed->HSyncEnd) ||
722
	    (Mode->CrtcHBlankEnd != Fixed->HTotal))
723
	    continue;
724
 
725
	if ((Mode->CrtcVBlankStart != Fixed->VDisplay) ||
726
	    (Mode->CrtcVSyncStart != Fixed->VSyncStart) ||
727
	    (Mode->CrtcVSyncEnd != Fixed->VSyncEnd) ||
728
	    (Mode->CrtcVBlankEnd != Fixed->VTotal))
729
	    continue;
730
 
731
	return TRUE;
732
    }
733
 
734
    return FALSE;
735
}
736
/*
737
 * TODO: review fixed modes when doing different modes on both crtcs.
738
 */
739
static int
740
rhdMonitorValid(struct rhdMonitor *Monitor, DisplayModePtr Mode)
741
{
742
    int i;
743
    Bool isNative = FALSE;
744
 
745
    if (Monitor->NativeMode && rhdModesEqual(Mode, Monitor->NativeMode))
746
	isNative = TRUE;
747
 
748
    for (i = 0; i < Monitor->numHSync; i++)
749
        if ((Mode->HSync >= (Monitor->HSync[i].lo * (1.0 - SYNC_TOLERANCE))) &&
750
            (Mode->HSync <= (Monitor->HSync[i].hi * (1.0 + SYNC_TOLERANCE))))
751
            break;
752
    if (Monitor->numHSync && (i == Monitor->numHSync))
753
        return MODE_HSYNC;
754
 
755
    for (i = 0; i < Monitor->numVRefresh; i++)
756
        if ((Mode->VRefresh >= (Monitor->VRefresh[i].lo * (1.0 - SYNC_TOLERANCE))) &&
757
            (Mode->VRefresh <= (Monitor->VRefresh[i].hi * (1.0 + SYNC_TOLERANCE))))
758
            break;
759
    if (Monitor->numVRefresh && (i == Monitor->numVRefresh))
760
        return MODE_VSYNC;
761
 
762
    if (Monitor->Bandwidth &&
763
	(Mode->SynthClock > (Monitor->Bandwidth * (1 + SYNC_TOLERANCE))))
764
        return MODE_CLOCK_HIGH;
765
 
766
    if (isNative) { /* if it's this monitor's native mode be less strict on validation */
767
    if (Monitor->ReducedAllowed) {
768
	    if ((Mode->CrtcHDisplay * 101) > (Mode->CrtcHTotal * 100)) /* 1% */
769
	    return MODE_HBLANK_NARROW;
770
    } else { /* no reduced blanking */
771
	if ((Mode->CrtcHDisplay * 23) > (Mode->CrtcHTotal * 20)) /* 15% */
772
	    return MODE_HBLANK_NARROW;
773
    }
774
    } else {
775
	if (((Mode->CrtcHDisplay * 5 / 4) & ~0x07) > Mode->CrtcHTotal) {
776
	    /* is this a cvt -r Mode, and only a cvt -r Mode? */
777
	    if (((Mode->CrtcHTotal - Mode->CrtcHDisplay) == 160) &&
778
		((Mode->CrtcHSyncEnd - Mode->CrtcHDisplay) == 80) &&
779
		((Mode->CrtcHSyncEnd - Mode->CrtcHSyncStart) == 32) &&
780
		((Mode->CrtcVSyncStart - Mode->CrtcVDisplay) == 3)) {
781
		if (!Monitor->ReducedAllowed)
782
		    return MODE_NO_REDUCED;
783
	    } else if ((Mode->CrtcHDisplay * 11) > (Mode->CrtcHTotal * 10))
784
		return MODE_HSYNC_NARROW;
785
	}
786
    }
787
 
788
    if (Monitor->UseFixedModes && !rhdMonitorFixedValid(Monitor, Mode))
789
	return MODE_FIXED;
790
 
791
    return MODE_OK;
792
}
793
 
794
#define RHD_MODE_VALIDATION_LOOPS 10
795
 
796
enum ValidationKind {
797
    VALIDATE_SCALE_NONE,
798
    VALIDATE_SCALE_FROM,
799
    VALIDATE_SCALE_TO
800
};
801
 
802
/*
803
 *
804
 */
805
static int
806
rhdModeValidateCrtc(struct rhdCrtc *Crtc, DisplayModePtr Mode, enum ValidationKind ValidateScaleModeKind)
807
{
808
    RHDPtr rhdPtr = RHDPTRI(Crtc);
809
    ScrnInfoPtr pScrn = rhdPtr->pScrn;
810
    int Status, i;
811
 
812
    RHDFUNC(Crtc);
813
 
814
    Status = rhdModeSanity(rhdPtr, Mode);
815
    if (Status != MODE_OK)
816
        return Status;
817
 
818
    rhdModeFillOutCrtcValues(Mode);
819
 
820
    /* We don't want to loop around this forever */
821
    for (i = 0; i < RHD_MODE_VALIDATION_LOOPS; i++) {
822
        struct rhdOutput *Output;
823
 
824
        Mode->CrtcHAdjusted = FALSE;
825
        Mode->CrtcVAdjusted = FALSE;
826
 
827
        Status = rhdModeCrtcSanity(Mode);
828
        if (Status != MODE_OK)
829
            return Status;
830
        if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
831
            continue;
832
 
833
	if (ValidateScaleModeKind != VALIDATE_SCALE_TO) {
834
 
835
	Status = Crtc->FBValid(Crtc, Mode->CrtcHDisplay, Mode->CrtcVDisplay,
836
			       pScrn->bitsPerPixel, rhdPtr->FbScanoutStart,
837
			       rhdPtr->FbScanoutSize, NULL);
838
        if (Status != MODE_OK)
839
            return Status;
840
 
841
	    if (Crtc->ScaleValid) {
842
		if (ValidateScaleModeKind == VALIDATE_SCALE_NONE)
843
		    Status = Crtc->ScaleValid(Crtc, RHD_CRTC_SCALE_TYPE_NONE, Mode, NULL);
844
		else
845
		    Status = Crtc->ScaleValid(Crtc, Crtc->ScaleType, Mode, Crtc->ScaledToMode);
846
        if (Status != MODE_OK)
847
            return Status;
848
        if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
849
            continue;
850
	    }
851
	}
852
 
853
	if (ValidateScaleModeKind != VALIDATE_SCALE_FROM) {
854
	    Status = Crtc->ModeValid(Crtc, Mode);
855
	    if (Status != MODE_OK)
856
		return Status;
857
	    if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
858
		continue;
859
 
860
	    if (Crtc->PLL && Crtc->PLL->Valid) { /* RandR may not have PLL filled out. oh well... */
861
	    Status = Crtc->PLL->Valid(Crtc->PLL, Mode->Clock);
862
	    if (Status != MODE_OK)
863
		return Status;
864
	    if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
865
		continue;
866
	}
867
 
868
        for (Output = rhdPtr->Outputs; Output; Output = Output->Next)
869
            if (Output->Active && (Output->Crtc == Crtc)) {
870
		/* Check the output */
871
                Status = Output->ModeValid(Output, Mode);
872
                if (Status != MODE_OK)
873
                    return Status;
874
                if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
875
                    break; /* restart. */
876
 
877
		/* Check the monitor attached to this output */
878
		if (Output->Connector && Output->Connector->Monitor)
879
		    Status = rhdMonitorValid(Output->Connector->Monitor, Mode);
880
		if (Status != MODE_OK)
881
                    return Status;
882
                if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
883
                    break; /* restart. */
884
            }
885
 
886
	    if (Output) /* We're done. This must be a good mode. */
887
		continue;
888
	}
889
 
890
            return MODE_OK;
891
    }
892
 
893
    /* Mode has been bouncing around for ages, on adjustments */
894
    xf86DrvMsg(Crtc->scrnIndex, X_ERROR, "%s: Mode \"%s\" (%dx%d:%3.1fMhz) was"
895
               " thrown around for too long.\n", __func__, Mode->name,
896
               Mode->HDisplay, Mode->VDisplay, Mode->Clock/1000.0);
897
    return MODE_ERROR;
898
}
899
 
900
/*
901
 *
902
 */
903
int
904
RHDValidateScaledToMode(struct rhdCrtc *Crtc, DisplayModePtr Mode)
905
{
906
    RHDPtr rhdPtr = RHDPTRI(Crtc);
907
    int Status;
908
 
909
    RHDFUNC(Crtc);
910
 
911
    Status = rhdModeSanity(rhdPtr, Mode);
912
    if (Status != MODE_OK)
913
        return Status;
914
 
915
    rhdModeFillOutCrtcValues(Mode);
916
 
917
    Status = rhdModeValidateCrtc(Crtc, Mode, VALIDATE_SCALE_TO);
918
    if (Status != MODE_OK)
919
	return Status;
920
 
921
    /* Do we want to also validate against a configured monitor? */
922
    if (rhdPtr->ConfigMonitor) {
923
	Status = rhdMonitorValid(rhdPtr->ConfigMonitor, Mode);
924
	if (Status != MODE_OK)
925
	    return Status;
926
    }
927
 
928
    return MODE_OK;
929
}
930
 
931
/*
932
 *
933
 */
934
static int
935
rhdModeValidate(ScrnInfoPtr pScrn, DisplayModePtr Mode)
936
{
937
    RHDPtr rhdPtr = RHDPTR(pScrn);
938
    struct rhdCrtc *Crtc;
939
    int Status;
940
    int i;
941
 
942
    Status = rhdModeSanity(rhdPtr, Mode);
943
    if (Status != MODE_OK)
944
        return Status;
945
 
946
    rhdModeFillOutCrtcValues(Mode);
947
 
948
    /* now let our modesetting tree have its say */
949
    for (i = 0; i < 2; i++) {
950
        Crtc = rhdPtr->Crtc[i];
951
        if (!Crtc->Active)
952
            continue;
953
 
954
	if (!Crtc->ScaledToMode) {
955
 
956
	    Status = rhdModeValidateCrtc(Crtc, Mode, VALIDATE_SCALE_NONE);
957
	if (Status != MODE_OK)
958
	    return Status;
959
 
960
	} else {
961
	    Status = rhdModeValidateCrtc(Crtc, Mode, VALIDATE_SCALE_FROM);
962
	    if (Status != MODE_OK)
963
		return Status;
964
    }
965
    }
966
 
967
    /* throw them at the configured monitor, so that the inadequate
968
     * conf file at least has some influence. */
969
    if (rhdPtr->ConfigMonitor) {
970
	Status = rhdMonitorValid(rhdPtr->ConfigMonitor, Mode);
971
	if (Status != MODE_OK)
972
	    return Status;
973
    }
974
 
975
    /* Did we set up virtual resolution already? */
976
    if ((pScrn->virtualX > 0) && (pScrn->virtualY > 0)) {
977
        if (pScrn->virtualX < Mode->CrtcHDisplay)
978
            return MODE_VIRTUAL_X;
979
        if (pScrn->virtualY < Mode->CrtcVDisplay)
980
            return MODE_VIRTUAL_Y;
981
    }
982
 
983
    return MODE_OK;
984
}
985
 
986
/*
987
 * Wrap the limited xf86 Mode statusses with our own message.
988
 */
989
struct {
990
    int Status;
991
    char *Message;
992
} rhdModeStatusMessages[] = {
993
    { MODE_NO_REDUCED,    "Reduced blanking is not supported."},
994
    { MODE_MEM_BW,        "Memory bandwidth exceeded."},
995
    { MODE_OUTPUT_UNDEF,  "Mode not defined by output device."},
996
    { MODE_NOT_PAL,       "This is not a PAL TV mode."},
997
    { MODE_NOT_NTSC,      "This is not an NTSC TV mode."},
998
    { MODE_HTOTAL_WIDE,   "Horizontal Total is out of range."},
999
    { MODE_HDISPLAY_WIDE, "Mode is too wide."},
1000
    { MODE_HSYNC_RANGE,   "Horizontal Sync Start is out of range."},
1001
    { MODE_HBLANK_RANGE,  "Horizontal Blanking Start is out of range."},
1002
    { MODE_VTOTAL_WIDE,   "Vertical Total is out of range.\n"},
1003
    { MODE_VDISPLAY_WIDE, "Mode is too high."},
1004
    { MODE_VSYNC_RANGE,   "Vertical Sync Start is out of range.\n"},
1005
    { MODE_VBLANK_RANGE,  "Vertical Blanking Start is out of range."},
1006
    { MODE_PITCH,         "Scanout buffer Pitch too wide."},
1007
    { MODE_OFFSET,        "Scanout buffer offset too high in FB."},
1008
    { MODE_MINHEIGHT,     "Height too low."},
1009
    { MODE_FIXED,         "Mode not compatible with fixed mode."},
1010
    { MODE_SCALE,         "Mode cannot be scaled to fixed mode."},
1011
    { MODE_NO_ENCODER,    "No encoder available for this output."},
1012
    { 0, NULL}
1013
};
1014
 
1015
const char * xf86ModeStatusToString(ModeStatus status)
1016
{
1017
    switch (status) {
1018
    case MODE_OK:
1019
	return "Mode OK";
1020
    case MODE_HSYNC:
1021
	return "hsync out of range";
1022
    case MODE_VSYNC:
1023
	return "vrefresh out of range";
1024
    case MODE_H_ILLEGAL:
1025
	return "illegal horizontal timings";
1026
    case MODE_V_ILLEGAL:
1027
	return "illegal vertical timings";
1028
    case MODE_BAD_WIDTH:
1029
	return "width requires unsupported line pitch";
1030
    case MODE_NOMODE:
1031
	return "no mode of this name";
1032
    case MODE_NO_INTERLACE:
1033
	return "interlace mode not supported";
1034
    case MODE_NO_DBLESCAN:
1035
	return "doublescan mode not supported";
1036
    case MODE_NO_VSCAN:
1037
	return "multiscan mode not supported";
1038
    case MODE_MEM:
1039
	return "insufficient memory for mode";
1040
    case MODE_VIRTUAL_X:
1041
	return "width too large for virtual size";
1042
    case MODE_VIRTUAL_Y:
1043
	return "height too large for virtual size";
1044
    case MODE_MEM_VIRT:
1045
	return "insufficient memory given virtual size";
1046
    case MODE_NOCLOCK:
1047
	return "no clock available for mode";
1048
    case MODE_CLOCK_HIGH:
1049
	return "mode clock too high";
1050
    case MODE_CLOCK_LOW:
1051
	return "mode clock too low";
1052
    case MODE_CLOCK_RANGE:
1053
	return "bad mode clock/interlace/doublescan";
1054
    case MODE_BAD_HVALUE:
1055
	return "horizontal timing out of range";
1056
    case MODE_BAD_VVALUE:
1057
	return "vertical timing out of range";
1058
    case MODE_BAD_VSCAN:
1059
	return "VScan value out of range";
1060
    case MODE_HSYNC_NARROW:
1061
	return "horizontal sync too narrow";
1062
    case MODE_HSYNC_WIDE:
1063
	return "horizontal sync too wide";
1064
    case MODE_HBLANK_NARROW:
1065
	return "horizontal blanking too narrow";
1066
    case MODE_HBLANK_WIDE:
1067
	return "horizontal blanking too wide";
1068
    case MODE_VSYNC_NARROW:
1069
	return "vertical sync too narrow";
1070
    case MODE_VSYNC_WIDE:
1071
	return "vertical sync too wide";
1072
    case MODE_VBLANK_NARROW:
1073
	return "vertical blanking too narrow";
1074
    case MODE_VBLANK_WIDE:
1075
	return "vertical blanking too wide";
1076
    case MODE_PANEL:
1077
	return "exceeds panel dimensions";
1078
    case MODE_INTERLACE_WIDTH:
1079
	return "width too large for interlaced mode";
1080
    case MODE_ONE_WIDTH:
1081
        return "all modes must have the same width";
1082
    case MODE_ONE_HEIGHT:
1083
        return "all modes must have the same height";
1084
    case MODE_ONE_SIZE:
1085
        return "all modes must have the same resolution";
1086
    case MODE_BAD:
1087
	return "unknown reason";
1088
    case MODE_ERROR:
1089
	return "internal error";
1090
    default:
1091
	return "unknown";
1092
    }
1093
}
1094
 
1095
 
1096
const char *
1097
RHDModeStatusToString(int Status)
1098
{
1099
    if ((Status & 0xFFF00) == RHD_MODE_STATUS) {
1100
        int i;
1101
 
1102
        for (i = 0; rhdModeStatusMessages[i].Message; i++)
1103
            if (rhdModeStatusMessages[i].Status == Status)
1104
                return rhdModeStatusMessages[i].Message;
1105
        ErrorF("%s: unhandled Status type: 0x%X\n", __func__, Status);
1106
        return "Unknown status.";
1107
 
1108
    } else
1109
        return xf86ModeStatusToString(Status);
1110
}
1111
 
1112
/*
1113
 *
1114
 */
1115
static DisplayModePtr
1116
rhdModesGrabOnNameAll(DisplayModePtr *Modes, char *name)
1117
{
1118
    DisplayModePtr Mode, Matched = NULL, Temp;
1119
 
1120
    for (Mode = *Modes; Mode; ) {
1121
        if (!strcmp(Mode->name, name)) {
1122
            Temp = Mode;
1123
            Mode = Mode->next;
1124
 
1125
            if (Temp->prev)
1126
                Temp->prev->next = Mode;
1127
            else
1128
                *Modes = Mode;
1129
 
1130
            if (Mode)
1131
                Mode->prev = Temp->prev;
1132
 
1133
            Temp->prev = NULL;
1134
            Temp->next = Matched;
1135
            if (Matched)
1136
                Matched->prev = Temp;
1137
            Matched = Temp;
1138
        } else
1139
            Mode = Mode->next;
1140
    }
1141
 
1142
    return Matched;
1143
}
1144
 
1145
/*
1146
 *
1147
 */
1148
static DisplayModePtr
1149
rhdModesGrabOnTypeAll(DisplayModePtr *Modes, int Type, int Mask)
1150
{
1151
    DisplayModePtr Mode, Matched = NULL, Temp;
1152
 
1153
    for (Mode = *Modes; Mode; ) {
1154
        if ((Mode->type & Mask) == (Type & Mask)) {
1155
            Temp = Mode;
1156
            Mode = Mode->next;
1157
 
1158
            if (Temp->prev)
1159
                Temp->prev->next = Mode;
1160
            else
1161
                *Modes = Mode;
1162
 
1163
            if (Mode)
1164
                Mode->prev = Temp->prev;
1165
 
1166
            Temp->next = Matched;
1167
            if (Matched)
1168
                Matched->prev = Temp;
1169
            Temp->prev = NULL;
1170
            Matched = Temp;
1171
        } else
1172
            Mode = Mode->next;
1173
    }
1174
 
1175
    return Matched;
1176
}
1177
 
1178
/*
1179
 *
1180
 */
1181
static DisplayModePtr
1182
rhdModesGrabBestRefresh(DisplayModePtr *Modes)
1183
{
1184
    DisplayModePtr Mode, Best = NULL;
1185
 
1186
    if (!*Modes)
1187
        return NULL;
1188
 
1189
    Best = *Modes;
1190
 
1191
    for (Mode = Best->next; Mode; Mode = Mode->next)
1192
        if (Best->VRefresh < Mode->VRefresh)
1193
            Best = Mode;
1194
        else if (Best->VRefresh == Mode->VRefresh) {
1195
            /* Same name != same resolution */
1196
            if ((Best->HDisplay * Best->VDisplay) <
1197
                (Mode->HDisplay * Mode->VDisplay))
1198
                Best = Mode;
1199
            else if ((Best->HDisplay * Best->VDisplay) ==
1200
                     (Mode->HDisplay * Mode->VDisplay)) {
1201
                /* Lower bandwidth == better! */
1202
                if (Best->Clock > Mode->Clock)
1203
                    Best = Mode;
1204
            }
1205
        }
1206
 
1207
    if (Best->next)
1208
        Best->next->prev = Best->prev;
1209
    if (Best->prev)
1210
        Best->prev->next = Best->next;
1211
    if (Best == *Modes)
1212
        *Modes = (*Modes)->next;
1213
 
1214
    Best->next = NULL;
1215
    Best->prev = NULL;
1216
 
1217
    return Best;
1218
}
1219
 
1220
/*
1221
 *
1222
 */
1223
static DisplayModePtr
1224
rhdModesGrabOnHighestType(DisplayModePtr *Modes)
1225
{
1226
    DisplayModePtr Mode;
1227
 
1228
    /* User provided, but can also have another source. */
1229
    Mode = rhdModesGrabOnTypeAll(Modes, M_T_USERDEF, 0xF0);
1230
    if (Mode)
1231
        return Mode;
1232
 
1233
    /* Often EDID provided, but can also have another source. */
1234
    Mode = rhdModesGrabOnTypeAll(Modes, M_T_DRIVER, 0xF0);
1235
    if (Mode)
1236
        return Mode;
1237
 
1238
    /* No reason why we should treat built-in and vesa separately */
1239
    Mode = *Modes;
1240
    *Modes = NULL;
1241
    return Mode;
1242
}
1243
 
1244
/*
1245
 *
1246
 */
1247
static DisplayModePtr
1248
rhdModesSortOnSize(DisplayModePtr Modes)
1249
{
1250
    DisplayModePtr Sorted, Mode, Temp, Next;
1251
 
1252
    if (!Modes)
1253
        return NULL;
1254
 
1255
    Sorted = Modes;
1256
    Modes = Modes->next;
1257
 
1258
    Sorted->next = NULL;
1259
    Sorted->prev = NULL;
1260
 
1261
    for (Next = Modes; Next; ) {
1262
        /* since we're taking modelines from in between */
1263
        Mode = Next;
1264
        Next = Next->next;
1265
 
1266
        for (Temp = Sorted; Temp; Temp = Temp->next) {
1267
            /* nasty ! */
1268
            if (((Temp->CrtcHDisplay * Temp->CrtcVDisplay) <
1269
                (Mode->CrtcHDisplay * Mode->CrtcVDisplay)) ||
1270
                (((Temp->CrtcHDisplay * Temp->CrtcVDisplay) ==
1271
                  (Mode->CrtcHDisplay * Mode->CrtcVDisplay)) &&
1272
                 ((Temp->VRefresh < Mode->VRefresh)  ||
1273
                  ((Temp->VRefresh < Mode->VRefresh) &&
1274
                   (Temp->SynthClock < Mode->SynthClock))))) {
1275
                Mode->next = Temp;
1276
                Mode->prev = Temp->prev;
1277
                Temp->prev = Mode;
1278
                if (Mode->prev)
1279
                    Mode->prev->next = Mode;
1280
                else
1281
                    Sorted = Mode;
1282
                break;
1283
            }
1284
 
1285
            if (!Temp->next) {
1286
                Temp->next = Mode;
1287
                Mode->prev = Temp;
1288
                Mode->next = NULL;
1289
                break;
1290
            }
1291
        }
1292
    }
1293
 
1294
    return Sorted;
1295
}
1296
 
1297
#if 0
1298
/*
1299
 * take a modename, try to parse it, if that works, generate the CVT modeline.
1300
 */
1301
static DisplayModePtr
1302
rhdModeCreateFromName(ScrnInfoPtr pScrn, char *name, Bool Silent)
1303
{
1304
    DisplayModePtr Mode;
1305
    int HDisplay = 0, VDisplay = 0, tmp;
1306
    float VRefresh = 0;
1307
    Bool Reduced;
1308
    int Status;
1309
 
1310
    sscanf(name, "%dx%d@%f", &HDisplay, &VDisplay, &VRefresh);
1311
    if (!HDisplay || !VDisplay) {
1312
        if (!Silent)
1313
            xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s: Unable to generate "
1314
                       "Modeline for Mode \"%s\"\n", __func__, name);
1315
        return NULL;
1316
    }
1317
 
1318
    tmp = strlen(name) - 1;
1319
    if ((name[tmp] == 'r') || (name[tmp] == 'R'))
1320
        Reduced = TRUE;
1321
    else
1322
        Reduced = FALSE;
1323
 
1324
    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1325
	       "Generating Modeline for \"%s\"\n", name);
1326
 
1327
    /* First, try a plain CVT mode */
1328
    Mode = RHDCVTMode(HDisplay, VDisplay, VRefresh, Reduced, FALSE);
1329
    xfree(Mode->name);
1330
    Mode->name = xnfstrdup(name);
1331
    Mode->type = M_T_USERDEF;
1332
 
1333
    Status = rhdModeValidate(pScrn, Mode);
1334
    if (Status == MODE_OK)
1335
        return Mode;
1336
    rhdModesDestroy(Mode);
1337
 
1338
#if 0 /* noscale mode */
1339
    /* Now see if we have fixed modes */
1340
    for (i = 0; i < 2; i++) {
1341
        Crtc = rhdPtr->Crtc[i];
1342
 
1343
        if (!Crtc->Active || !Crtc->FixedMode)
1344
            continue;
1345
 
1346
        Mode = RHDModeCopy(Crtc->FixedMode);
1347
        xfree(Mode->name);
1348
        Mode->name = xnfstrdup(name);
1349
        Mode->type = M_T_USERDEF;
1350
 
1351
        Mode->HDisplay = HDisplay;
1352
        Mode->CrtcHDisplay = 0; /* set by validation code */
1353
        Mode->VDisplay = VDisplay;
1354
        Mode->CrtcVDisplay = 0;
1355
 
1356
	Status = rhdModeValidate(pScrn, Mode);
1357
        if (Status == MODE_OK)
1358
            return Mode;
1359
        rhdModesDestroy(Mode);
1360
    }
1361
#endif
1362
 
1363
    if (!Silent)
1364
	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Rejected mode \"%s\" "
1365
		   "(%dx%d):\n\t %s\n", name, HDisplay, VDisplay,
1366
		   RHDModeStatusToString(Status));
1367
    return NULL;
1368
}
1369
#endif
1370
 
1371
/*
1372
 *
1373
 */
1374
static DisplayModePtr
1375
rhdModesListValidateAndCopy(ScrnInfoPtr pScrn, DisplayModePtr Modes, Bool Silent)
1376
{
1377
  DisplayModePtr Keepers = NULL, Check, Mode;
1378
  int Status;
1379
 
1380
    for (Check = Modes; Check; Check = Check->next) {
1381
    Mode = RHDModeCopy(Check);
1382
 
1383
    Status = rhdModeValidate(pScrn, Mode);
1384
    if (Status == MODE_OK)
1385
	    Keepers = RHDModesAdd(Keepers, Mode);
1386
	else {
1387
	    if (!Silent)
1388
		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Rejected mode \"%s\" "
1389
			   "(%dx%d:%3.1fMhz): %s\n", Mode->name,
1390
			   Mode->HDisplay, Mode->VDisplay,
1391
			   Mode->Clock / 1000.0, RHDModeStatusToString(Status));
1392
	    xfree(Mode->name);
1393
	    xfree(Mode);
1394
    }
1395
  }
1396
 
1397
  return Keepers;
1398
}
1399
 
1400
/*
1401
 * Create the list of all modes that are currently valid
1402
 */
1403
static DisplayModePtr
1404
rhdCreateModesListAndValidate(ScrnInfoPtr pScrn, Bool Silent)
1405
{
1406
    RHDPtr rhdPtr = RHDPTR(pScrn);
1407
  DisplayModePtr Keepers = NULL, Modes;
1408
  struct rhdCrtc *Crtc;
1409
  struct rhdOutput *Output;
1410
  int i;
1411
 
1412
    RHDFUNC(pScrn);
1413
 
1414
    /* Cycle through our monitors list, and find a fixed mode one */
1415
    for (i = 0; i < 2; i++) {
1416
    Crtc = rhdPtr->Crtc[i];
1417
	for (Output = rhdPtr->Outputs; Output; Output = Output->Next) {
1418
	    if (Output->Active && (Output->Crtc == Crtc)) {
1419
        if (Output->Connector && Output->Connector->Monitor
1420
		    && Output->Connector->Monitor->UseFixedModes
1421
		    && !Crtc->ScaledToMode) {
1422
          Modes = Output->Connector->Monitor->Modes;
1423
          if (!Silent && Modes)
1424
			xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Validating Fixed"
1425
                      " Modes from Monitor \"%s\"\n\t on Connector"
1426
                      " \"%s\"\n", Output->Connector->Monitor->Name,
1427
				   Output->Connector->Name);
1428
 
1429
          Modes = rhdModesListValidateAndCopy(pScrn, Modes, Silent);
1430
          Keepers = RHDModesAdd(Keepers, Modes);
1431
          return Keepers;
1432
        }
1433
	    }
1434
    }
1435
  }
1436
 
1437
 
1438
    /* Cycle through our actual monitors list */
1439
    for (i = 0; i < 2; i++) {
1440
    Crtc = rhdPtr->Crtc[i];
1441
 
1442
	for (Output = rhdPtr->Outputs; Output; Output = Output->Next) {
1443
	    if (Output->Active && (Output->Crtc == Crtc)) {
1444
		if (Output->Connector && Output->Connector->Monitor) {
1445
          Modes = Output->Connector->Monitor->Modes;
1446
          if (!Silent && Modes)
1447
			xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Validating Modes "
1448
                      "from Monitor \"%s\" on \"%s\"\n",
1449
                      Output->Connector->Monitor->Name,
1450
				   Output->Connector->Name);
1451
 
1452
          Modes = rhdModesListValidateAndCopy(pScrn, Modes, Silent);
1453
          Keepers = RHDModesAdd(Keepers, Modes);
1454
        }
1455
	    }
1456
    }
1457
  }
1458
 
1459
  return Keepers;
1460
}
1461
 
1462
/*
1463
 *
1464
 */
1465
DisplayModePtr
1466
RHDModesPoolCreate(ScrnInfoPtr pScrn, Bool Silent)
1467
{
1468
    DisplayModePtr Pool = NULL, List, TempList, Temp;
1469
    char **ModeNames = NULL; //pScrn->display->modes;
1470
    int i;
1471
 
1472
    RHDFUNC(pScrn);
1473
 
1474
    List = rhdCreateModesListAndValidate(pScrn, Silent);
1475
    if (!List)
1476
        return List;
1477
 
1478
    /* Reduce our list */
1479
    if (ModeNames && ModeNames[0]) { /* Find the best matching mode for each name */
1480
        for (i = 0; ModeNames[i]; i++) {
1481
        TempList = rhdModesGrabOnNameAll(&List, ModeNames[i]);
1482
            if (TempList) {
1483
          Temp = rhdModesGrabOnHighestType(&TempList);
1484
          rhdModesDestroy(TempList);
1485
 
1486
          TempList = Temp;
1487
          Temp = rhdModesGrabOnTypeAll(&TempList, M_T_PREFERRED, M_T_PREFERRED);
1488
                if (Temp) {
1489
            rhdModesDestroy(TempList);
1490
            TempList = Temp;
1491
          }
1492
 
1493
          Temp = rhdModesGrabBestRefresh(&TempList);
1494
 
1495
          rhdModesDestroy(TempList);
1496
        }
1497
      //  else /* No matching modes found, generate */
1498
      //    Temp = rhdModeCreateFromName(pScrn, ModeNames[i], Silent);
1499
 
1500
        if (Temp)
1501
          Pool = RHDModesAdd(Pool, Temp);
1502
      }
1503
      rhdModesDestroy(List);
1504
    } else { /* No names, just work the list directly */
1505
      Temp = rhdModesGrabOnHighestType(&List);
1506
      rhdModesDestroy(List);
1507
      List = Temp;
1508
 
1509
        while (List) {
1510
        TempList = rhdModesGrabOnNameAll(&List, List->name);
1511
 
1512
        Temp = rhdModesGrabOnTypeAll(&TempList, M_T_PREFERRED, M_T_PREFERRED);
1513
            if (Temp) {
1514
           rhdModesDestroy(TempList);
1515
           TempList = Temp;
1516
        }
1517
 
1518
        Temp = rhdModesGrabBestRefresh(&TempList);
1519
        rhdModesDestroy(TempList);
1520
 
1521
        Pool = RHDModesAdd(Pool, Temp);
1522
      }
1523
 
1524
        /* Sort our list */
1525
      TempList = Pool;
1526
 
1527
        /* Sort higher priority modes separately */
1528
      Pool = rhdModesGrabOnTypeAll(&TempList, M_T_PREFERRED, M_T_PREFERRED);
1529
      Pool = rhdModesSortOnSize(Pool);
1530
 
1531
      TempList = rhdModesSortOnSize(TempList);
1532
 
1533
      Pool = RHDModesAdd(Pool, TempList);
1534
    }
1535
 
1536
    return Pool;
1537
}
1538
 
1539
/*
1540
 *
1541
 */
1542
void
1543
RHDModesAttach(ScrnInfoPtr pScrn, DisplayModePtr Modes)
1544
{
1545
    DisplayModePtr Mode = Modes;
1546
 
1547
    pScrn->modes = Modes;
1548
    pScrn->currentMode = Modes;
1549
 
1550
    while (Mode->next) {
1551
        Mode->type = M_T_USERDEF; /* satisfy xf86ZoomViewport */
1552
        Mode = Mode->next;
1553
    }
1554
 
1555
    Mode->type = M_T_USERDEF;
1556
 
1557
    /* Make our list circular */
1558
    Mode->next = pScrn->modes;
1559
    pScrn->modes->prev = Mode;
1560
}
1561
 
1562
/*
1563
 *
1564
 */
1565
#if 0
1566
Bool
1567
RHDGetVirtualFromConfig(ScrnInfoPtr pScrn)
1568
{
1569
    RHDPtr rhdPtr = RHDPTR(pScrn);
1570
    struct rhdCrtc *Crtc1 = rhdPtr->Crtc[0], *Crtc2 = rhdPtr->Crtc[1];
1571
    CARD32 VirtualX = pScrn->display->virtualX;
1572
    CARD32 VirtualY = pScrn->display->virtualY;
1573
    CARD32 Pitch1, Pitch2;
1574
    float Ratio = (float) pScrn->display->virtualY / pScrn->display->virtualX;
1575
    int ret = FALSE;
1576
 
1577
    RHDFUNC(pScrn);
1578
 
1579
    while (VirtualX && VirtualY) {
1580
	ret = Crtc1->FBValid(Crtc1, VirtualX, VirtualY, pScrn->bitsPerPixel,
1581
			     rhdPtr->FbScanoutStart, rhdPtr->FbScanoutSize, &Pitch1);
1582
	if (ret != MODE_OK)
1583
	    goto shrink;
1584
	ret = Crtc2->FBValid(Crtc2, VirtualX, VirtualY, pScrn->bitsPerPixel,
1585
			     rhdPtr->FbScanoutStart, rhdPtr->FbScanoutSize, &Pitch2);
1586
	if (ret != MODE_OK)
1587
	    goto shrink;
1588
 
1589
	if (Pitch1 != Pitch2)
1590
	    goto shrink;
1591
#if 0
1592
	/* let 2d acceleration have a say as well */
1593
	if (rhdPtr->AccelMethod >= RHD_ACCEL_XAA)
1594
	    if (rhdPtr->ChipSet < RHD_R600) /* badly abstracted, i know */
1595
		if (!R5xx2DFBValid(rhdPtr, VirtualX, VirtualY, pScrn->bitsPerPixel,
1596
				   rhdPtr->FbScanoutStart, rhdPtr->FbScanoutSize, Pitch1))
1597
		    goto shrink;
1598
#endif
1599
	break; /* must be good then. */
1600
    shrink:
1601
	VirtualX--;
1602
	VirtualY = Ratio * VirtualX;
1603
    }
1604
 
1605
    if (VirtualX && VirtualY) {
1606
	pScrn->virtualX = VirtualX;
1607
	pScrn->virtualY = VirtualY;
1608
	pScrn->displayWidth = Pitch1;
1609
	return TRUE;
1610
    } else
1611
	return FALSE;
1612
}
1613
 
1614
/*
1615
 *
1616
 */
1617
void
1618
RHDGetVirtualFromModesAndFilter(ScrnInfoPtr pScrn, DisplayModePtr Modes, Bool Silent)
1619
{
1620
    RHDPtr rhdPtr = RHDPTR(pScrn);
1621
    struct rhdCrtc *Crtc1 = rhdPtr->Crtc[0], *Crtc2 = rhdPtr->Crtc[1];
1622
    DisplayModePtr Mode, Next;
1623
    CARD32 VirtualX = 0;
1624
    CARD32 VirtualY = 0;
1625
    CARD32 Pitch1, Pitch2;
1626
    int ret = FALSE;
1627
 
1628
    RHDFUNC(pScrn);
1629
 
1630
    /* assert */
1631
    if (!Modes)
1632
	return;
1633
 
1634
    Mode = Modes;
1635
 
1636
    while (Mode) {
1637
	if ((Mode->CrtcHDisplay > pScrn->virtualX) ||
1638
            (Mode->CrtcVDisplay > pScrn->virtualY)) {
1639
            if (Mode->CrtcHDisplay > pScrn->virtualX)
1640
                VirtualX = Mode->CrtcHDisplay;
1641
	    else
1642
		VirtualX = pScrn->virtualX;
1643
 
1644
            if (Mode->CrtcVDisplay > pScrn->virtualY)
1645
                VirtualY = Mode->CrtcVDisplay;
1646
	    else
1647
		VirtualY = pScrn->virtualY;
1648
 
1649
	    /* Check what Crtc1 thinks this should be. */
1650
	    ret = Crtc1->FBValid(Crtc1, VirtualX, VirtualY, pScrn->bitsPerPixel,
1651
				 rhdPtr->FbScanoutStart, rhdPtr->FbScanoutSize, &Pitch1);
1652
	    if (ret != MODE_OK) {
1653
		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s rejected mode \"%s\" "
1654
			   "(%dx%d): %s\n", Crtc1->Name, Mode->name,
1655
			   Mode->HDisplay, Mode->VDisplay,
1656
			   RHDModeStatusToString(ret));
1657
		goto rejected;
1658
	    }
1659
 
1660
	    /* Check what Crtc2 thinks this should be. */
1661
	    ret = Crtc2->FBValid(Crtc2, VirtualX, VirtualY, pScrn->bitsPerPixel,
1662
				 rhdPtr->FbScanoutStart, rhdPtr->FbScanoutSize, &Pitch2);
1663
	    if (ret != MODE_OK) {
1664
		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s rejected mode \"%s\" "
1665
			   "(%dx%d): %s\n", Crtc2->Name, Mode->name,
1666
			   Mode->HDisplay, Mode->VDisplay,
1667
			   RHDModeStatusToString(ret));
1668
		goto rejected;
1669
	    }
1670
 
1671
	    /* when needed, check whether this matches our 2D engine as well. */
1672
	    if (rhdPtr->AccelMethod >= RHD_ACCEL_XAA)
1673
		if (rhdPtr->ChipSet < RHD_R600) /* badly abstracted, i know */
1674
#if 0
1675
		    if (!R5xx2DFBValid(rhdPtr, VirtualX, VirtualY,
1676
				       pScrn->bitsPerPixel, rhdPtr->FbScanoutStart,
1677
				       rhdPtr->FbScanoutSize, Pitch1)) {
1678
			xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D acceleration "
1679
				   "rejected mode \"%s\" (%dx%d).\n",
1680
				   Mode->name, Mode->HDisplay, Mode->VDisplay);
1681
			goto rejected;
1682
		    }
1683
#endif
1684
	    /* mode is perfectly valid FB wise */
1685
	    Mode = Mode->next;
1686
	    pScrn->virtualX = VirtualX;
1687
	    pScrn->virtualY = VirtualY;
1688
	    pScrn->displayWidth = Pitch1;
1689
	    continue;
1690
 
1691
	rejected:
1692
	    Next = Mode->next;
1693
	    Modes = rhdModeDelete(Modes, Mode);
1694
	    Mode = Next;
1695
	} else
1696
	    Mode = Mode->next;
1697
    }
1698
}
1699
 
1700
/*
1701
 * RandR entry point: fixup per Crtc and Output (in RandR speech)
1702
 * Due to misconceptions we might end up fixing *everything* here.
1703
 */
1704
int
1705
RHDRRModeFixup(ScrnInfoPtr pScrn, DisplayModePtr Mode, struct rhdCrtc *Crtc,
1706
	       struct rhdConnector *Connector, struct rhdOutput *Output,
1707
	       struct rhdMonitor *Monitor, Bool ScaledMode)
1708
{
1709
    RHDPtr rhdPtr = RHDPTR(pScrn);
1710
    int i, Status;
1711
 
1712
    ASSERT(Connector);
1713
    ASSERT(Output);
1714
    RHDFUNC(Output);
1715
 
1716
    Status = rhdModeSanity(rhdPtr, Mode);
1717
    if (Status != MODE_OK)
1718
        return Status;
1719
 
1720
    rhdModeFillOutCrtcValues(Mode);
1721
 
1722
    if (!ScaledMode) {
1723
    /* We don't want to loop around this forever */
1724
	for (i = 0; i < RHD_MODE_VALIDATION_LOOPS; i++) {
1725
        Mode->CrtcHAdjusted = FALSE;
1726
        Mode->CrtcVAdjusted = FALSE;
1727
 
1728
	/* Sanitize */
1729
        Status = rhdModeCrtcSanity(Mode);
1730
        if (Status != MODE_OK)
1731
            return Status;
1732
        if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
1733
            continue;
1734
 
1735
	if (Crtc) {
1736
	    /* Check FB */
1737
	    Status = Crtc->FBValid(Crtc, Mode->CrtcHDisplay, Mode->CrtcVDisplay,
1738
				   pScrn->bitsPerPixel, rhdPtr->FbScanoutStart,
1739
				   rhdPtr->FbScanoutSize, NULL);
1740
	    if (Status != MODE_OK)
1741
		return Status;
1742
 
1743
		if (Crtc->ScaleValid) {
1744
		    Status = Crtc->ScaleValid(Crtc, RHD_CRTC_SCALE_TYPE_NONE, Mode, NULL);
1745
	    if (Status != MODE_OK)
1746
		return Status;
1747
	    if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
1748
		continue;
1749
		}
1750
 
1751
		/* Check Crtc */
1752
		Status = Crtc->ModeValid(Crtc, Mode);
1753
		if (Status != MODE_OK)
1754
		    return Status;
1755
		if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
1756
		    continue;
1757
 
1758
	    /* Check PLL */
1759
	    if (Crtc->PLL->Valid) {
1760
		Status = Crtc->PLL->Valid(Crtc->PLL, Mode->Clock);
1761
		if (Status != MODE_OK)
1762
		    return Status;
1763
		if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
1764
		    continue;
1765
	    }
1766
	}
1767
 
1768
	/* Check Output */
1769
	Status = Output->ModeValid(Output, Mode);
1770
	if (Status != MODE_OK)
1771
	    return Status;
1772
	if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
1773
	    continue;
1774
 
1775
	/* Check the monitor attached to this output */
1776
	if (Connector->Monitor)
1777
	    Status = rhdMonitorValid(Connector->Monitor, Mode);
1778
	if (Status != MODE_OK)
1779
	    return Status;
1780
	if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
1781
	    continue;
1782
 
1783
	/* Seems to be good */
1784
	break;
1785
    }
1786
 
1787
	if (i == RHD_MODE_VALIDATION_LOOPS) {
1788
	/* Mode has been bouncing around for ages, on adjustments */
1789
	xf86DrvMsg(Output->scrnIndex, X_ERROR,
1790
		   "%s: Mode \"%s\" (%dx%d:%3.1fMhz) was thrown around"
1791
		   " for too long.\n", __func__, Mode->name,
1792
		   Mode->HDisplay, Mode->VDisplay, Mode->Clock/1000.0);
1793
	return MODE_ERROR;
1794
    }
1795
 
1796
    /* throw them at the configured monitor */
1797
    if (Monitor) {
1798
	Status = rhdMonitorValid(Monitor, Mode);
1799
	if (Status != MODE_OK)
1800
	    return Status;
1801
    }
1802
 
1803
    } else {
1804
	if (Crtc) {
1805
	    Status = rhdModeValidateCrtc(Crtc, Mode, VALIDATE_SCALE_FROM);
1806
	    if (Status != MODE_OK)
1807
		return Status;
1808
	}
1809
    }
1810
 
1811
    /* Did we set up virtual resolution already? */
1812
    if ((pScrn->virtualX > 0) && (pScrn->virtualY > 0)) {
1813
        if (pScrn->virtualX < Mode->CrtcHDisplay)
1814
            return MODE_VIRTUAL_X;
1815
        if (pScrn->virtualY < Mode->CrtcVDisplay)
1816
            return MODE_VIRTUAL_Y;
1817
    }
1818
 
1819
    return MODE_OK;
1820
}
1821
#endif
1822
 
1823
/*
1824
 * RHDRRValidateScaledToMode(): like RHDValidateScaledMode() - but we cannot validate against a CRTC
1825
 * as this isn't known when this function is called. So at least validate against the 'output' here.
1826
 */
1827
int
1828
RHDRRValidateScaledToMode(struct rhdOutput *Output, DisplayModePtr Mode)
1829
{
1830
    RHDPtr rhdPtr = RHDPTRI(Output);
1831
    int Status;
1832
    int i;
1833
 
1834
    RHDFUNC(Output);
1835
 
1836
    Status = rhdModeSanity(rhdPtr, Mode);
1837
    if (Status != MODE_OK)
1838
        return Status;
1839
 
1840
    rhdModeFillOutCrtcValues(Mode);
1841
 
1842
    for (i = 0; i < RHD_MODE_VALIDATION_LOOPS; i++) {
1843
 
1844
        Mode->CrtcHAdjusted = FALSE;
1845
        Mode->CrtcVAdjusted = FALSE;
1846
 
1847
        Status = rhdModeCrtcSanity(Mode);
1848
        if (Status != MODE_OK)
1849
            return Status;
1850
        if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
1851
            continue;
1852
 
1853
	/* Check the output */
1854
	Status = Output->ModeValid(Output, Mode);
1855
	if (Status != MODE_OK)
1856
	    return Status;
1857
	if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
1858
	    continue; /* restart. */
1859
 
1860
	/* Check the monitor attached to this output */
1861
	if (Output->Connector && Output->Connector->Monitor)
1862
	    Status = rhdMonitorValid(Output->Connector->Monitor, Mode);
1863
	if (Status != MODE_OK)
1864
	    return Status;
1865
	if (Mode->CrtcHAdjusted || Mode->CrtcVAdjusted)
1866
	    continue;
1867
 
1868
	break;
1869
    }
1870
 
1871
    if (i == RHD_MODE_VALIDATION_LOOPS) {
1872
	/* Mode has been bouncing around for ages, on adjustments */
1873
	xf86DrvMsg(Output->scrnIndex, X_ERROR,
1874
		   "%s: Mode \"%s\" (%dx%d:%3.1fMhz) was thrown around"
1875
		   " for too long.\n", __func__, Mode->name,
1876
		   Mode->HDisplay, Mode->VDisplay, Mode->Clock/1000.0);
1877
	return MODE_ERROR;
1878
    }
1879
 
1880
    /* Do we want to also validate against a configured monitor? */
1881
    if (rhdPtr->ConfigMonitor) {
1882
	Status = rhdMonitorValid(rhdPtr->ConfigMonitor, Mode);
1883
	if (Status != MODE_OK)
1884
	    return Status;
1885
    }
1886
 
1887
    return MODE_OK;
1888
}
1889
 
1890
/*
1891
 * RHDSynthModes(): synthesize CVT modes for well known resolutions.
1892
 * For now we assume we want reduced modes only.
1893
 */
1894
void
1895
RHDSynthModes(int scrnIndex, DisplayModePtr Mode)
1896
{
1897
    RHDPtr rhdPtr = (RHDPtr)(scrnIndex);
1898
    DisplayModePtr Tmp;
1899
    unsigned int i;
1900
 
1901
    struct resolution{
1902
	int x;
1903
	int y;
1904
    } resolution_list[] = {
1905
	{  320,  200 },  /* CGA */
1906
	{  320,  240 },  /* QVGA */
1907
	{  640,  480 },  /* VGA */
1908
	{  720,  480 },  /* NTSC */
1909
	{  854,  480 },  /* WVGA */
1910
	{  768,  576 },  /* PAL */
1911
	{  800,  600 },  /* SVGA */
1912
	{ 1024,  768 },  /* XGA */
1913
	{ 1152,  768 },
1914
	{ 1280,  720 },  /* HD720 */
1915
	{ 1280,  960 },
1916
	{ 1280,  854 },
1917
	{ 1280,  960 },
1918
	{ 1280, 1024 },  /* SXGA */
1919
	{ 1440,  960 },
1920
 	{ 1400, 1050 },  /* SXGA+ */
1921
	{ 1680, 1050 },  /* WSXGA+ */
1922
	{ 1600, 1200 },  /* UXGA */
1923
	{ 1920, 1080 },  /* HD1080 */
1924
	{ 1920, 1200 },  /* WUXGA */
1925
	{ 2048, 1536 },  /* QXGA */
1926
	{ 2560, 1600 },  /* WQXGA */
1927
	{ 2560, 2048 }   /* QSXGA */
1928
    };
1929
 
1930
    RHDFUNC(pScrn);
1931
 
1932
    for (i = 0; i < (sizeof(resolution_list) / sizeof(struct resolution)); i++) {
1933
	/*
1934
	 *  chances are that the native mode of a display is a CVT mode with 60 Hz.
1935
	 *  This will make RandR share the CRTC which is undesireable for scaling.
1936
	 *  This we 'tweak' the frequency to be slightly higher.
1937
	 *  Don't tell me it's ugly - I know this already.
1938
	 */
1939
	Tmp = RHDCVTMode(resolution_list[i].x, resolution_list[i].y, 60.5, TRUE, FALSE);
1940
	Tmp->status = MODE_OK;
1941
	rhdModeFillOutCrtcValues(Tmp);
1942
	xfree(Tmp->name);
1943
	Tmp->name = xnfalloc(20);
1944
	snprintf(Tmp->name, 20, "%ix%iScaled",resolution_list[i].x,resolution_list[i].y);
1945
	Tmp->type = M_T_BUILTIN;
1946
  //  if (rhdPtr->verbosity > 6) {
1947
  //      xf86DrvMsg(scrnIndex, X_INFO, "%s: Adding Modeline ",__func__);
1948
  //      RHDPrintModeline(Tmp);
1949
  //  }
1950
	RHDModesAdd(Mode, Tmp);
1951
    }
1952
}