radeon_modes.c revision 68105dcb
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); 94209ff23fSmrg new->type = M_T_DRIVER | M_T_PREFERRED; 95209ff23fSmrg 96209ff23fSmrg return new; 97209ff23fSmrg} 98209ff23fSmrg 99209ff23fSmrgstatic DisplayModePtr 100209ff23fSmrgRADEONATOMTVModes(xf86OutputPtr output) 101209ff23fSmrg{ 102209ff23fSmrg DisplayModePtr last = NULL; 103209ff23fSmrg DisplayModePtr new = NULL; 104209ff23fSmrg DisplayModePtr first = NULL; 105b7e1c893Smrg int i; 106209ff23fSmrg /* Add some common sizes */ 107b7e1c893Smrg int widths[5] = {640, 720, 800, 848, 1024}; 108b7e1c893Smrg int heights[5] = {480, 480, 600, 480, 768}; 109209ff23fSmrg 110209ff23fSmrg for (i = 0; i < 5; i++) { 111b7e1c893Smrg new = xf86CVTMode(widths[i], heights[i], 60.0, FALSE, FALSE); 112209ff23fSmrg 113209ff23fSmrg new->type = M_T_DRIVER; 114209ff23fSmrg 115209ff23fSmrg new->next = NULL; 116209ff23fSmrg new->prev = last; 117209ff23fSmrg 118209ff23fSmrg if (last) last->next = new; 119209ff23fSmrg last = new; 120209ff23fSmrg if (!first) first = new; 121209ff23fSmrg } 122209ff23fSmrg 123209ff23fSmrg if (last) { 124209ff23fSmrg last->next = NULL; //first; 125209ff23fSmrg first->prev = NULL; //last; 126209ff23fSmrg } 127209ff23fSmrg 128209ff23fSmrg return first; 129209ff23fSmrg} 130209ff23fSmrg 131209ff23fSmrg/* This is used only when no mode is specified for FP and no ddc is 132209ff23fSmrg * available. We force it to native mode, if possible. 133209ff23fSmrg */ 134209ff23fSmrgstatic DisplayModePtr RADEONFPNativeMode(xf86OutputPtr output) 135209ff23fSmrg{ 136209ff23fSmrg ScrnInfoPtr pScrn = output->scrn; 137209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 138b7e1c893Smrg radeon_native_mode_ptr native_mode = &radeon_output->native_mode; 139209ff23fSmrg DisplayModePtr new = NULL; 140209ff23fSmrg char stmp[32]; 141209ff23fSmrg 142b7e1c893Smrg if (native_mode->PanelXRes != 0 && 143b7e1c893Smrg native_mode->PanelYRes != 0 && 144b7e1c893Smrg native_mode->DotClock != 0) { 145209ff23fSmrg 146209ff23fSmrg new = xnfcalloc(1, sizeof (DisplayModeRec)); 147b7e1c893Smrg sprintf(stmp, "%dx%d", native_mode->PanelXRes, native_mode->PanelYRes); 148209ff23fSmrg new->name = xnfalloc(strlen(stmp) + 1); 149209ff23fSmrg strcpy(new->name, stmp); 150b7e1c893Smrg new->HDisplay = native_mode->PanelXRes; 151b7e1c893Smrg new->VDisplay = native_mode->PanelYRes; 152209ff23fSmrg 153b7e1c893Smrg new->HTotal = new->HDisplay + native_mode->HBlank; 154b7e1c893Smrg new->HSyncStart = new->HDisplay + native_mode->HOverPlus; 155b7e1c893Smrg new->HSyncEnd = new->HSyncStart + native_mode->HSyncWidth; 156b7e1c893Smrg new->VTotal = new->VDisplay + native_mode->VBlank; 157b7e1c893Smrg new->VSyncStart = new->VDisplay + native_mode->VOverPlus; 158b7e1c893Smrg new->VSyncEnd = new->VSyncStart + native_mode->VSyncWidth; 159209ff23fSmrg 160b7e1c893Smrg new->Clock = native_mode->DotClock; 161ad43ddacSmrg new->Flags = native_mode->Flags; 162209ff23fSmrg 163209ff23fSmrg if (new) { 164209ff23fSmrg new->type = M_T_DRIVER | M_T_PREFERRED; 165209ff23fSmrg 166209ff23fSmrg new->next = NULL; 167209ff23fSmrg new->prev = NULL; 168209ff23fSmrg } 169209ff23fSmrg 170209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Added native panel mode: %dx%d\n", 171b7e1c893Smrg native_mode->PanelXRes, native_mode->PanelYRes); 172ad43ddacSmrg } else if (native_mode->PanelXRes != 0 && 173ad43ddacSmrg native_mode->PanelYRes != 0) { 174ad43ddacSmrg 175ad43ddacSmrg new = xf86CVTMode(native_mode->PanelXRes, native_mode->PanelYRes, 60.0, TRUE, FALSE); 176ad43ddacSmrg 177ad43ddacSmrg if (new) { 178ad43ddacSmrg new->type = M_T_DRIVER | M_T_PREFERRED; 179ad43ddacSmrg 180ad43ddacSmrg new->next = NULL; 181ad43ddacSmrg new->prev = NULL; 182ad43ddacSmrg } 183ad43ddacSmrg 184ad43ddacSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Added native panel mode using CVT: %dx%d\n", 185ad43ddacSmrg native_mode->PanelXRes, native_mode->PanelYRes); 186209ff23fSmrg } 187209ff23fSmrg 188209ff23fSmrg return new; 189209ff23fSmrg} 190209ff23fSmrg 191b7e1c893Smrg#if defined(__powerpc__) 192b7e1c893Smrg/* Apple eMacs need special modes for the internal CRT, e.g., 193b7e1c893Smrg * Modeline "640x480" 62.12 640 680 752 864 480 481 484 521 +HSync +Vsync 194b7e1c893Smrg * Modeline "800x600" 76.84 800 848 936 1072 600 601 604 640 +HSync +Vsync 195b7e1c893Smrg * Modeline "1024x768" 99.07 1024 1088 1200 1376 768 769 772 809 +HSync +Vsync 196b7e1c893Smrg * Modeline "1152x864" 112.36 1152 1224 1352 1552 864 865 868 905 +HSync +Vsync 197b7e1c893Smrg * Modeline "1280x960" 124.54 1280 1368 1504 1728 960 961 964 1001 +HSync +Vsync 198b7e1c893Smrg */ 199b7e1c893Smrgstatic DisplayModePtr RADEONeMacModes(xf86OutputPtr output) 200b7e1c893Smrg{ 201b7e1c893Smrg ScrnInfoPtr pScrn = output->scrn; 202b7e1c893Smrg DisplayModePtr last=NULL, new=NULL, first=NULL; 203b7e1c893Smrg int i, *modep; 204b7e1c893Smrg static const char *modenames[5] = { 205b7e1c893Smrg "640x480", "800x600", "1024x768", "1152x864", "1280x960" 206b7e1c893Smrg }; 207b7e1c893Smrg static int modes[9*5] = { 208b7e1c893Smrg 62120, 640, 680, 752, 864, 480, 481, 484, 521, 209b7e1c893Smrg 76840, 800, 848, 936, 1072, 600, 601, 604, 640, 210b7e1c893Smrg 99070, 1024, 1088, 1200, 1376, 768, 769, 772, 809, 211b7e1c893Smrg 112360, 1152, 1224, 1352, 1552, 864, 865, 868, 905, 212b7e1c893Smrg 124540, 1280, 1368, 1504, 1728, 960, 961, 964, 1001 213b7e1c893Smrg }; 214b7e1c893Smrg modep = modes; 215b7e1c893Smrg 216b7e1c893Smrg for (i=0; i<5; i++) { 217b7e1c893Smrg new = xnfcalloc(1, sizeof (DisplayModeRec)); 218b7e1c893Smrg if (new) { 219b7e1c893Smrg new->name = xnfalloc(strlen(modenames[i]) + 1); 220b7e1c893Smrg strcpy(new->name, modenames[i]); 221b7e1c893Smrg new->Clock = *modep++; 222b7e1c893Smrg 223b7e1c893Smrg new->HDisplay = *modep++; 224b7e1c893Smrg new->HSyncStart = *modep++; 225b7e1c893Smrg new->HSyncEnd = *modep++; 226b7e1c893Smrg new->HTotal = *modep++; 227b7e1c893Smrg 228b7e1c893Smrg new->VDisplay = *modep++; 229b7e1c893Smrg new->VSyncStart = *modep++; 230b7e1c893Smrg new->VSyncEnd = *modep++; 231b7e1c893Smrg new->VTotal = *modep++; 232b7e1c893Smrg 233b7e1c893Smrg new->Flags = 0; 234b7e1c893Smrg new->type = M_T_DRIVER; 235b7e1c893Smrg if (i==2) 236b7e1c893Smrg new->type |= M_T_PREFERRED; 237b7e1c893Smrg new->next = NULL; 238b7e1c893Smrg new->prev = last; 239b7e1c893Smrg if (last) last->next = new; 240b7e1c893Smrg last = new; 241b7e1c893Smrg if (!first) first = new; 242b7e1c893Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Added eMac mode %s\n", modenames[i]); 243b7e1c893Smrg } 244b7e1c893Smrg } 245b7e1c893Smrg 246b7e1c893Smrg return first; 247b7e1c893Smrg} 248b7e1c893Smrg#endif 249b7e1c893Smrg 250209ff23fSmrg/* this function is basically a hack to add the screen modes */ 251209ff23fSmrgstatic void RADEONAddScreenModes(xf86OutputPtr output, DisplayModePtr *modeList) 252209ff23fSmrg{ 253209ff23fSmrg ScrnInfoPtr pScrn = output->scrn; 254209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 255b7e1c893Smrg radeon_native_mode_ptr native_mode = &radeon_output->native_mode; 256209ff23fSmrg DisplayModePtr last = NULL; 257209ff23fSmrg DisplayModePtr new = NULL; 258209ff23fSmrg DisplayModePtr first = NULL; 259209ff23fSmrg int count = 0; 260209ff23fSmrg int i, width, height; 261209ff23fSmrg char **ppModeName = pScrn->display->modes; 262209ff23fSmrg 263209ff23fSmrg first = last = *modeList; 264209ff23fSmrg 265209ff23fSmrg /* We have a flat panel connected to the primary display, and we 266209ff23fSmrg * don't have any DDC info. 267209ff23fSmrg */ 268209ff23fSmrg for (i = 0; ppModeName[i] != NULL; i++) { 269209ff23fSmrg 270209ff23fSmrg if (sscanf(ppModeName[i], "%dx%d", &width, &height) != 2) continue; 271209ff23fSmrg 272b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { 273209ff23fSmrg /* already added the native mode */ 274b7e1c893Smrg if (width == native_mode->PanelXRes && height == native_mode->PanelYRes) 275209ff23fSmrg continue; 276209ff23fSmrg 277209ff23fSmrg /* Note: We allow all non-standard modes as long as they do not 278209ff23fSmrg * exceed the native resolution of the panel. Since these modes 279209ff23fSmrg * need the internal RMX unit in the video chips (and there is 280209ff23fSmrg * only one per card), this will only apply to the primary head. 281209ff23fSmrg */ 282b7e1c893Smrg if (width < 320 || width > native_mode->PanelXRes || 283b7e1c893Smrg height < 200 || height > native_mode->PanelYRes) { 284209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 285209ff23fSmrg "Mode %s is out of range.\n", ppModeName[i]); 286209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 287209ff23fSmrg "Valid FP modes must be between 320x200-%dx%d\n", 288b7e1c893Smrg native_mode->PanelXRes, native_mode->PanelYRes); 289209ff23fSmrg continue; 290209ff23fSmrg } 291209ff23fSmrg } 292209ff23fSmrg 293209ff23fSmrg new = xf86CVTMode(width, height, 60.0, FALSE, FALSE); 294209ff23fSmrg 295209ff23fSmrg new->type |= M_T_USERDEF; 296209ff23fSmrg 297209ff23fSmrg new->next = NULL; 298209ff23fSmrg new->prev = last; 299209ff23fSmrg 300209ff23fSmrg if (last) last->next = new; 301209ff23fSmrg last = new; 302209ff23fSmrg if (!first) first = new; 303209ff23fSmrg 304209ff23fSmrg count++; 305209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 306209ff23fSmrg "Adding Screen mode: %s\n", new->name); 307209ff23fSmrg } 308209ff23fSmrg 309209ff23fSmrg 310209ff23fSmrg /* Close the doubly-linked mode list, if we found any usable modes */ 311209ff23fSmrg if (last) { 312209ff23fSmrg last->next = NULL; //first; 313209ff23fSmrg first->prev = NULL; //last; 314209ff23fSmrg *modeList = first; 315209ff23fSmrg } 316209ff23fSmrg 317209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 318209ff23fSmrg "Total number of valid Screen mode(s) added: %d\n", count); 319209ff23fSmrg 320209ff23fSmrg} 321209ff23fSmrg 322b7e1c893Smrg/* BIOS may not have right panel size, we search through all supported 323b7e1c893Smrg * DDC modes looking for the maximum panel size. 324b7e1c893Smrg */ 325b7e1c893Smrgstatic void 326b7e1c893SmrgRADEONUpdatePanelSize(xf86OutputPtr output) 327b7e1c893Smrg{ 328b7e1c893Smrg ScrnInfoPtr pScrn = output->scrn; 329b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 330b7e1c893Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 331b7e1c893Smrg radeon_native_mode_ptr native_mode = &radeon_output->native_mode; 332b7e1c893Smrg int j; 333b7e1c893Smrg xf86MonPtr ddc = output->MonInfo; 334b7e1c893Smrg DisplayModePtr p; 335b7e1c893Smrg 336b7e1c893Smrg // update output's native mode 337b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { 338b7e1c893Smrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 339b7e1c893Smrg if (radeon_encoder) { 340b7e1c893Smrg radeon_lvds_ptr lvds = (radeon_lvds_ptr)radeon_encoder->dev_priv; 341b7e1c893Smrg if (lvds) 342b7e1c893Smrg radeon_output->native_mode = lvds->native_mode; 343b7e1c893Smrg } 344b7e1c893Smrg } 345b7e1c893Smrg 346b7e1c893Smrg // crtc should handle? 347b7e1c893Smrg if ((info->UseBiosDividers && native_mode->DotClock != 0) || (ddc == NULL)) 348b7e1c893Smrg return; 349b7e1c893Smrg 350b7e1c893Smrg /* Go thru detailed timing table first */ 351b7e1c893Smrg for (j = 0; j < 4; j++) { 352b7e1c893Smrg if (ddc->det_mon[j].type == 0) { 353b7e1c893Smrg struct detailed_timings *d_timings = 354b7e1c893Smrg &ddc->det_mon[j].section.d_timings; 355b7e1c893Smrg int match = 0; 356b7e1c893Smrg 357b7e1c893Smrg /* If we didn't get a panel clock or guessed one, try to match the 358b7e1c893Smrg * mode with the panel size. We do that because we _need_ a panel 359b7e1c893Smrg * clock, or ValidateFPModes will fail, even when UseBiosDividers 360b7e1c893Smrg * is set. 361b7e1c893Smrg */ 362b7e1c893Smrg if (native_mode->DotClock == 0 && 363b7e1c893Smrg native_mode->PanelXRes == d_timings->h_active && 364b7e1c893Smrg native_mode->PanelYRes == d_timings->v_active) 365b7e1c893Smrg match = 1; 366b7e1c893Smrg 367b7e1c893Smrg /* If we don't have a BIOS provided panel data with fixed dividers, 368b7e1c893Smrg * check for a larger panel size 369b7e1c893Smrg */ 370b7e1c893Smrg if (native_mode->PanelXRes < d_timings->h_active && 371b7e1c893Smrg native_mode->PanelYRes < d_timings->v_active && 372b7e1c893Smrg !info->UseBiosDividers) 373b7e1c893Smrg match = 1; 374b7e1c893Smrg 375b7e1c893Smrg if (match) { 376b7e1c893Smrg native_mode->PanelXRes = d_timings->h_active; 377b7e1c893Smrg native_mode->PanelYRes = d_timings->v_active; 378b7e1c893Smrg native_mode->DotClock = d_timings->clock / 1000; 379b7e1c893Smrg native_mode->HOverPlus = d_timings->h_sync_off; 380b7e1c893Smrg native_mode->HSyncWidth = d_timings->h_sync_width; 381b7e1c893Smrg native_mode->HBlank = d_timings->h_blanking; 382b7e1c893Smrg native_mode->VOverPlus = d_timings->v_sync_off; 383b7e1c893Smrg native_mode->VSyncWidth = d_timings->v_sync_width; 384b7e1c893Smrg native_mode->VBlank = d_timings->v_blanking; 385b7e1c893Smrg native_mode->Flags = (d_timings->interlaced ? V_INTERLACE : 0); 386b7e1c893Smrg switch (d_timings->misc) { 387b7e1c893Smrg case 0: native_mode->Flags |= V_NHSYNC | V_NVSYNC; break; 388b7e1c893Smrg case 1: native_mode->Flags |= V_PHSYNC | V_NVSYNC; break; 389b7e1c893Smrg case 2: native_mode->Flags |= V_NHSYNC | V_PVSYNC; break; 390b7e1c893Smrg case 3: native_mode->Flags |= V_PHSYNC | V_PVSYNC; break; 391b7e1c893Smrg } 392b7e1c893Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel infos found from DDC detailed: %dx%d\n", 393b7e1c893Smrg native_mode->PanelXRes, native_mode->PanelYRes); 394b7e1c893Smrg } 395b7e1c893Smrg } 396b7e1c893Smrg } 397b7e1c893Smrg 398b7e1c893Smrg if (info->UseBiosDividers && native_mode->DotClock != 0) 399b7e1c893Smrg return; 400b7e1c893Smrg 401b7e1c893Smrg /* Search thru standard VESA modes from EDID */ 402b7e1c893Smrg for (j = 0; j < 8; j++) { 403b7e1c893Smrg if ((native_mode->PanelXRes < ddc->timings2[j].hsize) && 404b7e1c893Smrg (native_mode->PanelYRes < ddc->timings2[j].vsize)) { 405b7e1c893Smrg for (p = pScrn->monitor->Modes; p; p = p->next) { 406b7e1c893Smrg if ((ddc->timings2[j].hsize == p->HDisplay) && 407b7e1c893Smrg (ddc->timings2[j].vsize == p->VDisplay)) { 408b7e1c893Smrg float refresh = 409b7e1c893Smrg (float)p->Clock * 1000.0 / p->HTotal / p->VTotal; 410b7e1c893Smrg 411b7e1c893Smrg if (abs((float)ddc->timings2[j].refresh - refresh) < 1.0) { 412b7e1c893Smrg /* Is this good enough? */ 413b7e1c893Smrg native_mode->PanelXRes = ddc->timings2[j].hsize; 414b7e1c893Smrg native_mode->PanelYRes = ddc->timings2[j].vsize; 415b7e1c893Smrg native_mode->HBlank = p->HTotal - p->HDisplay; 416b7e1c893Smrg native_mode->HOverPlus = p->HSyncStart - p->HDisplay; 417b7e1c893Smrg native_mode->HSyncWidth = p->HSyncEnd - p->HSyncStart; 418b7e1c893Smrg native_mode->VBlank = p->VTotal - p->VDisplay; 419b7e1c893Smrg native_mode->VOverPlus = p->VSyncStart - p->VDisplay; 420b7e1c893Smrg native_mode->VSyncWidth = p->VSyncEnd - p->VSyncStart; 421b7e1c893Smrg native_mode->DotClock = p->Clock; 422b7e1c893Smrg native_mode->Flags = p->Flags; 423b7e1c893Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel infos found from DDC VESA/EDID: %dx%d\n", 424b7e1c893Smrg native_mode->PanelXRes, native_mode->PanelYRes); 425b7e1c893Smrg } 426b7e1c893Smrg } 427b7e1c893Smrg } 428b7e1c893Smrg } 429b7e1c893Smrg } 430b7e1c893Smrg} 431b7e1c893Smrg 432b7e1c893Smrgstatic void 433b7e1c893Smrgradeon_add_common_modes(xf86OutputPtr output, DisplayModePtr modes) 434b7e1c893Smrg{ 435b7e1c893Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 436b7e1c893Smrg radeon_native_mode_ptr native_mode = &radeon_output->native_mode; 437b7e1c893Smrg DisplayModePtr last = NULL; 438b7e1c893Smrg DisplayModePtr new = NULL; 439b7e1c893Smrg DisplayModePtr first = NULL; 440b7e1c893Smrg int i; 441b7e1c893Smrg /* Add some common sizes */ 442b7e1c893Smrg int widths[15] = {640, 800, 1024, 1152, 1280, 1280, 1280, 1280, 1280, 1440, 1400, 1680, 1600, 1920, 1920}; 443b7e1c893Smrg int heights[15] = {480, 600, 768, 768, 720, 800, 854, 960, 1024, 900, 1050, 1050, 1200, 1080, 1200}; 444b7e1c893Smrg 445b7e1c893Smrg for (i = 0; i < 15; i++) { 446b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { 447b7e1c893Smrg /* already added the native mode */ 448b7e1c893Smrg if (widths[i] == native_mode->PanelXRes && heights[i] == native_mode->PanelYRes) 449b7e1c893Smrg continue; 450b7e1c893Smrg 451b7e1c893Smrg /* Note: We allow all non-standard modes as long as they do not 452b7e1c893Smrg * exceed the native resolution of the panel. Since these modes 453b7e1c893Smrg * need the internal RMX unit in the video chips (and there is 454b7e1c893Smrg * only one per card), this will only apply to the primary head. 455b7e1c893Smrg */ 456b7e1c893Smrg if (widths[i] < 320 || widths[i] > native_mode->PanelXRes || 457b7e1c893Smrg heights[i] < 200 || heights[i] > native_mode->PanelYRes) 458b7e1c893Smrg continue; 459b7e1c893Smrg } 460b7e1c893Smrg 461b7e1c893Smrg new = xf86CVTMode(widths[i], heights[i], 60.0, FALSE, FALSE); 462b7e1c893Smrg 463b7e1c893Smrg new->type = M_T_DRIVER; 464b7e1c893Smrg 465b7e1c893Smrg new->next = NULL; 466b7e1c893Smrg new->prev = last; 467b7e1c893Smrg 468b7e1c893Smrg if (last) last->next = new; 469b7e1c893Smrg last = new; 470b7e1c893Smrg if (!first) first = new; 471b7e1c893Smrg } 472b7e1c893Smrg 473b7e1c893Smrg if (last) { 474b7e1c893Smrg last->next = NULL; //first; 475b7e1c893Smrg first->prev = NULL; //last; 476b7e1c893Smrg } 477b7e1c893Smrg 478b7e1c893Smrg xf86ModesAdd(modes, first); 479b7e1c893Smrg 480b7e1c893Smrg} 481b7e1c893Smrg 482209ff23fSmrgDisplayModePtr 483209ff23fSmrgRADEONProbeOutputModes(xf86OutputPtr output) 484209ff23fSmrg{ 485209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 486209ff23fSmrg ScrnInfoPtr pScrn = output->scrn; 487209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 488209ff23fSmrg DisplayModePtr modes = NULL; 489209ff23fSmrg AtomBiosArgRec atomBiosArg; 490209ff23fSmrg AtomBiosResult atomBiosResult; 491209ff23fSmrg 492209ff23fSmrg if (output->status == XF86OutputStatusConnected) { 493b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) { 494209ff23fSmrg if (IS_AVIVO_VARIANT) 495209ff23fSmrg modes = RADEONATOMTVModes(output); 496209ff23fSmrg else 497209ff23fSmrg modes = RADEONTVModes(output); 498b7e1c893Smrg } else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) { 49968105dcbSveego atomBiosResult = RHDAtomBiosFunc(pScrn, info->atomBIOS, 500209ff23fSmrg ATOMBIOS_GET_CV_MODES, &atomBiosArg); 501209ff23fSmrg if (atomBiosResult == ATOM_SUCCESS) { 502209ff23fSmrg modes = atomBiosArg.modes; 503209ff23fSmrg } 504209ff23fSmrg } else { 505b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) 506b7e1c893Smrg RADEONUpdatePanelSize(output); 507209ff23fSmrg if (output->MonInfo) 508209ff23fSmrg modes = xf86OutputGetEDIDModes (output); 509b7e1c893Smrg#if defined(__powerpc__) 510b7e1c893Smrg if ((info->MacModel == RADEON_MAC_EMAC) && 511b7e1c893Smrg (radeon_output->active_device & ATOM_DEVICE_CRT1_SUPPORT) && 512b7e1c893Smrg (modes == NULL)) 513b7e1c893Smrg modes = RADEONeMacModes(output); 514b7e1c893Smrg#endif 515209ff23fSmrg if (modes == NULL) { 516b7e1c893Smrg if ((radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) && info->IsAtomBios) { 51768105dcbSveego atomBiosResult = RHDAtomBiosFunc(pScrn, 518209ff23fSmrg info->atomBIOS, 519209ff23fSmrg ATOMBIOS_GET_PANEL_EDID, &atomBiosArg); 520209ff23fSmrg if (atomBiosResult == ATOM_SUCCESS) { 521209ff23fSmrg output->MonInfo = xf86InterpretEDID(pScrn->scrnIndex, 522209ff23fSmrg atomBiosArg.EDIDBlock); 523209ff23fSmrg modes = xf86OutputGetEDIDModes(output); 524209ff23fSmrg } 525209ff23fSmrg } 526209ff23fSmrg if (modes == NULL) { 527b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) 528209ff23fSmrg modes = RADEONFPNativeMode(output); 529209ff23fSmrg /* add the screen modes */ 530b7e1c893Smrg if (modes == NULL) 531b7e1c893Smrg RADEONAddScreenModes(output, &modes); 532209ff23fSmrg } 533209ff23fSmrg } 534209ff23fSmrg } 535209ff23fSmrg } 536209ff23fSmrg 537b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) 538b7e1c893Smrg radeon_add_common_modes(output, modes); 539b7e1c893Smrg 540209ff23fSmrg return modes; 541209ff23fSmrg} 542209ff23fSmrg 543