1/* 2 * Copyright 2006-2013, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Alexander von Gluck, kallisti5@unixzen.com 7 * Bill Randle, billr@neocat.org 8 */ 9 10/* 11 * It's dangerous to go alone, take this! 12 * framebuffer -> crtc -> encoder -> transmitter -> connector -> monitor 13 */ 14 15 16#include "display.h" 17 18#include <stdlib.h> 19#include <string.h> 20 21#include "accelerant.h" 22#include "accelerant_protos.h" 23#include "bios.h" 24#include "connector.h" 25#include "displayport.h" 26#include "encoder.h" 27 28 29#define TRACE_DISPLAY 30#ifdef TRACE_DISPLAY 31extern "C" void _sPrintf(const char* format, ...); 32# define TRACE(x...) _sPrintf("radeon_hd: " x) 33#else 34# define TRACE(x...) ; 35#endif 36 37#define ERROR(x...) _sPrintf("radeon_hd: " x) 38 39 40/*! Populate regs with device dependant register locations */ 41status_t 42init_registers(register_info* regs, uint8 crtcID) 43{ 44 memset(regs, 0, sizeof(register_info)); 45 46 radeon_shared_info &info = *gInfo->shared_info; 47 48 if (info.chipsetID >= RADEON_CEDAR) { 49 // Evergreen 50 uint32 offset = 0; 51 52 switch (crtcID) { 53 case 0: 54 offset = EVERGREEN_CRTC0_REGISTER_OFFSET; 55 regs->vgaControl = AVIVO_D1VGA_CONTROL; 56 break; 57 case 1: 58 offset = EVERGREEN_CRTC1_REGISTER_OFFSET; 59 regs->vgaControl = AVIVO_D2VGA_CONTROL; 60 break; 61 case 2: 62 offset = EVERGREEN_CRTC2_REGISTER_OFFSET; 63 regs->vgaControl = EVERGREEN_D3VGA_CONTROL; 64 break; 65 case 3: 66 offset = EVERGREEN_CRTC3_REGISTER_OFFSET; 67 regs->vgaControl = EVERGREEN_D4VGA_CONTROL; 68 break; 69 case 4: 70 offset = EVERGREEN_CRTC4_REGISTER_OFFSET; 71 regs->vgaControl = EVERGREEN_D5VGA_CONTROL; 72 break; 73 case 5: 74 offset = EVERGREEN_CRTC5_REGISTER_OFFSET; 75 regs->vgaControl = EVERGREEN_D6VGA_CONTROL; 76 break; 77 default: 78 ERROR("%s: Unknown CRTC %" B_PRIu32 "\n", 79 __func__, crtcID); 80 return B_ERROR; 81 } 82 83 regs->crtcOffset = offset; 84 85 regs->grphEnable = EVERGREEN_GRPH_ENABLE + offset; 86 regs->grphControl = EVERGREEN_GRPH_CONTROL + offset; 87 regs->grphSwapControl = EVERGREEN_GRPH_SWAP_CONTROL + offset; 88 89 regs->grphPrimarySurfaceAddr 90 = EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + offset; 91 regs->grphSecondarySurfaceAddr 92 = EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + offset; 93 regs->grphPrimarySurfaceAddrHigh 94 = EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + offset; 95 regs->grphSecondarySurfaceAddrHigh 96 = EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + offset; 97 98 regs->grphPitch = EVERGREEN_GRPH_PITCH + offset; 99 regs->grphSurfaceOffsetX 100 = EVERGREEN_GRPH_SURFACE_OFFSET_X + offset; 101 regs->grphSurfaceOffsetY 102 = EVERGREEN_GRPH_SURFACE_OFFSET_Y + offset; 103 regs->grphXStart = EVERGREEN_GRPH_X_START + offset; 104 regs->grphYStart = EVERGREEN_GRPH_Y_START + offset; 105 regs->grphXEnd = EVERGREEN_GRPH_X_END + offset; 106 regs->grphYEnd = EVERGREEN_GRPH_Y_END + offset; 107 regs->modeDesktopHeight = EVERGREEN_DESKTOP_HEIGHT + offset; 108 regs->modeDataFormat = EVERGREEN_DATA_FORMAT + offset; 109 regs->viewportStart = EVERGREEN_VIEWPORT_START + offset; 110 regs->viewportSize = EVERGREEN_VIEWPORT_SIZE + offset; 111 112 } else if (info.chipsetID >= RADEON_RV770) { 113 // R700 series 114 uint32 offset = 0; 115 116 switch (crtcID) { 117 case 0: 118 offset = R700_CRTC0_REGISTER_OFFSET; 119 regs->vgaControl = AVIVO_D1VGA_CONTROL; 120 regs->grphPrimarySurfaceAddrHigh 121 = R700_D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH; 122 break; 123 case 1: 124 offset = R700_CRTC1_REGISTER_OFFSET; 125 regs->vgaControl = AVIVO_D2VGA_CONTROL; 126 regs->grphPrimarySurfaceAddrHigh 127 = R700_D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH; 128 break; 129 default: 130 ERROR("%s: Unknown CRTC %" B_PRIu32 "\n", 131 __func__, crtcID); 132 return B_ERROR; 133 } 134 135 regs->crtcOffset = offset; 136 137 regs->grphEnable = AVIVO_D1GRPH_ENABLE + offset; 138 regs->grphControl = AVIVO_D1GRPH_CONTROL + offset; 139 regs->grphSwapControl = AVIVO_D1GRPH_SWAP_CNTL + offset; 140 141 regs->grphPrimarySurfaceAddr 142 = R700_D1GRPH_PRIMARY_SURFACE_ADDRESS + offset; 143 regs->grphSecondarySurfaceAddr 144 = R700_D1GRPH_SECONDARY_SURFACE_ADDRESS + offset; 145 146 regs->grphPitch = AVIVO_D1GRPH_PITCH + offset; 147 regs->grphSurfaceOffsetX = AVIVO_D1GRPH_SURFACE_OFFSET_X + offset; 148 regs->grphSurfaceOffsetY = AVIVO_D1GRPH_SURFACE_OFFSET_Y + offset; 149 regs->grphXStart = AVIVO_D1GRPH_X_START + offset; 150 regs->grphYStart = AVIVO_D1GRPH_Y_START + offset; 151 regs->grphXEnd = AVIVO_D1GRPH_X_END + offset; 152 regs->grphYEnd = AVIVO_D1GRPH_Y_END + offset; 153 154 regs->modeDesktopHeight = AVIVO_D1MODE_DESKTOP_HEIGHT + offset; 155 regs->modeDataFormat = AVIVO_D1MODE_DATA_FORMAT + offset; 156 regs->viewportStart = AVIVO_D1MODE_VIEWPORT_START + offset; 157 regs->viewportSize = AVIVO_D1MODE_VIEWPORT_SIZE + offset; 158 159 } else if (info.chipsetID >= RADEON_RS600) { 160 // Avivo+ 161 uint32 offset = 0; 162 163 switch (crtcID) { 164 case 0: 165 offset = R600_CRTC0_REGISTER_OFFSET; 166 regs->vgaControl = AVIVO_D1VGA_CONTROL; 167 break; 168 case 1: 169 offset = R600_CRTC1_REGISTER_OFFSET; 170 regs->vgaControl = AVIVO_D2VGA_CONTROL; 171 break; 172 default: 173 ERROR("%s: Unknown CRTC %" B_PRIu32 "\n", 174 __func__, crtcID); 175 return B_ERROR; 176 } 177 178 regs->crtcOffset = offset; 179 180 regs->grphEnable = AVIVO_D1GRPH_ENABLE + offset; 181 regs->grphControl = AVIVO_D1GRPH_CONTROL + offset; 182 regs->grphSwapControl = AVIVO_D1GRPH_SWAP_CNTL + offset; 183 184 regs->grphPrimarySurfaceAddr 185 = AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + offset; 186 regs->grphSecondarySurfaceAddr 187 = AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + offset; 188 189 // Surface Address high only used on r700 and higher 190 regs->grphPrimarySurfaceAddrHigh = 0xDEAD; 191 regs->grphSecondarySurfaceAddrHigh = 0xDEAD; 192 193 regs->grphPitch = AVIVO_D1GRPH_PITCH + offset; 194 regs->grphSurfaceOffsetX = AVIVO_D1GRPH_SURFACE_OFFSET_X + offset; 195 regs->grphSurfaceOffsetY = AVIVO_D1GRPH_SURFACE_OFFSET_Y + offset; 196 regs->grphXStart = AVIVO_D1GRPH_X_START + offset; 197 regs->grphYStart = AVIVO_D1GRPH_Y_START + offset; 198 regs->grphXEnd = AVIVO_D1GRPH_X_END + offset; 199 regs->grphYEnd = AVIVO_D1GRPH_Y_END + offset; 200 201 regs->modeDesktopHeight = AVIVO_D1MODE_DESKTOP_HEIGHT + offset; 202 regs->modeDataFormat = AVIVO_D1MODE_DATA_FORMAT + offset; 203 regs->viewportStart = AVIVO_D1MODE_VIEWPORT_START + offset; 204 regs->viewportSize = AVIVO_D1MODE_VIEWPORT_SIZE + offset; 205 } else { 206 // this really shouldn't happen unless a driver PCIID chipset is wrong 207 TRACE("%s, unknown Radeon chipset: %s\n", __func__, 208 info.chipsetName); 209 return B_ERROR; 210 } 211 212 TRACE("%s, registers for ATI chipset %s crt #%d loaded\n", __func__, 213 info.chipsetName, crtcID); 214 215 return B_OK; 216} 217 218 219status_t 220detect_crt_ranges(uint32 crtid) 221{ 222 edid1_info* edid = &gDisplay[crtid]->edidData; 223 224 // Scan each display EDID description for monitor ranges 225 for (uint32 index = 0; index < EDID1_NUM_DETAILED_MONITOR_DESC; index++) { 226 227 edid1_detailed_monitor* monitor 228 = &edid->detailed_monitor[index]; 229 230 if (monitor->monitor_desc_type == EDID1_MONITOR_RANGES) { 231 edid1_monitor_range range = monitor->data.monitor_range; 232 gDisplay[crtid]->vfreqMin = range.min_v; /* in Hz */ 233 gDisplay[crtid]->vfreqMax = range.max_v; 234 gDisplay[crtid]->hfreqMin = range.min_h; /* in kHz */ 235 gDisplay[crtid]->hfreqMax = range.max_h; 236 return B_OK; 237 } 238 } 239 240 return B_ERROR; 241} 242 243 244static void 245remove_dup_displays(uint32 displayIndex, uint32 id) 246{ 247 /* hack for both digital and analog interfaces active */ 248 if ((displayIndex > 0) && gDisplay[displayIndex]->attached) { 249 if (gConnector[id-1]->encoder.type == VIDEO_ENCODER_TMDS) { 250 int gpioID1 = gConnector[id-1]->gpioID; 251 int gpioID2 = gConnector[id]->gpioID; 252 edid1_info* edid = &gDisplay[displayIndex-1]->edidData; 253 254 if ((gGPIOInfo[gpioID1]->hwPin == gGPIOInfo[gpioID2]->hwPin) && 255 edid->display.input_type) 256 // give preference to digital display when both are present 257 // and other display indicates it is digital 258 TRACE("%s: skipping connector %" B_PRIu32 259 ": giving preference to digital " 260 "connector %d\n", __func__, id, id-1); 261 gDisplay[displayIndex]->attached = 0; 262 } 263 } 264} 265 266 267status_t 268detect_displays() 269{ 270 // reset known displays 271 for (uint32 id = 0; id < MAX_DISPLAY; id++) { 272 gDisplay[id]->attached = false; 273 gDisplay[id]->powered = false; 274 gDisplay[id]->foundRanges = false; 275 } 276 277 uint32 displayIndex = 0; 278 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) { 279 if (gConnector[id]->valid == false) 280 continue; 281 if (displayIndex >= MAX_DISPLAY) 282 continue; 283 284 if (gConnector[id]->type == VIDEO_CONNECTOR_9DIN) { 285 TRACE("%s: connector(%" B_PRIu32 "): Skipping 9DIN connector " 286 "(not yet supported)\n", __func__, id); 287 continue; 288 } 289 290 if (gConnector[id]->type == VIDEO_CONNECTOR_DP) { 291 TRACE("%s: connector(%" B_PRIu32 "): Checking DP.\n", __func__, id); 292 293 edid1_info* edid = &gDisplay[displayIndex]->edidData; 294 gDisplay[displayIndex]->attached 295 = ddc2_dp_read_edid1(id, edid); 296 297 if (gDisplay[displayIndex]->attached) { 298 TRACE("%s: connector(%" B_PRIu32 "): Found DisplayPort EDID!\n", 299 __func__); 300 } 301 } 302 // TODO: Handle external DP brides - ?? 303 #if 0 304 if (gConnector[id]->encoderExternal.isDPBridge == true) { 305 // If this is a DisplayPort Bridge, setup ddc on bus 306 // TRAVIS (LVDS) or NUTMEG (VGA) 307 TRACE("%s: is bridge, performing bridge DDC setup\n", __func__); 308 encoder_external_setup(id, 23860, 309 EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP); 310 gDisplay[displayIndex]->attached = true; 311 312 // TODO: DDC Router switching for DisplayPort (and others?) 313 } 314 #endif 315 if (gConnector[id]->type == VIDEO_CONNECTOR_LVDS) { 316 // If plain (non-DP) laptop LVDS, read mode info from AtomBIOS 317 //TRACE("%s: non-DP laptop LVDS detected\n", __func__); 318 gDisplay[displayIndex]->attached = connector_read_mode_lvds(id, 319 &gDisplay[displayIndex]->preferredMode); 320 if (gDisplay[displayIndex]->attached) { 321 TRACE("%s: connector(%" B_PRIu32 "): found LVDS preferred " 322 "mode\n", __func__, id); 323 } 324 } 325 326 // If no display found yet, try more standard detection methods 327 if (gDisplay[displayIndex]->attached == false) { 328 TRACE("%s: connector(%" B_PRIu32 "): bit-banging ddc for EDID.\n", 329 __func__, id); 330 331 // Lets try bit-banging edid from connector 332 gDisplay[displayIndex]->attached 333 = connector_read_edid(id, &gDisplay[displayIndex]->edidData); 334 335 // Since DVI-I shows up as two connectors, and there is only one 336 // edid channel, we have to make *sure* the edid data received is 337 // valid for the connector. 338 339 // Found EDID data? 340 if (gDisplay[displayIndex]->attached) { 341 TRACE("%s: connector(%" B_PRIu32 "): found EDID data.\n", 342 __func__, id); 343 344 bool analogEncoder 345 = gConnector[id]->encoder.type == VIDEO_ENCODER_TVDAC 346 || gConnector[id]->encoder.type == VIDEO_ENCODER_DAC; 347 348 edid1_info* edid = &gDisplay[displayIndex]->edidData; 349 if (!edid->display.input_type && analogEncoder) { 350 // If non-digital EDID + the encoder is analog... 351 TRACE("%s: connector(%" B_PRIu32 "): has non-digital EDID " 352 "and a analog encoder.\n", __func__, id); 353 gDisplay[displayIndex]->attached 354 = encoder_analog_load_detect(id); 355 remove_dup_displays(displayIndex, id); 356 } else if (edid->display.input_type && !analogEncoder) { 357 // If EDID is digital, we make an assumption here. 358 TRACE("%s: connector(%" B_PRIu32 "): has digital EDID " 359 "and is not a analog encoder.\n", __func__, id); 360 } else { 361 // This generally means the monitor is of poor design 362 // Since we *know* there is no load on the analog encoder 363 // we assume that it is a digital display. 364 // This can also occur when a display has both DVI and VGA 365 // inputs and the graphics board has a DVI-I connector 366 // (reported as both digital and analog connectors) and the 367 // analog connection is the one in use. In that case, we 368 // get here when checking the digital connector and want 369 // to disable that display in favor of the analog one. 370 TRACE("%s: connector(%" B_PRIu32 "): Warning: monitor has " 371 "false digital EDID flag + unloaded analog encoder!\n", 372 __func__, id); 373 gDisplay[displayIndex]->attached = false; 374 } 375 } 376 } 377 378 if (gDisplay[displayIndex]->attached != true) { 379 // Nothing interesting here, move along 380 continue; 381 } 382 383 // We found a valid / attached display 384 385 gDisplay[displayIndex]->connectorIndex = id; 386 // Populate physical connector index from gConnector 387 388 init_registers(gDisplay[displayIndex]->regs, displayIndex); 389 390 if (gDisplay[displayIndex]->preferredMode.virtual_width > 0) { 391 // Found a single preferred mode 392 gDisplay[displayIndex]->foundRanges = false; 393 } else { 394 // Use edid data and pull ranges 395 if (detect_crt_ranges(displayIndex) == B_OK) 396 gDisplay[displayIndex]->foundRanges = true; 397 } 398 399 displayIndex++; 400 } 401 402 // fallback if no attached monitors were found 403 if (displayIndex == 0) { 404 // This is a hack, however as we don't support HPD just yet, 405 // it tries to prevent a "no displays" situation. 406 ERROR("%s: ERROR: 0 attached monitors were found on display connectors." 407 " Injecting first connector as a last resort.\n", __func__); 408 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) { 409 // skip TV DAC connectors as likely fallback isn't for TV 410 if (gConnector[id]->encoder.type == VIDEO_ENCODER_TVDAC) 411 continue; 412 gDisplay[0]->attached = true; 413 gDisplay[0]->connectorIndex = id; 414 init_registers(gDisplay[0]->regs, 0); 415 if (detect_crt_ranges(0) == B_OK) 416 gDisplay[0]->foundRanges = true; 417 break; 418 } 419 } 420 421 // Initial boot state is the first two crtc's powered 422 if (gDisplay[0]->attached == true) 423 gDisplay[0]->powered = true; 424 if (gDisplay[1]->attached == true) 425 gDisplay[1]->powered = true; 426 427 return B_OK; 428} 429 430 431void 432debug_displays() 433{ 434 TRACE("Currently detected monitors===============\n"); 435 for (uint32 id = 0; id < MAX_DISPLAY; id++) { 436 ERROR("Display #%" B_PRIu32 " attached = %s\n", 437 id, gDisplay[id]->attached ? "true" : "false"); 438 439 uint32 connectorIndex = gDisplay[id]->connectorIndex; 440 441 if (gDisplay[id]->attached) { 442 uint32 connectorType = gConnector[connectorIndex]->type; 443 uint32 encoderType = gConnector[connectorIndex]->encoder.type; 444 ERROR(" + connector ID: %" B_PRIu32 "\n", connectorIndex); 445 ERROR(" + connector type: %s\n", get_connector_name(connectorType)); 446 ERROR(" + encoder type: %s\n", get_encoder_name(encoderType)); 447 ERROR(" + limits: Vert Min/Max: %" B_PRIu32 "/%" B_PRIu32"\n", 448 gDisplay[id]->vfreqMin, gDisplay[id]->vfreqMax); 449 ERROR(" + limits: Horz Min/Max: %" B_PRIu32 "/%" B_PRIu32"\n", 450 gDisplay[id]->hfreqMin, gDisplay[id]->hfreqMax); 451 } 452 } 453 TRACE("==========================================\n"); 454} 455 456 457uint32 458display_get_encoder_mode(uint32 connectorIndex) 459{ 460 // Is external DisplayPort Bridge? 461 if (gConnector[connectorIndex]->encoderExternal.valid == true 462 && gConnector[connectorIndex]->encoderExternal.isDPBridge == true) { 463 return ATOM_ENCODER_MODE_DP; 464 } 465 466 // DVO Encoders (should be bridges) 467 switch (gConnector[connectorIndex]->encoder.objectID) { 468 case ENCODER_OBJECT_ID_INTERNAL_DVO1: 469 case ENCODER_OBJECT_ID_INTERNAL_DDI: 470 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 471 return ATOM_ENCODER_MODE_DVO; 472 } 473 474 // Find crtc for connector so we can identify source of edid data 475 int32 crtc = -1; 476 for (int32 id = 0; id < MAX_DISPLAY; id++) { 477 if (gDisplay[id]->connectorIndex == connectorIndex) { 478 crtc = id; 479 break; 480 } 481 } 482 bool edidDigital = false; 483 if (crtc == -1) { 484 ERROR("%s: BUG: executed on connector without crtc!\n", __func__); 485 } else { 486 edid1_info* edid = &gDisplay[crtc]->edidData; 487 edidDigital = edid->display.input_type ? true : false; 488 } 489 490 // Normal encoder situations 491 switch (gConnector[connectorIndex]->type) { 492 case VIDEO_CONNECTOR_DVII: 493 case VIDEO_CONNECTOR_HDMIB: /* HDMI-B is DL-DVI; analog works fine */ 494 // TODO: if audio detected on edid and DCE4, ATOM_ENCODER_MODE_DVI 495 // if audio detected on edid not DCE4, ATOM_ENCODER_MODE_HDMI 496 if (edidDigital) 497 return ATOM_ENCODER_MODE_DVI; 498 else 499 return ATOM_ENCODER_MODE_CRT; 500 break; 501 case VIDEO_CONNECTOR_DVID: 502 case VIDEO_CONNECTOR_HDMIA: 503 default: 504 // TODO: if audio detected on edid and DCE4, ATOM_ENCODER_MODE_DVI 505 // if audio detected on edid not DCE4, ATOM_ENCODER_MODE_HDMI 506 return ATOM_ENCODER_MODE_DVI; 507 case VIDEO_CONNECTOR_LVDS: 508 return ATOM_ENCODER_MODE_LVDS; 509 case VIDEO_CONNECTOR_DP: 510 // dig_connector = radeon_connector->con_priv; 511 // if ((dig_connector->dp_sink_type 512 // == CONNECTOR_OBJECT_ID_DISPLAYPORT) 513 // || (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) { 514 // return ATOM_ENCODER_MODE_DP; 515 // } 516 // TODO: if audio detected on edid and DCE4, ATOM_ENCODER_MODE_DVI 517 // if audio detected on edid not DCE4, ATOM_ENCODER_MODE_HDMI 518 return ATOM_ENCODER_MODE_DP; 519 case VIDEO_CONNECTOR_EDP: 520 return ATOM_ENCODER_MODE_DP; 521 case VIDEO_CONNECTOR_DVIA: 522 case VIDEO_CONNECTOR_VGA: 523 return ATOM_ENCODER_MODE_CRT; 524 case VIDEO_CONNECTOR_COMPOSITE: 525 case VIDEO_CONNECTOR_SVIDEO: 526 case VIDEO_CONNECTOR_9DIN: 527 return ATOM_ENCODER_MODE_TV; 528 } 529} 530 531 532void 533display_crtc_lock(uint8 crtcID, int command) 534{ 535 TRACE("%s\n", __func__); 536 537 ENABLE_CRTC_PS_ALLOCATION args; 538 int index 539 = GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters); 540 541 memset(&args, 0, sizeof(args)); 542 543 args.ucCRTC = crtcID; 544 args.ucEnable = command; 545 546 atom_execute_table(gAtomContext, index, (uint32*)&args); 547} 548 549 550void 551display_crtc_blank(uint8 crtcID, int command) 552{ 553 TRACE("%s\n", __func__); 554 555 BLANK_CRTC_PS_ALLOCATION args; 556 int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC); 557 558 memset(&args, 0, sizeof(args)); 559 560 args.ucCRTC = crtcID; 561 args.ucBlanking = command; 562 563 args.usBlackColorRCr = 0; 564 args.usBlackColorGY = 0; 565 args.usBlackColorBCb = 0; 566 567 atom_execute_table(gAtomContext, index, (uint32*)&args); 568} 569 570 571void 572display_crtc_scale(uint8 crtcID, display_mode* mode) 573{ 574 TRACE("%s\n", __func__); 575 ENABLE_SCALER_PS_ALLOCATION args; 576 int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); 577 578 memset(&args, 0, sizeof(args)); 579 580 args.ucScaler = crtcID; 581 args.ucEnable = ATOM_SCALER_DISABLE; 582 583 atom_execute_table(gAtomContext, index, (uint32*)&args); 584} 585 586 587void 588display_crtc_dpms(uint8 crtcID, int mode) 589{ 590 radeon_shared_info &info = *gInfo->shared_info; 591 592 switch (mode) { 593 case B_DPMS_ON: 594 TRACE("%s: crtc %" B_PRIu8 " dpms powerup\n", __func__, crtcID); 595 if (gDisplay[crtcID]->attached == false) 596 return; 597 display_crtc_power(crtcID, ATOM_ENABLE); 598 gDisplay[crtcID]->powered = true; 599 if (info.dceMajor >= 3) 600 display_crtc_memreq(crtcID, ATOM_ENABLE); 601 display_crtc_blank(crtcID, ATOM_BLANKING_OFF); 602 break; 603 case B_DPMS_STAND_BY: 604 case B_DPMS_SUSPEND: 605 case B_DPMS_OFF: 606 TRACE("%s: crtc %" B_PRIu8 " dpms powerdown\n", __func__, crtcID); 607 if (gDisplay[crtcID]->attached == false) 608 return; 609 if (gDisplay[crtcID]->powered == true) 610 display_crtc_blank(crtcID, ATOM_BLANKING); 611 if (info.dceMajor >= 3) 612 display_crtc_memreq(crtcID, ATOM_DISABLE); 613 display_crtc_power(crtcID, ATOM_DISABLE); 614 gDisplay[crtcID]->powered = false; 615 } 616} 617 618 619void 620display_dce45_crtc_load_lut(uint8 crtcID) 621{ 622 radeon_shared_info &info = *gInfo->shared_info; 623 register_info* regs = gDisplay[crtcID]->regs; 624 625 TRACE("%s: crtcID %" B_PRIu8 "\n", __func__, crtcID); 626 627 uint16* r = info.color_data; 628 uint16* g = r + 256; 629 uint16* b = r + 512; 630 631 if (info.dceMajor >= 5) { 632 Write32(OUT, NI_INPUT_CSC_CONTROL + regs->crtcOffset, 633 (NI_INPUT_CSC_GRPH_MODE(NI_INPUT_CSC_BYPASS) | 634 NI_INPUT_CSC_OVL_MODE(NI_INPUT_CSC_BYPASS))); 635 Write32(OUT, NI_PRESCALE_GRPH_CONTROL + regs->crtcOffset, 636 NI_GRPH_PRESCALE_BYPASS); 637 Write32(OUT, NI_PRESCALE_OVL_CONTROL + regs->crtcOffset, 638 NI_OVL_PRESCALE_BYPASS); 639 Write32(OUT, NI_INPUT_GAMMA_CONTROL + regs->crtcOffset, 640 (NI_GRPH_INPUT_GAMMA_MODE(NI_INPUT_GAMMA_USE_LUT) | 641 NI_OVL_INPUT_GAMMA_MODE(NI_INPUT_GAMMA_USE_LUT))); 642 } 643 644 Write32(OUT, EVERGREEN_DC_LUT_CONTROL + regs->crtcOffset, 0); 645 646 Write32(OUT, EVERGREEN_DC_LUT_BLACK_OFFSET_BLUE + regs->crtcOffset, 0); 647 Write32(OUT, EVERGREEN_DC_LUT_BLACK_OFFSET_GREEN + regs->crtcOffset, 0); 648 Write32(OUT, EVERGREEN_DC_LUT_BLACK_OFFSET_RED + regs->crtcOffset, 0); 649 650 Write32(OUT, EVERGREEN_DC_LUT_WHITE_OFFSET_BLUE + regs->crtcOffset, 0xffff); 651 Write32(OUT, EVERGREEN_DC_LUT_WHITE_OFFSET_GREEN + regs->crtcOffset, 0xffff); 652 Write32(OUT, EVERGREEN_DC_LUT_WHITE_OFFSET_RED + regs->crtcOffset, 0xffff); 653 654 Write32(OUT, EVERGREEN_DC_LUT_RW_MODE, 0); 655 Write32(OUT, EVERGREEN_DC_LUT_WRITE_EN_MASK, 0x00000007); 656 657 Write32(OUT, EVERGREEN_DC_LUT_RW_INDEX, 0); 658 for (int i = 0; i < 256; i++) { 659 Write32(OUT, EVERGREEN_DC_LUT_30_COLOR + regs->crtcOffset, 660 (r[i] << 20) | 661 (g[i] << 10) | 662 (b[i] << 0)); 663 } 664 665 if (info.dceMajor >= 5) { 666 Write32(OUT, NI_DEGAMMA_CONTROL + regs->crtcOffset, 667 (NI_GRPH_DEGAMMA_MODE(NI_DEGAMMA_BYPASS) | 668 NI_OVL_DEGAMMA_MODE(NI_DEGAMMA_BYPASS) | 669 NI_ICON_DEGAMMA_MODE(NI_DEGAMMA_BYPASS) | 670 NI_CURSOR_DEGAMMA_MODE(NI_DEGAMMA_BYPASS))); 671 Write32(OUT, NI_GAMUT_REMAP_CONTROL + regs->crtcOffset, 672 (NI_GRPH_GAMUT_REMAP_MODE(NI_GAMUT_REMAP_BYPASS) | 673 NI_OVL_GAMUT_REMAP_MODE(NI_GAMUT_REMAP_BYPASS))); 674 Write32(OUT, NI_REGAMMA_CONTROL + regs->crtcOffset, 675 (NI_GRPH_REGAMMA_MODE(NI_REGAMMA_BYPASS) | 676 NI_OVL_REGAMMA_MODE(NI_REGAMMA_BYPASS))); 677 Write32(OUT, NI_OUTPUT_CSC_CONTROL + regs->crtcOffset, 678 (NI_OUTPUT_CSC_GRPH_MODE(NI_OUTPUT_CSC_BYPASS) | 679 NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS))); 680 /* XXX match this to the depth of the crtc fmt block, move to modeset? */ 681 Write32(OUT, 0x6940 + regs->crtcOffset, 0); 682 } 683} 684 685 686void 687display_avivo_crtc_load_lut(uint8 crtcID) 688{ 689 radeon_shared_info &info = *gInfo->shared_info; 690 register_info* regs = gDisplay[crtcID]->regs; 691 692 TRACE("%s: crtcID %" B_PRIu8 "\n", __func__, crtcID); 693 694 uint16* r = info.color_data; 695 uint16* g = r + 256; 696 uint16* b = r + 512; 697 698 Write32(OUT, AVIVO_DC_LUTA_CONTROL + regs->crtcOffset, 0); 699 700 Write32(OUT, AVIVO_DC_LUTA_BLACK_OFFSET_BLUE + regs->crtcOffset, 0); 701 Write32(OUT, AVIVO_DC_LUTA_BLACK_OFFSET_GREEN + regs->crtcOffset, 0); 702 Write32(OUT, AVIVO_DC_LUTA_BLACK_OFFSET_RED + regs->crtcOffset, 0); 703 704 Write32(OUT, AVIVO_DC_LUTA_WHITE_OFFSET_BLUE + regs->crtcOffset, 0xffff); 705 Write32(OUT, AVIVO_DC_LUTA_WHITE_OFFSET_GREEN + regs->crtcOffset, 0xffff); 706 Write32(OUT, AVIVO_DC_LUTA_WHITE_OFFSET_RED + regs->crtcOffset, 0xffff); 707 708 Write32(OUT, AVIVO_DC_LUT_RW_SELECT, crtcID); 709 Write32(OUT, AVIVO_DC_LUT_RW_MODE, 0); 710 Write32(OUT, AVIVO_DC_LUT_WRITE_EN_MASK, 0x0000003f); 711 712 Write32(OUT, AVIVO_DC_LUT_RW_INDEX, 0); 713 for (int i = 0; i < 256; i++) { 714 Write32(OUT, AVIVO_DC_LUT_30_COLOR, 715 (r[i] << 20) | 716 (g[i] << 10) | 717 (b[i] << 0)); 718 } 719 720 Write32(OUT, AVIVO_D1GRPH_LUT_SEL + regs->crtcOffset, crtcID); 721} 722 723 724void 725display_crtc_fb_set(uint8 crtcID, display_mode* mode) 726{ 727 radeon_shared_info &info = *gInfo->shared_info; 728 register_info* regs = gDisplay[crtcID]->regs; 729 730 uint16* r = info.color_data; 731 uint16* g = r + 256; 732 uint16* b = r + 512; 733 734 uint32 fbSwap; 735 if (info.dceMajor >= 4) 736 fbSwap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE); 737 else 738 fbSwap = R600_D1GRPH_SWAP_ENDIAN_NONE; 739 740 uint32 fbFormat; 741 742 uint32 bytesPerPixel; 743 uint32 bitsPerPixel; 744 745 switch (mode->space) { 746 case B_CMAP8: 747 bytesPerPixel = 1; 748 bitsPerPixel = 8; 749 if (info.dceMajor >= 4) { 750 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) 751 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED)); 752 } else { 753 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_8BPP 754 | AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; 755 } 756 // TODO: copy system color map into shared info 757 break; 758 case B_RGB15_LITTLE: 759 bytesPerPixel = 2; 760 bitsPerPixel = 15; 761 if (info.dceMajor >= 4) { 762 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) 763 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555)); 764 } else { 765 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_16BPP 766 | AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; 767 } 768 break; 769 case B_RGB16_LITTLE: 770 bytesPerPixel = 2; 771 bitsPerPixel = 16; 772 773 if (info.dceMajor >= 4) { 774 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) 775 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565)); 776 #ifdef __POWERPC__ 777 fbSwap 778 = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 779 #endif 780 } else { 781 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_16BPP 782 | AVIVO_D1GRPH_CONTROL_16BPP_RGB565; 783 #ifdef __POWERPC__ 784 fbSwap = R600_D1GRPH_SWAP_ENDIAN_16BIT; 785 #endif 786 } 787 788 { 789 // default gamma table 790 uint16 gamma = 0; 791 for (int i = 0; i < 256; i++) { 792 r[i] = gamma; 793 g[i] = gamma; 794 b[i] = gamma; 795 gamma += 4; 796 } 797 } 798 break; 799 case B_RGB24_LITTLE: 800 case B_RGB32_LITTLE: 801 default: 802 bytesPerPixel = 4; 803 bitsPerPixel = 32; 804 if (info.dceMajor >= 4) { 805 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) 806 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); 807 #ifdef __POWERPC__ 808 fbSwap 809 = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 810 #endif 811 } else { 812 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_32BPP 813 | AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; 814 #ifdef __POWERPC__ 815 fbSwap = R600_D1GRPH_SWAP_ENDIAN_32BIT; 816 #endif 817 } 818 819 { 820 // default gamma table 821 uint16 gamma = 0; 822 for (int i = 0; i < 256; i++) { 823 r[i] = gamma; 824 g[i] = gamma; 825 b[i] = gamma; 826 gamma += 4; 827 } 828 } 829 break; 830 } 831 832 Write32(OUT, regs->vgaControl, 0); 833 834 uint64 fbAddress = gInfo->fb.vramStart; 835 836 TRACE("%s: Framebuffer at: 0x%" B_PRIX64 "\n", __func__, fbAddress); 837 838 if (info.chipsetID >= RADEON_RV770) { 839 TRACE("%s: Set SurfaceAddress High: 0x%" B_PRIX32 "\n", 840 __func__, (fbAddress >> 32) & 0xf); 841 842 Write32(OUT, regs->grphPrimarySurfaceAddrHigh, 843 (fbAddress >> 32) & 0xf); 844 Write32(OUT, regs->grphSecondarySurfaceAddrHigh, 845 (fbAddress >> 32) & 0xf); 846 } 847 848 TRACE("%s: Set SurfaceAddress: 0x%" B_PRIX64 "\n", 849 __func__, (fbAddress & 0xFFFFFFFF)); 850 851 Write32(OUT, regs->grphPrimarySurfaceAddr, (fbAddress & 0xFFFFFFFF)); 852 Write32(OUT, regs->grphSecondarySurfaceAddr, (fbAddress & 0xFFFFFFFF)); 853 854 if (info.chipsetID >= RADEON_R600) { 855 Write32(CRT, regs->grphControl, fbFormat); 856 Write32(CRT, regs->grphSwapControl, fbSwap); 857 } 858 859 // Align our framebuffer width 860 uint32 widthAligned = mode->virtual_width; 861 uint32 pitchMask = 0; 862 863 // assume micro-linear/macro-linear mode (i.e., not tiled) 864 switch (bytesPerPixel) { 865 case 1: 866 pitchMask = 63; 867 break; 868 case 2: 869 pitchMask = 31; 870 break; 871 case 3: 872 case 4: 873 pitchMask = 31; 874 break; 875 } 876 widthAligned += pitchMask; 877 widthAligned &= ~pitchMask; 878 879 TRACE("%s: fb: %" B_PRIu32 "x%" B_PRIu32 " (%" B_PRIu32 " bpp)\n", __func__, 880 mode->virtual_width, mode->virtual_height, bitsPerPixel); 881 TRACE("%s: fb pitch: %" B_PRIu32 " \n", __func__, 882 widthAligned); 883 TRACE("%s: fb width aligned: %" B_PRIu32 "\n", __func__, 884 widthAligned); 885 886 Write32(CRT, regs->grphSurfaceOffsetX, 0); 887 Write32(CRT, regs->grphSurfaceOffsetY, 0); 888 Write32(CRT, regs->grphXStart, 0); 889 Write32(CRT, regs->grphYStart, 0); 890 Write32(CRT, regs->grphXEnd, mode->virtual_width); 891 Write32(CRT, regs->grphYEnd, mode->virtual_height); 892 Write32(CRT, regs->grphPitch, widthAligned); 893 894 Write32(CRT, regs->grphEnable, 1); 895 // Enable Frame buffer 896 897 Write32(CRT, regs->modeDesktopHeight, mode->virtual_height); 898 899 uint32 viewportWidth = mode->timing.h_display; 900 uint32 viewportHeight = (mode->timing.v_display + 1) & ~1; 901 902 Write32(CRT, regs->viewportStart, 0); 903 Write32(CRT, regs->viewportSize, 904 (viewportWidth << 16) | viewportHeight); 905 906 // Pageflip setup 907 if (info.dceMajor >= 4) { 908 uint32 tmp 909 = Read32(OUT, EVERGREEN_GRPH_FLIP_CONTROL + regs->crtcOffset); 910 tmp &= ~EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN; 911 Write32(OUT, EVERGREEN_GRPH_FLIP_CONTROL + regs->crtcOffset, tmp); 912 913 Write32(OUT, EVERGREEN_MASTER_UPDATE_MODE + regs->crtcOffset, 0); 914 // Pageflip to happen anywhere in vblank 915 display_dce45_crtc_load_lut(crtcID); 916 } else { 917 uint32 tmp = Read32(OUT, AVIVO_D1GRPH_FLIP_CONTROL + regs->crtcOffset); 918 tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN; 919 Write32(OUT, AVIVO_D1GRPH_FLIP_CONTROL + regs->crtcOffset, tmp); 920 921 Write32(OUT, AVIVO_D1MODE_MASTER_UPDATE_MODE + regs->crtcOffset, 0); 922 // Pageflip to happen anywhere in vblank 923 display_avivo_crtc_load_lut(crtcID); 924 } 925 926 // update shared info 927 gInfo->shared_info->bytes_per_row = widthAligned * bytesPerPixel; 928 gInfo->shared_info->current_mode = *mode; 929 gInfo->shared_info->bits_per_pixel = bitsPerPixel; 930} 931 932 933void 934display_crtc_set(uint8 crtcID, display_mode* mode) 935{ 936 display_timing& displayTiming = mode->timing; 937 938 TRACE("%s called to do %dx%d\n", 939 __func__, displayTiming.h_display, displayTiming.v_display); 940 941 SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args; 942 int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing); 943 uint16 misc = 0; 944 945 memset(&args, 0, sizeof(args)); 946 947 args.usH_Total = B_HOST_TO_LENDIAN_INT16(displayTiming.h_total); 948 args.usH_Disp = B_HOST_TO_LENDIAN_INT16(displayTiming.h_display); 949 args.usH_SyncStart = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_start); 950 args.usH_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_end 951 - displayTiming.h_sync_start); 952 953 args.usV_Total = B_HOST_TO_LENDIAN_INT16(displayTiming.v_total); 954 args.usV_Disp = B_HOST_TO_LENDIAN_INT16(displayTiming.v_display); 955 args.usV_SyncStart = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_start); 956 args.usV_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_end 957 - displayTiming.v_sync_start); 958 959 args.ucOverscanRight = 0; 960 args.ucOverscanLeft = 0; 961 args.ucOverscanBottom = 0; 962 args.ucOverscanTop = 0; 963 964 if ((displayTiming.flags & B_POSITIVE_HSYNC) == 0) 965 misc |= ATOM_HSYNC_POLARITY; 966 if ((displayTiming.flags & B_POSITIVE_VSYNC) == 0) 967 misc |= ATOM_VSYNC_POLARITY; 968 969 args.susModeMiscInfo.usAccess = B_HOST_TO_LENDIAN_INT16(misc); 970 args.ucCRTC = crtcID; 971 972 atom_execute_table(gAtomContext, index, (uint32*)&args); 973} 974 975 976void 977display_crtc_set_dtd(uint8 crtcID, display_mode* mode) 978{ 979 display_timing& displayTiming = mode->timing; 980 981 TRACE("%s called to do %dx%d\n", __func__, 982 displayTiming.h_display, displayTiming.v_display); 983 984 SET_CRTC_USING_DTD_TIMING_PARAMETERS args; 985 int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming); 986 uint16 misc = 0; 987 988 memset(&args, 0, sizeof(args)); 989 990 // Note: the code below assumes H & V borders are both zero 991 uint16 blankStart 992 = MIN(displayTiming.h_sync_start, displayTiming.h_display); 993 uint16 blankEnd 994 = MAX(displayTiming.h_sync_end, displayTiming.h_total); 995 args.usH_Size = B_HOST_TO_LENDIAN_INT16(displayTiming.h_display); 996 args.usH_Blanking_Time = B_HOST_TO_LENDIAN_INT16(blankEnd - blankStart); 997 998 blankStart = MIN(displayTiming.v_sync_start, displayTiming.v_display); 999 blankEnd = MAX(displayTiming.v_sync_end, displayTiming.v_total); 1000 args.usV_Size = B_HOST_TO_LENDIAN_INT16(displayTiming.v_display); 1001 args.usV_Blanking_Time = B_HOST_TO_LENDIAN_INT16(blankEnd - blankStart); 1002 1003 args.usH_SyncOffset = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_start 1004 - displayTiming.h_display); 1005 args.usH_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_end 1006 - displayTiming.h_sync_start); 1007 1008 args.usV_SyncOffset = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_start 1009 - displayTiming.v_display); 1010 args.usV_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_end 1011 - displayTiming.v_sync_start); 1012 1013 args.ucH_Border = 0; 1014 args.ucV_Border = 0; 1015 1016 if ((displayTiming.flags & B_POSITIVE_HSYNC) == 0) 1017 misc |= ATOM_HSYNC_POLARITY; 1018 if ((displayTiming.flags & B_POSITIVE_VSYNC) == 0) 1019 misc |= ATOM_VSYNC_POLARITY; 1020 1021 args.susModeMiscInfo.usAccess = B_HOST_TO_LENDIAN_INT16(misc); 1022 args.ucCRTC = crtcID; 1023 1024 atom_execute_table(gAtomContext, index, (uint32*)&args); 1025} 1026 1027 1028void 1029display_crtc_ss(pll_info* pll, int command) 1030{ 1031 TRACE("%s\n", __func__); 1032 radeon_shared_info &info = *gInfo->shared_info; 1033 1034 int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); 1035 1036 union enableSS { 1037 ENABLE_LVDS_SS_PARAMETERS lvds_ss; 1038 ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2; 1039 ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1; 1040 ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2; 1041 ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3; 1042 }; 1043 1044 union enableSS args; 1045 memset(&args, 0, sizeof(args)); 1046 1047 if (info.dceMajor >= 5) { 1048 args.v3.usSpreadSpectrumAmountFrac = B_HOST_TO_LENDIAN_INT16(0); 1049 args.v3.ucSpreadSpectrumType 1050 = pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 1051 switch (pll->id) { 1052 case ATOM_PPLL1: 1053 args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL; 1054 args.v3.usSpreadSpectrumAmount 1055 = B_HOST_TO_LENDIAN_INT16(pll->ssAmount); 1056 args.v3.usSpreadSpectrumStep 1057 = B_HOST_TO_LENDIAN_INT16(pll->ssStep); 1058 break; 1059 case ATOM_PPLL2: 1060 args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL; 1061 args.v3.usSpreadSpectrumAmount 1062 = B_HOST_TO_LENDIAN_INT16(pll->ssAmount); 1063 args.v3.usSpreadSpectrumStep 1064 = B_HOST_TO_LENDIAN_INT16(pll->ssStep); 1065 break; 1066 case ATOM_DCPLL: 1067 args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL; 1068 args.v3.usSpreadSpectrumAmount = B_HOST_TO_LENDIAN_INT16(0); 1069 args.v3.usSpreadSpectrumStep = B_HOST_TO_LENDIAN_INT16(0); 1070 break; 1071 default: 1072 ERROR("%s: BUG: Invalid PLL ID!\n", __func__); 1073 return; 1074 } 1075 if (pll->ssPercentage == 0 1076 || ((pll->ssType & ATOM_EXTERNAL_SS_MASK) != 0)) { 1077 command = ATOM_DISABLE; 1078 } 1079 args.v3.ucEnable = command; 1080 } else if (info.dceMajor >= 4) { 1081 args.v2.usSpreadSpectrumPercentage 1082 = B_HOST_TO_LENDIAN_INT16(pll->ssPercentage); 1083 args.v2.ucSpreadSpectrumType 1084 = pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 1085 switch (pll->id) { 1086 case ATOM_PPLL1: 1087 args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL; 1088 args.v2.usSpreadSpectrumAmount 1089 = B_HOST_TO_LENDIAN_INT16(pll->ssAmount); 1090 args.v2.usSpreadSpectrumStep 1091 = B_HOST_TO_LENDIAN_INT16(pll->ssStep); 1092 break; 1093 case ATOM_PPLL2: 1094 args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL; 1095 args.v2.usSpreadSpectrumAmount 1096 = B_HOST_TO_LENDIAN_INT16(pll->ssAmount); 1097 args.v2.usSpreadSpectrumStep 1098 = B_HOST_TO_LENDIAN_INT16(pll->ssStep); 1099 break; 1100 case ATOM_DCPLL: 1101 args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL; 1102 args.v2.usSpreadSpectrumAmount = B_HOST_TO_LENDIAN_INT16(0); 1103 args.v2.usSpreadSpectrumStep = B_HOST_TO_LENDIAN_INT16(0); 1104 break; 1105 default: 1106 ERROR("%s: BUG: Invalid PLL ID!\n", __func__); 1107 return; 1108 } 1109 if (pll->ssPercentage == 0 1110 || ((pll->ssType & ATOM_EXTERNAL_SS_MASK) != 0) 1111 || (info.chipsetFlags & CHIP_APU) != 0 ) { 1112 command = ATOM_DISABLE; 1113 } 1114 args.v2.ucEnable = command; 1115 } else if (info.dceMajor >= 3) { 1116 args.v1.usSpreadSpectrumPercentage 1117 = B_HOST_TO_LENDIAN_INT16(pll->ssPercentage); 1118 args.v1.ucSpreadSpectrumType 1119 = pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 1120 args.v1.ucSpreadSpectrumStep = pll->ssStep; 1121 args.v1.ucSpreadSpectrumDelay = pll->ssDelay; 1122 args.v1.ucSpreadSpectrumRange = pll->ssRange; 1123 args.v1.ucPpll = pll->id; 1124 args.v1.ucEnable = command; 1125 } else if (info.dceMajor >= 2) { 1126 if ((command == ATOM_DISABLE) || (pll->ssPercentage == 0) 1127 || (pll->ssType & ATOM_EXTERNAL_SS_MASK)) { 1128 radeon_gpu_ss_control(pll, false); 1129 return; 1130 } 1131 args.lvds_ss_2.usSpreadSpectrumPercentage 1132 = B_HOST_TO_LENDIAN_INT16(pll->ssPercentage); 1133 args.lvds_ss_2.ucSpreadSpectrumType 1134 = pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 1135 args.lvds_ss_2.ucSpreadSpectrumStep = pll->ssStep; 1136 args.lvds_ss_2.ucSpreadSpectrumDelay = pll->ssDelay; 1137 args.lvds_ss_2.ucSpreadSpectrumRange = pll->ssRange; 1138 args.lvds_ss_2.ucEnable = command; 1139 } else { 1140 ERROR("%s: TODO: Old card SS control\n", __func__); 1141 return; 1142 } 1143 1144 atom_execute_table(gAtomContext, index, (uint32*)&args); 1145} 1146 1147 1148void 1149display_crtc_power(uint8 crtcID, int command) 1150{ 1151 TRACE("%s\n", __func__); 1152 int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC); 1153 ENABLE_CRTC_PS_ALLOCATION args; 1154 1155 memset(&args, 0, sizeof(args)); 1156 1157 args.ucCRTC = crtcID; 1158 args.ucEnable = command; 1159 1160 atom_execute_table(gAtomContext, index, (uint32*)&args); 1161} 1162 1163 1164void 1165display_crtc_memreq(uint8 crtcID, int command) 1166{ 1167 TRACE("%s\n", __func__); 1168 int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq); 1169 ENABLE_CRTC_PS_ALLOCATION args; 1170 1171 memset(&args, 0, sizeof(args)); 1172 1173 args.ucCRTC = crtcID; 1174 args.ucEnable = command; 1175 1176 atom_execute_table(gAtomContext, index, (uint32*)&args); 1177} 1178