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