2 * Copyright 2006-2011, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Alexander von Gluck, kallisti5@unixzen.com
17 #include "accelerant_protos.h"
18 #include "accelerant.h"
20 #include "connector.h"
22 #include "displayport.h"
29 extern "C" void _sPrintf(const char* format
, ...);
30 # define TRACE(x...) _sPrintf("radeon_hd: " x)
32 # define TRACE(x...) ;
35 #define ERROR(x...) _sPrintf("radeon_hd: " x)
37 // Pixel Clock Storage
39 // Haiku: 104000 khz 104 Mhz
40 // Linux: 104000 khz 104 Mhz
41 // AtomBIOS: 10400 * 10 khz 104 Mhz
43 // Haiku: 162000 * 10 khz 1.62 Ghz
44 // Linux: 162000 * 10 khz 1.62 Ghz
45 // AtomBIOS: 16200 * 10 Khz 0.162 * 10 Ghz
48 /* The PLL allows to synthesize a clock signal with a range of frequencies
49 * based on a single input reference clock signal. It uses several dividers
50 * to create a rational factor multiple of the input frequency.
52 * The reference clock signal frequency is pll_info::referenceFreq (in kHz).
53 * It is then, one after another...
54 * (1) divided by the (integer) reference divider (pll_info::referenceDiv).
55 * (2) multiplied by the fractional feedback divider, which sits in the
56 * PLL's feedback loop and thus multiplies the frequency. It allows
57 * using a rational number factor of the form "x.y", with
58 * x = pll_info::feedbackDiv and y = pll_info::feedbackDivFrac.
59 * (3) divided by the (integer) post divider (pll_info::postDiv).
60 * Allowed ranges are given in the pll_info min/max values.
62 * The resulting output pixel clock frequency is then:
64 * feedbackDiv + (feedbackDivFrac/10)
65 * f_out = referenceFreq * ------------------------------------
66 * referenceDiv * postDiv
71 pll_limit_probe(pll_info
* pll
)
77 int index
= GetIndexIntoMasterTable(DATA
, FirmwareInfo
);
78 if (atom_parse_data_header(gAtomContext
, index
, NULL
,
79 &tableMajor
, &tableMinor
, &tableOffset
) != B_OK
) {
80 ERROR("%s: Couldn't parse data header\n", __func__
);
84 TRACE("%s: table %" B_PRIu8
".%" B_PRIu8
"\n", __func__
,
85 tableMajor
, tableMinor
);
87 union atomFirmwareInfo
{
88 ATOM_FIRMWARE_INFO info
;
89 ATOM_FIRMWARE_INFO_V1_2 info_12
;
90 ATOM_FIRMWARE_INFO_V1_3 info_13
;
91 ATOM_FIRMWARE_INFO_V1_4 info_14
;
92 ATOM_FIRMWARE_INFO_V2_1 info_21
;
93 ATOM_FIRMWARE_INFO_V2_2 info_22
;
95 union atomFirmwareInfo
* firmwareInfo
96 = (union atomFirmwareInfo
*)(gAtomContext
->bios
+ tableOffset
);
98 /* pixel clock limits */
100 = B_LENDIAN_TO_HOST_INT16(firmwareInfo
->info
.usReferenceClock
) * 10;
102 if (tableMinor
< 2) {
104 = B_LENDIAN_TO_HOST_INT16(
105 firmwareInfo
->info
.usMinPixelClockPLL_Output
) * 10;
108 = B_LENDIAN_TO_HOST_INT32(
109 firmwareInfo
->info_12
.ulMinPixelClockPLL_Output
) * 10;
113 = B_LENDIAN_TO_HOST_INT32(
114 firmwareInfo
->info
.ulMaxPixelClockPLL_Output
) * 10;
116 if (tableMinor
>= 4) {
118 = B_LENDIAN_TO_HOST_INT16(
119 firmwareInfo
->info_14
.usLcdMinPixelClockPLL_Output
) * 1000;
121 if (pll
->lcdPllOutMin
== 0)
122 pll
->lcdPllOutMin
= pll
->pllOutMin
;
125 = B_LENDIAN_TO_HOST_INT16(
126 firmwareInfo
->info_14
.usLcdMaxPixelClockPLL_Output
) * 1000;
128 if (pll
->lcdPllOutMax
== 0)
129 pll
->lcdPllOutMax
= pll
->pllOutMax
;
132 pll
->lcdPllOutMin
= pll
->pllOutMin
;
133 pll
->lcdPllOutMax
= pll
->pllOutMax
;
136 if (pll
->pllOutMin
== 0) {
137 pll
->pllOutMin
= 64800 * 10;
141 pll
->minPostDiv
= POST_DIV_MIN
;
142 pll
->maxPostDiv
= POST_DIV_LIMIT
;
143 pll
->minRefDiv
= REF_DIV_MIN
;
144 pll
->maxRefDiv
= REF_DIV_LIMIT
;
145 pll
->minFeedbackDiv
= FB_DIV_MIN
;
146 pll
->maxFeedbackDiv
= FB_DIV_LIMIT
;
148 pll
->pllInMin
= B_LENDIAN_TO_HOST_INT16(
149 firmwareInfo
->info
.usMinPixelClockPLL_Input
) * 10;
150 pll
->pllInMax
= B_LENDIAN_TO_HOST_INT16(
151 firmwareInfo
->info
.usMaxPixelClockPLL_Input
) * 10;
153 TRACE("%s: referenceFreq: %" B_PRIu32
"; pllOutMin: %" B_PRIu32
"; "
154 " pllOutMax: %" B_PRIu32
"; pllInMin: %" B_PRIu32
";"
155 "pllInMax: %" B_PRIu32
"\n", __func__
, pll
->referenceFreq
,
156 pll
->pllOutMin
, pll
->pllOutMax
, pll
->pllInMin
, pll
->pllInMax
);
163 pll_ppll_ss_probe(pll_info
* pll
, uint32 ssID
)
170 int index
= GetIndexIntoMasterTable(DATA
, PPLL_SS_Info
);
171 if (atom_parse_data_header(gAtomContext
, index
, &headerSize
,
172 &tableMajor
, &tableMinor
, &headerOffset
) != B_OK
) {
173 ERROR("%s: Couldn't parse data header\n", __func__
);
174 pll
->ssEnabled
= false;
178 struct _ATOM_SPREAD_SPECTRUM_INFO
*ss_info
179 = (struct _ATOM_SPREAD_SPECTRUM_INFO
*)((uint16
*)gAtomContext
->bios
182 int indices
= (headerSize
- sizeof(ATOM_COMMON_TABLE_HEADER
))
183 / sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT
);
186 for (i
= 0; i
< indices
; i
++) {
187 if (ss_info
->asSS_Info
[i
].ucSS_Id
== ssID
) {
188 pll
->ssPercentage
= B_LENDIAN_TO_HOST_INT16(
189 ss_info
->asSS_Info
[i
].usSpreadSpectrumPercentage
);
190 pll
->ssType
= ss_info
->asSS_Info
[i
].ucSpreadSpectrumType
;
191 pll
->ssStep
= ss_info
->asSS_Info
[i
].ucSS_Step
;
192 pll
->ssDelay
= ss_info
->asSS_Info
[i
].ucSS_Delay
;
193 pll
->ssRange
= ss_info
->asSS_Info
[i
].ucSS_Range
;
195 = ss_info
->asSS_Info
[i
].ucRecommendedRef_Div
;
196 pll
->ssEnabled
= true;
201 pll
->ssEnabled
= false;
207 pll_asic_ss_probe(pll_info
* pll
, uint32 ssID
)
214 int index
= GetIndexIntoMasterTable(DATA
, ASIC_InternalSS_Info
);
215 if (atom_parse_data_header(gAtomContext
, index
, &headerSize
,
216 &tableMajor
, &tableMinor
, &headerOffset
) != B_OK
) {
217 ERROR("%s: Couldn't parse data header\n", __func__
);
218 pll
->ssEnabled
= false;
223 struct _ATOM_ASIC_INTERNAL_SS_INFO info
;
224 struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 info_2
;
225 struct _ATOM_ASIC_INTERNAL_SS_INFO_V3 info_3
;
228 union asicSSInfo
*ss_info
229 = (union asicSSInfo
*)((uint16
*)gAtomContext
->bios
+ headerOffset
);
233 switch (tableMajor
) {
235 indices
= (headerSize
- sizeof(ATOM_COMMON_TABLE_HEADER
))
236 / sizeof(ATOM_ASIC_SS_ASSIGNMENT
);
238 for (i
= 0; i
< indices
; i
++) {
239 if (ss_info
->info
.asSpreadSpectrum
[i
].ucClockIndication
243 TRACE("%s: ss match found\n", __func__
);
244 if (pll
->pixelClock
/ 10 > B_LENDIAN_TO_HOST_INT32(
245 ss_info
->info
.asSpreadSpectrum
[i
].ulTargetClockRange
)) {
246 TRACE("%s: pixelClock > targetClockRange!\n", __func__
);
250 pll
->ssPercentage
= B_LENDIAN_TO_HOST_INT16(
251 ss_info
->info
.asSpreadSpectrum
[i
].usSpreadSpectrumPercentage
255 = ss_info
->info
.asSpreadSpectrum
[i
].ucSpreadSpectrumMode
;
256 pll
->ssRate
= B_LENDIAN_TO_HOST_INT16(
257 ss_info
->info
.asSpreadSpectrum
[i
].usSpreadRateInKhz
);
258 pll
->ssPercentageDiv
= 100;
259 pll
->ssEnabled
= true;
264 indices
= (headerSize
- sizeof(ATOM_COMMON_TABLE_HEADER
))
265 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2
);
267 for (i
= 0; i
< indices
; i
++) {
268 if (ss_info
->info_2
.asSpreadSpectrum
[i
].ucClockIndication
272 TRACE("%s: ss match found\n", __func__
);
273 if (pll
->pixelClock
/ 10 > B_LENDIAN_TO_HOST_INT32(
274 ss_info
->info_2
.asSpreadSpectrum
[i
].ulTargetClockRange
)) {
275 TRACE("%s: pixelClock > targetClockRange!\n", __func__
);
279 pll
->ssPercentage
= B_LENDIAN_TO_HOST_INT16(
281 ->info_2
.asSpreadSpectrum
[i
].usSpreadSpectrumPercentage
285 = ss_info
->info_2
.asSpreadSpectrum
[i
].ucSpreadSpectrumMode
;
286 pll
->ssRate
= B_LENDIAN_TO_HOST_INT16(
287 ss_info
->info_2
.asSpreadSpectrum
[i
].usSpreadRateIn10Hz
);
288 pll
->ssPercentageDiv
= 100;
289 pll
->ssEnabled
= true;
294 indices
= (headerSize
- sizeof(ATOM_COMMON_TABLE_HEADER
))
295 / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3
);
297 for (i
= 0; i
< indices
; i
++) {
298 if (ss_info
->info_3
.asSpreadSpectrum
[i
].ucClockIndication
302 TRACE("%s: ss match found\n", __func__
);
303 if (pll
->pixelClock
/ 10 > B_LENDIAN_TO_HOST_INT32(
304 ss_info
->info_3
.asSpreadSpectrum
[i
].ulTargetClockRange
)) {
305 TRACE("%s: pixelClock > targetClockRange!\n", __func__
);
309 pll
->ssPercentage
= B_LENDIAN_TO_HOST_INT16(
311 ->info_3
.asSpreadSpectrum
[i
].usSpreadSpectrumPercentage
314 = ss_info
->info_3
.asSpreadSpectrum
[i
].ucSpreadSpectrumMode
;
315 pll
->ssRate
= B_LENDIAN_TO_HOST_INT16(
316 ss_info
->info_3
.asSpreadSpectrum
[i
].usSpreadRateIn10Hz
);
318 if ((ss_info
->info_3
.asSpreadSpectrum
[i
].ucSpreadSpectrumMode
319 & SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK
) != 0)
320 pll
->ssPercentageDiv
= 1000;
322 pll
->ssPercentageDiv
= 100;
324 if (ssID
== ASIC_INTERNAL_ENGINE_SS
325 || ssID
== ASIC_INTERNAL_MEMORY_SS
)
328 pll
->ssEnabled
= true;
333 ERROR("%s: Unknown SS table version!\n", __func__
);
334 pll
->ssEnabled
= false;
338 ERROR("%s: No potential spread spectrum data found!\n", __func__
);
339 pll
->ssEnabled
= false;
345 pll_compute_post_divider(pll_info
* pll
)
347 if ((pll
->flags
& PLL_USE_POST_DIV
) != 0) {
348 TRACE("%s: using AtomBIOS post divider\n", __func__
);
353 if ((pll
->flags
& PLL_PREFER_MINM_OVER_MAXP
) != 0) {
354 if ((pll
->flags
& PLL_IS_LCD
) != 0)
355 vco
= pll
->lcdPllOutMin
;
357 vco
= pll
->pllOutMax
;
359 if ((pll
->flags
& PLL_IS_LCD
) != 0)
360 vco
= pll
->lcdPllOutMax
;
362 vco
= pll
->pllOutMin
;
365 TRACE("%s: vco = %" B_PRIu32
"\n", __func__
, vco
);
367 uint32 postDivider
= vco
/ pll
->adjustedClock
;
368 uint32 tmp
= vco
% pll
->adjustedClock
;
370 if ((pll
->flags
& PLL_PREFER_MINM_OVER_MAXP
) != 0) {
378 if (postDivider
> pll
->maxPostDiv
)
379 postDivider
= pll
->maxPostDiv
;
380 else if (postDivider
< pll
->minPostDiv
)
381 postDivider
= pll
->minPostDiv
;
383 pll
->postDiv
= postDivider
;
384 TRACE("%s: postDiv = %" B_PRIu32
"\n", __func__
, postDivider
);
388 /*! Compute values for the fractional feedback divider to match the desired
389 * pixel clock frequency as closely as possible. Reference and post divider
390 * values are already filled in (if used).
393 pll_compute(pll_info
* pll
)
395 radeon_shared_info
&info
= *gInfo
->shared_info
;
397 pll_compute_post_divider(pll
);
399 const uint32 targetClock
= pll
->adjustedClock
;
401 pll
->feedbackDiv
= 0;
402 pll
->feedbackDivFrac
= 0;
404 if ((pll
->flags
& PLL_USE_REF_DIV
) != 0) {
405 TRACE("%s: using AtomBIOS reference divider\n", __func__
);
407 TRACE("%s: using minimum reference divider\n", __func__
);
408 pll
->referenceDiv
= pll
->minRefDiv
;
411 if ((pll
->flags
& PLL_USE_FRAC_FB_DIV
) != 0) {
412 TRACE("%s: using AtomBIOS fractional feedback divider\n", __func__
);
414 const uint32 numerator
= pll
->postDiv
* pll
->referenceDiv
416 pll
->feedbackDiv
= numerator
/ pll
->referenceFreq
;
417 pll
->feedbackDivFrac
= numerator
% pll
->referenceFreq
;
419 if (pll
->feedbackDiv
> pll
->maxFeedbackDiv
)
420 pll
->feedbackDiv
= pll
->maxFeedbackDiv
;
421 else if (pll
->feedbackDiv
< pll
->minFeedbackDiv
)
422 pll
->feedbackDiv
= pll
->minFeedbackDiv
;
424 // Put first 2 digits after the decimal point into feedbackDivFrac
426 = (100 * pll
->feedbackDivFrac
) / pll
->referenceFreq
;
428 // Now round it to one digit
429 if (pll
->feedbackDivFrac
>= 5) {
430 pll
->feedbackDivFrac
-= 5;
431 pll
->feedbackDivFrac
/= 10;
432 pll
->feedbackDivFrac
++;
434 if (pll
->feedbackDivFrac
>= 10) {
436 pll
->feedbackDivFrac
= 0;
439 TRACE("%s: performing fractional feedback calculations\n", __func__
);
441 while (pll
->referenceDiv
<= pll
->maxRefDiv
) {
442 // get feedback divider
443 uint32 retroEncabulator
= pll
->postDiv
* pll
->referenceDiv
;
445 retroEncabulator
*= targetClock
;
446 pll
->feedbackDiv
= retroEncabulator
/ pll
->referenceFreq
;
448 = retroEncabulator
% pll
->referenceFreq
;
450 if (pll
->feedbackDiv
> pll
->maxFeedbackDiv
)
451 pll
->feedbackDiv
= pll
->maxFeedbackDiv
;
452 else if (pll
->feedbackDiv
< pll
->minFeedbackDiv
)
453 pll
->feedbackDiv
= pll
->minFeedbackDiv
;
455 if (pll
->feedbackDivFrac
>= (pll
->referenceFreq
/ 2))
458 pll
->feedbackDivFrac
= 0;
460 if (pll
->referenceDiv
== 0
462 || targetClock
== 0) {
463 TRACE("%s: Caught division by zero!\n", __func__
);
464 TRACE("%s: referenceDiv %" B_PRIu32
"\n",
465 __func__
, pll
->referenceDiv
);
466 TRACE("%s: postDiv %" B_PRIu32
"\n",
467 __func__
, pll
->postDiv
);
468 TRACE("%s: targetClock %" B_PRIu32
"\n",
469 __func__
, targetClock
);
472 uint32 tmp
= (pll
->referenceFreq
* pll
->feedbackDiv
)
473 / (pll
->postDiv
* pll
->referenceDiv
);
474 tmp
= (tmp
* 1000) / targetClock
;
476 if (tmp
> (1000 + (MAX_TOLERANCE
/ 10)))
478 else if (tmp
>= (1000 - (MAX_TOLERANCE
/ 10)))
485 if (pll
->referenceDiv
== 0 || pll
->postDiv
== 0) {
486 TRACE("%s: Caught division by zero of post or reference divider\n",
491 uint32 calculatedClock
492 = ((pll
->referenceFreq
* pll
->feedbackDiv
* 10)
493 + (pll
->referenceFreq
* pll
->feedbackDivFrac
))
494 / (pll
->referenceDiv
* pll
->postDiv
* 10);
496 TRACE("%s: Calculated pixel clock of %" B_PRIu32
" based on:\n", __func__
,
498 TRACE("%s: referenceFrequency: %" B_PRIu32
"; "
499 "referenceDivider: %" B_PRIu32
"\n", __func__
, pll
->referenceFreq
,
501 TRACE("%s: feedbackDivider: %" B_PRIu32
"; "
502 "feedbackDividerFrac: %" B_PRIu32
"\n", __func__
, pll
->feedbackDiv
,
503 pll
->feedbackDivFrac
);
504 TRACE("%s: postDivider: %" B_PRIu32
"\n", __func__
, pll
->postDiv
);
506 if (pll
->adjustedClock
!= calculatedClock
) {
507 TRACE("%s: pixel clock %" B_PRIu32
" was changed to %" B_PRIu32
"\n",
508 __func__
, pll
->adjustedClock
, calculatedClock
);
509 pll
->pixelClock
= calculatedClock
;
512 // Calcuate needed SS data on DCE4
513 if (info
.dceMajor
>= 4 && pll
->ssEnabled
) {
514 if (pll
->ssPercentageDiv
== 0) {
515 // Avoid div by 0, shouldn't happen but be mindful of it
516 TRACE("%s: ssPercentageDiv is less than 0, aborting SS calcualation",
518 pll
->ssEnabled
= false;
521 uint32 amount
= ((pll
->feedbackDiv
* 10) + pll
->feedbackDivFrac
);
522 amount
*= pll
->ssPercentage
;
523 amount
/= pll
->ssPercentageDiv
* 100;
524 pll
->ssAmount
= (amount
/ 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK
;
525 pll
->ssAmount
|= ((amount
- (amount
/ 10))
526 << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT
) & ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK
;
528 uint32 centerSpreadMultiplier
= 2;
529 if ((pll
->ssType
& ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD
) != 0)
530 centerSpreadMultiplier
= 4;
531 pll
->ssStep
= (centerSpreadMultiplier
* amount
* pll
->referenceDiv
532 * (pll
->ssRate
* 2048)) / (125 * 25 * pll
->referenceFreq
/ 100);
540 pll_setup_flags(pll_info
* pll
, uint8 crtcID
)
542 radeon_shared_info
&info
= *gInfo
->shared_info
;
543 uint32 connectorIndex
= gDisplay
[crtcID
]->connectorIndex
;
544 uint32 connectorFlags
= gConnector
[connectorIndex
]->flags
;
546 uint32 dceVersion
= (info
.dceMajor
* 100) + info
.dceMinor
;
548 TRACE("%s: CRTC: %" B_PRIu8
", PLL: %" B_PRIu8
"\n", __func__
,
551 if (dceVersion
>= 302 && pll
->pixelClock
> 200000)
552 pll
->flags
|= PLL_PREFER_HIGH_FB_DIV
;
554 pll
->flags
|= PLL_PREFER_LOW_REF_DIV
;
556 if (info
.chipsetID
< RADEON_RV770
)
557 pll
->flags
|= PLL_PREFER_MINM_OVER_MAXP
;
559 if ((connectorFlags
& ATOM_DEVICE_LCD_SUPPORT
) != 0) {
560 pll
->flags
|= PLL_IS_LCD
;
562 // use reference divider for spread spectrum
563 TRACE("%s: Spread Spectrum is %" B_PRIu32
"%%\n", __func__
,
565 if (pll
->ssPercentage
> 0) {
566 if (pll
->ssReferenceDiv
> 0) {
567 TRACE("%s: using Spread Spectrum reference divider. "
568 "refDiv was: %" B_PRIu32
", now: %" B_PRIu32
"\n",
569 __func__
, pll
->referenceDiv
, pll
->ssReferenceDiv
);
570 pll
->flags
|= PLL_USE_REF_DIV
;
571 pll
->referenceDiv
= pll
->ssReferenceDiv
;
574 pll
->flags
|= PLL_USE_FRAC_FB_DIV
;
579 if ((connectorFlags
& ATOM_DEVICE_TV_SUPPORT
) != 0)
580 pll
->flags
|= PLL_PREFER_CLOSEST_LOWER
;
582 if ((info
.chipsetFlags
& CHIP_APU
) != 0) {
583 // Use fractional feedback on APU's
584 pll
->flags
|= PLL_USE_FRAC_FB_DIV
;
590 * pll_adjust - Ask AtomBIOS if it wants to make adjustments to our pll
592 * Returns B_OK on successful execution.
595 pll_adjust(pll_info
* pll
, display_mode
* mode
, uint8 crtcID
)
597 radeon_shared_info
&info
= *gInfo
->shared_info
;
599 uint32 pixelClock
= pll
->pixelClock
;
600 // original as pixel_clock will be adjusted
602 uint32 connectorIndex
= gDisplay
[crtcID
]->connectorIndex
;
603 connector_info
* connector
= gConnector
[connectorIndex
];
605 uint32 encoderID
= connector
->encoder
.objectID
;
606 uint32 encoderMode
= display_get_encoder_mode(connectorIndex
);
607 uint32 connectorFlags
= connector
->flags
;
609 uint32 externalEncoderID
= 0;
610 pll
->adjustedClock
= pll
->pixelClock
;
611 if (connector
->encoderExternal
.isDPBridge
)
612 externalEncoderID
= connector
->encoderExternal
.objectID
;
614 if (info
.dceMajor
>= 3) {
619 int index
= GetIndexIntoMasterTable(COMMAND
, AdjustDisplayPll
);
620 if (atom_parse_cmd_header(gAtomContext
, index
, &tableMajor
, &tableMinor
)
622 ERROR("%s: Couldn't find AtomBIOS PLL adjustment\n", __func__
);
626 TRACE("%s: table %" B_PRIu8
".%" B_PRIu8
"\n", __func__
,
627 tableMajor
, tableMinor
);
629 // Prepare arguments for AtomBIOS call
630 union adjustPixelClock
{
631 ADJUST_DISPLAY_PLL_PS_ALLOCATION v1
;
632 ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 v3
;
634 union adjustPixelClock args
;
635 memset(&args
, 0, sizeof(args
));
637 switch (tableMajor
) {
639 switch (tableMinor
) {
643 = B_HOST_TO_LENDIAN_INT16(pixelClock
/ 10);
644 args
.v1
.ucTransmitterID
= encoderID
;
645 args
.v1
.ucEncodeMode
= encoderMode
;
646 if (pll
->ssPercentage
> 0) {
648 |= ADJUST_DISPLAY_CONFIG_SS_ENABLE
;
651 atom_execute_table(gAtomContext
, index
, (uint32
*)&args
);
652 // get returned adjusted clock
654 = B_LENDIAN_TO_HOST_INT16(args
.v1
.usPixelClock
);
655 pll
->adjustedClock
*= 10;
658 args
.v3
.sInput
.usPixelClock
659 = B_HOST_TO_LENDIAN_INT16(pixelClock
/ 10);
660 args
.v3
.sInput
.ucTransmitterID
= encoderID
;
661 args
.v3
.sInput
.ucEncodeMode
= encoderMode
;
662 args
.v3
.sInput
.ucDispPllConfig
= 0;
663 if (pll
->ssPercentage
> 0) {
664 args
.v3
.sInput
.ucDispPllConfig
665 |= DISPPLL_CONFIG_SS_ENABLE
;
668 // Handle DP adjustments
669 if (encoderMode
== ATOM_ENCODER_MODE_DP
670 || encoderMode
== ATOM_ENCODER_MODE_DP_MST
) {
671 TRACE("%s: encoderMode is DP\n", __func__
);
672 args
.v3
.sInput
.ucDispPllConfig
673 |= DISPPLL_CONFIG_COHERENT_MODE
;
674 /* 162000 or 270000 */
676 = dp_get_link_rate(connectorIndex
, mode
);
678 args
.v3
.sInput
.usPixelClock
679 = B_HOST_TO_LENDIAN_INT16(dpLinkSpeed
/ 10);
680 } else if ((connectorFlags
& ATOM_DEVICE_DFP_SUPPORT
)
683 if (encoderMode
== ATOM_ENCODER_MODE_HDMI
) {
684 /* deep color support */
685 args
.v3
.sInput
.usPixelClock
=
686 cpu_to_le16((mode
->clock
* bpc
/ 8) / 10);
689 if (pixelClock
> 165000) {
690 args
.v3
.sInput
.ucDispPllConfig
691 |= DISPPLL_CONFIG_DUAL_LINK
;
693 if (1) { // dig coherent mode?
694 args
.v3
.sInput
.ucDispPllConfig
695 |= DISPPLL_CONFIG_COHERENT_MODE
;
699 args
.v3
.sInput
.ucExtTransmitterID
= externalEncoderID
;
701 atom_execute_table(gAtomContext
, index
, (uint32
*)&args
);
703 // get returned adjusted clock
704 pll
->adjustedClock
= B_LENDIAN_TO_HOST_INT32(
705 args
.v3
.sOutput
.ulDispPllFreq
);
706 pll
->adjustedClock
*= 10;
707 // convert to kHz for storage
709 if (args
.v3
.sOutput
.ucRefDiv
) {
710 pll
->flags
|= PLL_USE_FRAC_FB_DIV
;
711 pll
->flags
|= PLL_USE_REF_DIV
;
712 pll
->referenceDiv
= args
.v3
.sOutput
.ucRefDiv
;
714 if (args
.v3
.sOutput
.ucPostDiv
) {
715 pll
->flags
|= PLL_USE_FRAC_FB_DIV
;
716 pll
->flags
|= PLL_USE_POST_DIV
;
717 pll
->postDiv
= args
.v3
.sOutput
.ucPostDiv
;
721 TRACE("%s: ERROR: table version %" B_PRIu8
".%" B_PRIu8
722 " unknown\n", __func__
, tableMajor
, tableMinor
);
727 TRACE("%s: ERROR: table version %" B_PRIu8
".%" B_PRIu8
728 " unknown\n", __func__
, tableMajor
, tableMinor
);
733 TRACE("%s: was: %" B_PRIu32
", now: %" B_PRIu32
"\n", __func__
,
734 pixelClock
, pll
->adjustedClock
);
741 * pll_set - Calculate and set a pll on the crtc provided based on the mode.
743 * Returns B_OK on successful execution
746 pll_set(display_mode
* mode
, uint8 crtcID
)
748 uint32 connectorIndex
= gDisplay
[crtcID
]->connectorIndex
;
749 uint32 encoderMode
= display_get_encoder_mode(connectorIndex
);
750 pll_info
* pll
= &gConnector
[connectorIndex
]->encoder
.pll
;
751 uint32 dp_clock
= gConnector
[connectorIndex
]->dpInfo
.linkRate
;
753 pll
->ssEnabled
= false;
755 pll
->pixelClock
= mode
->timing
.pixel_clock
;
757 radeon_shared_info
&info
= *gInfo
->shared_info
;
759 // Probe for PLL spread spectrum info;
760 pll
->ssPercentage
= 0;
765 pll
->ssReferenceDiv
= 0;
767 switch (encoderMode
) {
768 case ATOM_ENCODER_MODE_DP_MST
:
769 case ATOM_ENCODER_MODE_DP
:
770 if (info
.dceMajor
>= 4)
771 pll_asic_ss_probe(pll
, ASIC_INTERNAL_SS_ON_DP
);
773 if (dp_clock
== 162000) {
774 pll_ppll_ss_probe(pll
, ATOM_DP_SS_ID2
);
776 pll_ppll_ss_probe(pll
, ATOM_DP_SS_ID1
);
778 pll_ppll_ss_probe(pll
, ATOM_DP_SS_ID1
);
781 case ATOM_ENCODER_MODE_LVDS
:
782 if (info
.dceMajor
>= 4)
783 pll_asic_ss_probe(pll
, gInfo
->lvdsSpreadSpectrumID
);
785 pll_ppll_ss_probe(pll
, gInfo
->lvdsSpreadSpectrumID
);
787 case ATOM_ENCODER_MODE_DVI
:
788 if (info
.dceMajor
>= 4)
789 pll_asic_ss_probe(pll
, ASIC_INTERNAL_SS_ON_TMDS
);
791 case ATOM_ENCODER_MODE_HDMI
:
792 if (info
.dceMajor
>= 4)
793 pll_asic_ss_probe(pll
, ASIC_INTERNAL_SS_ON_HDMI
);
797 pll_setup_flags(pll
, crtcID
);
798 // set up any special flags
799 pll_adjust(pll
, mode
, crtcID
);
800 // get any needed clock adjustments, set reference/post dividers
802 // compute dividers and spread spectrum
807 int index
= GetIndexIntoMasterTable(COMMAND
, SetPixelClock
);
808 atom_parse_cmd_header(gAtomContext
, index
, &tableMajor
, &tableMinor
);
810 TRACE("%s: table %" B_PRIu8
".%" B_PRIu8
"\n", __func__
,
811 tableMajor
, tableMinor
);
813 uint32 bitsPerColor
= 8;
814 // TODO: Digital Depth, EDID 1.4+ on digital displays
815 // isn't in Haiku edid common code?
817 // Prepare arguments for AtomBIOS call
818 union setPixelClock
{
819 SET_PIXEL_CLOCK_PS_ALLOCATION base
;
820 PIXEL_CLOCK_PARAMETERS v1
;
821 PIXEL_CLOCK_PARAMETERS_V2 v2
;
822 PIXEL_CLOCK_PARAMETERS_V3 v3
;
823 PIXEL_CLOCK_PARAMETERS_V5 v5
;
824 PIXEL_CLOCK_PARAMETERS_V6 v6
;
825 PIXEL_CLOCK_PARAMETERS_V7 v7
;
827 union setPixelClock args
;
828 memset(&args
, 0, sizeof(args
));
830 switch (tableMinor
) {
833 = B_HOST_TO_LENDIAN_INT16(pll
->pixelClock
/ 10);
834 args
.v1
.usRefDiv
= B_HOST_TO_LENDIAN_INT16(pll
->referenceDiv
);
835 args
.v1
.usFbDiv
= B_HOST_TO_LENDIAN_INT16(pll
->feedbackDiv
);
836 args
.v1
.ucFracFbDiv
= pll
->feedbackDivFrac
;
837 args
.v1
.ucPostDiv
= pll
->postDiv
;
838 args
.v1
.ucPpll
= pll
->id
;
839 args
.v1
.ucCRTC
= crtcID
;
840 args
.v1
.ucRefDivSrc
= 1;
844 = B_HOST_TO_LENDIAN_INT16(pll
->pixelClock
/ 10);
845 args
.v2
.usRefDiv
= B_HOST_TO_LENDIAN_INT16(pll
->referenceDiv
);
846 args
.v2
.usFbDiv
= B_HOST_TO_LENDIAN_INT16(pll
->feedbackDiv
);
847 args
.v2
.ucFracFbDiv
= pll
->feedbackDivFrac
;
848 args
.v2
.ucPostDiv
= pll
->postDiv
;
849 args
.v2
.ucPpll
= pll
->id
;
850 args
.v2
.ucCRTC
= crtcID
;
851 args
.v2
.ucRefDivSrc
= 1;
855 = B_HOST_TO_LENDIAN_INT16(pll
->pixelClock
/ 10);
856 args
.v3
.usRefDiv
= B_HOST_TO_LENDIAN_INT16(pll
->referenceDiv
);
857 args
.v3
.usFbDiv
= B_HOST_TO_LENDIAN_INT16(pll
->feedbackDiv
);
858 args
.v3
.ucFracFbDiv
= pll
->feedbackDivFrac
;
859 args
.v3
.ucPostDiv
= pll
->postDiv
;
860 args
.v3
.ucPpll
= pll
->id
;
861 args
.v3
.ucMiscInfo
= (pll
->id
<< 2);
862 if (pll
->ssPercentage
> 0
863 && (pll
->ssType
& ATOM_EXTERNAL_SS_MASK
) != 0) {
864 args
.v3
.ucMiscInfo
|= PIXEL_CLOCK_MISC_REF_DIV_SRC
;
866 args
.v3
.ucTransmitterId
867 = gConnector
[connectorIndex
]->encoder
.objectID
;
868 args
.v3
.ucEncoderMode
= display_get_encoder_mode(connectorIndex
);
871 args
.v5
.ucCRTC
= crtcID
;
873 = B_HOST_TO_LENDIAN_INT16(pll
->pixelClock
/ 10);
874 args
.v5
.ucRefDiv
= pll
->referenceDiv
;
875 args
.v5
.usFbDiv
= B_HOST_TO_LENDIAN_INT16(pll
->feedbackDiv
);
876 args
.v5
.ulFbDivDecFrac
877 = B_HOST_TO_LENDIAN_INT32(pll
->feedbackDivFrac
* 100000);
878 args
.v5
.ucPostDiv
= pll
->postDiv
;
879 args
.v5
.ucMiscInfo
= 0; /* HDMI depth, etc. */
880 if (pll
->ssPercentage
> 0
881 && (pll
->ssType
& ATOM_EXTERNAL_SS_MASK
) != 0) {
882 args
.v5
.ucMiscInfo
|= PIXEL_CLOCK_V5_MISC_REF_DIV_SRC
;
884 switch (bitsPerColor
) {
887 args
.v5
.ucMiscInfo
|= PIXEL_CLOCK_V5_MISC_HDMI_24BPP
;
890 args
.v5
.ucMiscInfo
|= PIXEL_CLOCK_V5_MISC_HDMI_30BPP
;
893 args
.v5
.ucTransmitterID
894 = gConnector
[connectorIndex
]->encoder
.objectID
;
895 args
.v5
.ucEncoderMode
896 = display_get_encoder_mode(connectorIndex
);
897 args
.v5
.ucPpll
= pll
->id
;
900 args
.v6
.ulDispEngClkFreq
901 = B_HOST_TO_LENDIAN_INT32(crtcID
<< 24 | pll
->pixelClock
/ 10);
902 args
.v6
.ucRefDiv
= pll
->referenceDiv
;
903 args
.v6
.usFbDiv
= B_HOST_TO_LENDIAN_INT16(pll
->feedbackDiv
);
904 args
.v6
.ulFbDivDecFrac
905 = B_HOST_TO_LENDIAN_INT32(pll
->feedbackDivFrac
* 100000);
906 args
.v6
.ucPostDiv
= pll
->postDiv
;
907 args
.v6
.ucMiscInfo
= 0; /* HDMI depth, etc. */
908 if (pll
->ssPercentage
> 0
909 && (pll
->ssType
& ATOM_EXTERNAL_SS_MASK
) != 0) {
910 args
.v6
.ucMiscInfo
|= PIXEL_CLOCK_V6_MISC_REF_DIV_SRC
;
912 switch (bitsPerColor
) {
915 args
.v6
.ucMiscInfo
|= PIXEL_CLOCK_V6_MISC_HDMI_24BPP
;
918 args
.v6
.ucMiscInfo
|= PIXEL_CLOCK_V6_MISC_HDMI_30BPP
;
921 args
.v6
.ucMiscInfo
|= PIXEL_CLOCK_V6_MISC_HDMI_36BPP
;
924 args
.v6
.ucMiscInfo
|= PIXEL_CLOCK_V6_MISC_HDMI_48BPP
;
927 args
.v6
.ucTransmitterID
928 = gConnector
[connectorIndex
]->encoder
.objectID
;
929 args
.v6
.ucEncoderMode
= display_get_encoder_mode(connectorIndex
);
930 args
.v6
.ucPpll
= pll
->id
;
934 = B_HOST_TO_LENDIAN_INT32(pll
->pixelClock
/ 10);
935 args
.v7
.ucMiscInfo
= 0;
936 if (gConnector
[connectorIndex
]->type
== VIDEO_CONNECTOR_DVID
937 && pll
->pixelClock
> 165000) {
938 args
.v7
.ucMiscInfo
|= PIXEL_CLOCK_V7_MISC_DVI_DUALLINK_EN
;
940 args
.v7
.ucCRTC
= crtcID
;
941 if (encoderMode
== ATOM_ENCODER_MODE_HDMI
) {
942 switch (bitsPerColor
) {
945 args
.v7
.ucDeepColorRatio
946 = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_DIS
;
949 args
.v7
.ucDeepColorRatio
950 = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_5_4
;
953 args
.v7
.ucDeepColorRatio
954 = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_3_2
;
957 args
.v7
.ucDeepColorRatio
958 = PIXEL_CLOCK_V7_DEEPCOLOR_RATIO_2_1
;
962 args
.v7
.ucTransmitterID
963 = gConnector
[connectorIndex
]->encoder
.objectID
;
964 args
.v7
.ucEncoderMode
= display_get_encoder_mode(connectorIndex
);
965 args
.v7
.ucPpll
= pll
->id
;
968 TRACE("%s: ERROR: table version %" B_PRIu8
".%" B_PRIu8
" TODO\n",
969 __func__
, tableMajor
, tableMinor
);
973 TRACE("%s: set adjusted pixel clock %" B_PRIu32
" (was %" B_PRIu32
")\n",
974 __func__
, pll
->pixelClock
, mode
->timing
.pixel_clock
);
976 status_t result
= atom_execute_table(gAtomContext
, index
, (uint32
*)&args
);
979 display_crtc_ss(pll
, ATOM_ENABLE
);
981 display_crtc_ss(pll
, ATOM_DISABLE
);
988 * pll_set_external - Sets external default pll via SetPixelClock
990 * Applies a clock frequency to card's external PLL clock.
993 pll_set_external(uint32 clock
)
995 TRACE("%s: set external pll clock to %" B_PRIu32
"\n", __func__
, clock
);
998 ERROR("%s: Warning: default display clock is 0?\n", __func__
);
1000 // also known as PLL display engineering
1004 int index
= GetIndexIntoMasterTable(COMMAND
, SetPixelClock
);
1005 atom_parse_cmd_header(gAtomContext
, index
, &tableMajor
, &tableMinor
);
1007 TRACE("%s: table %" B_PRIu8
".%" B_PRIu8
"\n", __func__
,
1008 tableMajor
, tableMinor
);
1010 union setPixelClock
{
1011 SET_PIXEL_CLOCK_PS_ALLOCATION base
;
1012 PIXEL_CLOCK_PARAMETERS v1
;
1013 PIXEL_CLOCK_PARAMETERS_V2 v2
;
1014 PIXEL_CLOCK_PARAMETERS_V3 v3
;
1015 PIXEL_CLOCK_PARAMETERS_V5 v5
;
1016 PIXEL_CLOCK_PARAMETERS_V6 v6
;
1017 PIXEL_CLOCK_PARAMETERS_V7 v7
;
1019 union setPixelClock args
;
1020 memset(&args
, 0, sizeof(args
));
1022 radeon_shared_info
&info
= *gInfo
->shared_info
;
1023 uint32 dceVersion
= (info
.dceMajor
* 100) + info
.dceMinor
;
1024 switch (tableMajor
) {
1026 switch (tableMinor
) {
1028 // If the default DC PLL clock is specified,
1029 // SetPixelClock provides the dividers.
1030 args
.v5
.ucCRTC
= ATOM_CRTC_INVALID
;
1031 args
.v5
.usPixelClock
= B_HOST_TO_LENDIAN_INT16(clock
/ 10);
1032 args
.v5
.ucPpll
= ATOM_DCPLL
;
1035 // If the default DC PLL clock is specified,
1036 // SetPixelClock provides the dividers.
1037 args
.v6
.ulDispEngClkFreq
1038 = B_HOST_TO_LENDIAN_INT32(clock
/ 10);
1039 if (dceVersion
== 601)
1040 args
.v6
.ucPpll
= ATOM_EXT_PLL1
;
1041 else if (dceVersion
>= 600)
1042 args
.v6
.ucPpll
= ATOM_PPLL0
;
1044 args
.v6
.ucPpll
= ATOM_DCPLL
;
1047 ERROR("%s: Unknown table version %" B_PRIu8
1048 ".%" B_PRIu8
"\n", __func__
, tableMajor
, tableMinor
);
1052 ERROR("%s: Unknown table version %" B_PRIu8
1053 ".%" B_PRIu8
"\n", __func__
, tableMajor
, tableMinor
);
1055 return atom_execute_table(gAtomContext
, index
, (uint32
*)&args
);
1060 * pll_set_dce - Sets external default pll via DCE Clock Allocation
1062 * Applies a clock frequency to card's external PLL clock via SetDCEClock
1066 pll_set_dce(uint32 clock
, uint8 clockType
, uint8 clockSource
)
1068 TRACE("%s: set external pll clock to %" B_PRIu32
"\n", __func__
, clock
);
1071 ERROR("%s: Warning: default display clock is 0?\n", __func__
);
1076 int index
= GetIndexIntoMasterTable(COMMAND
, SetDCEClock
);
1077 atom_parse_cmd_header(gAtomContext
, index
, &tableMajor
, &tableMinor
);
1079 TRACE("%s: table %" B_PRIu8
".%" B_PRIu8
"\n", __func__
,
1080 tableMajor
, tableMinor
);
1083 SET_DCE_CLOCK_PS_ALLOCATION_V1_1 v1
;
1084 SET_DCE_CLOCK_PS_ALLOCATION_V2_1 v2
;
1086 union setDCEClock args
;
1087 memset(&args
, 0, sizeof(args
));
1089 switch (tableMajor
) {
1091 switch (tableMinor
) {
1093 args
.v2
.asParam
.ulDCEClkFreq
1094 = B_HOST_TO_LENDIAN_INT32(clock
/ 10);
1095 args
.v2
.asParam
.ucDCEClkType
= clockType
;
1096 args
.v2
.asParam
.ucDCEClkSrc
= clockSource
;
1099 ERROR("%s: Unknown table version %" B_PRIu8
1100 ".%" B_PRIu8
"\n", __func__
, tableMajor
, tableMinor
);
1105 ERROR("%s: Unknown table version %" B_PRIu8
1106 ".%" B_PRIu8
"\n", __func__
, tableMajor
, tableMinor
);
1109 return atom_execute_table(gAtomContext
, index
, (uint32
*)&args
);
1114 * pll_external_init - Sets external default pll to sane value
1116 * Takes the AtomBIOS ulDefaultDispEngineClkFreq and applies it
1117 * back to the card's external PLL clock via SetPixelClock
1122 radeon_shared_info
&info
= *gInfo
->shared_info
;
1124 if (info
.dceMajor
>= 12) {
1125 pll_set_dce(gInfo
->displayClockFrequency
,
1126 DCE_CLOCK_TYPE_DISPCLK
, ATOM_GCK_DFS
);
1127 pll_set_dce(gInfo
->displayClockFrequency
,
1128 DCE_CLOCK_TYPE_DPREFCLK
, ATOM_GCK_DFS
);
1129 } else if (info
.dceMajor
>= 6) {
1130 pll_set_external(gInfo
->displayClockFrequency
);
1131 } else if (info
.dceMajor
>= 4) {
1132 // Create our own pseudo pll
1134 pll
.pixelClock
= gInfo
->displayClockFrequency
;
1136 pll_asic_ss_probe(&pll
, ASIC_INTERNAL_SS_ON_DCPLL
);
1138 display_crtc_ss(&pll
, ATOM_DISABLE
);
1139 pll_set_external(pll
.pixelClock
);
1141 display_crtc_ss(&pll
, ATOM_ENABLE
);
1147 * pll_usage_mask - Calculate which PLL's are in use
1149 * Returns the mask of which PLL's are in use
1155 for (uint32 id
= 0; id
< ATOM_MAX_SUPPORTED_DEVICE
; id
++) {
1156 if (gConnector
[id
]->valid
== true) {
1157 pll_info
* pll
= &gConnector
[id
]->encoder
.pll
;
1158 if (pll
->id
!= ATOM_PPLL_INVALID
)
1159 pllMask
|= (1 << pll
->id
);
1167 * pll_usage_count - Find number of connectors attached to a PLL
1169 * Returns the count of connectors using specified PLL
1172 pll_usage_count(uint32 pllID
)
1174 uint32 pllCount
= 0;
1175 for (uint32 id
= 0; id
< ATOM_MAX_SUPPORTED_DEVICE
; id
++) {
1176 if (gConnector
[id
]->valid
== true) {
1177 pll_info
* pll
= &gConnector
[id
]->encoder
.pll
;
1178 if (pll
->id
== pllID
)
1188 * pll_shared_dp - Find any existing PLL's used for DP connectors
1190 * Returns the PLL shared by other DP connectors
1195 for (uint32 id
= 0; id
< ATOM_MAX_SUPPORTED_DEVICE
; id
++) {
1196 if (gConnector
[id
]->valid
== true) {
1197 if (connector_is_dp(id
)) {
1198 pll_info
* pll
= &gConnector
[id
]->encoder
.pll
;
1203 return ATOM_PPLL_INVALID
;
1208 * pll_next_available - Find the next available PLL
1210 * Returns the next available PLL
1213 pll_next_available()
1215 radeon_shared_info
&info
= *gInfo
->shared_info
;
1216 uint32 dceVersion
= (info
.dceMajor
* 100) + info
.dceMinor
;
1218 uint32 pllMask
= pll_usage_mask();
1220 if (dceVersion
== 802 || dceVersion
== 601) {
1221 if (!(pllMask
& (1 << ATOM_PPLL0
)))
1225 if (!(pllMask
& (1 << ATOM_PPLL1
)))
1227 if (dceVersion
!= 601) {
1228 if (!(pllMask
& (1 << ATOM_PPLL2
)))
1231 // TODO: If this starts happening, we likely need to
1232 // add the sharing of PLL's with identical clock rates
1233 // (see radeon_atom_pick_pll in drm)
1234 ERROR("%s: Unable to find a PLL! (0x%" B_PRIX32
")\n", __func__
, pllMask
);
1235 return ATOM_PPLL_INVALID
;
1240 pll_pick(uint32 connectorIndex
)
1242 pll_info
* pll
= &gConnector
[connectorIndex
]->encoder
.pll
;
1243 radeon_shared_info
&info
= *gInfo
->shared_info
;
1244 uint32 dceVersion
= (info
.dceMajor
* 100) + info
.dceMinor
;
1246 bool linkB
= gConnector
[connectorIndex
]->encoder
.linkEnumeration
1247 == GRAPH_OBJECT_ENUM_ID2
? true : false;
1249 pll
->id
= ATOM_PPLL_INVALID
;
1251 // DCE 6.1 APU, UNIPHYA requires PLL2
1252 if (gConnector
[connectorIndex
]->encoder
.objectID
1253 == ENCODER_OBJECT_ID_INTERNAL_UNIPHY
&& !linkB
) {
1254 pll
->id
= ATOM_PPLL2
;
1258 if (connector_is_dp(connectorIndex
)) {
1259 // If DP external clock, set to invalid except on DCE 6.1
1260 if (gInfo
->dpExternalClock
&& !(dceVersion
== 601)) {
1261 pll
->id
= ATOM_PPLL_INVALID
;
1265 // DCE 6.1+, we can share DP PLLs. See if any other DP connectors
1266 // have been assigned a PLL yet.
1267 if (dceVersion
>= 601) {
1268 pll
->id
= pll_shared_dp();
1269 if (pll
->id
!= ATOM_PPLL_INVALID
)
1271 // Continue through to pll_next_available
1272 } else if (dceVersion
== 600) {
1273 pll
->id
= ATOM_PPLL0
;
1275 } else if (info
.dceMajor
>= 5) {
1276 pll
->id
= ATOM_DCPLL
;
1281 if (info
.dceMajor
>= 4) {
1282 pll
->id
= pll_next_available();
1286 // TODO: Should return the CRTCID here.
1287 pll
->id
= ATOM_PPLL1
;