radeon_crtc.c revision 042789b0
1/* 2 * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and 3 * VA Linux Systems Inc., Fremont, California. 4 * 5 * All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining 8 * a copy of this software and associated documentation files (the 9 * "Software"), to deal in the Software without restriction, including 10 * without limitation on the rights to use, copy, modify, merge, 11 * publish, distribute, sublicense, and/or sell copies of the Software, 12 * and to permit persons to whom the Software is furnished to do so, 13 * subject to the following conditions: 14 * 15 * The above copyright notice and this permission notice (including the 16 * next paragraph) shall be included in all copies or substantial 17 * portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 * NON-INFRINGEMENT. IN NO EVENT SHALL ATI, VA LINUX SYSTEMS AND/OR 23 * THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 * DEALINGS IN THE SOFTWARE. 27 */ 28 29#ifdef HAVE_CONFIG_H 30#include "config.h" 31#endif 32 33#include <string.h> 34#include <stdio.h> 35#include <assert.h> 36#include <math.h> 37 38/* X and server generic header files */ 39#include "xf86.h" 40#include "xf86_OSproc.h" 41#include "vgaHW.h" 42#include "xf86Modes.h" 43 44/* Driver data structures */ 45#include "radeon.h" 46#include "radeon_reg.h" 47#include "radeon_macros.h" 48#include "radeon_probe.h" 49#include "radeon_version.h" 50 51#ifdef XF86DRI 52#define _XF86DRI_SERVER_ 53#include "radeon_drm.h" 54#include "sarea.h" 55#endif 56 57extern void atombios_crtc_mode_set(xf86CrtcPtr crtc, 58 DisplayModePtr mode, 59 DisplayModePtr adjusted_mode, 60 int x, int y); 61extern void atombios_crtc_dpms(xf86CrtcPtr crtc, int mode); 62extern void 63RADEONInitDispBandwidthLegacy(ScrnInfoPtr pScrn, 64 DisplayModePtr mode1, int pixel_bytes1, 65 DisplayModePtr mode2, int pixel_bytes2); 66extern void 67RADEONInitDispBandwidthAVIVO(ScrnInfoPtr pScrn, 68 DisplayModePtr mode1, int pixel_bytes1, 69 DisplayModePtr mode2, int pixel_bytes2); 70 71void 72radeon_do_crtc_dpms(xf86CrtcPtr crtc, int mode) 73{ 74 RADEONInfoPtr info = RADEONPTR(crtc->scrn); 75 RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn); 76 xf86CrtcPtr crtc0 = pRADEONEnt->pCrtc[0]; 77 RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; 78 79 if (IS_AVIVO_VARIANT || info->r4xx_atom) { 80 atombios_crtc_dpms(crtc, mode); 81 } else { 82 83 /* need to restore crtc1 before crtc0 or we may get a blank screen 84 * in some cases 85 */ 86 if ((radeon_crtc->crtc_id == 1) && (mode == DPMSModeOn)) { 87 if (crtc0->enabled) 88 legacy_crtc_dpms(crtc0, DPMSModeOff); 89 } 90 91 legacy_crtc_dpms(crtc, mode); 92 93 if ((radeon_crtc->crtc_id == 1) && (mode == DPMSModeOn)) { 94 if (crtc0->enabled) 95 legacy_crtc_dpms(crtc0, mode); 96 } 97 } 98} 99 100void 101radeon_crtc_dpms(xf86CrtcPtr crtc, int mode) 102{ 103 RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; 104 105 if ((mode == DPMSModeOn) && radeon_crtc->enabled) 106 return; 107 108 if (mode == DPMSModeOff) 109 radeon_crtc_modeset_ioctl(crtc, FALSE); 110 111 radeon_do_crtc_dpms(crtc, mode); 112 113 if (mode != DPMSModeOff) { 114 radeon_crtc_modeset_ioctl(crtc, TRUE); 115 radeon_crtc_load_lut(crtc); 116 } 117 118 if (mode == DPMSModeOn) 119 radeon_crtc->enabled = TRUE; 120 else 121 radeon_crtc->enabled = FALSE; 122} 123 124static Bool 125radeon_crtc_mode_fixup(xf86CrtcPtr crtc, DisplayModePtr mode, 126 DisplayModePtr adjusted_mode) 127{ 128 return TRUE; 129} 130 131static void 132radeon_crtc_mode_prepare(xf86CrtcPtr crtc) 133{ 134 RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; 135 136 if (radeon_crtc->enabled) 137 crtc->funcs->hide_cursor(crtc); 138} 139 140static uint32_t RADEONDiv(CARD64 n, uint32_t d) 141{ 142 return (n + (d / 2)) / d; 143} 144 145static void 146RADEONComputePLL_old(RADEONPLLPtr pll, 147 unsigned long freq, 148 uint32_t *chosen_dot_clock_freq, 149 uint32_t *chosen_feedback_div, 150 uint32_t *chosen_frac_feedback_div, 151 uint32_t *chosen_reference_div, 152 uint32_t *chosen_post_div, 153 int flags) 154{ 155 uint32_t min_ref_div = pll->min_ref_div; 156 uint32_t max_ref_div = pll->max_ref_div; 157 uint32_t min_post_div = pll->min_post_div; 158 uint32_t max_post_div = pll->max_post_div; 159 uint32_t min_fractional_feed_div = 0; 160 uint32_t max_fractional_feed_div = 0; 161 uint32_t best_vco = pll->best_vco; 162 uint32_t best_post_div = 1; 163 uint32_t best_ref_div = 1; 164 uint32_t best_feedback_div = 1; 165 uint32_t best_frac_feedback_div = 0; 166 uint32_t best_freq = -1; 167 uint32_t best_error = 0xffffffff; 168 uint32_t best_vco_diff = 1; 169 uint32_t post_div; 170 171 freq = freq * 1000; 172 173/* ErrorF("freq: %lu\n", freq); */ 174 175 if (flags & RADEON_PLL_USE_REF_DIV) 176 min_ref_div = max_ref_div = pll->reference_div; 177 else { 178 while (min_ref_div < max_ref_div-1) { 179 uint32_t mid=(min_ref_div+max_ref_div)/2; 180 uint32_t pll_in = pll->reference_freq / mid; 181 if (pll_in < pll->pll_in_min) 182 max_ref_div = mid; 183 else if (pll_in > pll->pll_in_max) 184 min_ref_div = mid; 185 else break; 186 } 187 } 188 189 if (flags & RADEON_PLL_USE_POST_DIV) 190 min_post_div = max_post_div = pll->post_div; 191 192 if (flags & RADEON_PLL_USE_FRAC_FB_DIV) { 193 min_fractional_feed_div = pll->min_frac_feedback_div; 194 max_fractional_feed_div = pll->max_frac_feedback_div; 195 } 196 197 for (post_div = min_post_div; post_div <= max_post_div; ++post_div) { 198 uint32_t ref_div; 199 200 if ((flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1)) 201 continue; 202 203 /* legacy radeons only have a few post_divs */ 204 if (flags & RADEON_PLL_LEGACY) { 205 if ((post_div == 5) || 206 (post_div == 7) || 207 (post_div == 9) || 208 (post_div == 10) || 209 (post_div == 11)) 210 continue; 211 } 212 213 for (ref_div = min_ref_div; ref_div <= max_ref_div; ++ref_div) { 214 uint32_t feedback_div, current_freq = 0, error, vco_diff; 215 uint32_t pll_in = pll->reference_freq / ref_div; 216 uint32_t min_feed_div = pll->min_feedback_div; 217 uint32_t max_feed_div = pll->max_feedback_div+1; 218 219 if (pll_in < pll->pll_in_min || pll_in > pll->pll_in_max) 220 continue; 221 222 while (min_feed_div < max_feed_div) { 223 uint32_t vco; 224 uint32_t min_frac_feed_div = min_fractional_feed_div; 225 uint32_t max_frac_feed_div = max_fractional_feed_div+1; 226 uint32_t frac_feedback_div; 227 CARD64 tmp; 228 229 feedback_div = (min_feed_div+max_feed_div)/2; 230 231 tmp = (CARD64)pll->reference_freq * feedback_div; 232 vco = RADEONDiv(tmp, ref_div); 233 234 if (vco < pll->pll_out_min) { 235 min_feed_div = feedback_div+1; 236 continue; 237 } else if(vco > pll->pll_out_max) { 238 max_feed_div = feedback_div; 239 continue; 240 } 241 242 while (min_frac_feed_div < max_frac_feed_div) { 243 frac_feedback_div = (min_frac_feed_div+max_frac_feed_div)/2; 244 tmp = (CARD64)pll->reference_freq * 10000 * feedback_div; 245 tmp += (CARD64)pll->reference_freq * 1000 * frac_feedback_div; 246 current_freq = RADEONDiv(tmp, ref_div * post_div); 247 248 if (flags & RADEON_PLL_PREFER_CLOSEST_LOWER) { 249 error = freq - current_freq; 250 error = (int32_t)error < 0 ? 0xffffffff : error; 251 } else 252 error = abs(current_freq - freq); 253 vco_diff = abs(vco - best_vco); 254 255 if ((best_vco == 0 && error < best_error) || 256 (best_vco != 0 && 257 (error < best_error - 100 || 258 (abs(error - best_error) < 100 && vco_diff < best_vco_diff )))) { 259 best_post_div = post_div; 260 best_ref_div = ref_div; 261 best_feedback_div = feedback_div; 262 best_frac_feedback_div = frac_feedback_div; 263 best_freq = current_freq; 264 best_error = error; 265 best_vco_diff = vco_diff; 266 } else if (current_freq == freq) { 267 if (best_freq == -1) { 268 best_post_div = post_div; 269 best_ref_div = ref_div; 270 best_feedback_div = feedback_div; 271 best_frac_feedback_div = frac_feedback_div; 272 best_freq = current_freq; 273 best_error = error; 274 best_vco_diff = vco_diff; 275 } else if (((flags & RADEON_PLL_PREFER_LOW_REF_DIV) && (ref_div < best_ref_div)) || 276 ((flags & RADEON_PLL_PREFER_HIGH_REF_DIV) && (ref_div > best_ref_div)) || 277 ((flags & RADEON_PLL_PREFER_LOW_FB_DIV) && (feedback_div < best_feedback_div)) || 278 ((flags & RADEON_PLL_PREFER_HIGH_FB_DIV) && (feedback_div > best_feedback_div)) || 279 ((flags & RADEON_PLL_PREFER_LOW_POST_DIV) && (post_div < best_post_div)) || 280 ((flags & RADEON_PLL_PREFER_HIGH_POST_DIV) && (post_div > best_post_div))) { 281 best_post_div = post_div; 282 best_ref_div = ref_div; 283 best_feedback_div = feedback_div; 284 best_frac_feedback_div = frac_feedback_div; 285 best_freq = current_freq; 286 best_error = error; 287 best_vco_diff = vco_diff; 288 } 289 } 290 if (current_freq < freq) 291 min_frac_feed_div = frac_feedback_div+1; 292 else 293 max_frac_feed_div = frac_feedback_div; 294 } 295 if (current_freq < freq) 296 min_feed_div = feedback_div+1; 297 else 298 max_feed_div = feedback_div; 299 } 300 } 301 } 302 303/* 304 ErrorF("best_freq: %u\n", (unsigned int)best_freq); 305 ErrorF("best_feedback_div: %u\n", (unsigned int)best_feedback_div); 306 ErrorF("best_frac_feedback_div: %u\n", (unsigned int)best_frac_feedback_div); 307 ErrorF("best_ref_div: %u\n", (unsigned int)best_ref_div); 308 ErrorF("best_post_div: %u\n", (unsigned int)best_post_div); 309*/ 310 311 if (best_freq == -1) 312 FatalError("Couldn't find valid PLL dividers\n"); 313 *chosen_dot_clock_freq = best_freq / 10000; 314 *chosen_feedback_div = best_feedback_div; 315 *chosen_frac_feedback_div = best_frac_feedback_div; 316 *chosen_reference_div = best_ref_div; 317 *chosen_post_div = best_post_div; 318 319} 320 321static Bool 322calc_fb_div(RADEONPLLPtr pll, 323 unsigned long freq, 324 int flags, 325 int post_div, 326 int ref_div, 327 int *fb_div, 328 int *fb_div_frac) 329{ 330 float ffreq = freq / 10; 331 float vco_freq = ffreq * post_div; 332 float feedback_divider = vco_freq * ref_div / pll->reference_freq; 333 334 if (flags & RADEON_PLL_USE_FRAC_FB_DIV) { 335 feedback_divider = floor((feedback_divider * 10.0) + 0.5) * 0.1; 336 337 *fb_div = floor(feedback_divider); 338 *fb_div_frac = fmod(feedback_divider, 1.0) * 10.0; 339 340 } else { 341 *fb_div = floor(feedback_divider + 0.5); 342 *fb_div_frac = 0; 343 } 344 if ((*fb_div < pll->min_feedback_div) || (*fb_div > pll->max_feedback_div)) 345 return FALSE; 346 else 347 return TRUE; 348} 349 350static Bool 351calc_fb_ref_div(RADEONPLLPtr pll, 352 unsigned long freq, 353 int flags, 354 int post_div, 355 int *fb_div, 356 int *fb_div_frac, 357 int *ref_div) 358{ 359 float ffreq = freq / 10; 360 float max_error = ffreq * 0.0025; 361 float vco, error, pll_out; 362 363 for ((*ref_div) = pll->min_ref_div; (*ref_div) < pll->max_ref_div; ++(*ref_div)) { 364 if (calc_fb_div(pll, freq, flags, post_div, (*ref_div), fb_div, fb_div_frac)) { 365 vco = pll->reference_freq * ((*fb_div) + ((*fb_div_frac) * 0.1)) / (*ref_div); 366 367 if ((vco < pll->pll_out_min) || (vco > pll->pll_out_max)) 368 continue; 369 370 pll_out = vco / post_div; 371 372 error = pll_out - ffreq; 373 if ((fabs(error) <= max_error) && (error >= 0)) 374 return TRUE; 375 } 376 } 377 return FALSE; 378} 379 380static void 381RADEONComputePLL_new(RADEONPLLPtr pll, 382 unsigned long freq, 383 uint32_t *chosen_dot_clock_freq, 384 uint32_t *chosen_feedback_div, 385 uint32_t *chosen_frac_feedback_div, 386 uint32_t *chosen_reference_div, 387 uint32_t *chosen_post_div, 388 int flags) 389{ 390 float ffreq = freq / 10; 391 float vco_frequency; 392 int fb_div = 0, fb_div_frac = 0, post_div = 0, ref_div = 0; 393 uint32_t best_freq = 0; 394 395 if (flags & RADEON_PLL_USE_POST_DIV) { 396 post_div = pll->post_div; 397 if ((post_div < pll->min_post_div) || (post_div > pll->max_post_div)) 398 goto done; 399 vco_frequency = ffreq * post_div; 400 if ((vco_frequency < pll->pll_out_min) || (vco_frequency > pll->pll_out_max)) 401 goto done; 402 403 if (flags & RADEON_PLL_USE_REF_DIV) { 404 ref_div = pll->reference_div; 405 if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div)) 406 goto done; 407 if (!calc_fb_div(pll, freq, flags, post_div, ref_div, &fb_div, &fb_div_frac)) 408 goto done; 409 } 410 } else { 411 for (post_div = pll->max_post_div; post_div >= pll->min_post_div; --post_div) { 412 if (flags & RADEON_PLL_LEGACY) { 413 if ((post_div == 5) || 414 (post_div == 7) || 415 (post_div == 9) || 416 (post_div == 10) || 417 (post_div == 11)) 418 continue; 419 } 420 if ((flags & RADEON_PLL_NO_ODD_POST_DIV) && (post_div & 1)) 421 continue; 422 423 vco_frequency = ffreq * post_div; 424 if ((vco_frequency < pll->pll_out_min) || (vco_frequency > pll->pll_out_max)) 425 continue; 426 if (flags & RADEON_PLL_USE_REF_DIV) { 427 ref_div = pll->reference_div; 428 if ((ref_div < pll->min_ref_div) || (ref_div > pll->max_ref_div)) 429 goto done; 430 if (calc_fb_div(pll, freq, flags, post_div, ref_div, &fb_div, &fb_div_frac)) 431 break; 432 } else { 433 if (calc_fb_ref_div(pll, freq, flags, post_div, &fb_div, &fb_div_frac, &ref_div)) 434 break; 435 } 436 } 437 } 438 439 best_freq = pll->reference_freq * 10 * fb_div; 440 best_freq += pll->reference_freq * fb_div_frac; 441 best_freq = best_freq / (ref_div * post_div); 442 443/* 444 ErrorF("best_freq: %u\n", (unsigned int)best_freq); 445 ErrorF("best_feedback_div: %u\n", (unsigned int)fb_div); 446 ErrorF("best_frac_feedback_div: %u\n", (unsigned int)fb_div_frac); 447 ErrorF("best_ref_div: %u\n", (unsigned int)ref_div); 448 ErrorF("best_post_div: %u\n", (unsigned int)post_div); 449*/ 450 451done: 452 if (best_freq == 0) 453 FatalError("Couldn't find valid PLL dividers\n"); 454 455 *chosen_dot_clock_freq = best_freq; 456 *chosen_feedback_div = fb_div; 457 *chosen_frac_feedback_div = fb_div_frac; 458 *chosen_reference_div = ref_div; 459 *chosen_post_div = post_div; 460 461} 462 463void 464RADEONComputePLL(xf86CrtcPtr crtc, 465 RADEONPLLPtr pll, 466 unsigned long freq, 467 uint32_t *chosen_dot_clock_freq, 468 uint32_t *chosen_feedback_div, 469 uint32_t *chosen_frac_feedback_div, 470 uint32_t *chosen_reference_div, 471 uint32_t *chosen_post_div, 472 int flags) 473{ 474 RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; 475 476 switch (radeon_crtc->pll_algo) { 477 case RADEON_PLL_OLD: 478 RADEONComputePLL_old(pll, freq, chosen_dot_clock_freq, 479 chosen_feedback_div, chosen_frac_feedback_div, 480 chosen_reference_div, chosen_post_div, flags); 481 break; 482 case RADEON_PLL_NEW: 483 /* disable frac fb dividers */ 484 flags &= ~RADEON_PLL_USE_FRAC_FB_DIV; 485 RADEONComputePLL_new(pll, freq, chosen_dot_clock_freq, 486 chosen_feedback_div, chosen_frac_feedback_div, 487 chosen_reference_div, chosen_post_div, flags); 488 break; 489 } 490} 491 492static void 493radeon_crtc_mode_set(xf86CrtcPtr crtc, DisplayModePtr mode, 494 DisplayModePtr adjusted_mode, int x, int y) 495{ 496 ScrnInfoPtr pScrn = crtc->scrn; 497 RADEONInfoPtr info = RADEONPTR(pScrn); 498 499 if (IS_AVIVO_VARIANT || info->r4xx_atom) { 500 atombios_crtc_mode_set(crtc, mode, adjusted_mode, x, y); 501 } else { 502 legacy_crtc_mode_set(crtc, mode, adjusted_mode, x, y); 503 } 504} 505 506static void 507radeon_crtc_mode_commit(xf86CrtcPtr crtc) 508{ 509 if (crtc->scrn->pScreen != NULL) 510 xf86_reload_cursors(crtc->scrn->pScreen); 511} 512 513void 514radeon_crtc_load_lut(xf86CrtcPtr crtc) 515{ 516 ScrnInfoPtr pScrn = crtc->scrn; 517 RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; 518 RADEONInfoPtr info = RADEONPTR(pScrn); 519 unsigned char *RADEONMMIO = info->MMIO; 520 int i; 521 522 if (!crtc->enabled) 523 return; 524 525 radeon_save_palette_on_demand(pScrn, radeon_crtc->crtc_id); 526 527 if (IS_DCE4_VARIANT) { 528 OUTREG(EVERGREEN_DC_LUT_CONTROL + radeon_crtc->crtc_offset, 0); 529 530 OUTREG(EVERGREEN_DC_LUT_BLACK_OFFSET_BLUE + radeon_crtc->crtc_offset, 0); 531 OUTREG(EVERGREEN_DC_LUT_BLACK_OFFSET_GREEN + radeon_crtc->crtc_offset, 0); 532 OUTREG(EVERGREEN_DC_LUT_BLACK_OFFSET_RED + radeon_crtc->crtc_offset, 0); 533 534 OUTREG(EVERGREEN_DC_LUT_WHITE_OFFSET_BLUE + radeon_crtc->crtc_offset, 0x0000ffff); 535 OUTREG(EVERGREEN_DC_LUT_WHITE_OFFSET_GREEN + radeon_crtc->crtc_offset, 0x0000ffff); 536 OUTREG(EVERGREEN_DC_LUT_WHITE_OFFSET_RED + radeon_crtc->crtc_offset, 0x0000ffff); 537 538 OUTREG(EVERGREEN_DC_LUT_RW_MODE + radeon_crtc->crtc_offset, 0); 539 OUTREG(EVERGREEN_DC_LUT_WRITE_EN_MASK + radeon_crtc->crtc_offset, 0x00000007); 540 541 for (i = 0; i < 256; i++) { 542 OUTREG(EVERGREEN_DC_LUT_RW_INDEX + radeon_crtc->crtc_offset, i); 543 OUTREG(EVERGREEN_DC_LUT_30_COLOR + radeon_crtc->crtc_offset, 544 (((radeon_crtc->lut_r[i]) << 20) | 545 ((radeon_crtc->lut_g[i]) << 10) | 546 (radeon_crtc->lut_b[i]))); 547 } 548 } else { 549 if (IS_AVIVO_VARIANT) { 550 OUTREG(AVIVO_DC_LUTA_CONTROL + radeon_crtc->crtc_offset, 0); 551 552 OUTREG(AVIVO_DC_LUTA_BLACK_OFFSET_BLUE + radeon_crtc->crtc_offset, 0); 553 OUTREG(AVIVO_DC_LUTA_BLACK_OFFSET_GREEN + radeon_crtc->crtc_offset, 0); 554 OUTREG(AVIVO_DC_LUTA_BLACK_OFFSET_RED + radeon_crtc->crtc_offset, 0); 555 556 OUTREG(AVIVO_DC_LUTA_WHITE_OFFSET_BLUE + radeon_crtc->crtc_offset, 0x0000ffff); 557 OUTREG(AVIVO_DC_LUTA_WHITE_OFFSET_GREEN + radeon_crtc->crtc_offset, 0x0000ffff); 558 OUTREG(AVIVO_DC_LUTA_WHITE_OFFSET_RED + radeon_crtc->crtc_offset, 0x0000ffff); 559 } 560 561 PAL_SELECT(radeon_crtc->crtc_id); 562 563 if (IS_AVIVO_VARIANT) { 564 OUTREG(AVIVO_DC_LUT_RW_MODE, 0); 565 OUTREG(AVIVO_DC_LUT_WRITE_EN_MASK, 0x0000003f); 566 } 567 568 for (i = 0; i < 256; i++) { 569 OUTPAL(i, radeon_crtc->lut_r[i], radeon_crtc->lut_g[i], radeon_crtc->lut_b[i]); 570 } 571 572 if (IS_AVIVO_VARIANT) 573 OUTREG(AVIVO_D1GRPH_LUT_SEL + radeon_crtc->crtc_offset, radeon_crtc->crtc_id); 574 } 575} 576 577static void 578radeon_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 579 uint16_t *blue, int size) 580{ 581 RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; 582 int i; 583 584 for (i = 0; i < 256; i++) { 585 radeon_crtc->lut_r[i] = red[i] >> 6; 586 radeon_crtc->lut_g[i] = green[i] >> 6; 587 radeon_crtc->lut_b[i] = blue[i] >> 6; 588 } 589 590 radeon_crtc_load_lut(crtc); 591} 592 593static Bool 594radeon_crtc_lock(xf86CrtcPtr crtc) 595{ 596 ScrnInfoPtr pScrn = crtc->scrn; 597 RADEONInfoPtr info = RADEONPTR(pScrn); 598 599#ifdef XF86DRI 600 if (info->cp->CPStarted && pScrn->pScreen) { 601 DRILock(pScrn->pScreen, 0); 602 if (info->accelOn) 603 RADEON_SYNC(info, pScrn); 604 return TRUE; 605 } 606#endif 607 if (info->accelOn) 608 RADEON_SYNC(info, pScrn); 609 610 return FALSE; 611 612} 613 614static void 615radeon_crtc_unlock(xf86CrtcPtr crtc) 616{ 617 ScrnInfoPtr pScrn = crtc->scrn; 618 RADEONInfoPtr info = RADEONPTR(pScrn); 619 620#ifdef XF86DRI 621 if (info->cp->CPStarted && pScrn->pScreen) DRIUnlock(pScrn->pScreen); 622#endif 623 624 if (info->accelOn) 625 RADEON_SYNC(info, pScrn); 626} 627 628/** 629 * Allocates memory for a locked-in-framebuffer shadow of the given 630 * width and height for this CRTC's rotated shadow framebuffer. 631 */ 632 633static void * 634radeon_crtc_shadow_allocate (xf86CrtcPtr crtc, int width, int height) 635{ 636 ScrnInfoPtr pScrn = crtc->scrn; 637 RADEONInfoPtr info = RADEONPTR(pScrn); 638 RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; 639 unsigned long rotate_pitch; 640 unsigned long rotate_offset; 641 int size; 642 int cpp = pScrn->bitsPerPixel / 8; 643 644 /* No rotation without accel */ 645 if (((info->ChipFamily >= CHIP_FAMILY_R600) && !info->directRenderingEnabled) || 646 xf86ReturnOptValBool(info->Options, OPTION_NOACCEL, FALSE)) { 647 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 648 "Acceleration required for rotation\n"); 649 return NULL; 650 } 651 652 rotate_pitch = pScrn->displayWidth * cpp; 653 size = rotate_pitch * height; 654 655 /* We could get close to what we want here by just creating a pixmap like 656 * normal, but we have to lock it down in framebuffer, and there is no 657 * setter for offscreen area locking in EXA currently. So, we just 658 * allocate offscreen memory and fake up a pixmap header for it. 659 */ 660 rotate_offset = radeon_legacy_allocate_memory(pScrn, &radeon_crtc->crtc_rotate_mem, 661 size, RADEON_GPU_PAGE_SIZE, RADEON_GEM_DOMAIN_VRAM); 662 if (rotate_offset == 0) 663 return NULL; 664 665 return info->FB + rotate_offset; 666} 667 668/** 669 * Creates a pixmap for this CRTC's rotated shadow framebuffer. 670 */ 671static PixmapPtr 672radeon_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 673{ 674 ScrnInfoPtr pScrn = crtc->scrn; 675 unsigned long rotate_pitch; 676 PixmapPtr rotate_pixmap; 677 int cpp = pScrn->bitsPerPixel / 8; 678 679 if (!data) 680 data = radeon_crtc_shadow_allocate(crtc, width, height); 681 682 rotate_pitch = pScrn->displayWidth * cpp; 683 684 rotate_pixmap = GetScratchPixmapHeader(pScrn->pScreen, 685 width, height, 686 pScrn->depth, 687 pScrn->bitsPerPixel, 688 rotate_pitch, 689 data); 690 691 if (rotate_pixmap == NULL) { 692 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 693 "Couldn't allocate shadow pixmap for rotated CRTC\n"); 694 } 695 696 return rotate_pixmap; 697} 698 699static void 700radeon_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) 701{ 702 ScrnInfoPtr pScrn = crtc->scrn; 703 RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; 704 705 if (rotate_pixmap) 706 FreeScratchPixmapHeader(rotate_pixmap); 707 708 if (data) { 709 radeon_legacy_free_memory(pScrn, radeon_crtc->crtc_rotate_mem); 710 radeon_crtc->crtc_rotate_mem = NULL; 711 } 712 713} 714 715#if XF86_CRTC_VERSION >= 2 716#include "radeon_atombios.h" 717 718extern AtomBiosResult 719atombios_lock_crtc(atomBiosHandlePtr atomBIOS, int crtc, int lock); 720extern void 721RADEONInitCrtcBase(xf86CrtcPtr crtc, RADEONSavePtr save, 722 int x, int y); 723extern void 724RADEONInitCrtc2Base(xf86CrtcPtr crtc, RADEONSavePtr save, 725 int x, int y); 726extern void 727RADEONRestoreCrtcBase(ScrnInfoPtr pScrn, 728 RADEONSavePtr restore); 729extern void 730RADEONRestoreCrtc2Base(ScrnInfoPtr pScrn, 731 RADEONSavePtr restore); 732 733static void 734radeon_crtc_set_origin(xf86CrtcPtr crtc, int x, int y) 735{ 736 ScrnInfoPtr pScrn = crtc->scrn; 737 RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; 738 RADEONInfoPtr info = RADEONPTR(pScrn); 739 unsigned char *RADEONMMIO = info->MMIO; 740 741 742 if (IS_DCE4_VARIANT) { 743 x &= ~3; 744 y &= ~1; 745 atombios_lock_crtc(info->atomBIOS, radeon_crtc->crtc_id, 1); 746 OUTREG(EVERGREEN_VIEWPORT_START + radeon_crtc->crtc_offset, (x << 16) | y); 747 atombios_lock_crtc(info->atomBIOS, radeon_crtc->crtc_id, 0); 748 } else if (IS_AVIVO_VARIANT) { 749 x &= ~3; 750 y &= ~1; 751 atombios_lock_crtc(info->atomBIOS, radeon_crtc->crtc_id, 1); 752 OUTREG(AVIVO_D1MODE_VIEWPORT_START + radeon_crtc->crtc_offset, (x << 16) | y); 753 atombios_lock_crtc(info->atomBIOS, radeon_crtc->crtc_id, 0); 754 } else { 755 switch (radeon_crtc->crtc_id) { 756 case 0: 757 RADEONInitCrtcBase(crtc, info->ModeReg, x, y); 758 RADEONRestoreCrtcBase(pScrn, info->ModeReg); 759 break; 760 case 1: 761 RADEONInitCrtc2Base(crtc, info->ModeReg, x, y); 762 RADEONRestoreCrtc2Base(pScrn, info->ModeReg); 763 break; 764 default: 765 break; 766 } 767 } 768} 769#endif 770 771 772static xf86CrtcFuncsRec radeon_crtc_funcs = { 773 .dpms = radeon_crtc_dpms, 774 .save = NULL, /* XXX */ 775 .restore = NULL, /* XXX */ 776 .mode_fixup = radeon_crtc_mode_fixup, 777 .prepare = radeon_crtc_mode_prepare, 778 .mode_set = radeon_crtc_mode_set, 779 .commit = radeon_crtc_mode_commit, 780 .gamma_set = radeon_crtc_gamma_set, 781 .lock = radeon_crtc_lock, 782 .unlock = radeon_crtc_unlock, 783 .shadow_create = radeon_crtc_shadow_create, 784 .shadow_allocate = radeon_crtc_shadow_allocate, 785 .shadow_destroy = radeon_crtc_shadow_destroy, 786 .set_cursor_colors = radeon_crtc_set_cursor_colors, 787 .set_cursor_position = radeon_crtc_set_cursor_position, 788 .show_cursor = radeon_crtc_show_cursor, 789 .hide_cursor = radeon_crtc_hide_cursor, 790 .load_cursor_argb = radeon_crtc_load_cursor_argb, 791 .destroy = NULL, /* XXX */ 792#if XF86_CRTC_VERSION >= 2 793 .set_origin = radeon_crtc_set_origin, 794#endif 795}; 796 797void 798RADEONInitDispBandwidth(ScrnInfoPtr pScrn) 799{ 800 RADEONInfoPtr info = RADEONPTR(pScrn); 801 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 802 DisplayModePtr mode1 = NULL, mode2 = NULL; 803 int pixel_bytes1 = info->CurrentLayout.pixel_bytes; 804 int pixel_bytes2 = info->CurrentLayout.pixel_bytes; 805 806 /* XXX fix me */ 807 if (IS_DCE4_VARIANT) 808 return; 809 810 if (xf86_config->num_crtc == 2) { 811 if (xf86_config->crtc[1]->enabled && 812 xf86_config->crtc[0]->enabled) { 813 mode1 = &xf86_config->crtc[0]->mode; 814 mode2 = &xf86_config->crtc[1]->mode; 815 } else if (xf86_config->crtc[0]->enabled) { 816 mode1 = &xf86_config->crtc[0]->mode; 817 } else if (xf86_config->crtc[1]->enabled) { 818 mode2 = &xf86_config->crtc[1]->mode; 819 } else 820 return; 821 } else { 822 if (info->IsPrimary) 823 mode1 = &xf86_config->crtc[0]->mode; 824 else if (info->IsSecondary) 825 mode2 = &xf86_config->crtc[0]->mode; 826 else if (xf86_config->crtc[0]->enabled) 827 mode1 = &xf86_config->crtc[0]->mode; 828 else 829 return; 830 } 831 832 if (IS_AVIVO_VARIANT) 833 RADEONInitDispBandwidthAVIVO(pScrn, mode1, pixel_bytes1, mode2, pixel_bytes2); 834 else 835 RADEONInitDispBandwidthLegacy(pScrn, mode1, pixel_bytes1, mode2, pixel_bytes2); 836} 837 838Bool RADEONAllocateControllers(ScrnInfoPtr pScrn, int mask) 839{ 840 RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 841 RADEONInfoPtr info = RADEONPTR(pScrn); 842 int i; 843 844 if (!xf86ReturnOptValBool(info->Options, OPTION_NOACCEL, FALSE)) { 845 radeon_crtc_funcs.shadow_create = radeon_crtc_shadow_create; 846 radeon_crtc_funcs.shadow_allocate = radeon_crtc_shadow_allocate; 847 radeon_crtc_funcs.shadow_destroy = radeon_crtc_shadow_destroy; 848 } 849 850 if (mask & 1) { 851 if (pRADEONEnt->Controller[0]) 852 return TRUE; 853 854 pRADEONEnt->pCrtc[0] = xf86CrtcCreate(pScrn, &radeon_crtc_funcs); 855 if (!pRADEONEnt->pCrtc[0]) 856 return FALSE; 857 858 pRADEONEnt->Controller[0] = xnfcalloc(sizeof(RADEONCrtcPrivateRec), 1); 859 if (!pRADEONEnt->Controller[0]) 860 return FALSE; 861 862 pRADEONEnt->pCrtc[0]->driver_private = pRADEONEnt->Controller[0]; 863 pRADEONEnt->Controller[0]->crtc_id = 0; 864 pRADEONEnt->Controller[0]->crtc_offset = 0; 865 pRADEONEnt->Controller[0]->initialized = FALSE; 866 if (info->allowColorTiling) 867 pRADEONEnt->Controller[0]->can_tile = 1; 868 else 869 pRADEONEnt->Controller[0]->can_tile = 0; 870 pRADEONEnt->Controller[0]->pll_id = -1; 871 } 872 873 if (mask & 2) { 874 if (!pRADEONEnt->HasCRTC2) 875 return TRUE; 876 877 pRADEONEnt->pCrtc[1] = xf86CrtcCreate(pScrn, &radeon_crtc_funcs); 878 if (!pRADEONEnt->pCrtc[1]) 879 return FALSE; 880 881 pRADEONEnt->Controller[1] = xnfcalloc(sizeof(RADEONCrtcPrivateRec), 1); 882 if (!pRADEONEnt->Controller[1]) 883 { 884 free(pRADEONEnt->Controller[0]); 885 return FALSE; 886 } 887 888 pRADEONEnt->pCrtc[1]->driver_private = pRADEONEnt->Controller[1]; 889 pRADEONEnt->Controller[1]->crtc_id = 1; 890 if (IS_DCE4_VARIANT) 891 pRADEONEnt->Controller[1]->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET; 892 else 893 pRADEONEnt->Controller[1]->crtc_offset = AVIVO_D2CRTC_H_TOTAL - AVIVO_D1CRTC_H_TOTAL; 894 pRADEONEnt->Controller[1]->initialized = FALSE; 895 if (info->allowColorTiling) 896 pRADEONEnt->Controller[1]->can_tile = 1; 897 else 898 pRADEONEnt->Controller[1]->can_tile = 0; 899 pRADEONEnt->Controller[1]->pll_id = -1; 900 } 901 902 /* 6 crtcs on DCE4 chips */ 903 if (IS_DCE4_VARIANT && ((mask & 3) == 3) && !IS_DCE41_VARIANT) { 904 for (i = 2; i < RADEON_MAX_CRTC; i++) { 905 pRADEONEnt->pCrtc[i] = xf86CrtcCreate(pScrn, &radeon_crtc_funcs); 906 if (!pRADEONEnt->pCrtc[i]) 907 return FALSE; 908 909 pRADEONEnt->Controller[i] = xnfcalloc(sizeof(RADEONCrtcPrivateRec), 1); 910 if (!pRADEONEnt->Controller[i]) 911 { 912 free(pRADEONEnt->Controller[i]); 913 return FALSE; 914 } 915 916 pRADEONEnt->pCrtc[i]->driver_private = pRADEONEnt->Controller[i]; 917 pRADEONEnt->Controller[i]->crtc_id = i; 918 switch (i) { 919 case 0: 920 pRADEONEnt->Controller[i]->crtc_offset = EVERGREEN_CRTC0_REGISTER_OFFSET; 921 break; 922 case 1: 923 pRADEONEnt->Controller[i]->crtc_offset = EVERGREEN_CRTC1_REGISTER_OFFSET; 924 break; 925 case 2: 926 pRADEONEnt->Controller[i]->crtc_offset = EVERGREEN_CRTC2_REGISTER_OFFSET; 927 break; 928 case 3: 929 pRADEONEnt->Controller[i]->crtc_offset = EVERGREEN_CRTC3_REGISTER_OFFSET; 930 break; 931 case 4: 932 pRADEONEnt->Controller[i]->crtc_offset = EVERGREEN_CRTC4_REGISTER_OFFSET; 933 break; 934 case 5: 935 pRADEONEnt->Controller[i]->crtc_offset = EVERGREEN_CRTC5_REGISTER_OFFSET; 936 break; 937 } 938 pRADEONEnt->Controller[i]->initialized = FALSE; 939 if (info->allowColorTiling) 940 pRADEONEnt->Controller[i]->can_tile = 1; 941 else 942 pRADEONEnt->Controller[i]->can_tile = 0; 943 pRADEONEnt->Controller[i]->pll_id = -1; 944 } 945 } 946 947 return TRUE; 948} 949 950/** 951 * In the current world order, there are lists of modes per output, which may 952 * or may not include the mode that was asked to be set by XFree86's mode 953 * selection. Find the closest one, in the following preference order: 954 * 955 * - Equality 956 * - Closer in size to the requested mode, but no larger 957 * - Closer in refresh rate to the requested mode. 958 */ 959DisplayModePtr 960RADEONCrtcFindClosestMode(xf86CrtcPtr crtc, DisplayModePtr pMode) 961{ 962 ScrnInfoPtr pScrn = crtc->scrn; 963 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 964 DisplayModePtr pBest = NULL, pScan = NULL; 965 int i; 966 967 /* Assume that there's only one output connected to the given CRTC. */ 968 for (i = 0; i < xf86_config->num_output; i++) 969 { 970 xf86OutputPtr output = xf86_config->output[i]; 971 if (output->crtc == crtc && output->probed_modes != NULL) 972 { 973 pScan = output->probed_modes; 974 break; 975 } 976 } 977 978 /* If the pipe doesn't have any detected modes, just let the system try to 979 * spam the desired mode in. 980 */ 981 if (pScan == NULL) { 982 RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; 983 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 984 "No crtc mode list for crtc %d," 985 "continuing with desired mode\n", radeon_crtc->crtc_id); 986 return pMode; 987 } 988 989 for (; pScan != NULL; pScan = pScan->next) { 990 assert(pScan->VRefresh != 0.0); 991 992 /* If there's an exact match, we're done. */ 993 if (xf86ModesEqual(pScan, pMode)) { 994 pBest = pMode; 995 break; 996 } 997 998 /* Reject if it's larger than the desired mode. */ 999 if (pScan->HDisplay > pMode->HDisplay || 1000 pScan->VDisplay > pMode->VDisplay) 1001 { 1002 continue; 1003 } 1004 1005 if (pBest == NULL) { 1006 pBest = pScan; 1007 continue; 1008 } 1009 1010 /* Find if it's closer to the right size than the current best 1011 * option. 1012 */ 1013 if ((pScan->HDisplay > pBest->HDisplay && 1014 pScan->VDisplay >= pBest->VDisplay) || 1015 (pScan->HDisplay >= pBest->HDisplay && 1016 pScan->VDisplay > pBest->VDisplay)) 1017 { 1018 pBest = pScan; 1019 continue; 1020 } 1021 1022 /* Find if it's still closer to the right refresh than the current 1023 * best resolution. 1024 */ 1025 if (pScan->HDisplay == pBest->HDisplay && 1026 pScan->VDisplay == pBest->VDisplay && 1027 (fabs(pScan->VRefresh - pMode->VRefresh) < 1028 fabs(pBest->VRefresh - pMode->VRefresh))) { 1029 pBest = pScan; 1030 } 1031 } 1032 1033 if (pBest == NULL) { 1034 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1035 "No suitable mode found to program for the pipe.\n" 1036 " continuing with desired mode %dx%d@%.1f\n", 1037 pMode->HDisplay, pMode->VDisplay, pMode->VRefresh); 1038 } else if (!xf86ModesEqual(pBest, pMode)) { 1039 RADEONCrtcPrivatePtr radeon_crtc = crtc->driver_private; 1040 int crtc = radeon_crtc->crtc_id; 1041 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1042 "Choosing pipe %d's mode %dx%d@%.1f instead of xf86 " 1043 "mode %dx%d@%.1f\n", crtc, 1044 pBest->HDisplay, pBest->VDisplay, pBest->VRefresh, 1045 pMode->HDisplay, pMode->VDisplay, pMode->VRefresh); 1046 pMode = pBest; 1047 } 1048 return pMode; 1049} 1050 1051void 1052RADEONBlank(ScrnInfoPtr pScrn) 1053{ 1054 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1055 xf86OutputPtr output; 1056 xf86CrtcPtr crtc; 1057 int o, c; 1058 1059 for (c = 0; c < xf86_config->num_crtc; c++) { 1060 crtc = xf86_config->crtc[c]; 1061 for (o = 0; o < xf86_config->num_output; o++) { 1062 output = xf86_config->output[o]; 1063 if (output->crtc != crtc) 1064 continue; 1065 1066 output->funcs->dpms(output, DPMSModeOff); 1067 } 1068 crtc->funcs->dpms(crtc, DPMSModeOff); 1069 } 1070} 1071 1072void 1073RADEONUnblank(ScrnInfoPtr pScrn) 1074{ 1075 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1076 xf86OutputPtr output; 1077 xf86CrtcPtr crtc; 1078 int o, c; 1079 1080 for (c = 0; c < xf86_config->num_crtc; c++) { 1081 crtc = xf86_config->crtc[c]; 1082 if(!crtc->enabled) 1083 continue; 1084 crtc->funcs->dpms(crtc, DPMSModeOn); 1085 for (o = 0; o < xf86_config->num_output; o++) { 1086 output = xf86_config->output[o]; 1087 if (output->crtc != crtc) 1088 continue; 1089 1090 output->funcs->dpms(output, DPMSModeOn); 1091 } 1092 } 1093} 1094 1095Bool 1096RADEONSetTiling(ScrnInfoPtr pScrn) 1097{ 1098 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1099 RADEONInfoPtr info = RADEONPTR(pScrn); 1100 RADEONCrtcPrivatePtr radeon_crtc; 1101 xf86CrtcPtr crtc; 1102 int c; 1103 int can_tile = 1; 1104 Bool changed = FALSE; 1105 1106 for (c = 0; c < xf86_config->num_crtc; c++) { 1107 crtc = xf86_config->crtc[c]; 1108 radeon_crtc = crtc->driver_private; 1109 1110 if (crtc->enabled) { 1111 if (!radeon_crtc->can_tile) 1112 can_tile = 0; 1113 } 1114 } 1115 1116 if (info->tilingEnabled != can_tile) 1117 changed = TRUE; 1118 1119#ifdef XF86DRI 1120 if (info->directRenderingEnabled && (info->tilingEnabled != can_tile)) { 1121 drm_radeon_sarea_t *pSAREAPriv; 1122 if (RADEONDRISetParam(pScrn, RADEON_SETPARAM_SWITCH_TILING, (can_tile ? 1 : 0)) < 0) 1123 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1124 "[drm] failed changing tiling status\n"); 1125 /* if this is called during ScreenInit() we don't have pScrn->pScreen yet */ 1126 pSAREAPriv = DRIGetSAREAPrivate(xf86ScrnToScreen(pScrn)); 1127 info->tilingEnabled = pSAREAPriv->tiling_enabled ? TRUE : FALSE; 1128 } 1129#endif 1130 1131 return changed; 1132} 1133