radeon_modes.c revision b7e1c893
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) { 70b7e1c893Smrg case 1: pitch_mask = align_large ? 255 : 127; 71b7e1c893Smrg break; 72b7e1c893Smrg case 2: pitch_mask = align_large ? 127 : 31; 73b7e1c893Smrg break; 74b7e1c893Smrg case 3: 75b7e1c893Smrg case 4: pitch_mask = align_large ? 63 : 15; 76b7e1c893Smrg break; 77b7e1c893Smrg } 78b7e1c893Smrg } else 79b7e1c893Smrg pitch_mask = 255; /* r6xx/r7xx need 256B alignment for accel */ 80b7e1c893Smrg 81209ff23fSmrg dummy = (pScrn->virtualX + pitch_mask) & ~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; 161209ff23fSmrg new->Flags = 0; 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); 172209ff23fSmrg } 173209ff23fSmrg 174209ff23fSmrg return new; 175209ff23fSmrg} 176209ff23fSmrg 177b7e1c893Smrg#if defined(__powerpc__) 178b7e1c893Smrg/* Apple eMacs need special modes for the internal CRT, e.g., 179b7e1c893Smrg * Modeline "640x480" 62.12 640 680 752 864 480 481 484 521 +HSync +Vsync 180b7e1c893Smrg * Modeline "800x600" 76.84 800 848 936 1072 600 601 604 640 +HSync +Vsync 181b7e1c893Smrg * Modeline "1024x768" 99.07 1024 1088 1200 1376 768 769 772 809 +HSync +Vsync 182b7e1c893Smrg * Modeline "1152x864" 112.36 1152 1224 1352 1552 864 865 868 905 +HSync +Vsync 183b7e1c893Smrg * Modeline "1280x960" 124.54 1280 1368 1504 1728 960 961 964 1001 +HSync +Vsync 184b7e1c893Smrg */ 185b7e1c893Smrgstatic DisplayModePtr RADEONeMacModes(xf86OutputPtr output) 186b7e1c893Smrg{ 187b7e1c893Smrg ScrnInfoPtr pScrn = output->scrn; 188b7e1c893Smrg DisplayModePtr last=NULL, new=NULL, first=NULL; 189b7e1c893Smrg int i, *modep; 190b7e1c893Smrg static const char *modenames[5] = { 191b7e1c893Smrg "640x480", "800x600", "1024x768", "1152x864", "1280x960" 192b7e1c893Smrg }; 193b7e1c893Smrg static int modes[9*5] = { 194b7e1c893Smrg 62120, 640, 680, 752, 864, 480, 481, 484, 521, 195b7e1c893Smrg 76840, 800, 848, 936, 1072, 600, 601, 604, 640, 196b7e1c893Smrg 99070, 1024, 1088, 1200, 1376, 768, 769, 772, 809, 197b7e1c893Smrg 112360, 1152, 1224, 1352, 1552, 864, 865, 868, 905, 198b7e1c893Smrg 124540, 1280, 1368, 1504, 1728, 960, 961, 964, 1001 199b7e1c893Smrg }; 200b7e1c893Smrg modep = modes; 201b7e1c893Smrg 202b7e1c893Smrg for (i=0; i<5; i++) { 203b7e1c893Smrg new = xnfcalloc(1, sizeof (DisplayModeRec)); 204b7e1c893Smrg if (new) { 205b7e1c893Smrg new->name = xnfalloc(strlen(modenames[i]) + 1); 206b7e1c893Smrg strcpy(new->name, modenames[i]); 207b7e1c893Smrg new->Clock = *modep++; 208b7e1c893Smrg 209b7e1c893Smrg new->HDisplay = *modep++; 210b7e1c893Smrg new->HSyncStart = *modep++; 211b7e1c893Smrg new->HSyncEnd = *modep++; 212b7e1c893Smrg new->HTotal = *modep++; 213b7e1c893Smrg 214b7e1c893Smrg new->VDisplay = *modep++; 215b7e1c893Smrg new->VSyncStart = *modep++; 216b7e1c893Smrg new->VSyncEnd = *modep++; 217b7e1c893Smrg new->VTotal = *modep++; 218b7e1c893Smrg 219b7e1c893Smrg new->Flags = 0; 220b7e1c893Smrg new->type = M_T_DRIVER; 221b7e1c893Smrg if (i==2) 222b7e1c893Smrg new->type |= M_T_PREFERRED; 223b7e1c893Smrg new->next = NULL; 224b7e1c893Smrg new->prev = last; 225b7e1c893Smrg if (last) last->next = new; 226b7e1c893Smrg last = new; 227b7e1c893Smrg if (!first) first = new; 228b7e1c893Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Added eMac mode %s\n", modenames[i]); 229b7e1c893Smrg } 230b7e1c893Smrg } 231b7e1c893Smrg 232b7e1c893Smrg return first; 233b7e1c893Smrg} 234b7e1c893Smrg#endif 235b7e1c893Smrg 236209ff23fSmrg/* this function is basically a hack to add the screen modes */ 237209ff23fSmrgstatic void RADEONAddScreenModes(xf86OutputPtr output, DisplayModePtr *modeList) 238209ff23fSmrg{ 239209ff23fSmrg ScrnInfoPtr pScrn = output->scrn; 240209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 241b7e1c893Smrg radeon_native_mode_ptr native_mode = &radeon_output->native_mode; 242209ff23fSmrg DisplayModePtr last = NULL; 243209ff23fSmrg DisplayModePtr new = NULL; 244209ff23fSmrg DisplayModePtr first = NULL; 245209ff23fSmrg int count = 0; 246209ff23fSmrg int i, width, height; 247209ff23fSmrg char **ppModeName = pScrn->display->modes; 248209ff23fSmrg 249209ff23fSmrg first = last = *modeList; 250209ff23fSmrg 251209ff23fSmrg /* We have a flat panel connected to the primary display, and we 252209ff23fSmrg * don't have any DDC info. 253209ff23fSmrg */ 254209ff23fSmrg for (i = 0; ppModeName[i] != NULL; i++) { 255209ff23fSmrg 256209ff23fSmrg if (sscanf(ppModeName[i], "%dx%d", &width, &height) != 2) continue; 257209ff23fSmrg 258b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { 259209ff23fSmrg /* already added the native mode */ 260b7e1c893Smrg if (width == native_mode->PanelXRes && height == native_mode->PanelYRes) 261209ff23fSmrg continue; 262209ff23fSmrg 263209ff23fSmrg /* Note: We allow all non-standard modes as long as they do not 264209ff23fSmrg * exceed the native resolution of the panel. Since these modes 265209ff23fSmrg * need the internal RMX unit in the video chips (and there is 266209ff23fSmrg * only one per card), this will only apply to the primary head. 267209ff23fSmrg */ 268b7e1c893Smrg if (width < 320 || width > native_mode->PanelXRes || 269b7e1c893Smrg height < 200 || height > native_mode->PanelYRes) { 270209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 271209ff23fSmrg "Mode %s is out of range.\n", ppModeName[i]); 272209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 273209ff23fSmrg "Valid FP modes must be between 320x200-%dx%d\n", 274b7e1c893Smrg native_mode->PanelXRes, native_mode->PanelYRes); 275209ff23fSmrg continue; 276209ff23fSmrg } 277209ff23fSmrg } 278209ff23fSmrg 279209ff23fSmrg new = xf86CVTMode(width, height, 60.0, FALSE, FALSE); 280209ff23fSmrg 281209ff23fSmrg new->type |= M_T_USERDEF; 282209ff23fSmrg 283209ff23fSmrg new->next = NULL; 284209ff23fSmrg new->prev = last; 285209ff23fSmrg 286209ff23fSmrg if (last) last->next = new; 287209ff23fSmrg last = new; 288209ff23fSmrg if (!first) first = new; 289209ff23fSmrg 290209ff23fSmrg count++; 291209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 292209ff23fSmrg "Adding Screen mode: %s\n", new->name); 293209ff23fSmrg } 294209ff23fSmrg 295209ff23fSmrg 296209ff23fSmrg /* Close the doubly-linked mode list, if we found any usable modes */ 297209ff23fSmrg if (last) { 298209ff23fSmrg last->next = NULL; //first; 299209ff23fSmrg first->prev = NULL; //last; 300209ff23fSmrg *modeList = first; 301209ff23fSmrg } 302209ff23fSmrg 303209ff23fSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 304209ff23fSmrg "Total number of valid Screen mode(s) added: %d\n", count); 305209ff23fSmrg 306209ff23fSmrg} 307209ff23fSmrg 308b7e1c893Smrg/* BIOS may not have right panel size, we search through all supported 309b7e1c893Smrg * DDC modes looking for the maximum panel size. 310b7e1c893Smrg */ 311b7e1c893Smrgstatic void 312b7e1c893SmrgRADEONUpdatePanelSize(xf86OutputPtr output) 313b7e1c893Smrg{ 314b7e1c893Smrg ScrnInfoPtr pScrn = output->scrn; 315b7e1c893Smrg RADEONInfoPtr info = RADEONPTR(pScrn); 316b7e1c893Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 317b7e1c893Smrg radeon_native_mode_ptr native_mode = &radeon_output->native_mode; 318b7e1c893Smrg int j; 319b7e1c893Smrg xf86MonPtr ddc = output->MonInfo; 320b7e1c893Smrg DisplayModePtr p; 321b7e1c893Smrg 322b7e1c893Smrg // update output's native mode 323b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { 324b7e1c893Smrg radeon_encoder_ptr radeon_encoder = radeon_get_encoder(output); 325b7e1c893Smrg if (radeon_encoder) { 326b7e1c893Smrg radeon_lvds_ptr lvds = (radeon_lvds_ptr)radeon_encoder->dev_priv; 327b7e1c893Smrg if (lvds) 328b7e1c893Smrg radeon_output->native_mode = lvds->native_mode; 329b7e1c893Smrg } 330b7e1c893Smrg } 331b7e1c893Smrg 332b7e1c893Smrg // crtc should handle? 333b7e1c893Smrg if ((info->UseBiosDividers && native_mode->DotClock != 0) || (ddc == NULL)) 334b7e1c893Smrg return; 335b7e1c893Smrg 336b7e1c893Smrg /* Go thru detailed timing table first */ 337b7e1c893Smrg for (j = 0; j < 4; j++) { 338b7e1c893Smrg if (ddc->det_mon[j].type == 0) { 339b7e1c893Smrg struct detailed_timings *d_timings = 340b7e1c893Smrg &ddc->det_mon[j].section.d_timings; 341b7e1c893Smrg int match = 0; 342b7e1c893Smrg 343b7e1c893Smrg /* If we didn't get a panel clock or guessed one, try to match the 344b7e1c893Smrg * mode with the panel size. We do that because we _need_ a panel 345b7e1c893Smrg * clock, or ValidateFPModes will fail, even when UseBiosDividers 346b7e1c893Smrg * is set. 347b7e1c893Smrg */ 348b7e1c893Smrg if (native_mode->DotClock == 0 && 349b7e1c893Smrg native_mode->PanelXRes == d_timings->h_active && 350b7e1c893Smrg native_mode->PanelYRes == d_timings->v_active) 351b7e1c893Smrg match = 1; 352b7e1c893Smrg 353b7e1c893Smrg /* If we don't have a BIOS provided panel data with fixed dividers, 354b7e1c893Smrg * check for a larger panel size 355b7e1c893Smrg */ 356b7e1c893Smrg if (native_mode->PanelXRes < d_timings->h_active && 357b7e1c893Smrg native_mode->PanelYRes < d_timings->v_active && 358b7e1c893Smrg !info->UseBiosDividers) 359b7e1c893Smrg match = 1; 360b7e1c893Smrg 361b7e1c893Smrg if (match) { 362b7e1c893Smrg native_mode->PanelXRes = d_timings->h_active; 363b7e1c893Smrg native_mode->PanelYRes = d_timings->v_active; 364b7e1c893Smrg native_mode->DotClock = d_timings->clock / 1000; 365b7e1c893Smrg native_mode->HOverPlus = d_timings->h_sync_off; 366b7e1c893Smrg native_mode->HSyncWidth = d_timings->h_sync_width; 367b7e1c893Smrg native_mode->HBlank = d_timings->h_blanking; 368b7e1c893Smrg native_mode->VOverPlus = d_timings->v_sync_off; 369b7e1c893Smrg native_mode->VSyncWidth = d_timings->v_sync_width; 370b7e1c893Smrg native_mode->VBlank = d_timings->v_blanking; 371b7e1c893Smrg native_mode->Flags = (d_timings->interlaced ? V_INTERLACE : 0); 372b7e1c893Smrg switch (d_timings->misc) { 373b7e1c893Smrg case 0: native_mode->Flags |= V_NHSYNC | V_NVSYNC; break; 374b7e1c893Smrg case 1: native_mode->Flags |= V_PHSYNC | V_NVSYNC; break; 375b7e1c893Smrg case 2: native_mode->Flags |= V_NHSYNC | V_PVSYNC; break; 376b7e1c893Smrg case 3: native_mode->Flags |= V_PHSYNC | V_PVSYNC; break; 377b7e1c893Smrg } 378b7e1c893Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel infos found from DDC detailed: %dx%d\n", 379b7e1c893Smrg native_mode->PanelXRes, native_mode->PanelYRes); 380b7e1c893Smrg } 381b7e1c893Smrg } 382b7e1c893Smrg } 383b7e1c893Smrg 384b7e1c893Smrg if (info->UseBiosDividers && native_mode->DotClock != 0) 385b7e1c893Smrg return; 386b7e1c893Smrg 387b7e1c893Smrg /* Search thru standard VESA modes from EDID */ 388b7e1c893Smrg for (j = 0; j < 8; j++) { 389b7e1c893Smrg if ((native_mode->PanelXRes < ddc->timings2[j].hsize) && 390b7e1c893Smrg (native_mode->PanelYRes < ddc->timings2[j].vsize)) { 391b7e1c893Smrg for (p = pScrn->monitor->Modes; p; p = p->next) { 392b7e1c893Smrg if ((ddc->timings2[j].hsize == p->HDisplay) && 393b7e1c893Smrg (ddc->timings2[j].vsize == p->VDisplay)) { 394b7e1c893Smrg float refresh = 395b7e1c893Smrg (float)p->Clock * 1000.0 / p->HTotal / p->VTotal; 396b7e1c893Smrg 397b7e1c893Smrg if (abs((float)ddc->timings2[j].refresh - refresh) < 1.0) { 398b7e1c893Smrg /* Is this good enough? */ 399b7e1c893Smrg native_mode->PanelXRes = ddc->timings2[j].hsize; 400b7e1c893Smrg native_mode->PanelYRes = ddc->timings2[j].vsize; 401b7e1c893Smrg native_mode->HBlank = p->HTotal - p->HDisplay; 402b7e1c893Smrg native_mode->HOverPlus = p->HSyncStart - p->HDisplay; 403b7e1c893Smrg native_mode->HSyncWidth = p->HSyncEnd - p->HSyncStart; 404b7e1c893Smrg native_mode->VBlank = p->VTotal - p->VDisplay; 405b7e1c893Smrg native_mode->VOverPlus = p->VSyncStart - p->VDisplay; 406b7e1c893Smrg native_mode->VSyncWidth = p->VSyncEnd - p->VSyncStart; 407b7e1c893Smrg native_mode->DotClock = p->Clock; 408b7e1c893Smrg native_mode->Flags = p->Flags; 409b7e1c893Smrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Panel infos found from DDC VESA/EDID: %dx%d\n", 410b7e1c893Smrg native_mode->PanelXRes, native_mode->PanelYRes); 411b7e1c893Smrg } 412b7e1c893Smrg } 413b7e1c893Smrg } 414b7e1c893Smrg } 415b7e1c893Smrg } 416b7e1c893Smrg} 417b7e1c893Smrg 418b7e1c893Smrgstatic void 419b7e1c893Smrgradeon_add_common_modes(xf86OutputPtr output, DisplayModePtr modes) 420b7e1c893Smrg{ 421b7e1c893Smrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 422b7e1c893Smrg radeon_native_mode_ptr native_mode = &radeon_output->native_mode; 423b7e1c893Smrg DisplayModePtr last = NULL; 424b7e1c893Smrg DisplayModePtr new = NULL; 425b7e1c893Smrg DisplayModePtr first = NULL; 426b7e1c893Smrg int i; 427b7e1c893Smrg /* Add some common sizes */ 428b7e1c893Smrg int widths[15] = {640, 800, 1024, 1152, 1280, 1280, 1280, 1280, 1280, 1440, 1400, 1680, 1600, 1920, 1920}; 429b7e1c893Smrg int heights[15] = {480, 600, 768, 768, 720, 800, 854, 960, 1024, 900, 1050, 1050, 1200, 1080, 1200}; 430b7e1c893Smrg 431b7e1c893Smrg for (i = 0; i < 15; i++) { 432b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) { 433b7e1c893Smrg /* already added the native mode */ 434b7e1c893Smrg if (widths[i] == native_mode->PanelXRes && heights[i] == native_mode->PanelYRes) 435b7e1c893Smrg continue; 436b7e1c893Smrg 437b7e1c893Smrg /* Note: We allow all non-standard modes as long as they do not 438b7e1c893Smrg * exceed the native resolution of the panel. Since these modes 439b7e1c893Smrg * need the internal RMX unit in the video chips (and there is 440b7e1c893Smrg * only one per card), this will only apply to the primary head. 441b7e1c893Smrg */ 442b7e1c893Smrg if (widths[i] < 320 || widths[i] > native_mode->PanelXRes || 443b7e1c893Smrg heights[i] < 200 || heights[i] > native_mode->PanelYRes) 444b7e1c893Smrg continue; 445b7e1c893Smrg } 446b7e1c893Smrg 447b7e1c893Smrg new = xf86CVTMode(widths[i], heights[i], 60.0, FALSE, FALSE); 448b7e1c893Smrg 449b7e1c893Smrg new->type = M_T_DRIVER; 450b7e1c893Smrg 451b7e1c893Smrg new->next = NULL; 452b7e1c893Smrg new->prev = last; 453b7e1c893Smrg 454b7e1c893Smrg if (last) last->next = new; 455b7e1c893Smrg last = new; 456b7e1c893Smrg if (!first) first = new; 457b7e1c893Smrg } 458b7e1c893Smrg 459b7e1c893Smrg if (last) { 460b7e1c893Smrg last->next = NULL; //first; 461b7e1c893Smrg first->prev = NULL; //last; 462b7e1c893Smrg } 463b7e1c893Smrg 464b7e1c893Smrg xf86ModesAdd(modes, first); 465b7e1c893Smrg 466b7e1c893Smrg} 467b7e1c893Smrg 468209ff23fSmrgDisplayModePtr 469209ff23fSmrgRADEONProbeOutputModes(xf86OutputPtr output) 470209ff23fSmrg{ 471209ff23fSmrg RADEONOutputPrivatePtr radeon_output = output->driver_private; 472209ff23fSmrg ScrnInfoPtr pScrn = output->scrn; 473209ff23fSmrg RADEONInfoPtr info = RADEONPTR(pScrn); 474209ff23fSmrg DisplayModePtr modes = NULL; 475209ff23fSmrg AtomBiosArgRec atomBiosArg; 476209ff23fSmrg AtomBiosResult atomBiosResult; 477209ff23fSmrg 478209ff23fSmrg if (output->status == XF86OutputStatusConnected) { 479b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_TV_SUPPORT)) { 480209ff23fSmrg if (IS_AVIVO_VARIANT) 481209ff23fSmrg modes = RADEONATOMTVModes(output); 482209ff23fSmrg else 483209ff23fSmrg modes = RADEONTVModes(output); 484b7e1c893Smrg } else if (radeon_output->active_device & (ATOM_DEVICE_CV_SUPPORT)) { 485209ff23fSmrg atomBiosResult = RHDAtomBiosFunc(pScrn->scrnIndex, info->atomBIOS, 486209ff23fSmrg ATOMBIOS_GET_CV_MODES, &atomBiosArg); 487209ff23fSmrg if (atomBiosResult == ATOM_SUCCESS) { 488209ff23fSmrg modes = atomBiosArg.modes; 489209ff23fSmrg } 490209ff23fSmrg } else { 491b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_DFP_SUPPORT | ATOM_DEVICE_LCD_SUPPORT)) 492b7e1c893Smrg RADEONUpdatePanelSize(output); 493209ff23fSmrg if (output->MonInfo) 494209ff23fSmrg modes = xf86OutputGetEDIDModes (output); 495b7e1c893Smrg#if defined(__powerpc__) 496b7e1c893Smrg if ((info->MacModel == RADEON_MAC_EMAC) && 497b7e1c893Smrg (radeon_output->active_device & ATOM_DEVICE_CRT1_SUPPORT) && 498b7e1c893Smrg (modes == NULL)) 499b7e1c893Smrg modes = RADEONeMacModes(output); 500b7e1c893Smrg#endif 501209ff23fSmrg if (modes == NULL) { 502b7e1c893Smrg if ((radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) && info->IsAtomBios) { 503209ff23fSmrg atomBiosResult = RHDAtomBiosFunc(pScrn->scrnIndex, 504209ff23fSmrg info->atomBIOS, 505209ff23fSmrg ATOMBIOS_GET_PANEL_EDID, &atomBiosArg); 506209ff23fSmrg if (atomBiosResult == ATOM_SUCCESS) { 507209ff23fSmrg output->MonInfo = xf86InterpretEDID(pScrn->scrnIndex, 508209ff23fSmrg atomBiosArg.EDIDBlock); 509209ff23fSmrg modes = xf86OutputGetEDIDModes(output); 510209ff23fSmrg } 511209ff23fSmrg } 512209ff23fSmrg if (modes == NULL) { 513b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) 514209ff23fSmrg modes = RADEONFPNativeMode(output); 515209ff23fSmrg /* add the screen modes */ 516b7e1c893Smrg if (modes == NULL) 517b7e1c893Smrg RADEONAddScreenModes(output, &modes); 518209ff23fSmrg } 519209ff23fSmrg } 520209ff23fSmrg } 521209ff23fSmrg } 522209ff23fSmrg 523b7e1c893Smrg if (radeon_output->active_device & (ATOM_DEVICE_LCD_SUPPORT)) 524b7e1c893Smrg radeon_add_common_modes(output, modes); 525b7e1c893Smrg 526209ff23fSmrg return modes; 527209ff23fSmrg} 528209ff23fSmrg 529