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