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 = R600_CRTC0_REGISTER_OFFSET; 117 regs->vgaControl = AVIVO_D1VGA_CONTROL; 118 regs->grphPrimarySurfaceAddrHigh 119 = D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH; 120 break; 121 case 1: 122 offset = R600_CRTC1_REGISTER_OFFSET; 123 regs->vgaControl = AVIVO_D2VGA_CONTROL; 124 regs->grphPrimarySurfaceAddrHigh 125 = 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 = D1GRPH_SWAP_CNTL + offset; 138 139 regs->grphPrimarySurfaceAddr 140 = D1GRPH_PRIMARY_SURFACE_ADDRESS + offset; 141 regs->grphSecondarySurfaceAddr 142 = 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 = D1GRPH_SWAP_CNTL + offset; 181 182 regs->grphPrimarySurfaceAddr 183 = D1GRPH_PRIMARY_SURFACE_ADDRESS + offset; 184 regs->grphSecondarySurfaceAddr 185 = 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]->edid_info; 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]->vfreq_min = range.min_v; /* in Hz */ 232 gDisplay[crtid]->vfreq_max = range.max_v; 233 gDisplay[crtid]->hfreq_min = range.min_h; /* in kHz */ 234 gDisplay[crtid]->hfreq_max = 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]->active = false; 249 gDisplay[id]->found_ranges = false; 250 } 251 252 uint32 displayIndex = 0; 253 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) { 254 if (gConnector[id]->valid == false) 255 continue; 256 if (displayIndex >= MAX_DISPLAY) 257 continue; 258 259 // TODO: As DP aux transactions don't work yet, just use LVDS as a hack 260 #if 0 261 if (gConnector[id]->encoder.isDPBridge == true) { 262 // If this is a DisplayPort Bridge, setup ddc on bus 263 // TRAVIS (LVDS) or NUTMEG (VGA) 264 TRACE("%s: is bridge, performing bridge DDC setup\n", __func__); 265 encoder_external_setup(id, 23860, 266 EXTERNAL_ENCODER_ACTION_V3_DDC_SETUP); 267 } else if (gConnector[id]->type == VIDEO_CONNECTOR_LVDS) { 268 #endif 269 if (gConnector[id]->type == VIDEO_CONNECTOR_LVDS) { 270 // If plain (non-DP) laptop LVDS, read mode info from AtomBIOS 271 //TRACE("%s: non-DP laptop LVDS detected\n", __func__); 272 gDisplay[displayIndex]->active 273 = connector_read_mode_lvds(id, 274 &gDisplay[displayIndex]->preferredMode); 275 } 276 277 if (gDisplay[displayIndex]->active == false) { 278 TRACE("%s: bit-banging ddc for edid on connector %" B_PRIu32 "\n", 279 __func__, id); 280 // Lets try bit-banging edid from connector 281 gDisplay[displayIndex]->active = 282 connector_read_edid(id, &gDisplay[displayIndex]->edid_info); 283 284 if (gConnector[id]->encoder.type == VIDEO_ENCODER_TVDAC 285 || gConnector[id]->encoder.type == VIDEO_ENCODER_DAC) { 286 // analog? with valid EDID? lets make sure there is load. 287 // There is only one ddc communications path on DVI-I 288 if (encoder_analog_load_detect(id) != true) { 289 TRACE("%s: no analog load on EDID valid connector " 290 "#%" B_PRIu32 "\n", __func__, id); 291 gDisplay[displayIndex]->active = false; 292 } 293 } 294 } 295 296 if (gDisplay[displayIndex]->active != true) { 297 // Nothing interesting here, move along 298 continue; 299 } 300 301 // We found a valid / active display 302 303 gDisplay[displayIndex]->connectorIndex = id; 304 // Populate physical connector index from gConnector 305 306 init_registers(gDisplay[displayIndex]->regs, displayIndex); 307 308 if (gDisplay[displayIndex]->preferredMode.virtual_width > 0) { 309 // Found a single preferred mode 310 gDisplay[displayIndex]->found_ranges = false; 311 } else { 312 // Use edid data and pull ranges 313 if (detect_crt_ranges(displayIndex) == B_OK) 314 gDisplay[displayIndex]->found_ranges = true; 315 } 316 317 displayIndex++; 318 } 319 320 // fallback if no active monitors were found 321 if (displayIndex == 0) { 322 ERROR("%s: ERROR: 0 attached monitors were found on display connectors." 323 " Injecting first connector as a last resort.\n", __func__); 324 for (uint32 id = 0; id < ATOM_MAX_SUPPORTED_DEVICE; id++) { 325 // skip TV DAC connectors as likely fallback isn't for TV 326 if (gConnector[id]->encoder.type == VIDEO_ENCODER_TVDAC) 327 continue; 328 gDisplay[0]->active = true; 329 gDisplay[0]->connectorIndex = id; 330 init_registers(gDisplay[0]->regs, 0); 331 if (detect_crt_ranges(0) == B_OK) 332 gDisplay[0]->found_ranges = true; 333 break; 334 } 335 } 336 337 return B_OK; 338 } 339 340 341 void 342 debug_displays() 343 { 344 TRACE("Currently detected monitors===============\n"); 345 for (uint32 id = 0; id < MAX_DISPLAY; id++) { 346 ERROR("Display #%" B_PRIu32 " active = %s\n", 347 id, gDisplay[id]->active ? "true" : "false"); 348 349 uint32 connectorIndex = gDisplay[id]->connectorIndex; 350 351 if (gDisplay[id]->active) { 352 uint32 connectorType = gConnector[connectorIndex]->type; 353 uint32 encoderType = gConnector[connectorIndex]->encoder.type; 354 ERROR(" + connector ID: %" B_PRIu32 "\n", connectorIndex); 355 ERROR(" + connector type: %s\n", get_connector_name(connectorType)); 356 ERROR(" + encoder type: %s\n", get_encoder_name(encoderType)); 357 ERROR(" + limits: Vert Min/Max: %" B_PRIu32 "/%" B_PRIu32"\n", 358 gDisplay[id]->vfreq_min, gDisplay[id]->vfreq_max); 359 ERROR(" + limits: Horz Min/Max: %" B_PRIu32 "/%" B_PRIu32"\n", 360 gDisplay[id]->hfreq_min, gDisplay[id]->hfreq_max); 361 } 362 } 363 TRACE("==========================================\n"); 364 } 365 366 367 uint32 368 display_get_encoder_mode(uint32 connectorIndex) 369 { 370 switch (gConnector[connectorIndex]->type) { 371 case VIDEO_CONNECTOR_DVII: 372 case VIDEO_CONNECTOR_HDMIB: /* HDMI-B is DL-DVI; analog works fine */ 373 // TODO: if audio detected on edid and DCE4, ATOM_ENCODER_MODE_DVI 374 // if audio detected on edid not DCE4, ATOM_ENCODER_MODE_HDMI 375 // if (gConnector[connectorIndex]->use_digital) 376 // return ATOM_ENCODER_MODE_DVI; 377 // else 378 return ATOM_ENCODER_MODE_CRT; 379 break; 380 case VIDEO_CONNECTOR_DVID: 381 case VIDEO_CONNECTOR_HDMIA: 382 default: 383 // TODO: if audio detected on edid and DCE4, ATOM_ENCODER_MODE_DVI 384 // if audio detected on edid not DCE4, ATOM_ENCODER_MODE_HDMI 385 return ATOM_ENCODER_MODE_DVI; 386 case VIDEO_CONNECTOR_LVDS: 387 return ATOM_ENCODER_MODE_LVDS; 388 case VIDEO_CONNECTOR_DP: 389 // dig_connector = radeon_connector->con_priv; 390 // if ((dig_connector->dp_sink_type 391 // == CONNECTOR_OBJECT_ID_DISPLAYPORT) 392 // || (dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) { 393 // return ATOM_ENCODER_MODE_DP; 394 // } 395 // TODO: if audio detected on edid and DCE4, ATOM_ENCODER_MODE_DVI 396 // if audio detected on edid not DCE4, ATOM_ENCODER_MODE_HDMI 397 return ATOM_ENCODER_MODE_DVI; 398 case VIDEO_CONNECTOR_EDP: 399 return ATOM_ENCODER_MODE_DP; 400 case VIDEO_CONNECTOR_DVIA: 401 case VIDEO_CONNECTOR_VGA: 402 return ATOM_ENCODER_MODE_CRT; 403 case VIDEO_CONNECTOR_COMPOSITE: 404 case VIDEO_CONNECTOR_SVIDEO: 405 case VIDEO_CONNECTOR_9DIN: 406 return ATOM_ENCODER_MODE_TV; 407 } 408 } 409 410 411 void 412 display_crtc_lock(uint8 crtcID, int command) 413 { 414 TRACE("%s\n", __func__); 415 ENABLE_CRTC_PS_ALLOCATION args; 416 int index 417 = GetIndexIntoMasterTable(COMMAND, UpdateCRTC_DoubleBufferRegisters); 418 419 memset(&args, 0, sizeof(args)); 420 421 args.ucCRTC = crtcID; 422 args.ucEnable = command; 423 424 atom_execute_table(gAtomContext, index, (uint32*)&args); 425 } 426 427 428 void 429 display_crtc_blank(uint8 crtcID, int command) 430 { 431 TRACE("%s\n", __func__); 432 BLANK_CRTC_PS_ALLOCATION args; 433 int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC); 434 435 memset(&args, 0, sizeof(args)); 436 437 args.ucCRTC = crtcID; 438 args.ucBlanking = command; 439 440 // DEBUG: Radeon red to know when we are blanked :) 441 args.usBlackColorRCr = 255; 442 args.usBlackColorGY = 0; 443 args.usBlackColorBCb = 0; 444 445 atom_execute_table(gAtomContext, index, (uint32*)&args); 446 } 447 448 449 void 450 display_crtc_scale(uint8 crtcID, display_mode* mode) 451 { 452 TRACE("%s\n", __func__); 453 ENABLE_SCALER_PS_ALLOCATION args; 454 int index = GetIndexIntoMasterTable(COMMAND, EnableScaler); 455 456 memset(&args, 0, sizeof(args)); 457 458 args.ucScaler = crtcID; 459 args.ucEnable = ATOM_SCALER_DISABLE; 460 461 atom_execute_table(gAtomContext, index, (uint32*)&args); 462 } 463 464 465 void 466 display_crtc_fb_set(uint8 crtcID, display_mode* mode) 467 { 468 radeon_shared_info &info = *gInfo->shared_info; 469 register_info* regs = gDisplay[crtcID]->regs; 470 471 uint32 fbSwap; 472 if (info.dceMajor >= 4) 473 fbSwap = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_NONE); 474 else 475 fbSwap = R600_D1GRPH_SWAP_ENDIAN_NONE; 476 477 uint32 fbFormat; 478 479 uint32 bytesPerPixel; 480 uint32 bitsPerPixel; 481 482 switch (mode->space) { 483 case B_CMAP8: 484 bytesPerPixel = 1; 485 bitsPerPixel = 8; 486 if (info.dceMajor >= 4) { 487 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_8BPP) 488 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_INDEXED)); 489 } else { 490 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_8BPP 491 | AVIVO_D1GRPH_CONTROL_8BPP_INDEXED; 492 } 493 break; 494 case B_RGB15_LITTLE: 495 bytesPerPixel = 2; 496 bitsPerPixel = 15; 497 if (info.dceMajor >= 4) { 498 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) 499 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB1555)); 500 } else { 501 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_16BPP 502 | AVIVO_D1GRPH_CONTROL_16BPP_ARGB1555; 503 } 504 break; 505 case B_RGB16_LITTLE: 506 bytesPerPixel = 2; 507 bitsPerPixel = 16; 508 509 if (info.dceMajor >= 4) { 510 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_16BPP) 511 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB565)); 512 #ifdef __POWERPC__ 513 fbSwap 514 = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN16); 515 #endif 516 } else { 517 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_16BPP 518 | AVIVO_D1GRPH_CONTROL_16BPP_RGB565; 519 #ifdef __POWERPC__ 520 fbSwap = R600_D1GRPH_SWAP_ENDIAN_16BIT; 521 #endif 522 } 523 break; 524 case B_RGB24_LITTLE: 525 case B_RGB32_LITTLE: 526 default: 527 bytesPerPixel = 4; 528 bitsPerPixel = 32; 529 if (info.dceMajor >= 4) { 530 fbFormat = (EVERGREEN_GRPH_DEPTH(EVERGREEN_GRPH_DEPTH_32BPP) 531 | EVERGREEN_GRPH_FORMAT(EVERGREEN_GRPH_FORMAT_ARGB8888)); 532 #ifdef __POWERPC__ 533 fbSwap 534 = EVERGREEN_GRPH_ENDIAN_SWAP(EVERGREEN_GRPH_ENDIAN_8IN32); 535 #endif 536 } else { 537 fbFormat = AVIVO_D1GRPH_CONTROL_DEPTH_32BPP 538 | AVIVO_D1GRPH_CONTROL_32BPP_ARGB8888; 539 #ifdef __POWERPC__ 540 fbSwap = R600_D1GRPH_SWAP_ENDIAN_32BIT; 541 #endif 542 } 543 break; 544 } 545 546 uint32 bytesPerRow = mode->virtual_width * bytesPerPixel; 547 548 Write32(OUT, regs->vgaControl, 0); 549 550 uint64 fbAddress = gInfo->fb.vramStart; 551 552 TRACE("%s: Framebuffer at: 0x%" B_PRIX64 "\n", __func__, fbAddress); 553 554 if (info.chipsetID >= RADEON_RV770) { 555 TRACE("%s: Set SurfaceAddress High: 0x%" B_PRIX32 "\n", 556 __func__, (fbAddress >> 32) & 0xf); 557 558 Write32(OUT, regs->grphPrimarySurfaceAddrHigh, 559 (fbAddress >> 32) & 0xf); 560 Write32(OUT, regs->grphSecondarySurfaceAddrHigh, 561 (fbAddress >> 32) & 0xf); 562 } 563 564 TRACE("%s: Set SurfaceAddress: 0x%" B_PRIX32 "\n", 565 __func__, (fbAddress & 0xFFFFFFFF)); 566 567 Write32(OUT, regs->grphPrimarySurfaceAddr, (fbAddress & 0xFFFFFFFF)); 568 Write32(OUT, regs->grphSecondarySurfaceAddr, (fbAddress & 0xFFFFFFFF)); 569 570 if (info.chipsetID >= RADEON_R600) { 571 Write32(CRT, regs->grphControl, fbFormat); 572 Write32(CRT, regs->grphSwapControl, fbSwap); 573 } 574 575 Write32(CRT, regs->grphSurfaceOffsetX, 0); 576 Write32(CRT, regs->grphSurfaceOffsetY, 0); 577 Write32(CRT, regs->grphXStart, 0); 578 Write32(CRT, regs->grphYStart, 0); 579 Write32(CRT, regs->grphXEnd, mode->virtual_width); 580 Write32(CRT, regs->grphYEnd, mode->virtual_height); 581 Write32(CRT, regs->grphPitch, (bytesPerRow / 4)); 582 583 Write32(CRT, regs->grphEnable, 1); 584 // Enable Frame buffer 585 586 Write32(CRT, regs->modeDesktopHeight, mode->virtual_height); 587 588 uint32 viewport_w = mode->timing.h_display; 589 uint32 viewport_h = (mode->timing.v_display + 1) & ~1; 590 591 Write32(CRT, regs->viewportStart, 0); 592 Write32(CRT, regs->viewportSize, 593 (viewport_w << 16) | viewport_h); 594 595 // Pageflip setup 596 if (info.dceMajor >= 4) { 597 uint32 tmp 598 = Read32(OUT, EVERGREEN_GRPH_FLIP_CONTROL + regs->crtcOffset); 599 tmp &= ~EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN; 600 Write32(OUT, EVERGREEN_GRPH_FLIP_CONTROL + regs->crtcOffset, tmp); 601 602 Write32(OUT, EVERGREEN_MASTER_UPDATE_MODE + regs->crtcOffset, 0); 603 // Pageflip to happen anywhere in vblank 604 605 } else { 606 uint32 tmp = Read32(OUT, AVIVO_D1GRPH_FLIP_CONTROL + regs->crtcOffset); 607 tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN; 608 Write32(OUT, AVIVO_D1GRPH_FLIP_CONTROL + regs->crtcOffset, tmp); 609 610 Write32(OUT, AVIVO_D1MODE_MASTER_UPDATE_MODE + regs->crtcOffset, 0); 611 // Pageflip to happen anywhere in vblank 612 } 613 614 // update shared info 615 gInfo->shared_info->bytes_per_row = bytesPerRow; 616 gInfo->shared_info->current_mode = *mode; 617 gInfo->shared_info->bits_per_pixel = bitsPerPixel; 618 } 619 620 621 void 622 display_crtc_set(uint8 crtcID, display_mode* mode) 623 { 624 display_timing& displayTiming = mode->timing; 625 626 TRACE("%s called to do %dx%d\n", 627 __func__, displayTiming.h_display, displayTiming.v_display); 628 629 SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION args; 630 int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_Timing); 631 uint16 misc = 0; 632 633 memset(&args, 0, sizeof(args)); 634 635 args.usH_Total = B_HOST_TO_LENDIAN_INT16(displayTiming.h_total); 636 args.usH_Disp = B_HOST_TO_LENDIAN_INT16(displayTiming.h_display); 637 args.usH_SyncStart = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_start); 638 args.usH_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_end 639 - displayTiming.h_sync_start); 640 641 args.usV_Total = B_HOST_TO_LENDIAN_INT16(displayTiming.v_total); 642 args.usV_Disp = B_HOST_TO_LENDIAN_INT16(displayTiming.v_display); 643 args.usV_SyncStart = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_start); 644 args.usV_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_end 645 - displayTiming.v_sync_start); 646 647 args.ucOverscanRight = 0; 648 args.ucOverscanLeft = 0; 649 args.ucOverscanBottom = 0; 650 args.ucOverscanTop = 0; 651 652 if ((displayTiming.flags & B_POSITIVE_HSYNC) == 0) 653 misc |= ATOM_HSYNC_POLARITY; 654 if ((displayTiming.flags & B_POSITIVE_VSYNC) == 0) 655 misc |= ATOM_VSYNC_POLARITY; 656 657 args.susModeMiscInfo.usAccess = B_HOST_TO_LENDIAN_INT16(misc); 658 args.ucCRTC = crtcID; 659 660 atom_execute_table(gAtomContext, index, (uint32*)&args); 661 } 662 663 664 void 665 display_crtc_set_dtd(uint8 crtcID, display_mode* mode) 666 { 667 display_timing& displayTiming = mode->timing; 668 669 TRACE("%s called to do %dx%d\n", 670 __func__, displayTiming.h_display, displayTiming.v_display); 671 672 SET_CRTC_USING_DTD_TIMING_PARAMETERS args; 673 int index = GetIndexIntoMasterTable(COMMAND, SetCRTC_UsingDTDTiming); 674 uint16 misc = 0; 675 676 memset(&args, 0, sizeof(args)); 677 678 uint16 blankStart 679 = MIN(displayTiming.h_sync_start, displayTiming.h_display); 680 uint16 blankEnd 681 = MAX(displayTiming.h_sync_end, displayTiming.h_total); 682 args.usH_Size = B_HOST_TO_LENDIAN_INT16(displayTiming.h_display); 683 args.usH_Blanking_Time = B_HOST_TO_LENDIAN_INT16(blankEnd - blankStart); 684 685 blankStart = MIN(displayTiming.v_sync_start, displayTiming.v_display); 686 blankEnd = MAX(displayTiming.v_sync_end, displayTiming.v_total); 687 args.usV_Size = B_HOST_TO_LENDIAN_INT16(displayTiming.v_display); 688 args.usV_Blanking_Time = B_HOST_TO_LENDIAN_INT16(blankEnd - blankStart); 689 690 args.usH_SyncOffset = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_start 691 - displayTiming.h_display); 692 args.usH_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.h_sync_end 693 - displayTiming.h_sync_start); 694 695 args.usV_SyncOffset = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_start 696 - displayTiming.v_display); 697 args.usV_SyncWidth = B_HOST_TO_LENDIAN_INT16(displayTiming.v_sync_end 698 - displayTiming.v_sync_start); 699 700 args.ucH_Border = 0; 701 args.ucV_Border = 0; 702 703 if ((displayTiming.flags & B_POSITIVE_HSYNC) == 0) 704 misc |= ATOM_HSYNC_POLARITY; 705 if ((displayTiming.flags & B_POSITIVE_VSYNC) == 0) 706 misc |= ATOM_VSYNC_POLARITY; 707 708 args.susModeMiscInfo.usAccess = B_HOST_TO_LENDIAN_INT16(misc); 709 args.ucCRTC = crtcID; 710 711 atom_execute_table(gAtomContext, index, (uint32*)&args); 712 } 713 714 715 void 716 display_crtc_power(uint8 crtcID, int command) 717 { 718 TRACE("%s\n", __func__); 719 int index = GetIndexIntoMasterTable(COMMAND, EnableCRTC); 720 ENABLE_CRTC_PS_ALLOCATION args; 721 722 memset(&args, 0, sizeof(args)); 723 724 args.ucCRTC = crtcID; 725 args.ucEnable = command; 726 727 atom_execute_table(gAtomContext, index, (uint32*)&args); 728 } 729 730 731 void 732 display_crtc_memreq(uint8 crtcID, int command) 733 { 734 TRACE("%s\n", __func__); 735 int index = GetIndexIntoMasterTable(COMMAND, EnableCRTCMemReq); 736 ENABLE_CRTC_PS_ALLOCATION args; 737 738 memset(&args, 0, sizeof(args)); 739 740 args.ucCRTC = crtcID; 741 args.ucEnable = command; 742 743 atom_execute_table(gAtomContext, index, (uint32*)&args); 744 } 745