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 #include "pll.h" 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <math.h> 16 17 #include "accelerant_protos.h" 18 #include "accelerant.h" 19 #include "bios.h" 20 #include "display.h" 21 #include "displayport.h" 22 #include "encoder.h" 23 #include "utility.h" 24 25 26 #define TRACE_PLL 27 #ifdef TRACE_PLL 28 extern "C" void _sPrintf(const char* format, ...); 29 # define TRACE(x...) _sPrintf("radeon_hd: " x) 30 #else 31 # define TRACE(x...) ; 32 #endif 33 34 #define ERROR(x...) _sPrintf("radeon_hd: " x) 35 36 37 status_t 38 pll_limit_probe(pll_info* pll) 39 { 40 radeon_shared_info &info = *gInfo->shared_info; 41 42 uint8 tableMajor; 43 uint8 tableMinor; 44 uint16 tableOffset; 45 46 int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); 47 if (atom_parse_data_header(gAtomContext, index, NULL, 48 &tableMajor, &tableMinor, &tableOffset) != B_OK) { 49 ERROR("%s: Couldn't parse data header\n", __func__); 50 return B_ERROR; 51 } 52 53 union atomFirmwareInfo { 54 ATOM_FIRMWARE_INFO info; 55 ATOM_FIRMWARE_INFO_V1_2 info_12; 56 ATOM_FIRMWARE_INFO_V1_3 info_13; 57 ATOM_FIRMWARE_INFO_V1_4 info_14; 58 ATOM_FIRMWARE_INFO_V2_1 info_21; 59 ATOM_FIRMWARE_INFO_V2_2 info_22; 60 }; 61 union atomFirmwareInfo* firmwareInfo 62 = (union atomFirmwareInfo*)(gAtomContext->bios + tableOffset); 63 64 /* pixel clock limits */ 65 pll->referenceFreq 66 = B_LENDIAN_TO_HOST_INT16(firmwareInfo->info.usReferenceClock) * 10; 67 68 if (tableMinor < 2) { 69 pll->pllOutMin 70 = B_LENDIAN_TO_HOST_INT16( 71 firmwareInfo->info.usMinPixelClockPLL_Output) * 10; 72 } else { 73 pll->pllOutMin 74 = B_LENDIAN_TO_HOST_INT32( 75 firmwareInfo->info_12.ulMinPixelClockPLL_Output) * 10; 76 } 77 78 pll->pllOutMax 79 = B_LENDIAN_TO_HOST_INT32( 80 firmwareInfo->info.ulMaxPixelClockPLL_Output) * 10; 81 82 if (tableMinor >= 4) { 83 pll->lcdPllOutMin 84 = B_LENDIAN_TO_HOST_INT16( 85 firmwareInfo->info_14.usLcdMinPixelClockPLL_Output) * 1000; 86 87 if (pll->lcdPllOutMin == 0) 88 pll->lcdPllOutMin = pll->pllOutMin; 89 90 pll->lcdPllOutMax 91 = B_LENDIAN_TO_HOST_INT16( 92 firmwareInfo->info_14.usLcdMaxPixelClockPLL_Output) * 1000; 93 94 if (pll->lcdPllOutMax == 0) 95 pll->lcdPllOutMax = pll->pllOutMax; 96 97 } else { 98 pll->lcdPllOutMin = pll->pllOutMin; 99 pll->lcdPllOutMax = pll->pllOutMax; 100 } 101 102 if (pll->pllOutMin == 0) { 103 pll->pllOutMin = 64800 * 10; 104 // Avivo+ limit 105 } 106 107 pll->minPostDiv = POST_DIV_MIN; 108 pll->maxPostDiv = POST_DIV_LIMIT; 109 pll->minRefDiv = REF_DIV_MIN; 110 pll->maxRefDiv = REF_DIV_LIMIT; 111 pll->minFeedbackDiv = FB_DIV_MIN; 112 pll->maxFeedbackDiv = FB_DIV_LIMIT; 113 114 pll->pllInMin = B_LENDIAN_TO_HOST_INT16( 115 firmwareInfo->info.usMinPixelClockPLL_Input) * 10; 116 pll->pllInMax = B_LENDIAN_TO_HOST_INT16( 117 firmwareInfo->info.usMaxPixelClockPLL_Input) * 10; 118 119 if (info.dceMajor >= 4) { 120 pll->dpExternalClock = B_LENDIAN_TO_HOST_INT16( 121 firmwareInfo->info_21.usUniphyDPModeExtClkFreq); 122 } else 123 pll->dpExternalClock = 0; 124 125 TRACE("%s: referenceFreq: %" B_PRIu16 "; pllOutMin: %" B_PRIu16 "; " 126 " pllOutMax: %" B_PRIu16 "; pllInMin: %" B_PRIu16 ";" 127 "pllInMax: %" B_PRIu16 "\n", __func__, pll->referenceFreq, 128 pll->pllOutMin, pll->pllOutMax, pll->pllInMin, pll->pllInMax); 129 130 return B_OK; 131 } 132 133 134 void 135 pll_compute_post_divider(pll_info* pll) 136 { 137 if ((pll->flags & PLL_USE_POST_DIV) != 0) { 138 TRACE("%s: using AtomBIOS post divider\n", __func__); 139 return; 140 } 141 142 uint32 vco; 143 if ((pll->flags & PLL_PREFER_MINM_OVER_MAXP) != 0) { 144 if ((pll->flags & PLL_IS_LCD) != 0) 145 vco = pll->lcdPllOutMin; 146 else 147 vco = pll->pllOutMin; 148 } else { 149 if ((pll->flags & PLL_IS_LCD) != 0) 150 vco = pll->lcdPllOutMax; 151 else 152 vco = pll->pllOutMin; 153 } 154 155 TRACE("%s: vco = %" B_PRIu32 "\n", __func__, vco); 156 157 uint32 postDivider = vco / pll->pixelClock; 158 uint32 tmp = vco % pll->pixelClock; 159 160 if ((pll->flags & PLL_PREFER_MINM_OVER_MAXP) != 0) { 161 if (tmp) 162 postDivider++; 163 } else { 164 if (!tmp) 165 postDivider--; 166 } 167 168 if (postDivider > pll->maxPostDiv) 169 postDivider = pll->maxPostDiv; 170 else if (postDivider < pll->minPostDiv) 171 postDivider = pll->minPostDiv; 172 173 pll->postDiv = postDivider; 174 TRACE("%s: postDiv = %" B_PRIu32 "\n", __func__, postDivider); 175 } 176 177 178 status_t 179 pll_compute(pll_info* pll) 180 { 181 pll_compute_post_divider(pll); 182 183 uint32 targetClock = pll->pixelClock; 184 185 pll->feedbackDiv = 0; 186 pll->feedbackDivFrac = 0; 187 uint32 referenceFrequency = pll->referenceFreq; 188 189 if ((pll->flags & PLL_USE_REF_DIV) != 0) { 190 TRACE("%s: using AtomBIOS reference divider\n", __func__); 191 return B_OK; 192 } else { 193 pll->referenceDiv = pll->minRefDiv; 194 } 195 196 if ((pll->flags & PLL_USE_FRAC_FB_DIV) != 0) { 197 TRACE("%s: using AtomBIOS fractional feedback divider\n", __func__); 198 199 uint32 tmp = pll->postDiv * pll->referenceDiv; 200 tmp *= targetClock; 201 pll->feedbackDiv = tmp / pll->referenceFreq; 202 pll->feedbackDivFrac = tmp % pll->referenceFreq; 203 204 if (pll->feedbackDiv > pll->maxFeedbackDiv) 205 pll->feedbackDiv = pll->maxFeedbackDiv; 206 else if (pll->feedbackDiv < pll->minFeedbackDiv) 207 pll->feedbackDiv = pll->minFeedbackDiv; 208 209 pll->feedbackDivFrac 210 = (100 * pll->feedbackDivFrac) / pll->referenceFreq; 211 212 if (pll->feedbackDivFrac >= 5) { 213 pll->feedbackDivFrac -= 5; 214 pll->feedbackDivFrac /= 10; 215 pll->feedbackDivFrac++; 216 } 217 if (pll->feedbackDivFrac >= 10) { 218 pll->feedbackDiv++; 219 pll->feedbackDivFrac = 0; 220 } 221 } else { 222 TRACE("%s: performing fractional feedback calculations\n", __func__); 223 224 while (pll->referenceDiv <= pll->maxRefDiv) { 225 // get feedback divider 226 uint32 retroEncabulator = pll->postDiv * pll->referenceDiv; 227 228 retroEncabulator *= targetClock; 229 pll->feedbackDiv = retroEncabulator / referenceFrequency; 230 pll->feedbackDivFrac 231 = retroEncabulator % referenceFrequency; 232 233 if (pll->feedbackDiv > pll->maxFeedbackDiv) 234 pll->feedbackDiv = pll->maxFeedbackDiv; 235 else if (pll->feedbackDiv < pll->minFeedbackDiv) 236 pll->feedbackDiv = pll->minFeedbackDiv; 237 238 if (pll->feedbackDivFrac >= (referenceFrequency / 2)) 239 pll->feedbackDiv++; 240 241 pll->feedbackDivFrac = 0; 242 243 if (pll->referenceDiv == 0 244 || pll->postDiv == 0 245 || targetClock == 0) { 246 TRACE("%s: Caught division by zero!\n", __func__); 247 TRACE("%s: referenceDiv %" B_PRIu32 "\n", 248 __func__, pll->referenceDiv); 249 TRACE("%s: postDiv %" B_PRIu32 "\n", 250 __func__, pll->postDiv); 251 TRACE("%s: targetClock %" B_PRIu32 "\n", 252 __func__, targetClock); 253 return B_ERROR; 254 } 255 uint32 tmp = (referenceFrequency * pll->feedbackDiv) 256 / (pll->postDiv * pll->referenceDiv); 257 tmp = (tmp * 1000) / targetClock; 258 259 if (tmp > (1000 + (MAX_TOLERANCE / 10))) 260 pll->referenceDiv++; 261 else if (tmp >= (1000 - (MAX_TOLERANCE / 10))) 262 break; 263 else 264 pll->referenceDiv++; 265 } 266 } 267 268 if (pll->referenceDiv == 0 || pll->postDiv == 0) { 269 TRACE("%s: Caught division by zero of post or reference divider\n", 270 __func__); 271 return B_ERROR; 272 } 273 274 uint32 calculatedClock 275 = ((referenceFrequency * pll->feedbackDiv * 10) 276 + (referenceFrequency * pll->feedbackDivFrac)) 277 / (pll->referenceDiv * pll->postDiv * 10); 278 279 TRACE("%s: pixel clock: %" B_PRIu32 " gives:" 280 " feedbackDivider = %" B_PRIu32 ".%" B_PRIu32 281 "; referenceDivider = %" B_PRIu32 "; postDivider = %" B_PRIu32 "\n", 282 __func__, pll->pixelClock, pll->feedbackDiv, pll->feedbackDivFrac, 283 pll->referenceDiv, pll->postDiv); 284 285 if (pll->pixelClock != calculatedClock) { 286 TRACE("%s: pixel clock %" B_PRIu32 " was changed to %" B_PRIu32 "\n", 287 __func__, pll->pixelClock, calculatedClock); 288 pll->pixelClock = calculatedClock; 289 } 290 291 return B_OK; 292 } 293 294 295 void 296 pll_setup_flags(pll_info* pll, uint8 crtcID) 297 { 298 radeon_shared_info &info = *gInfo->shared_info; 299 uint32 connectorIndex = gDisplay[crtcID]->connectorIndex; 300 uint32 encoderFlags = gConnector[connectorIndex]->encoder.flags; 301 302 if ((info.dceMajor >= 3 && info.dceMinor >= 2) 303 && pll->pixelClock > 200000) { 304 pll->flags |= PLL_PREFER_HIGH_FB_DIV; 305 } else 306 pll->flags |= PLL_PREFER_LOW_REF_DIV; 307 308 309 if (info.chipsetID < RADEON_RV770) 310 pll->flags |= PLL_PREFER_MINM_OVER_MAXP; 311 312 313 if ((encoderFlags & ATOM_DEVICE_LCD_SUPPORT) != 0) { 314 pll->flags |= PLL_IS_LCD; 315 316 // TODO: Spread Spectrum PLL 317 // use reference divider for spread spectrum 318 if (0) { // SS enabled 319 if (0) { // if we have a SS reference divider 320 pll->flags |= PLL_USE_REF_DIV; 321 //pll->reference_div = ss->refdiv; 322 pll->flags |= PLL_USE_FRAC_FB_DIV; 323 } 324 } 325 } 326 327 if ((encoderFlags & ATOM_DEVICE_TV_SUPPORT) != 0) 328 pll->flags |= PLL_PREFER_CLOSEST_LOWER; 329 } 330 331 332 status_t 333 pll_adjust(pll_info* pll, uint8 crtcID) 334 { 335 // TODO: PLL flags 336 radeon_shared_info &info = *gInfo->shared_info; 337 338 uint32 pixelClock = pll->pixelClock; 339 // original as pixel_clock will be adjusted 340 341 uint32 connectorIndex = gDisplay[crtcID]->connectorIndex; 342 uint32 encoderID = gConnector[connectorIndex]->encoder.objectID; 343 uint32 encoderMode = display_get_encoder_mode(connectorIndex); 344 uint32 encoderFlags = gConnector[connectorIndex]->encoder.flags; 345 bool dpBridge = false; 346 347 if ((encoderFlags & (ATOM_DEVICE_LCD_SUPPORT | ATOM_DEVICE_DFP_SUPPORT)) 348 || gConnector[connectorIndex]->encoder.isDPBridge) { 349 TRACE("%s: external DP bridge detected!\n", __func__); 350 dpBridge = true; 351 } 352 353 354 if (info.dceMajor >= 3) { 355 356 uint8 tableMajor; 357 uint8 tableMinor; 358 359 int index = GetIndexIntoMasterTable(COMMAND, AdjustDisplayPll); 360 if (atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor) 361 != B_OK) { 362 return B_ERROR; 363 } 364 365 // Prepare arguments for AtomBIOS call 366 union adjustPixelClock { 367 ADJUST_DISPLAY_PLL_PS_ALLOCATION v1; 368 ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3; 369 }; 370 union adjustPixelClock args; 371 memset(&args, 0, sizeof(args)); 372 373 switch (tableMajor) { 374 case 1: 375 switch (tableMinor) { 376 case 1: 377 case 2: 378 args.v1.usPixelClock 379 = B_HOST_TO_LENDIAN_INT16(pixelClock / 10); 380 args.v1.ucTransmitterID = encoderID; 381 args.v1.ucEncodeMode = encoderMode; 382 // TODO: SS and SS % > 0 383 if (0) { 384 args.v1.ucConfig 385 |= ADJUST_DISPLAY_CONFIG_SS_ENABLE; 386 } 387 388 atom_execute_table(gAtomContext, index, (uint32*)&args); 389 // get returned adjusted clock 390 pll->pixelClock 391 = B_LENDIAN_TO_HOST_INT16(args.v1.usPixelClock); 392 pll->pixelClock *= 10; 393 break; 394 case 3: 395 args.v3.sInput.usPixelClock 396 = B_HOST_TO_LENDIAN_INT16(pixelClock / 10); 397 args.v3.sInput.ucTransmitterID = encoderID; 398 args.v3.sInput.ucEncodeMode = encoderMode; 399 args.v3.sInput.ucDispPllConfig = 0; 400 // TODO: SS and SS % > 0 401 if (0) { 402 args.v3.sInput.ucDispPllConfig 403 |= DISPPLL_CONFIG_SS_ENABLE; 404 } 405 406 // Handle DP adjustments 407 if (encoderMode == ATOM_ENCODER_MODE_DP 408 || encoderMode == ATOM_ENCODER_MODE_DP_MST) { 409 TRACE("%s: encoderMode is DP\n", __func__); 410 args.v3.sInput.ucDispPllConfig 411 |= DISPPLL_CONFIG_COHERENT_MODE; 412 /* 16200 or 27000 */ 413 uint32 dpLinkSpeed 414 = dp_get_link_clock(connectorIndex); 415 args.v3.sInput.usPixelClock 416 = B_LENDIAN_TO_HOST_INT16(dpLinkSpeed / 10); 417 } else if ((encoderFlags & ATOM_DEVICE_DFP_SUPPORT) 418 != 0) { 419 TRACE("%s: encoderFlags are DFP but not DP mode.\n", 420 __func__); 421 #if 0 422 if (encoderMode == ATOM_ENCODER_MODE_HDMI) { 423 /* deep color support */ 424 args.v3.sInput.usPixelClock = 425 cpu_to_le16((mode->clock * bpc / 8) / 10); 426 } 427 #endif 428 if (pixelClock > 165000) { 429 args.v3.sInput.ucDispPllConfig 430 |= DISPPLL_CONFIG_DUAL_LINK; 431 } 432 if (1) { // dig coherent mode? 433 args.v3.sInput.ucDispPllConfig 434 |= DISPPLL_CONFIG_COHERENT_MODE; 435 } 436 } 437 438 args.v3.sInput.ucExtTransmitterID 439 = dpBridge ? encoderID : 0; 440 441 atom_execute_table(gAtomContext, index, (uint32*)&args); 442 443 // get returned adjusted clock 444 pll->pixelClock 445 = B_LENDIAN_TO_HOST_INT32( 446 args.v3.sOutput.ulDispPllFreq); 447 pll->pixelClock *= 10; 448 // convert to kHz for storage 449 450 if (args.v3.sOutput.ucRefDiv) { 451 pll->flags |= PLL_USE_FRAC_FB_DIV; 452 pll->flags |= PLL_USE_REF_DIV; 453 pll->referenceDiv = args.v3.sOutput.ucRefDiv; 454 } 455 if (args.v3.sOutput.ucPostDiv) { 456 pll->flags |= PLL_USE_FRAC_FB_DIV; 457 pll->flags |= PLL_USE_POST_DIV; 458 pll->postDiv = args.v3.sOutput.ucPostDiv; 459 } 460 break; 461 default: 462 TRACE("%s: ERROR: table version %" B_PRIu8 ".%" B_PRIu8 463 " unknown\n", __func__, tableMajor, tableMinor); 464 return B_ERROR; 465 } 466 break; 467 default: 468 TRACE("%s: ERROR: table version %" B_PRIu8 ".%" B_PRIu8 469 " unknown\n", __func__, tableMajor, tableMinor); 470 return B_ERROR; 471 } 472 } 473 474 TRACE("%s: was: %" B_PRIu32 ", now: %" B_PRIu32 "\n", __func__, 475 pixelClock, pll->pixelClock); 476 477 return B_OK; 478 } 479 480 481 status_t 482 pll_set(uint8 pllID, uint32 pixelClock, uint8 crtcID) 483 { 484 uint32 connectorIndex = gDisplay[crtcID]->connectorIndex; 485 pll_info* pll = &gConnector[connectorIndex]->encoder.pll; 486 487 pll->pixelClock = pixelClock; 488 pll->id = pllID; 489 490 pll_setup_flags(pll, crtcID); 491 // set up any special flags 492 pll_adjust(pll, crtcID); 493 // get any needed clock adjustments, set reference/post dividers 494 pll_compute(pll); 495 // compute dividers 496 497 uint8 tableMajor; 498 uint8 tableMinor; 499 500 int index = GetIndexIntoMasterTable(COMMAND, SetPixelClock); 501 atom_parse_cmd_header(gAtomContext, index, &tableMajor, &tableMinor); 502 503 uint32 bitsPerColor = 8; 504 // TODO: Digital Depth, EDID 1.4+ on digital displays 505 // isn't in Haiku edid common code? 506 507 // Prepare arguments for AtomBIOS call 508 union setPixelClock { 509 SET_PIXEL_CLOCK_PS_ALLOCATION base; 510 PIXEL_CLOCK_PARAMETERS v1; 511 PIXEL_CLOCK_PARAMETERS_V2 v2; 512 PIXEL_CLOCK_PARAMETERS_V3 v3; 513 PIXEL_CLOCK_PARAMETERS_V5 v5; 514 PIXEL_CLOCK_PARAMETERS_V6 v6; 515 }; 516 union setPixelClock args; 517 memset(&args, 0, sizeof(args)); 518 519 switch (tableMinor) { 520 case 1: 521 args.v1.usPixelClock 522 = B_HOST_TO_LENDIAN_INT16(pll->pixelClock / 10); 523 args.v1.usRefDiv = B_HOST_TO_LENDIAN_INT16(pll->referenceDiv); 524 args.v1.usFbDiv = B_HOST_TO_LENDIAN_INT16(pll->feedbackDiv); 525 args.v1.ucFracFbDiv = pll->feedbackDivFrac; 526 args.v1.ucPostDiv = pll->postDiv; 527 args.v1.ucPpll = pll->id; 528 args.v1.ucCRTC = crtcID; 529 args.v1.ucRefDivSrc = 1; 530 break; 531 case 2: 532 args.v2.usPixelClock 533 = B_HOST_TO_LENDIAN_INT16(pll->pixelClock / 10); 534 args.v2.usRefDiv = B_HOST_TO_LENDIAN_INT16(pll->referenceDiv); 535 args.v2.usFbDiv = B_HOST_TO_LENDIAN_INT16(pll->feedbackDiv); 536 args.v2.ucFracFbDiv = pll->feedbackDivFrac; 537 args.v2.ucPostDiv = pll->postDiv; 538 args.v2.ucPpll = pll->id; 539 args.v2.ucCRTC = crtcID; 540 args.v2.ucRefDivSrc = 1; 541 break; 542 case 3: 543 args.v3.usPixelClock 544 = B_HOST_TO_LENDIAN_INT16(pll->pixelClock / 10); 545 args.v3.usRefDiv = B_HOST_TO_LENDIAN_INT16(pll->referenceDiv); 546 args.v3.usFbDiv = B_HOST_TO_LENDIAN_INT16(pll->feedbackDiv); 547 args.v3.ucFracFbDiv = pll->feedbackDivFrac; 548 args.v3.ucPostDiv = pll->postDiv; 549 args.v3.ucPpll = pll->id; 550 args.v3.ucMiscInfo = (pll->id << 2); 551 // if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 552 // args.v3.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC; 553 args.v3.ucTransmitterId 554 = gConnector[connectorIndex]->encoder.objectID; 555 args.v3.ucEncoderMode = display_get_encoder_mode(connectorIndex); 556 break; 557 case 5: 558 args.v5.ucCRTC = crtcID; 559 args.v5.usPixelClock 560 = B_HOST_TO_LENDIAN_INT16(pll->pixelClock / 10); 561 args.v5.ucRefDiv = pll->referenceDiv; 562 args.v5.usFbDiv = B_HOST_TO_LENDIAN_INT16(pll->feedbackDiv); 563 args.v5.ulFbDivDecFrac 564 = B_HOST_TO_LENDIAN_INT32(pll->feedbackDivFrac * 100000); 565 args.v5.ucPostDiv = pll->postDiv; 566 args.v5.ucMiscInfo = 0; /* HDMI depth, etc. */ 567 // if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 568 // args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC; 569 switch (bitsPerColor) { 570 case 8: 571 default: 572 args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_24BPP; 573 break; 574 case 10: 575 args.v5.ucMiscInfo |= PIXEL_CLOCK_V5_MISC_HDMI_30BPP; 576 break; 577 } 578 args.v5.ucTransmitterID 579 = gConnector[connectorIndex]->encoder.objectID; 580 args.v5.ucEncoderMode 581 = display_get_encoder_mode(connectorIndex); 582 args.v5.ucPpll = pllID; 583 break; 584 case 6: 585 args.v6.ulDispEngClkFreq 586 = B_HOST_TO_LENDIAN_INT32(crtcID << 24 | pll->pixelClock / 10); 587 args.v6.ucRefDiv = pll->referenceDiv; 588 args.v6.usFbDiv = B_HOST_TO_LENDIAN_INT16(pll->feedbackDiv); 589 args.v6.ulFbDivDecFrac 590 = B_HOST_TO_LENDIAN_INT32(pll->feedbackDivFrac * 100000); 591 args.v6.ucPostDiv = pll->postDiv; 592 args.v6.ucMiscInfo = 0; /* HDMI depth, etc. */ 593 // if (ss_enabled && (ss->type & ATOM_EXTERNAL_SS_MASK)) 594 // args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC; 595 switch (bitsPerColor) { 596 case 8: 597 default: 598 args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_24BPP; 599 break; 600 case 10: 601 args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_30BPP; 602 break; 603 case 12: 604 args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_36BPP; 605 break; 606 case 16: 607 args.v6.ucMiscInfo |= PIXEL_CLOCK_V6_MISC_HDMI_48BPP; 608 break; 609 } 610 args.v6.ucTransmitterID 611 = gConnector[connectorIndex]->encoder.objectID; 612 args.v6.ucEncoderMode = display_get_encoder_mode(connectorIndex); 613 args.v6.ucPpll = pllID; 614 break; 615 default: 616 TRACE("%s: ERROR: table version %" B_PRIu8 ".%" B_PRIu8 " TODO\n", 617 __func__, tableMajor, tableMinor); 618 return B_ERROR; 619 } 620 621 TRACE("%s: set adjusted pixel clock %" B_PRIu32 " (was %" B_PRIu32 ")\n", 622 __func__, pll->pixelClock, pixelClock); 623 624 return atom_execute_table(gAtomContext, index, (uint32*)&args); 625 } 626