radeon_modes.c revision 9d25673e
1209ff23fSmrg/*
2209ff23fSmrg * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and
3209ff23fSmrg *                VA Linux Systems Inc., Fremont, California.
4209ff23fSmrg *
5209ff23fSmrg * All Rights Reserved.
6209ff23fSmrg *
7209ff23fSmrg * Permission is hereby granted, free of charge, to any person obtaining
8209ff23fSmrg * a copy of this software and associated documentation files (the
9209ff23fSmrg * "Software"), to deal in the Software without restriction, including
10209ff23fSmrg * without limitation on the rights to use, copy, modify, merge,
11209ff23fSmrg * publish, distribute, sublicense, and/or sell copies of the Software,
12209ff23fSmrg * and to permit persons to whom the Software is furnished to do so,
13209ff23fSmrg * subject to the following conditions:
14209ff23fSmrg *
15209ff23fSmrg * The above copyright notice and this permission notice (including the
16209ff23fSmrg * next paragraph) shall be included in all copies or substantial
17209ff23fSmrg * portions of the Software.
18209ff23fSmrg *
19209ff23fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20209ff23fSmrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21209ff23fSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22209ff23fSmrg * NON-INFRINGEMENT.  IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR
23209ff23fSmrg * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24209ff23fSmrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25209ff23fSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26209ff23fSmrg * DEALINGS IN THE SOFTWARE.
27209ff23fSmrg */
28209ff23fSmrg
29209ff23fSmrg#ifdef HAVE_CONFIG_H
30209ff23fSmrg#include "config.h"
31209ff23fSmrg#endif
32209ff23fSmrg
33209ff23fSmrg/*
34209ff23fSmrg * Authors:
35209ff23fSmrg *   Kevin E. Martin <martin@xfree86.org>
36209ff23fSmrg *   Rickard E. Faith <faith@valinux.com>
37209ff23fSmrg *   Alan Hourihane <alanh@fairlite.demon.co.uk>
38209ff23fSmrg */
39209ff23fSmrg
40209ff23fSmrg#include <string.h>
41209ff23fSmrg#include <stdio.h>
42209ff23fSmrg
43209ff23fSmrg#include "xf86.h"
44209ff23fSmrg				/* Driver data structures */
45209ff23fSmrg#include "randrstr.h"
46209ff23fSmrg#include "radeon_probe.h"
47209ff23fSmrg#include "radeon.h"
48209ff23fSmrg#include "radeon_reg.h"
49209ff23fSmrg#include "radeon_macros.h"
50209ff23fSmrg#include "radeon_version.h"
51209ff23fSmrg#include "radeon_atombios.h"
52209ff23fSmrg
53209ff23fSmrg#include "xf86Modes.h"
54209ff23fSmrg				/* DDC support */
55209ff23fSmrg#include "xf86DDC.h"
56209ff23fSmrg#include <randrstr.h>
57209ff23fSmrg
58209ff23fSmrgvoid RADEONSetPitch (ScrnInfoPtr pScrn)
59209ff23fSmrg{
60209ff23fSmrg    int  dummy = pScrn->virtualX;
61209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
62209ff23fSmrg    int pitch_mask = 0;
63209ff23fSmrg    int align_large;
64209ff23fSmrg
65209ff23fSmrg    align_large = info->allowColorTiling || IS_AVIVO_VARIANT;
66209ff23fSmrg
67209ff23fSmrg    /* FIXME: May need to validate line pitch here */
68b7e1c893Smrg    if (info->ChipFamily < CHIP_FAMILY_R600) {
69b7e1c893Smrg	switch (pScrn->depth / 8) {
70ad43ddacSmrg	case 1: pitch_mask = align_large ? 256 : 128;
71b7e1c893Smrg	    break;
72ad43ddacSmrg	case 2: pitch_mask = align_large ? 128 : 32;
73b7e1c893Smrg	    break;
74b7e1c893Smrg	case 3:
75ad43ddacSmrg	case 4: pitch_mask = align_large ? 64 : 16;
76b7e1c893Smrg	    break;
77b7e1c893Smrg	}
78b7e1c893Smrg    } else
79ad43ddacSmrg	pitch_mask = 256; /* r6xx/r7xx need 256B alignment for accel */
80b7e1c893Smrg
81ad43ddacSmrg    dummy = RADEON_ALIGN(pScrn->virtualX, pitch_mask);
82209ff23fSmrg    pScrn->displayWidth = dummy;
83209ff23fSmrg    info->CurrentLayout.displayWidth = pScrn->displayWidth;
84209ff23fSmrg
85209ff23fSmrg}
86209ff23fSmrg
87209ff23fSmrgstatic DisplayModePtr
88209ff23fSmrgRADEONTVModes(xf86OutputPtr output)
89209ff23fSmrg{
90209ff23fSmrg    DisplayModePtr new  = NULL;
91209ff23fSmrg
92209ff23fSmrg    /* just a place holder */
93209ff23fSmrg    new = xf86CVTMode(800, 600, 60.00, FALSE, FALSE);
949d25673eSmacallan    xf86SetModeDefaultName(new);
95209ff23fSmrg    new->type = M_T_DRIVER | M_T_PREFERRED;
96209ff23fSmrg
97209ff23fSmrg    return new;
98209ff23fSmrg}
99209ff23fSmrg
100209ff23fSmrgstatic DisplayModePtr
101209ff23fSmrgRADEONATOMTVModes(xf86OutputPtr output)
102209ff23fSmrg{
103209ff23fSmrg    DisplayModePtr  last       = NULL;
104209ff23fSmrg    DisplayModePtr  new        = NULL;
105209ff23fSmrg    DisplayModePtr  first      = NULL;
106b7e1c893Smrg    int i;
107209ff23fSmrg    /* Add some common sizes */
108b7e1c893Smrg    int widths[5] =  {640, 720, 800, 848, 1024};
109b7e1c893Smrg    int heights[5] = {480, 480, 600, 480,  768};
110209ff23fSmrg
111209ff23fSmrg    for (i = 0; i < 5; i++) {
112b7e1c893Smrg	new = xf86CVTMode(widths[i], heights[i], 60.0, FALSE, FALSE);
1139d25673eSmacallan	xf86SetModeDefaultName(new);
114209ff23fSmrg
115209ff23fSmrg	new->type       = M_T_DRIVER;
116209ff23fSmrg
117209ff23fSmrg	new->next       = NULL;
118209ff23fSmrg	new->prev       = last;
119209ff23fSmrg
120209ff23fSmrg	if (last) last->next = new;
121209ff23fSmrg	last = new;
122209ff23fSmrg	if (!first) first = new;
123209ff23fSmrg    }
124209ff23fSmrg
125209ff23fSmrg    if (last) {
126209ff23fSmrg	last->next   = NULL; //first;
127209ff23fSmrg	first->prev  = NULL; //last;
128209ff23fSmrg    }
129209ff23fSmrg
130209ff23fSmrg    return first;
131209ff23fSmrg}
132209ff23fSmrg
133209ff23fSmrg/* This is used only when no mode is specified for FP and no ddc is
134209ff23fSmrg * available.  We force it to native mode, if possible.
135209ff23fSmrg */
136209ff23fSmrgstatic DisplayModePtr RADEONFPNativeMode(xf86OutputPtr output)
137209ff23fSmrg{
138209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
139209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
140b7e1c893Smrg    radeon_native_mode_ptr native_mode = &radeon_output->native_mode;
141209ff23fSmrg    DisplayModePtr  new   = NULL;
142209ff23fSmrg    char            stmp[32];
143209ff23fSmrg
144b7e1c893Smrg    if (native_mode->PanelXRes != 0 &&
145b7e1c893Smrg	native_mode->PanelYRes != 0 &&
146b7e1c893Smrg	native_mode->DotClock != 0) {
147209ff23fSmrg
148209ff23fSmrg	new             = xnfcalloc(1, sizeof (DisplayModeRec));
149b7e1c893Smrg	sprintf(stmp, "%dx%d", native_mode->PanelXRes, native_mode->PanelYRes);
150209ff23fSmrg	new->name       = xnfalloc(strlen(stmp) + 1);
151a7f02474Smrg	/*
152a7f02474Smrg	 * XXX - expanded __UNCONST() version, new->name became const in
153a7f02474Smrg	 * xorg-server 21.*
154a7f02474Smrg	 */
155a7f02474Smrg	strcpy((void *)(unsigned long)(const void *)new->name, stmp);
156b7e1c893Smrg	new->HDisplay   = native_mode->PanelXRes;
157b7e1c893Smrg	new->VDisplay   = native_mode->PanelYRes;
158209ff23fSmrg
159b7e1c893Smrg	new->HTotal     = new->HDisplay + native_mode->HBlank;
160b7e1c893Smrg	new->HSyncStart = new->HDisplay + native_mode->HOverPlus;
161b7e1c893Smrg	new->HSyncEnd   = new->HSyncStart + native_mode->HSyncWidth;
162b7e1c893Smrg	new->VTotal     = new->VDisplay + native_mode->VBlank;
163b7e1c893Smrg	new->VSyncStart = new->VDisplay + native_mode->VOverPlus;
164b7e1c893Smrg	new->VSyncEnd   = new->VSyncStart + native_mode->VSyncWidth;
165209ff23fSmrg
166b7e1c893Smrg	new->Clock      = native_mode->DotClock;
167ad43ddacSmrg	new->Flags      = native_mode->Flags;
168209ff23fSmrg
169209ff23fSmrg	if (new) {
170209ff23fSmrg	    new->type       = M_T_DRIVER | M_T_PREFERRED;
171209ff23fSmrg
172209ff23fSmrg	    new->next       = NULL;
173209ff23fSmrg	    new->prev       = NULL;
174209ff23fSmrg	}
175209ff23fSmrg
176209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Added native panel mode: %dx%d\n",
177b7e1c893Smrg		   native_mode->PanelXRes, native_mode->PanelYRes);
178ad43ddacSmrg    } else if (native_mode->PanelXRes != 0 &&
179ad43ddacSmrg	       native_mode->PanelYRes != 0) {
180ad43ddacSmrg
181ad43ddacSmrg	new = xf86CVTMode(native_mode->PanelXRes, native_mode->PanelYRes, 60.0, TRUE, FALSE);
182ad43ddacSmrg
183ad43ddacSmrg	if (new) {
184ad43ddacSmrg	    new->type       = M_T_DRIVER | M_T_PREFERRED;
1859d25673eSmacallan	    xf86SetModeDefaultName(new);
186ad43ddacSmrg
187ad43ddacSmrg	    new->next       = NULL;
188ad43ddacSmrg	    new->prev       = NULL;
189ad43ddacSmrg	}
190ad43ddacSmrg
191ad43ddacSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Added native panel mode using CVT: %dx%d\n",
192ad43ddacSmrg		   native_mode->PanelXRes, native_mode->PanelYRes);
193209ff23fSmrg    }
194209ff23fSmrg
195209ff23fSmrg    return new;
196209ff23fSmrg}
197209ff23fSmrg
198b7e1c893Smrg#if defined(__powerpc__)
199b7e1c893Smrg/* Apple eMacs need special modes for the internal CRT, e.g.,
200b7e1c893Smrg * Modeline "640x480"    62.12   640  680  752  864  480 481 484  521 +HSync +Vsync
201b7e1c893Smrg * Modeline "800x600"    76.84   800  848  936 1072  600 601 604  640 +HSync +Vsync
202b7e1c893Smrg * Modeline "1024x768"   99.07  1024 1088 1200 1376  768 769 772  809 +HSync +Vsync
203b7e1c893Smrg * Modeline "1152x864"  112.36  1152 1224 1352 1552  864 865 868  905 +HSync +Vsync
204b7e1c893Smrg * Modeline "1280x960"  124.54  1280 1368 1504 1728  960 961 964 1001 +HSync +Vsync
205b7e1c893Smrg */
206b7e1c893Smrgstatic DisplayModePtr RADEONeMacModes(xf86OutputPtr output)
207b7e1c893Smrg{
208b7e1c893Smrg    ScrnInfoPtr pScrn = output->scrn;
209b7e1c893Smrg    DisplayModePtr last=NULL, new=NULL, first=NULL;
210b7e1c893Smrg    int i, *modep;
211b7e1c893Smrg    static const char *modenames[5] = {
212b7e1c893Smrg	"640x480", "800x600", "1024x768", "1152x864", "1280x960"
213b7e1c893Smrg    };
214b7e1c893Smrg    static int modes[9*5] = {
215b7e1c893Smrg	 62120,  640,  680,  752,  864, 480, 481, 484,  521,
216b7e1c893Smrg	 76840,  800,  848,  936, 1072, 600, 601, 604,  640,
217b7e1c893Smrg	 99070, 1024, 1088, 1200, 1376, 768, 769, 772,  809,
218b7e1c893Smrg	112360, 1152, 1224, 1352, 1552, 864, 865, 868,  905,
219b7e1c893Smrg	124540, 1280, 1368, 1504, 1728, 960, 961, 964, 1001
220b7e1c893Smrg    };
221b7e1c893Smrg    modep = modes;
222b7e1c893Smrg
223b7e1c893Smrg    for (i=0; i<5; i++) {
224b7e1c893Smrg	new = xnfcalloc(1, sizeof (DisplayModeRec));
225b7e1c893Smrg	if (new) {
226b7e1c893Smrg	    new->name       = xnfalloc(strlen(modenames[i]) + 1);
227b7e1c893Smrg	    strcpy(new->name, modenames[i]);
228b7e1c893Smrg	    new->Clock      = *modep++;
229b7e1c893Smrg
230b7e1c893Smrg	    new->HDisplay   = *modep++;
231b7e1c893Smrg	    new->HSyncStart = *modep++;
232b7e1c893Smrg	    new->HSyncEnd   = *modep++;
233b7e1c893Smrg	    new->HTotal     = *modep++;
234b7e1c893Smrg
235b7e1c893Smrg	    new->VDisplay   = *modep++;
236b7e1c893Smrg	    new->VSyncStart = *modep++;
237b7e1c893Smrg	    new->VSyncEnd   = *modep++;
238b7e1c893Smrg	    new->VTotal     = *modep++;
239b7e1c893Smrg
240b7e1c893Smrg	    new->Flags      = 0;
241b7e1c893Smrg	    new->type       = M_T_DRIVER;
242b7e1c893Smrg	    if (i==2)
243b7e1c893Smrg		new->type |= M_T_PREFERRED;
244b7e1c893Smrg	    new->next       = NULL;
245b7e1c893Smrg	    new->prev       = last;
246b7e1c893Smrg	    if (last) last->next = new;
247b7e1c893Smrg	    last = new;
248b7e1c893Smrg	    if (!first) first = new;
249b7e1c893Smrg	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Added eMac mode %s\n", modenames[i]);
250b7e1c893Smrg	}
251b7e1c893Smrg    }
252b7e1c893Smrg
253b7e1c893Smrg    return first;
254b7e1c893Smrg}
255b7e1c893Smrg#endif
256b7e1c893Smrg
257209ff23fSmrg/* this function is basically a hack to add the screen modes */
258209ff23fSmrgstatic void RADEONAddScreenModes(xf86OutputPtr output, DisplayModePtr *modeList)
259209ff23fSmrg{
260209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
261209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
262b7e1c893Smrg    radeon_native_mode_ptr native_mode = &radeon_output->native_mode;
263209ff23fSmrg    DisplayModePtr  last       = NULL;
264209ff23fSmrg    DisplayModePtr  new        = NULL;
265209ff23fSmrg    DisplayModePtr  first      = NULL;
266209ff23fSmrg    int             count      = 0;
267209ff23fSmrg    int             i, width, height;
268861b9feeSmrg    const char **ppModeName = pScrn->display->modes;
269209ff23fSmrg
270209ff23fSmrg    first = last = *modeList;
271209ff23fSmrg
272209ff23fSmrg    /* We have a flat panel connected to the primary display, and we
273209ff23fSmrg     * don't have any DDC info.
274209ff23fSmrg     */
275209ff23fSmrg    for (i = 0; ppModeName[i] != NULL; i++) {
276209ff23fSmrg
277209ff23fSmrg	if (sscanf(ppModeName[i], "%dx%d", &width, &height) != 2) continue;
278209ff23fSmrg
279b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
280209ff23fSmrg	    /* already added the native mode */
281b7e1c893Smrg	    if (width == native_mode->PanelXRes && height == native_mode->PanelYRes)
282209ff23fSmrg		continue;
283209ff23fSmrg
284209ff23fSmrg	    /* Note: We allow all non-standard modes as long as they do not
285209ff23fSmrg	     * exceed the native resolution of the panel.  Since these modes
286209ff23fSmrg	     * need the internal RMX unit in the video chips (and there is
287209ff23fSmrg	     * only one per card), this will only apply to the primary head.
288209ff23fSmrg	     */
289b7e1c893Smrg	    if (width < 320 || width > native_mode->PanelXRes ||
290b7e1c893Smrg		height < 200 || height > native_mode->PanelYRes) {
291209ff23fSmrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
292209ff23fSmrg			   "Mode %s is out of range.\n", ppModeName[i]);
293209ff23fSmrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
294209ff23fSmrg			   "Valid FP modes must be between 320x200-%dx%d\n",
295b7e1c893Smrg			   native_mode->PanelXRes, native_mode->PanelYRes);
296209ff23fSmrg		continue;
297209ff23fSmrg	    }
298209ff23fSmrg	}
299209ff23fSmrg
300209ff23fSmrg	new = xf86CVTMode(width, height, 60.0, FALSE, FALSE);
3019d25673eSmacallan	xf86SetModeDefaultName(new);
302209ff23fSmrg
303209ff23fSmrg	new->type      |= M_T_USERDEF;
304209ff23fSmrg
305209ff23fSmrg	new->next       = NULL;
306209ff23fSmrg	new->prev       = last;
307209ff23fSmrg
308209ff23fSmrg	if (last) last->next = new;
309209ff23fSmrg	last = new;
310209ff23fSmrg	if (!first) first = new;
311209ff23fSmrg
312209ff23fSmrg	count++;
313209ff23fSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
314209ff23fSmrg		   "Adding Screen mode: %s\n", new->name);
315209ff23fSmrg    }
316209ff23fSmrg
317209ff23fSmrg
318209ff23fSmrg    /* Close the doubly-linked mode list, if we found any usable modes */
319209ff23fSmrg    if (last) {
320209ff23fSmrg	last->next   = NULL; //first;
321209ff23fSmrg	first->prev  = NULL; //last;
322209ff23fSmrg	*modeList = first;
323209ff23fSmrg    }
324209ff23fSmrg
325209ff23fSmrg    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
326209ff23fSmrg	       "Total number of valid Screen mode(s) added: %d\n", count);
327209ff23fSmrg
328209ff23fSmrg}
329209ff23fSmrg
330b7e1c893Smrg/* BIOS may not have right panel size, we search through all supported
331b7e1c893Smrg * DDC modes looking for the maximum panel size.
332b7e1c893Smrg */
333b7e1c893Smrgstatic void
334b7e1c893SmrgRADEONUpdatePanelSize(xf86OutputPtr output)
335b7e1c893Smrg{
336b7e1c893Smrg    ScrnInfoPtr pScrn = output->scrn;
337b7e1c893Smrg    RADEONInfoPtr  info       = RADEONPTR(pScrn);
338b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
339b7e1c893Smrg    radeon_native_mode_ptr native_mode = &radeon_output->native_mode;
340b7e1c893Smrg    int             j;
341b7e1c893Smrg    xf86MonPtr ddc = output->MonInfo;
342b7e1c893Smrg    DisplayModePtr  p;
343b7e1c893Smrg
344b7e1c893Smrg    // update output's native mode
345b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
346b7e1c893Smrg	radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output);
347b7e1c893Smrg	if (radeon_encoder) {
348b7e1c893Smrg	    radeon_lvds_ptr lvds = (radeon_lvds_ptr)radeon_encoder->dev_priv;
349b7e1c893Smrg	    if (lvds)
350b7e1c893Smrg		radeon_output->native_mode = lvds->native_mode;
351b7e1c893Smrg	}
352b7e1c893Smrg    }
353b7e1c893Smrg
354b7e1c893Smrg    // crtc should handle?
355b7e1c893Smrg    if ((info->UseBiosDividers && native_mode->DotClock != 0) || (ddc == NULL))
356b7e1c893Smrg       return;
357b7e1c893Smrg
358b7e1c893Smrg    /* Go thru detailed timing table first */
359b7e1c893Smrg    for (j = 0; j < 4; j++) {
360b7e1c893Smrg	if (ddc->det_mon[j].type == 0) {
361b7e1c893Smrg	    struct detailed_timings *d_timings =
362b7e1c893Smrg		&ddc->det_mon[j].section.d_timings;
363b7e1c893Smrg           int match = 0;
364b7e1c893Smrg
365b7e1c893Smrg           /* If we didn't get a panel clock or guessed one, try to match the
366b7e1c893Smrg            * mode with the panel size. We do that because we _need_ a panel
367b7e1c893Smrg            * clock, or ValidateFPModes will fail, even when UseBiosDividers
368b7e1c893Smrg            * is set.
369b7e1c893Smrg            */
370b7e1c893Smrg           if (native_mode->DotClock == 0 &&
371b7e1c893Smrg               native_mode->PanelXRes == d_timings->h_active &&
372b7e1c893Smrg               native_mode->PanelYRes == d_timings->v_active)
373b7e1c893Smrg               match = 1;
374b7e1c893Smrg
375b7e1c893Smrg           /* If we don't have a BIOS provided panel data with fixed dividers,
376b7e1c893Smrg            * check for a larger panel size
377b7e1c893Smrg            */
378b7e1c893Smrg	    if (native_mode->PanelXRes < d_timings->h_active &&
379b7e1c893Smrg		native_mode->PanelYRes < d_timings->v_active &&
380b7e1c893Smrg		!info->UseBiosDividers)
381b7e1c893Smrg		match = 1;
382b7e1c893Smrg
383b7e1c893Smrg             if (match) {
384b7e1c893Smrg		native_mode->PanelXRes  = d_timings->h_active;
385b7e1c893Smrg		native_mode->PanelYRes  = d_timings->v_active;
386b7e1c893Smrg		native_mode->DotClock   = d_timings->clock / 1000;
387b7e1c893Smrg		native_mode->HOverPlus  = d_timings->h_sync_off;
388b7e1c893Smrg		native_mode->HSyncWidth = d_timings->h_sync_width;
389b7e1c893Smrg		native_mode->HBlank     = d_timings->h_blanking;
390b7e1c893Smrg		native_mode->VOverPlus  = d_timings->v_sync_off;
391b7e1c893Smrg		native_mode->VSyncWidth = d_timings->v_sync_width;
392b7e1c893Smrg		native_mode->VBlank     = d_timings->v_blanking;
393b7e1c893Smrg                native_mode->Flags      = (d_timings->interlaced ? V_INTERLACE : 0);
394b7e1c893Smrg                switch (d_timings->misc) {
395b7e1c893Smrg                case 0: native_mode->Flags |= V_NHSYNC | V_NVSYNC; break;
396b7e1c893Smrg                case 1: native_mode->Flags |= V_PHSYNC | V_NVSYNC; break;
397b7e1c893Smrg                case 2: native_mode->Flags |= V_NHSYNC | V_PVSYNC; break;
398b7e1c893Smrg                case 3: native_mode->Flags |= V_PHSYNC | V_PVSYNC; break;
399b7e1c893Smrg                }
400b7e1c893Smrg                xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel infos found from DDC detailed: %dx%d\n",
401b7e1c893Smrg                           native_mode->PanelXRes, native_mode->PanelYRes);
402b7e1c893Smrg	    }
403b7e1c893Smrg	}
404b7e1c893Smrg    }
405b7e1c893Smrg
406b7e1c893Smrg    if (info->UseBiosDividers && native_mode->DotClock != 0)
407b7e1c893Smrg       return;
408b7e1c893Smrg
409b7e1c893Smrg    /* Search thru standard VESA modes from EDID */
410b7e1c893Smrg    for (j = 0; j < 8; j++) {
411b7e1c893Smrg	if ((native_mode->PanelXRes < ddc->timings2[j].hsize) &&
412b7e1c893Smrg	    (native_mode->PanelYRes < ddc->timings2[j].vsize)) {
413b7e1c893Smrg	    for (p = pScrn->monitor->Modes; p; p = p->next) {
414b7e1c893Smrg		if ((ddc->timings2[j].hsize == p->HDisplay) &&
415b7e1c893Smrg		    (ddc->timings2[j].vsize == p->VDisplay)) {
416b7e1c893Smrg		    float  refresh =
417b7e1c893Smrg			(float)p->Clock * 1000.0 / p->HTotal / p->VTotal;
418b7e1c893Smrg
419c459fb98Schristos		    if (fabsf((float)ddc->timings2[j].refresh - refresh) < 1.0) {
420b7e1c893Smrg			/* Is this good enough? */
421b7e1c893Smrg			native_mode->PanelXRes  = ddc->timings2[j].hsize;
422b7e1c893Smrg			native_mode->PanelYRes  = ddc->timings2[j].vsize;
423b7e1c893Smrg			native_mode->HBlank     = p->HTotal - p->HDisplay;
424b7e1c893Smrg			native_mode->HOverPlus  = p->HSyncStart - p->HDisplay;
425b7e1c893Smrg			native_mode->HSyncWidth = p->HSyncEnd - p->HSyncStart;
426b7e1c893Smrg			native_mode->VBlank     = p->VTotal - p->VDisplay;
427b7e1c893Smrg			native_mode->VOverPlus  = p->VSyncStart - p->VDisplay;
428b7e1c893Smrg			native_mode->VSyncWidth = p->VSyncEnd - p->VSyncStart;
429b7e1c893Smrg			native_mode->DotClock   = p->Clock;
430b7e1c893Smrg                        native_mode->Flags      = p->Flags;
431b7e1c893Smrg                        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel infos found from DDC VESA/EDID: %dx%d\n",
432b7e1c893Smrg                                   native_mode->PanelXRes, native_mode->PanelYRes);
433b7e1c893Smrg		    }
434b7e1c893Smrg		}
435b7e1c893Smrg	    }
436b7e1c893Smrg	}
437b7e1c893Smrg    }
438b7e1c893Smrg}
439b7e1c893Smrg
440b7e1c893Smrgstatic void
441b7e1c893Smrgradeon_add_common_modes(xf86OutputPtr output, DisplayModePtr modes)
442b7e1c893Smrg{
443b7e1c893Smrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
444b7e1c893Smrg    radeon_native_mode_ptr native_mode = &radeon_output->native_mode;
445b7e1c893Smrg    DisplayModePtr  last       = NULL;
446b7e1c893Smrg    DisplayModePtr  new        = NULL;
447b7e1c893Smrg    DisplayModePtr  first      = NULL;
448b7e1c893Smrg    int i;
449b7e1c893Smrg    /* Add some common sizes */
450b7e1c893Smrg    int widths[15]  = {640, 800, 1024, 1152, 1280, 1280, 1280, 1280, 1280, 1440, 1400, 1680, 1600, 1920, 1920};
451b7e1c893Smrg    int heights[15] = {480, 600,  768,  768,  720,  800,  854,  960, 1024,  900, 1050, 1050, 1200, 1080, 1200};
452b7e1c893Smrg
453b7e1c893Smrg    for (i = 0; i < 15; i++) {
454b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) {
455b7e1c893Smrg	    /* already added the native mode */
456b7e1c893Smrg	    if (widths[i] == native_mode->PanelXRes && heights[i] == native_mode->PanelYRes)
457b7e1c893Smrg		continue;
458b7e1c893Smrg
459b7e1c893Smrg	    /* Note: We allow all non-standard modes as long as they do not
460b7e1c893Smrg	     * exceed the native resolution of the panel.  Since these modes
461b7e1c893Smrg	     * need the internal RMX unit in the video chips (and there is
462b7e1c893Smrg	     * only one per card), this will only apply to the primary head.
463b7e1c893Smrg	     */
464b7e1c893Smrg	    if (widths[i] < 320 || widths[i] > native_mode->PanelXRes ||
465b7e1c893Smrg		heights[i] < 200 || heights[i] > native_mode->PanelYRes)
466b7e1c893Smrg		continue;
467b7e1c893Smrg	}
468b7e1c893Smrg
469b7e1c893Smrg	new = xf86CVTMode(widths[i], heights[i], 60.0, FALSE, FALSE);
4709d25673eSmacallan	xf86SetModeDefaultName(new);
471b7e1c893Smrg
472b7e1c893Smrg	new->type       = M_T_DRIVER;
473b7e1c893Smrg
474b7e1c893Smrg	new->next       = NULL;
475b7e1c893Smrg	new->prev       = last;
476b7e1c893Smrg
477b7e1c893Smrg	if (last) last->next = new;
478b7e1c893Smrg	last = new;
479b7e1c893Smrg	if (!first) first = new;
480b7e1c893Smrg    }
481b7e1c893Smrg
482b7e1c893Smrg    if (last) {
483b7e1c893Smrg	last->next   = NULL; //first;
484b7e1c893Smrg	first->prev  = NULL; //last;
485b7e1c893Smrg    }
486b7e1c893Smrg
487b7e1c893Smrg    xf86ModesAdd(modes, first);
488b7e1c893Smrg
489b7e1c893Smrg}
490b7e1c893Smrg
491209ff23fSmrgDisplayModePtr
492209ff23fSmrgRADEONProbeOutputModes(xf86OutputPtr output)
493209ff23fSmrg{
494209ff23fSmrg    RADEONOutputPrivatePtr radeon_output = output->driver_private;
495209ff23fSmrg    ScrnInfoPtr pScrn = output->scrn;
496209ff23fSmrg    RADEONInfoPtr info = RADEONPTR(pScrn);
497209ff23fSmrg    DisplayModePtr	    modes = NULL;
498209ff23fSmrg    AtomBiosArgRec atomBiosArg;
499209ff23fSmrg    AtomBiosResult atomBiosResult;
500209ff23fSmrg
501209ff23fSmrg    if (output->status == XF86OutputStatusConnected) {
502b7e1c893Smrg	if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) {
503209ff23fSmrg	    if (IS_AVIVO_VARIANT)
504209ff23fSmrg		modes = RADEONATOMTVModes(output);
505209ff23fSmrg	    else
506209ff23fSmrg		modes = RADEONTVModes(output);
507b7e1c893Smrg	} else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) {
50868105dcbSveego	    atomBiosResult = RHDAtomBiosFunc(pScrn, info->atomBIOS,
509209ff23fSmrg					     ATOMBIOS_GET_CV_MODES, &atomBiosArg);
510209ff23fSmrg	    if (atomBiosResult == ATOM_SUCCESS) {
511209ff23fSmrg		modes = atomBiosArg.modes;
512209ff23fSmrg	    }
513209ff23fSmrg	} else {
514b7e1c893Smrg	    if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT))
515b7e1c893Smrg		RADEONUpdatePanelSize(output);
516209ff23fSmrg	    if (output->MonInfo)
517209ff23fSmrg		modes = xf86OutputGetEDIDModes (output);
518b7e1c893Smrg#if defined(__powerpc__)
519b7e1c893Smrg	    if ((info->MacModel == RADEON_MAC_EMAC) &&
520b7e1c893Smrg		(radeon_output->active_device & ATOM_DEVICE_CRT1_SUPPORT) &&
521b7e1c893Smrg		(modes == NULL))
522b7e1c893Smrg		modes = RADEONeMacModes(output);
523b7e1c893Smrg#endif
524209ff23fSmrg	    if (modes == NULL) {
525b7e1c893Smrg		if ((radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) && info->IsAtomBios) {
52668105dcbSveego		    atomBiosResult = RHDAtomBiosFunc(pScrn,
527209ff23fSmrg						     info->atomBIOS,
528209ff23fSmrg						     ATOMBIOS_GET_PANEL_EDID, &atomBiosArg);
529209ff23fSmrg		    if (atomBiosResult == ATOM_SUCCESS) {
530209ff23fSmrg			output->MonInfo = xf86InterpretEDID(pScrn->scrnIndex,
531209ff23fSmrg							    atomBiosArg.EDIDBlock);
532209ff23fSmrg			modes = xf86OutputGetEDIDModes(output);
533209ff23fSmrg		    }
534209ff23fSmrg		}
535209ff23fSmrg		if (modes == NULL) {
536b7e1c893Smrg		    if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT))
537209ff23fSmrg			modes = RADEONFPNativeMode(output);
538209ff23fSmrg		    /* add the screen modes */
539b7e1c893Smrg		    if (modes == NULL)
540b7e1c893Smrg			RADEONAddScreenModes(output, &modes);
541209ff23fSmrg		}
542209ff23fSmrg	    }
543209ff23fSmrg	}
544209ff23fSmrg    }
545209ff23fSmrg
546b7e1c893Smrg    if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT))
547b7e1c893Smrg	radeon_add_common_modes(output, modes);
548b7e1c893Smrg
549209ff23fSmrg    return modes;
550209ff23fSmrg}
551209ff23fSmrg
552