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 31 extern "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 */ 41 status_t 42 init_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 219 status_t 220 detect_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 244 status_t 245 detect_displays() 246 { 247 // reset known displays 248 for (uint32 id = 0; id < MAX_DISPLAY; id++) { 249 gDisplay[id]->attached = false; 250 gDisplay[id]->powered = false; 251 gDisplay[id]->foundRanges = false; 252 } 253 254 uint32 displayIndex = 0; 255 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) { 256 if (gConnector[id]->valid == false) 257 continue; 258 if (displayIndex >= MAX_DISPLAY) 259 continue; 260 261 if (gConnector[id]->type == VIDEO_CONNECTOR_9DIN) { 262 TRACE("%s: connector(%" B_PRIu32 "): Skipping 9DIN connector " 263 "(not yet supported)\n", __func__, id); 264 continue; 265 } 266 267 if (gConnector[id]->type == VIDEO_CONNECTOR_DP) { 268 TRACE("%s: connector(%" B_PRIu32 "): Checking DP.\n", __func__, id); 269 270 edid1_info* edid = &gDisplay[displayIndex]->edidData; 271 gDisplay[displayIndex]->attached 272 = ddc2_dp_read_edid1(id, edid); 273 274 if (gDisplay[displayIndex]->attached) { 275 TRACE("%s: connector(%" B_PRIu32 "): Found DisplayPort EDID!\n", 276 __func__); 277 } 278 } 279 280 // TODO: Handle external DP brides - ?? 281 #if 0 282 if (gConnector[id]->encoderExternal.isDPBridge == true) { 283 // If this is a DisplayPort Bridge, setup ddc on bus 284 // TRAVIS (LVDS) or NUTMEG (VGA) 285 TRACE("%s: is bridge, performing bridge DDC setup\n", __func__); 286 encoder_external_setup(id, 23860, 287 EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP); 288 gDisplay[displayIndex]->attached = true; 289 290 // TODO: DDC Router switching for DisplayPort (and others?) 291 } 292 #endif 293 294 if (gConnector[id]->type == VIDEO_CONNECTOR_LVDS) { 295 display_mode preferredMode; 296 bool lvdsInfoFound = connector_read_mode_lvds(id, 297 &preferredMode); 298 TRACE("%s: connector(%" B_PRIu32 "): bit-banging LVDS for EDID.\n", 299 __func__, id); 300 301 gDisplay[displayIndex]->attached = connector_read_edid(id, 302 &gDisplay[displayIndex]->edidData); 303 304 if (!gDisplay[displayIndex]->attached && lvdsInfoFound) { 305 // If we didn't find ddc edid data, fallback to lvdsInfo 306 // We have to call connector_read_mode_lvds first to 307 // collect SS data for the lvds connector 308 TRACE("%s: connector(%" B_PRIu32 "): using AtomBIOS LVDS_Info " 309 "preferred mode\n", __func__, id); 310 gDisplay[displayIndex]->attached = true; 311 memcpy(&gDisplay[displayIndex]->preferredMode, 312 &preferredMode, sizeof(display_mode)); 313 } 314 } 315 316 // If no display found yet, try more standard detection methods 317 if (gDisplay[displayIndex]->attached == false) { 318 TRACE("%s: connector(%" B_PRIu32 "): bit-banging ddc for EDID.\n", 319 __func__, id); 320 321 // Bit-bang edid from connector 322 gDisplay[displayIndex]->attached = connector_read_edid(id, 323 &gDisplay[displayIndex]->edidData); 324 325 // Found EDID data? 326 if (gDisplay[displayIndex]->attached) { 327 TRACE("%s: connector(%" B_PRIu32 "): found EDID data.\n", 328 __func__, id); 329 330 if (gConnector[id]->type == VIDEO_CONNECTOR_DVII 331 || gConnector[id]->type == VIDEO_CONNECTOR_HDMIB) { 332 // These connectors can share gpio pins for data 333 // communication between digital and analog encoders 334 // (DVI-I is most common) 335 edid1_info* edid = &gDisplay[displayIndex]->edidData; 336 337 bool analogEncoder 338 = gConnector[id]->encoder.type == VIDEO_ENCODER_TVDAC 339 || gConnector[id]->encoder.type == VIDEO_ENCODER_DAC; 340 bool digitalEncoder 341 = gConnector[id]->encoder.type == VIDEO_ENCODER_TMDS; 342 343 bool digitalEdid = edid->display.input_type ? true : false; 344 345 if (digitalEdid && analogEncoder) { 346 // Digital EDID + analog encoder? Lets try a load test 347 gDisplay[displayIndex]->attached 348 = encoder_analog_load_detect(id); 349 } else if (!digitalEdid && digitalEncoder) { 350 // non-digital EDID + digital encoder? Nope. 351 gDisplay[displayIndex]->attached = false; 352 } 353 354 // Else... everything aligns as it should and attached = 1 355 } 356 } 357 } 358 359 if (gDisplay[displayIndex]->attached != true) { 360 // Nothing interesting here, move along 361 continue; 362 } 363 364 // We found a valid / attached display 365 366 gDisplay[displayIndex]->connectorIndex = id; 367 // Populate physical connector index from gConnector 368 369 init_registers(gDisplay[displayIndex]->regs, displayIndex); 370 371 if (gDisplay[displayIndex]->preferredMode.virtual_width > 0) { 372 // Found a single preferred mode 373 gDisplay[displayIndex]->foundRanges = false; 374 } else { 375 // Use edid data and pull ranges 376 if (detect_crt_ranges(displayIndex) == B_OK) 377 gDisplay[displayIndex]->foundRanges = true; 378 } 379 380 displayIndex++; 381 } 382 383 // fallback if no attached monitors were found 384 if (displayIndex == 0) { 385 // This is a hack, however as we don't support HPD just yet, 386 // it tries to prevent a "no displays" situation. 387 ERROR("%s: ERROR: 0 attached monitors were found on display connectors." 388 " Injecting first connector as a last resort.\n", __func__); 389 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) { 390 // skip TV DAC connectors as likely fallback isn't for TV 391 if (gConnector[id]->encoder.type == VIDEO_ENCODER_TVDAC) 392 continue; 393 gDisplay[0]->attached = true; 394 gDisplay[0]->connectorIndex = id; 395 init_registers(gDisplay[0]->regs, 0); 396 if (detect_crt_ranges(0) == B_OK) 397 gDisplay[0]->foundRanges = true; 398 break; 399 } 400 } 401 402 // Initial boot state is the first two crtc's powered 403 if (gDisplay[0]->attached == true) 404 gDisplay[0]->powered = true; 405 if (gDisplay[1]->attached == true) 406 gDisplay[1]->powered = true; 407 408 return B_OK; 409 } 410 411 412 void 413 debug_displays() 414 { 415 TRACE("Currently detected monitors===============\n"); 416 for (uint32 id = 0; id < MAX_DISPLAY; id++) { 417 ERROR("Display #%" B_PRIu32 " attached = %s\n", 418 id, gDisplay[id]->attached ? "true" : "false"); 419 420 uint32 connectorIndex = gDisplay[id]->connectorIndex; 421 422 if (gDisplay[id]->attached) { 423 uint32 connectorType = gConnector[connectorIndex]->type; 424 uint32 encoderType = gConnector[connectorIndex]->encoder.type; 425 ERROR(" + connector ID: %" B_PRIu32 "\n", connectorIndex); 426 ERROR(" + connector type: %s\n", get_connector_name(connectorType)); 427 ERROR(" + encoder type: %s\n", get_encoder_name(encoderType)); 428 ERROR(" + limits: Vert Min/Max: %" B_PRIu32 "/%" B_PRIu32"\n", 429 gDisplay[id]->vfreqMin, gDisplay[id]->vfreqMax); 430 ERROR(" + limits: Horz Min/Max: %" B_PRIu32 "/%" B_PRIu32"\n", 431 gDisplay[id]->hfreqMin, gDisplay[id]->hfreqMax); 432 } 433 } 434 TRACE("==========================================\n"); 435 } 436 437 438 uint32 439 display_get_encoder_mode(uint32 connectorIndex) 440 { 441 // Is external DisplayPort Bridge? 442 if (gConnector[connectorIndex]->encoderExternal.valid == true 443 && gConnector[connectorIndex]->encoderExternal.isDPBridge == true) { 444 return ATOM_ENCODER_MODE_DP; 445 } 446 447 // DVO Encoders (should be bridges) 448 switch (gConnector[connectorIndex]->encoder.objectID) { 449 case ENCODER_OBJECT_ID_INTERNAL_DVO1: 450 case ENCODER_OBJECT_ID_INTERNAL_DDI: 451 case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1: 452 return ATOM_ENCODER_MODE_DVO; 453 } 454 455 // Find crtc for connector so we can identify source of edid data 456 int32 crtc = -1; 457 for (int32 id = 0; id < MAX_DISPLAY; id++) { 458 if (gDisplay[id]->connectorIndex == connectorIndex) { 459 crtc = id; 460 break; 461 } 462 } 463 bool edidDigital = false; 464 if (crtc == -1) { 465 ERROR("%s: BUG: executed on connector without crtc!\n", __func__); 466 } else { 467 edid1_info* edid = &gDisplay[crtc]->edidData; 468 edidDigital = edid->display.input_type ? true : false; 469 } 470 471 // Normal encoder situations 472 switch (gConnector[connectorIndex]->type) { 473 case VIDEO_CONNECTOR_DVII: 474 case VIDEO_CONNECTOR_HDMIB: /* HDMI-B is DL-DVI; analog works fine */ 475 // TODO: if audio detected on edid and DCE4, ATOM_ENCODER_MODE_DVI 476 // if audio detected on edid not DCE4, ATOM_ENCODER_MODE_HDMI 477 if (edidDigital) 478 return ATOM_ENCODER_MODE_DVI; 479 else 480 return ATOM_ENCODER_MODE_CRT; 481 break; 482 case VIDEO_CONNECTOR_DVID: 483 case VIDEO_CONNECTOR_HDMIA: 484 default: 485 // TODO: if audio detected on edid and DCE4, ATOM_ENCODER_MODE_DVI 486 // if audio detected on edid not DCE4, ATOM_ENCODER_MODE_HDMI 487 return ATOM_ENCODER_MODE_DVI; 488 case VIDEO_CONNECTOR_LVDS: 489 return ATOM_ENCODER_MODE_LVDS; 490 case VIDEO_CONNECTOR_DP: 491 // dig_connector = radeon_connector->con_priv; 492 // if ((dig_connector->dp_sink_type 493 // == CONNECTOR_OBJECT_ID_DISPLAYPORT) 494 // || (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) { 495 // return ATOM_ENCODER_MODE_DP; 496 // } 497 // TODO: if audio detected on edid and DCE4, ATOM_ENCODER_MODE_DVI 498 // if audio detected on edid not DCE4, ATOM_ENCODER_MODE_HDMI 499 return ATOM_ENCODER_MODE_DP; 500 case VIDEO_CONNECTOR_EDP: 501 return ATOM_ENCODER_MODE_DP; 502 case VIDEO_CONNECTOR_DVIA: 503 case VIDEO_CONNECTOR_VGA: 504 return ATOM_ENCODER_MODE_CRT; 505 case VIDEO_CONNECTOR_COMPOSITE: 506 case VIDEO_CONNECTOR_SVIDEO: 507 case VIDEO_CONNECTOR_9DIN: 508 return ATOM_ENCODER_MODE_TV; 509 } 510 } 511 512 513 void 514 display_crtc_lock(uint8 crtcID, int command) 515 { 516 TRACE("%s\n", __func__); 517 518 ENABLE_CRTC_PS_ALLOCATION args; 519 int index 520 = GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters); 521 522 memset(&args, 0, sizeof(args)); 523 524 args.ucCRTC = crtcID; 525 args.ucEnable = command; 526 527 atom_execute_table(gAtomContext, index, (uint32*)&args); 528 } 529 530 531 void 532 display_crtc_blank(uint8 crtcID, int command) 533 { 534 TRACE("%s\n", __func__); 535 536 BLANK_CRTC_PS_ALLOCATION args; 537 int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC); 538 539 memset(&args, 0, sizeof(args)); 540 541 args.ucCRTC = crtcID; 542 args.ucBlanking = command; 543 544 args.usBlackColorRCr = 0; 545 args.usBlackColorGY = 0; 546 args.usBlackColorBCb = 0; 547 548 atom_execute_table(gAtomContext, index, (uint32*)&args); 549 } 550 551 552 void 553 display_crtc_scale(uint8 crtcID, display_mode* mode) 554 { 555 TRACE("%s\n", __func__); 556 ENABLE_SCALER_PS_ALLOCATION args; 557 int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); 558 559 memset(&args, 0, sizeof(args)); 560 561 args.ucScaler = crtcID; 562 args.ucEnable = ATOM_SCALER_DISABLE; 563 564 atom_execute_table(gAtomContext, index, (uint32*)&args); 565 } 566 567 568 void 569 display_crtc_dpms(uint8 crtcID, int mode) 570 { 571 radeon_shared_info &info = *gInfo->shared_info; 572 573 switch (mode) { 574 case B_DPMS_ON: 575 TRACE("%s: crtc %" B_PRIu8 " dpms powerup\n", __func__, crtcID); 576 if (gDisplay[crtcID]->attached == false) 577 return; 578 display_crtc_power(crtcID, ATOM_ENABLE); 579 gDisplay[crtcID]->powered = true; 580 if (info.dceMajor >= 3) 581 display_crtc_memreq(crtcID, ATOM_ENABLE); 582 display_crtc_blank(crtcID, ATOM_BLANKING_OFF); 583 break; 584 case B_DPMS_STAND_BY: 585 case B_DPMS_SUSPEND: 586 case B_DPMS_OFF: 587 TRACE("%s: crtc %" B_PRIu8 " dpms powerdown\n", __func__, crtcID); 588 if (gDisplay[crtcID]->attached == false) 589 return; 590 if (gDisplay[crtcID]->powered == true) 591 display_crtc_blank(crtcID, ATOM_BLANKING); 592 if (info.dceMajor >= 3) 593 display_crtc_memreq(crtcID, ATOM_DISABLE); 594 display_crtc_power(crtcID, ATOM_DISABLE); 595 gDisplay[crtcID]->powered = false; 596 } 597 } 598 599 600 void 601 display_dce45_crtc_load_lut(uint8 crtcID) 602 { 603 radeon_shared_info &info = *gInfo->shared_info; 604 register_info* regs = gDisplay[crtcID]->regs; 605 606 TRACE("%s: crtcID %" B_PRIu8 "\n", __func__, crtcID); 607 608 uint16* r = info.color_data; 609 uint16* g = r + 256; 610 uint16* b = r + 512; 611 612 if (info.dceMajor >= 5) { 613 Write32(OUT, NI_INPUT_CSC_CONTROL + regs->crtcOffset, 614 (NI_INPUT_CSC_GRPH_MODE(NI_INPUT_CSC_BYPASS) | 615 NI_INPUT_CSC_OVL_MODE(NI_INPUT_CSC_BYPASS))); 616 Write32(OUT, NI_PRESCALE_GRPH_CONTROL + regs->crtcOffset, 617 NI_GRPH_PRESCALE_BYPASS); 618 Write32(OUT, NI_PRESCALE_OVL_CONTROL + regs->crtcOffset, 619 NI_OVL_PRESCALE_BYPASS); 620 Write32(OUT, NI_INPUT_GAMMA_CONTROL + regs->crtcOffset, 621 (NI_GRPH_INPUT_GAMMA_MODE(NI_INPUT_GAMMA_USE_LUT) | 622 NI_OVL_INPUT_GAMMA_MODE(NI_INPUT_GAMMA_USE_LUT))); 623 } 624 625 Write32(OUT, EVERGREEN_DC_LUT_CONTROL + regs->crtcOffset, 0); 626 627 Write32(OUT, EVERGREEN_DC_LUT_BLACK_OFFSET_BLUE + regs->crtcOffset, 0); 628 Write32(OUT, EVERGREEN_DC_LUT_BLACK_OFFSET_GREEN + regs->crtcOffset, 0); 629 Write32(OUT, EVERGREEN_DC_LUT_BLACK_OFFSET_RED + regs->crtcOffset, 0); 630 631 Write32(OUT, EVERGREEN_DC_LUT_WHITE_OFFSET_BLUE + regs->crtcOffset, 0xffff); 632 Write32(OUT, EVERGREEN_DC_LUT_WHITE_OFFSET_GREEN + regs->crtcOffset, 0xffff); 633 Write32(OUT, EVERGREEN_DC_LUT_WHITE_OFFSET_RED + regs->crtcOffset, 0xffff); 634 635 Write32(OUT, EVERGREEN_DC_LUT_RW_MODE, 0); 636 Write32(OUT, EVERGREEN_DC_LUT_WRITE_EN_MASK, 0x00000007); 637 638 Write32(OUT, EVERGREEN_DC_LUT_RW_INDEX, 0); 639 for (int i = 0; i < 256; i++) { 640 Write32(OUT, EVERGREEN_DC_LUT_30_COLOR + regs->crtcOffset, 641 (r[i] << 20) | 642 (g[i] << 10) | 643 (b[i] << 0)); 644 } 645 646 if (info.dceMajor >= 5) { 647 Write32(OUT, NI_DEGAMMA_CONTROL + regs->crtcOffset, 648 (NI_GRPH_DEGAMMA_MODE(NI_DEGAMMA_BYPASS) | 649 NI_OVL_DEGAMMA_MODE(NI_DEGAMMA_BYPASS) | 650 NI_ICON_DEGAMMA_MODE(NI_DEGAMMA_BYPASS) | 651 NI_CURSOR_DEGAMMA_MODE(NI_DEGAMMA_BYPASS))); 652 Write32(OUT, NI_GAMUT_REMAP_CONTROL + regs->crtcOffset, 653 (NI_GRPH_GAMUT_REMAP_MODE(NI_GAMUT_REMAP_BYPASS) | 654 NI_OVL_GAMUT_REMAP_MODE(NI_GAMUT_REMAP_BYPASS))); 655 Write32(OUT, NI_REGAMMA_CONTROL + regs->crtcOffset, 656 (NI_GRPH_REGAMMA_MODE(NI_REGAMMA_BYPASS) | 657 NI_OVL_REGAMMA_MODE(NI_REGAMMA_BYPASS))); 658 Write32(OUT, NI_OUTPUT_CSC_CONTROL + regs->crtcOffset, 659 (NI_OUTPUT_CSC_GRPH_MODE(NI_OUTPUT_CSC_BYPASS) | 660 NI_OUTPUT_CSC_OVL_MODE(NI_OUTPUT_CSC_BYPASS))); 661 /* XXX match this to the depth of the crtc fmt block, move to modeset? */ 662 Write32(OUT, 0x6940 + regs->crtcOffset, 0); 663 } 664 } 665 666 667 void 668 display_avivo_crtc_load_lut(uint8 crtcID) 669 { 670 radeon_shared_info &info = *gInfo->shared_info; 671 register_info* regs = gDisplay[crtcID]->regs; 672 673 TRACE("%s: crtcID %" B_PRIu8 "\n", __func__, crtcID); 674 675 uint16* r = info.color_data; 676 uint16* g = r + 256; 677 uint16* b = r + 512; 678 679 Write32(OUT, AVIVO_DC_LUTA_CONTROL + regs->crtcOffset, 0); 680 681 Write32(OUT, AVIVO_DC_LUTA_BLACK_OFFSET_BLUE + regs->crtcOffset, 0); 682 Write32(OUT, AVIVO_DC_LUTA_BLACK_OFFSET_GREEN + regs->crtcOffset, 0); 683 Write32(OUT, AVIVO_DC_LUTA_BLACK_OFFSET_RED + regs->crtcOffset, 0); 684 685 Write32(OUT, AVIVO_DC_LUTA_WHITE_OFFSET_BLUE + regs->crtcOffset, 0xffff); 686 Write32(OUT, AVIVO_DC_LUTA_WHITE_OFFSET_GREEN + regs->crtcOffset, 0xffff); 687 Write32(OUT, AVIVO_DC_LUTA_WHITE_OFFSET_RED + regs->crtcOffset, 0xffff); 688 689 Write32(OUT, AVIVO_DC_LUT_RW_SELECT, crtcID); 690 Write32(OUT, AVIVO_DC_LUT_RW_MODE, 0); 691 Write32(OUT, AVIVO_DC_LUT_WRITE_EN_MASK, 0x0000003f); 692 693 Write32(OUT, AVIVO_DC_LUT_RW_INDEX, 0); 694 for (int i = 0; i < 256; i++) { 695 Write32(OUT, AVIVO_DC_LUT_30_COLOR, 696 (r[i] << 20) | 697 (g[i] << 10) | 698 (b[i] << 0)); 699 } 700 701 Write32(OUT, AVIVO_D1GRPH_LUT_SEL + regs->crtcOffset, crtcID); 702 } 703 704 705 void 706 display_crtc_fb_set(uint8 crtcID, display_mode* mode) 707 { 708 radeon_shared_info &info = *gInfo->shared_info; 709 register_info* regs = gDisplay[crtcID]->regs; 710 711 uint16* r = info.color_data; 712 uint16* g = r + 256; 713 uint16* b = r + 512; 714 715 uint32 fbSwap; 716 if (info.dceMajor >= 4) 717 fbSwap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE); 718 else 719 fbSwap = R600_D1GRPH_SWAP_ENDIAN_NONE; 720 721 uint32 fbFormat; 722 723 uint32 bytesPerPixel; 724 uint32 bitsPerPixel; 725 726 switch (mode->space) { 727 case B_CMAP8: 728 bytesPerPixel = 1; 729 bitsPerPixel = 8; 730 if (info.dceMajor >= 4) { 731 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) 732 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED)); 733 } else { 734 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_8BPP 735 | AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; 736 } 737 // TODO: copy system color map into shared info 738 break; 739 case B_RGB15_LITTLE: 740 bytesPerPixel = 2; 741 bitsPerPixel = 15; 742 if (info.dceMajor >= 4) { 743 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) 744 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555)); 745 } else { 746 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_16BPP 747 | AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; 748 } 749 break; 750 case B_RGB16_LITTLE: 751 bytesPerPixel = 2; 752 bitsPerPixel = 16; 753 754 if (info.dceMajor >= 4) { 755 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) 756 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565)); 757 #ifdef __POWERPC__ 758 fbSwap 759 = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 760 #endif 761 } else { 762 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_16BPP 763 | AVIVO_D1GRPH_CONTROL_16BPP_RGB565; 764 #ifdef __POWERPC__ 765 fbSwap = R600_D1GRPH_SWAP_ENDIAN_16BIT; 766 #endif 767 } 768 769 { 770 // default gamma table 771 uint16 gamma = 0; 772 for (int i = 0; i < 256; i++) { 773 r[i] = gamma; 774 g[i] = gamma; 775 b[i] = gamma; 776 gamma += 4; 777 } 778 } 779 break; 780 case B_RGB24_LITTLE: 781 case B_RGB32_LITTLE: 782 default: 783 bytesPerPixel = 4; 784 bitsPerPixel = 32; 785 if (info.dceMajor >= 4) { 786 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) 787 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); 788 #ifdef __POWERPC__ 789 fbSwap 790 = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 791 #endif 792 } else { 793 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_32BPP 794 | AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; 795 #ifdef __POWERPC__ 796 fbSwap = R600_D1GRPH_SWAP_ENDIAN_32BIT; 797 #endif 798 } 799 800 { 801 // default gamma table 802 uint16 gamma = 0; 803 for (int i = 0; i < 256; i++) { 804 r[i] = gamma; 805 g[i] = gamma; 806 b[i] = gamma; 807 gamma += 4; 808 } 809 } 810 break; 811 } 812 813 Write32(OUT, regs->vgaControl, 0); 814 815 uint64 fbAddress = gInfo->fb.vramStart; 816 817 TRACE("%s: Framebuffer at: 0x%" B_PRIX64 "\n", __func__, fbAddress); 818 819 if (info.chipsetID >= RADEON_RV770) { 820 TRACE("%s: Set SurfaceAddress High: 0x%" B_PRIX32 "\n", 821 __func__, (fbAddress >> 32) & 0xf); 822 823 Write32(OUT, regs->grphPrimarySurfaceAddrHigh, 824 (fbAddress >> 32) & 0xf); 825 Write32(OUT, regs->grphSecondarySurfaceAddrHigh, 826 (fbAddress >> 32) & 0xf); 827 } 828 829 TRACE("%s: Set SurfaceAddress: 0x%" B_PRIX64 "\n", 830 __func__, (fbAddress & 0xFFFFFFFF)); 831 832 Write32(OUT, regs->grphPrimarySurfaceAddr, (fbAddress & 0xFFFFFFFF)); 833 Write32(OUT, regs->grphSecondarySurfaceAddr, (fbAddress & 0xFFFFFFFF)); 834 835 if (info.chipsetID >= RADEON_R600) { 836 Write32(CRT, regs->grphControl, fbFormat); 837 Write32(CRT, regs->grphSwapControl, fbSwap); 838 } 839 840 // Align our framebuffer width 841 uint32 widthAligned = mode->virtual_width; 842 uint32 pitchMask = 0; 843 844 // assume micro-linear/macro-linear mode (i.e., not tiled) 845 switch (bytesPerPixel) { 846 case 1: 847 pitchMask = 63; 848 break; 849 case 2: 850 pitchMask = 31; 851 break; 852 case 3: 853 case 4: 854 pitchMask = 31; 855 break; 856 } 857 widthAligned += pitchMask; 858 widthAligned &= ~pitchMask; 859 860 TRACE("%s: fb: %" B_PRIu32 "x%" B_PRIu32 " (%" B_PRIu32 " bpp)\n", __func__, 861 mode->virtual_width, mode->virtual_height, bitsPerPixel); 862 TRACE("%s: fb pitch: %" B_PRIu32 " \n", __func__, 863 widthAligned); 864 TRACE("%s: fb width aligned: %" B_PRIu32 "\n", __func__, 865 widthAligned); 866 867 Write32(CRT, regs->grphSurfaceOffsetX, 0); 868 Write32(CRT, regs->grphSurfaceOffsetY, 0); 869 Write32(CRT, regs->grphXStart, 0); 870 Write32(CRT, regs->grphYStart, 0); 871 Write32(CRT, regs->grphXEnd, mode->virtual_width); 872 Write32(CRT, regs->grphYEnd, mode->virtual_height); 873 Write32(CRT, regs->grphPitch, widthAligned); 874 875 Write32(CRT, regs->grphEnable, 1); 876 // Enable Frame buffer 877 878 Write32(CRT, regs->modeDesktopHeight, mode->virtual_height); 879 880 uint32 viewportWidth = mode->timing.h_display; 881 uint32 viewportHeight = (mode->timing.v_display + 1) & ~1; 882 883 Write32(CRT, regs->viewportStart, 0); 884 Write32(CRT, regs->viewportSize, 885 (viewportWidth << 16) | viewportHeight); 886 887 // Pageflip setup 888 if (info.dceMajor >= 4) { 889 uint32 tmp 890 = Read32(OUT, EVERGREEN_GRPH_FLIP_CONTROL + regs->crtcOffset); 891 tmp &= ~EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN; 892 Write32(OUT, EVERGREEN_GRPH_FLIP_CONTROL + regs->crtcOffset, tmp); 893 894 Write32(OUT, EVERGREEN_MASTER_UPDATE_MODE + regs->crtcOffset, 0); 895 // Pageflip to happen anywhere in vblank 896 display_dce45_crtc_load_lut(crtcID); 897 } else { 898 uint32 tmp = Read32(OUT, AVIVO_D1GRPH_FLIP_CONTROL + regs->crtcOffset); 899 tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN; 900 Write32(OUT, AVIVO_D1GRPH_FLIP_CONTROL + regs->crtcOffset, tmp); 901 902 Write32(OUT, AVIVO_D1MODE_MASTER_UPDATE_MODE + regs->crtcOffset, 0); 903 // Pageflip to happen anywhere in vblank 904 display_avivo_crtc_load_lut(crtcID); 905 } 906 907 // update shared info 908 gInfo->shared_info->bytes_per_row = widthAligned * bytesPerPixel; 909 gInfo->shared_info->current_mode = *mode; 910 gInfo->shared_info->bits_per_pixel = bitsPerPixel; 911 } 912 913 914 void 915 display_crtc_set(uint8 crtcID, display_mode* mode) 916 { 917 display_timing& displayTiming = mode->timing; 918 919 TRACE("%s called to do %dx%d\n", 920 __func__, displayTiming.h_display, displayTiming.v_display); 921 922 SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args; 923 int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing); 924 uint16 misc = 0; 925 926 memset(&args, 0, sizeof(args)); 927 928 args.usH_Total = B_HOST_TO_LENDIAN_INT16(displayTiming.h_total); 929 args.usH_Disp = B_HOST_TO_LENDIAN_INT16(displayTiming.h_display); 930 args.usH_SyncStart = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_start); 931 args.usH_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_end 932 - displayTiming.h_sync_start); 933 934 args.usV_Total = B_HOST_TO_LENDIAN_INT16(displayTiming.v_total); 935 args.usV_Disp = B_HOST_TO_LENDIAN_INT16(displayTiming.v_display); 936 args.usV_SyncStart = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_start); 937 args.usV_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_end 938 - displayTiming.v_sync_start); 939 940 args.ucOverscanRight = 0; 941 args.ucOverscanLeft = 0; 942 args.ucOverscanBottom = 0; 943 args.ucOverscanTop = 0; 944 945 if ((displayTiming.flags & B_POSITIVE_HSYNC) == 0) 946 misc |= ATOM_HSYNC_POLARITY; 947 if ((displayTiming.flags & B_POSITIVE_VSYNC) == 0) 948 misc |= ATOM_VSYNC_POLARITY; 949 950 args.susModeMiscInfo.usAccess = B_HOST_TO_LENDIAN_INT16(misc); 951 args.ucCRTC = crtcID; 952 953 atom_execute_table(gAtomContext, index, (uint32*)&args); 954 } 955 956 957 void 958 display_crtc_set_dtd(uint8 crtcID, display_mode* mode) 959 { 960 display_timing& displayTiming = mode->timing; 961 962 TRACE("%s called to do %dx%d\n", __func__, 963 displayTiming.h_display, displayTiming.v_display); 964 965 SET_CRTC_USING_DTD_TIMING_PARAMETERS args; 966 int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming); 967 uint16 misc = 0; 968 969 memset(&args, 0, sizeof(args)); 970 971 // Note: the code below assumes H & V borders are both zero 972 uint16 blankStart 973 = MIN(displayTiming.h_sync_start, displayTiming.h_display); 974 uint16 blankEnd 975 = MAX(displayTiming.h_sync_end, displayTiming.h_total); 976 args.usH_Size = B_HOST_TO_LENDIAN_INT16(displayTiming.h_display); 977 args.usH_Blanking_Time = B_HOST_TO_LENDIAN_INT16(blankEnd - blankStart); 978 979 blankStart = MIN(displayTiming.v_sync_start, displayTiming.v_display); 980 blankEnd = MAX(displayTiming.v_sync_end, displayTiming.v_total); 981 args.usV_Size = B_HOST_TO_LENDIAN_INT16(displayTiming.v_display); 982 args.usV_Blanking_Time = B_HOST_TO_LENDIAN_INT16(blankEnd - blankStart); 983 984 args.usH_SyncOffset = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_start 985 - displayTiming.h_display); 986 args.usH_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_end 987 - displayTiming.h_sync_start); 988 989 args.usV_SyncOffset = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_start 990 - displayTiming.v_display); 991 args.usV_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_end 992 - displayTiming.v_sync_start); 993 994 args.ucH_Border = 0; 995 args.ucV_Border = 0; 996 997 if ((displayTiming.flags & B_POSITIVE_HSYNC) == 0) 998 misc |= ATOM_HSYNC_POLARITY; 999 if ((displayTiming.flags & B_POSITIVE_VSYNC) == 0) 1000 misc |= ATOM_VSYNC_POLARITY; 1001 1002 args.susModeMiscInfo.usAccess = B_HOST_TO_LENDIAN_INT16(misc); 1003 args.ucCRTC = crtcID; 1004 1005 atom_execute_table(gAtomContext, index, (uint32*)&args); 1006 } 1007 1008 1009 void 1010 display_crtc_ss(pll_info* pll, int command) 1011 { 1012 TRACE("%s\n", __func__); 1013 radeon_shared_info &info = *gInfo->shared_info; 1014 1015 int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL); 1016 1017 union enableSS { 1018 ENABLE_LVDS_SS_PARAMETERS lvds_ss; 1019 ENABLE_LVDS_SS_PARAMETERS_V2 lvds_ss_2; 1020 ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION v1; 1021 ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 v2; 1022 ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 v3; 1023 }; 1024 1025 union enableSS args; 1026 memset(&args, 0, sizeof(args)); 1027 1028 if (info.dceMajor >= 5) { 1029 args.v3.usSpreadSpectrumAmountFrac = B_HOST_TO_LENDIAN_INT16(0); 1030 args.v3.ucSpreadSpectrumType 1031 = pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 1032 switch (pll->id) { 1033 case ATOM_PPLL1: 1034 args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P1PLL; 1035 args.v3.usSpreadSpectrumAmount 1036 = B_HOST_TO_LENDIAN_INT16(pll->ssAmount); 1037 args.v3.usSpreadSpectrumStep 1038 = B_HOST_TO_LENDIAN_INT16(pll->ssStep); 1039 break; 1040 case ATOM_PPLL2: 1041 args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL; 1042 args.v3.usSpreadSpectrumAmount 1043 = B_HOST_TO_LENDIAN_INT16(pll->ssAmount); 1044 args.v3.usSpreadSpectrumStep 1045 = B_HOST_TO_LENDIAN_INT16(pll->ssStep); 1046 break; 1047 case ATOM_DCPLL: 1048 args.v3.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL; 1049 args.v3.usSpreadSpectrumAmount = B_HOST_TO_LENDIAN_INT16(0); 1050 args.v3.usSpreadSpectrumStep = B_HOST_TO_LENDIAN_INT16(0); 1051 break; 1052 default: 1053 ERROR("%s: BUG: Invalid PLL ID!\n", __func__); 1054 return; 1055 } 1056 if (pll->ssPercentage == 0 1057 || ((pll->ssType & ATOM_EXTERNAL_SS_MASK) != 0)) { 1058 command = ATOM_DISABLE; 1059 } 1060 args.v3.ucEnable = command; 1061 } else if (info.dceMajor >= 4) { 1062 args.v2.usSpreadSpectrumPercentage 1063 = B_HOST_TO_LENDIAN_INT16(pll->ssPercentage); 1064 args.v2.ucSpreadSpectrumType 1065 = pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 1066 switch (pll->id) { 1067 case ATOM_PPLL1: 1068 args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V2_P1PLL; 1069 args.v2.usSpreadSpectrumAmount 1070 = B_HOST_TO_LENDIAN_INT16(pll->ssAmount); 1071 args.v2.usSpreadSpectrumStep 1072 = B_HOST_TO_LENDIAN_INT16(pll->ssStep); 1073 break; 1074 case ATOM_PPLL2: 1075 args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_P2PLL; 1076 args.v2.usSpreadSpectrumAmount 1077 = B_HOST_TO_LENDIAN_INT16(pll->ssAmount); 1078 args.v2.usSpreadSpectrumStep 1079 = B_HOST_TO_LENDIAN_INT16(pll->ssStep); 1080 break; 1081 case ATOM_DCPLL: 1082 args.v2.ucSpreadSpectrumType |= ATOM_PPLL_SS_TYPE_V3_DCPLL; 1083 args.v2.usSpreadSpectrumAmount = B_HOST_TO_LENDIAN_INT16(0); 1084 args.v2.usSpreadSpectrumStep = B_HOST_TO_LENDIAN_INT16(0); 1085 break; 1086 default: 1087 ERROR("%s: BUG: Invalid PLL ID!\n", __func__); 1088 return; 1089 } 1090 if (pll->ssPercentage == 0 1091 || ((pll->ssType & ATOM_EXTERNAL_SS_MASK) != 0) 1092 || (info.chipsetFlags & CHIP_APU) != 0 ) { 1093 command = ATOM_DISABLE; 1094 } 1095 args.v2.ucEnable = command; 1096 } else if (info.dceMajor >= 3) { 1097 args.v1.usSpreadSpectrumPercentage 1098 = B_HOST_TO_LENDIAN_INT16(pll->ssPercentage); 1099 args.v1.ucSpreadSpectrumType 1100 = pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 1101 args.v1.ucSpreadSpectrumStep = pll->ssStep; 1102 args.v1.ucSpreadSpectrumDelay = pll->ssDelay; 1103 args.v1.ucSpreadSpectrumRange = pll->ssRange; 1104 args.v1.ucPpll = pll->id; 1105 args.v1.ucEnable = command; 1106 } else if (info.dceMajor >= 2) { 1107 if ((command == ATOM_DISABLE) || (pll->ssPercentage == 0) 1108 || (pll->ssType & ATOM_EXTERNAL_SS_MASK)) { 1109 radeon_gpu_ss_control(pll, false); 1110 return; 1111 } 1112 args.lvds_ss_2.usSpreadSpectrumPercentage 1113 = B_HOST_TO_LENDIAN_INT16(pll->ssPercentage); 1114 args.lvds_ss_2.ucSpreadSpectrumType 1115 = pll->ssType & ATOM_SS_CENTRE_SPREAD_MODE_MASK; 1116 args.lvds_ss_2.ucSpreadSpectrumStep = pll->ssStep; 1117 args.lvds_ss_2.ucSpreadSpectrumDelay = pll->ssDelay; 1118 args.lvds_ss_2.ucSpreadSpectrumRange = pll->ssRange; 1119 args.lvds_ss_2.ucEnable = command; 1120 } else { 1121 ERROR("%s: TODO: Old card SS control\n", __func__); 1122 return; 1123 } 1124 1125 atom_execute_table(gAtomContext, index, (uint32*)&args); 1126 } 1127 1128 1129 void 1130 display_crtc_power(uint8 crtcID, int command) 1131 { 1132 TRACE("%s\n", __func__); 1133 int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC); 1134 ENABLE_CRTC_PS_ALLOCATION args; 1135 1136 memset(&args, 0, sizeof(args)); 1137 1138 args.ucCRTC = crtcID; 1139 args.ucEnable = command; 1140 1141 atom_execute_table(gAtomContext, index, (uint32*)&args); 1142 } 1143 1144 1145 void 1146 display_crtc_memreq(uint8 crtcID, int command) 1147 { 1148 TRACE("%s\n", __func__); 1149 int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq); 1150 ENABLE_CRTC_PS_ALLOCATION args; 1151 1152 memset(&args, 0, sizeof(args)); 1153 1154 args.ucCRTC = crtcID; 1155 args.ucEnable = command; 1156 1157 atom_execute_table(gAtomContext, index, (uint32*)&args); 1158 } 1159