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