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