1 /* 2 * Copyright 2012-15 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 26 #include "dm_services.h" 27 28 29 #include "dc_types.h" 30 #include "core_types.h" 31 32 #include "include/grph_object_id.h" 33 #include "include/logger_interface.h" 34 35 #include "dce_clock_source.h" 36 37 #include "reg_helper.h" 38 39 #define REG(reg)\ 40 (clk_src->regs->reg) 41 42 #define CTX \ 43 clk_src->base.ctx 44 #define DC_LOGGER \ 45 calc_pll_cs->ctx->logger 46 #undef FN 47 #define FN(reg_name, field_name) \ 48 clk_src->cs_shift->field_name, clk_src->cs_mask->field_name 49 50 #define FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM 6 51 #define CALC_PLL_CLK_SRC_ERR_TOLERANCE 1 52 #define MAX_PLL_CALC_ERROR 0xFFFFFFFF 53 54 static const struct spread_spectrum_data *get_ss_data_entry( 55 struct dce110_clk_src *clk_src, 56 enum signal_type signal, 57 uint32_t pix_clk_khz) 58 { 59 60 uint32_t entrys_num; 61 uint32_t i; 62 struct spread_spectrum_data *ss_parm = NULL; 63 struct spread_spectrum_data *ret = NULL; 64 65 switch (signal) { 66 case SIGNAL_TYPE_DVI_SINGLE_LINK: 67 case SIGNAL_TYPE_DVI_DUAL_LINK: 68 ss_parm = clk_src->dvi_ss_params; 69 entrys_num = clk_src->dvi_ss_params_cnt; 70 break; 71 72 case SIGNAL_TYPE_HDMI_TYPE_A: 73 ss_parm = clk_src->hdmi_ss_params; 74 entrys_num = clk_src->hdmi_ss_params_cnt; 75 break; 76 77 case SIGNAL_TYPE_DISPLAY_PORT: 78 case SIGNAL_TYPE_DISPLAY_PORT_MST: 79 case SIGNAL_TYPE_EDP: 80 case SIGNAL_TYPE_VIRTUAL: 81 ss_parm = clk_src->dp_ss_params; 82 entrys_num = clk_src->dp_ss_params_cnt; 83 break; 84 85 default: 86 ss_parm = NULL; 87 entrys_num = 0; 88 break; 89 } 90 91 if (ss_parm == NULL) 92 return ret; 93 94 for (i = 0; i < entrys_num; ++i, ++ss_parm) { 95 if (ss_parm->freq_range_khz >= pix_clk_khz) { 96 ret = ss_parm; 97 break; 98 } 99 } 100 101 return ret; 102 } 103 104 /** 105 * Function: calculate_fb_and_fractional_fb_divider 106 * 107 * * DESCRIPTION: Calculates feedback and fractional feedback dividers values 108 * 109 *PARAMETERS: 110 * targetPixelClock Desired frequency in 10 KHz 111 * ref_divider Reference divider (already known) 112 * postDivider Post Divider (already known) 113 * feedback_divider_param Pointer where to store 114 * calculated feedback divider value 115 * fract_feedback_divider_param Pointer where to store 116 * calculated fract feedback divider value 117 * 118 *RETURNS: 119 * It fills the locations pointed by feedback_divider_param 120 * and fract_feedback_divider_param 121 * It returns - true if feedback divider not 0 122 * - false should never happen) 123 */ 124 static bool calculate_fb_and_fractional_fb_divider( 125 struct calc_pll_clock_source *calc_pll_cs, 126 uint32_t target_pix_clk_khz, 127 uint32_t ref_divider, 128 uint32_t post_divider, 129 uint32_t *feedback_divider_param, 130 uint32_t *fract_feedback_divider_param) 131 { 132 uint64_t feedback_divider; 133 134 feedback_divider = 135 (uint64_t)(target_pix_clk_khz * ref_divider * post_divider); 136 feedback_divider *= 10; 137 /* additional factor, since we divide by 10 afterwards */ 138 feedback_divider *= (uint64_t)(calc_pll_cs->fract_fb_divider_factor); 139 feedback_divider = div_u64(feedback_divider, calc_pll_cs->ref_freq_khz); 140 141 /*Round to the number of precision 142 * The following code replace the old code (ullfeedbackDivider + 5)/10 143 * for example if the difference between the number 144 * of fractional feedback decimal point and the fractional FB Divider precision 145 * is 2 then the equation becomes (ullfeedbackDivider + 5*100) / (10*100))*/ 146 147 feedback_divider += (uint64_t) 148 (5 * calc_pll_cs->fract_fb_divider_precision_factor); 149 feedback_divider = 150 div_u64(feedback_divider, 151 calc_pll_cs->fract_fb_divider_precision_factor * 10); 152 feedback_divider *= (uint64_t) 153 (calc_pll_cs->fract_fb_divider_precision_factor); 154 155 *feedback_divider_param = 156 div_u64_rem( 157 feedback_divider, 158 calc_pll_cs->fract_fb_divider_factor, 159 fract_feedback_divider_param); 160 161 if (*feedback_divider_param != 0) 162 return true; 163 return false; 164 } 165 166 /** 167 *calc_fb_divider_checking_tolerance 168 * 169 *DESCRIPTION: Calculates Feedback and Fractional Feedback divider values 170 * for passed Reference and Post divider, checking for tolerance. 171 *PARAMETERS: 172 * pll_settings Pointer to structure 173 * ref_divider Reference divider (already known) 174 * postDivider Post Divider (already known) 175 * tolerance Tolerance for Calculated Pixel Clock to be within 176 * 177 *RETURNS: 178 * It fills the PLLSettings structure with PLL Dividers values 179 * if calculated values are within required tolerance 180 * It returns - true if eror is within tolerance 181 * - false if eror is not within tolerance 182 */ 183 static bool calc_fb_divider_checking_tolerance( 184 struct calc_pll_clock_source *calc_pll_cs, 185 struct pll_settings *pll_settings, 186 uint32_t ref_divider, 187 uint32_t post_divider, 188 uint32_t tolerance) 189 { 190 uint32_t feedback_divider; 191 uint32_t fract_feedback_divider; 192 uint32_t actual_calculated_clock_khz; 193 uint32_t abs_err; 194 uint64_t actual_calc_clk_khz; 195 196 calculate_fb_and_fractional_fb_divider( 197 calc_pll_cs, 198 pll_settings->adjusted_pix_clk, 199 ref_divider, 200 post_divider, 201 &feedback_divider, 202 &fract_feedback_divider); 203 204 /*Actual calculated value*/ 205 actual_calc_clk_khz = (uint64_t)(feedback_divider * 206 calc_pll_cs->fract_fb_divider_factor) + 207 fract_feedback_divider; 208 actual_calc_clk_khz *= calc_pll_cs->ref_freq_khz; 209 actual_calc_clk_khz = 210 div_u64(actual_calc_clk_khz, 211 ref_divider * post_divider * 212 calc_pll_cs->fract_fb_divider_factor); 213 214 actual_calculated_clock_khz = (uint32_t)(actual_calc_clk_khz); 215 216 abs_err = (actual_calculated_clock_khz > 217 pll_settings->adjusted_pix_clk) 218 ? actual_calculated_clock_khz - 219 pll_settings->adjusted_pix_clk 220 : pll_settings->adjusted_pix_clk - 221 actual_calculated_clock_khz; 222 223 if (abs_err <= tolerance) { 224 /*found good values*/ 225 pll_settings->reference_freq = calc_pll_cs->ref_freq_khz; 226 pll_settings->reference_divider = ref_divider; 227 pll_settings->feedback_divider = feedback_divider; 228 pll_settings->fract_feedback_divider = fract_feedback_divider; 229 pll_settings->pix_clk_post_divider = post_divider; 230 pll_settings->calculated_pix_clk = 231 actual_calculated_clock_khz; 232 pll_settings->vco_freq = 233 actual_calculated_clock_khz * post_divider; 234 return true; 235 } 236 return false; 237 } 238 239 static bool calc_pll_dividers_in_range( 240 struct calc_pll_clock_source *calc_pll_cs, 241 struct pll_settings *pll_settings, 242 uint32_t min_ref_divider, 243 uint32_t max_ref_divider, 244 uint32_t min_post_divider, 245 uint32_t max_post_divider, 246 uint32_t err_tolerance) 247 { 248 uint32_t ref_divider; 249 uint32_t post_divider; 250 uint32_t tolerance; 251 252 /* This is err_tolerance / 10000 = 0.0025 - acceptable error of 0.25% 253 * This is errorTolerance / 10000 = 0.0001 - acceptable error of 0.01%*/ 254 tolerance = (pll_settings->adjusted_pix_clk * err_tolerance) / 255 10000; 256 if (tolerance < CALC_PLL_CLK_SRC_ERR_TOLERANCE) 257 tolerance = CALC_PLL_CLK_SRC_ERR_TOLERANCE; 258 259 for ( 260 post_divider = max_post_divider; 261 post_divider >= min_post_divider; 262 --post_divider) { 263 for ( 264 ref_divider = min_ref_divider; 265 ref_divider <= max_ref_divider; 266 ++ref_divider) { 267 if (calc_fb_divider_checking_tolerance( 268 calc_pll_cs, 269 pll_settings, 270 ref_divider, 271 post_divider, 272 tolerance)) { 273 return true; 274 } 275 } 276 } 277 278 return false; 279 } 280 281 static uint32_t calculate_pixel_clock_pll_dividers( 282 struct calc_pll_clock_source *calc_pll_cs, 283 struct pll_settings *pll_settings) 284 { 285 uint32_t err_tolerance; 286 uint32_t min_post_divider; 287 uint32_t max_post_divider; 288 uint32_t min_ref_divider; 289 uint32_t max_ref_divider; 290 291 if (pll_settings->adjusted_pix_clk == 0) { 292 DC_LOG_ERROR( 293 "%s Bad requested pixel clock", __func__); 294 return MAX_PLL_CALC_ERROR; 295 } 296 297 /* 1) Find Post divider ranges */ 298 if (pll_settings->pix_clk_post_divider) { 299 min_post_divider = pll_settings->pix_clk_post_divider; 300 max_post_divider = pll_settings->pix_clk_post_divider; 301 } else { 302 min_post_divider = calc_pll_cs->min_pix_clock_pll_post_divider; 303 if (min_post_divider * pll_settings->adjusted_pix_clk < 304 calc_pll_cs->min_vco_khz) { 305 min_post_divider = calc_pll_cs->min_vco_khz / 306 pll_settings->adjusted_pix_clk; 307 if ((min_post_divider * 308 pll_settings->adjusted_pix_clk) < 309 calc_pll_cs->min_vco_khz) 310 min_post_divider++; 311 } 312 313 max_post_divider = calc_pll_cs->max_pix_clock_pll_post_divider; 314 if (max_post_divider * pll_settings->adjusted_pix_clk 315 > calc_pll_cs->max_vco_khz) 316 max_post_divider = calc_pll_cs->max_vco_khz / 317 pll_settings->adjusted_pix_clk; 318 } 319 320 /* 2) Find Reference divider ranges 321 * When SS is enabled, or for Display Port even without SS, 322 * pll_settings->referenceDivider is not zero. 323 * So calculate PPLL FB and fractional FB divider 324 * using the passed reference divider*/ 325 326 if (pll_settings->reference_divider) { 327 min_ref_divider = pll_settings->reference_divider; 328 max_ref_divider = pll_settings->reference_divider; 329 } else { 330 min_ref_divider = ((calc_pll_cs->ref_freq_khz 331 / calc_pll_cs->max_pll_input_freq_khz) 332 > calc_pll_cs->min_pll_ref_divider) 333 ? calc_pll_cs->ref_freq_khz 334 / calc_pll_cs->max_pll_input_freq_khz 335 : calc_pll_cs->min_pll_ref_divider; 336 337 max_ref_divider = ((calc_pll_cs->ref_freq_khz 338 / calc_pll_cs->min_pll_input_freq_khz) 339 < calc_pll_cs->max_pll_ref_divider) 340 ? calc_pll_cs->ref_freq_khz / 341 calc_pll_cs->min_pll_input_freq_khz 342 : calc_pll_cs->max_pll_ref_divider; 343 } 344 345 /* If some parameters are invalid we could have scenario when "min">"max" 346 * which produced endless loop later. 347 * We should investigate why we get the wrong parameters. 348 * But to follow the similar logic when "adjustedPixelClock" is set to be 0 349 * it is better to return here than cause system hang/watchdog timeout later. 350 * ## SVS Wed 15 Jul 2009 */ 351 352 if (min_post_divider > max_post_divider) { 353 DC_LOG_ERROR( 354 "%s Post divider range is invalid", __func__); 355 return MAX_PLL_CALC_ERROR; 356 } 357 358 if (min_ref_divider > max_ref_divider) { 359 DC_LOG_ERROR( 360 "%s Reference divider range is invalid", __func__); 361 return MAX_PLL_CALC_ERROR; 362 } 363 364 /* 3) Try to find PLL dividers given ranges 365 * starting with minimal error tolerance. 366 * Increase error tolerance until PLL dividers found*/ 367 err_tolerance = MAX_PLL_CALC_ERROR; 368 369 while (!calc_pll_dividers_in_range( 370 calc_pll_cs, 371 pll_settings, 372 min_ref_divider, 373 max_ref_divider, 374 min_post_divider, 375 max_post_divider, 376 err_tolerance)) 377 err_tolerance += (err_tolerance > 10) 378 ? (err_tolerance / 10) 379 : 1; 380 381 return err_tolerance; 382 } 383 384 static bool pll_adjust_pix_clk( 385 struct dce110_clk_src *clk_src, 386 struct pixel_clk_params *pix_clk_params, 387 struct pll_settings *pll_settings) 388 { 389 uint32_t actual_pix_clk_khz = 0; 390 uint32_t requested_clk_khz = 0; 391 struct bp_adjust_pixel_clock_parameters bp_adjust_pixel_clock_params = { 392 0 }; 393 enum bp_result bp_result; 394 switch (pix_clk_params->signal_type) { 395 case SIGNAL_TYPE_HDMI_TYPE_A: { 396 requested_clk_khz = pix_clk_params->requested_pix_clk; 397 if (pix_clk_params->pixel_encoding != PIXEL_ENCODING_YCBCR422) { 398 switch (pix_clk_params->color_depth) { 399 case COLOR_DEPTH_101010: 400 requested_clk_khz = (requested_clk_khz * 5) >> 2; 401 break; /* x1.25*/ 402 case COLOR_DEPTH_121212: 403 requested_clk_khz = (requested_clk_khz * 6) >> 2; 404 break; /* x1.5*/ 405 case COLOR_DEPTH_161616: 406 requested_clk_khz = requested_clk_khz * 2; 407 break; /* x2.0*/ 408 default: 409 break; 410 } 411 } 412 actual_pix_clk_khz = requested_clk_khz; 413 } 414 break; 415 416 case SIGNAL_TYPE_DISPLAY_PORT: 417 case SIGNAL_TYPE_DISPLAY_PORT_MST: 418 case SIGNAL_TYPE_EDP: 419 requested_clk_khz = pix_clk_params->requested_sym_clk; 420 actual_pix_clk_khz = pix_clk_params->requested_pix_clk; 421 break; 422 423 default: 424 requested_clk_khz = pix_clk_params->requested_pix_clk; 425 actual_pix_clk_khz = pix_clk_params->requested_pix_clk; 426 break; 427 } 428 429 bp_adjust_pixel_clock_params.pixel_clock = requested_clk_khz; 430 bp_adjust_pixel_clock_params. 431 encoder_object_id = pix_clk_params->encoder_object_id; 432 bp_adjust_pixel_clock_params.signal_type = pix_clk_params->signal_type; 433 bp_adjust_pixel_clock_params. 434 ss_enable = pix_clk_params->flags.ENABLE_SS; 435 bp_result = clk_src->bios->funcs->adjust_pixel_clock( 436 clk_src->bios, &bp_adjust_pixel_clock_params); 437 if (bp_result == BP_RESULT_OK) { 438 pll_settings->actual_pix_clk = actual_pix_clk_khz; 439 pll_settings->adjusted_pix_clk = 440 bp_adjust_pixel_clock_params.adjusted_pixel_clock; 441 pll_settings->reference_divider = 442 bp_adjust_pixel_clock_params.reference_divider; 443 pll_settings->pix_clk_post_divider = 444 bp_adjust_pixel_clock_params.pixel_clock_post_divider; 445 446 return true; 447 } 448 449 return false; 450 } 451 452 /** 453 * Calculate PLL Dividers for given Clock Value. 454 * First will call VBIOS Adjust Exec table to check if requested Pixel clock 455 * will be Adjusted based on usage. 456 * Then it will calculate PLL Dividers for this Adjusted clock using preferred 457 * method (Maximum VCO frequency). 458 * 459 * \return 460 * Calculation error in units of 0.01% 461 */ 462 463 static uint32_t dce110_get_pix_clk_dividers_helper ( 464 struct dce110_clk_src *clk_src, 465 struct pll_settings *pll_settings, 466 struct pixel_clk_params *pix_clk_params) 467 { 468 uint32_t field = 0; 469 uint32_t pll_calc_error = MAX_PLL_CALC_ERROR; 470 struct calc_pll_clock_source *calc_pll_cs = &clk_src->calc_pll; 471 /* Check if reference clock is external (not pcie/xtalin) 472 * HW Dce80 spec: 473 * 00 - PCIE_REFCLK, 01 - XTALIN, 02 - GENERICA, 03 - GENERICB 474 * 04 - HSYNCA, 05 - GENLK_CLK, 06 - PCIE_REFCLK, 07 - DVOCLK0 */ 475 REG_GET(PLL_CNTL, PLL_REF_DIV_SRC, &field); 476 pll_settings->use_external_clk = (field > 1); 477 478 /* VBIOS by default enables DP SS (spread on IDCLK) for DCE 8.0 always 479 * (we do not care any more from SI for some older DP Sink which 480 * does not report SS support, no known issues) */ 481 if ((pix_clk_params->flags.ENABLE_SS) || 482 (dc_is_dp_signal(pix_clk_params->signal_type))) { 483 484 const struct spread_spectrum_data *ss_data = get_ss_data_entry( 485 clk_src, 486 pix_clk_params->signal_type, 487 pll_settings->adjusted_pix_clk); 488 489 if (NULL != ss_data) 490 pll_settings->ss_percentage = ss_data->percentage; 491 } 492 493 /* Check VBIOS AdjustPixelClock Exec table */ 494 if (!pll_adjust_pix_clk(clk_src, pix_clk_params, pll_settings)) { 495 /* Should never happen, ASSERT and fill up values to be able 496 * to continue. */ 497 DC_LOG_ERROR( 498 "%s: Failed to adjust pixel clock!!", __func__); 499 pll_settings->actual_pix_clk = 500 pix_clk_params->requested_pix_clk; 501 pll_settings->adjusted_pix_clk = 502 pix_clk_params->requested_pix_clk; 503 504 if (dc_is_dp_signal(pix_clk_params->signal_type)) 505 pll_settings->adjusted_pix_clk = 100000; 506 } 507 508 /* Calculate Dividers */ 509 if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) 510 /*Calculate Dividers by HDMI object, no SS case or SS case */ 511 pll_calc_error = 512 calculate_pixel_clock_pll_dividers( 513 &clk_src->calc_pll_hdmi, 514 pll_settings); 515 else 516 /*Calculate Dividers by default object, no SS case or SS case */ 517 pll_calc_error = 518 calculate_pixel_clock_pll_dividers( 519 &clk_src->calc_pll, 520 pll_settings); 521 522 return pll_calc_error; 523 } 524 525 static void dce112_get_pix_clk_dividers_helper ( 526 struct dce110_clk_src *clk_src, 527 struct pll_settings *pll_settings, 528 struct pixel_clk_params *pix_clk_params) 529 { 530 uint32_t actualPixelClockInKHz; 531 532 actualPixelClockInKHz = pix_clk_params->requested_pix_clk; 533 /* Calculate Dividers */ 534 if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) { 535 switch (pix_clk_params->color_depth) { 536 case COLOR_DEPTH_101010: 537 actualPixelClockInKHz = (actualPixelClockInKHz * 5) >> 2; 538 break; 539 case COLOR_DEPTH_121212: 540 actualPixelClockInKHz = (actualPixelClockInKHz * 6) >> 2; 541 break; 542 case COLOR_DEPTH_161616: 543 actualPixelClockInKHz = actualPixelClockInKHz * 2; 544 break; 545 default: 546 break; 547 } 548 } 549 pll_settings->actual_pix_clk = actualPixelClockInKHz; 550 pll_settings->adjusted_pix_clk = actualPixelClockInKHz; 551 pll_settings->calculated_pix_clk = pix_clk_params->requested_pix_clk; 552 } 553 554 static uint32_t dce110_get_pix_clk_dividers( 555 struct clock_source *cs, 556 struct pixel_clk_params *pix_clk_params, 557 struct pll_settings *pll_settings) 558 { 559 struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(cs); 560 struct calc_pll_clock_source *calc_pll_cs = &clk_src->calc_pll; 561 uint32_t pll_calc_error = MAX_PLL_CALC_ERROR; 562 563 if (pix_clk_params == NULL || pll_settings == NULL 564 || pix_clk_params->requested_pix_clk == 0) { 565 DC_LOG_ERROR( 566 "%s: Invalid parameters!!\n", __func__); 567 return pll_calc_error; 568 } 569 570 memset(pll_settings, 0, sizeof(*pll_settings)); 571 572 if (cs->id == CLOCK_SOURCE_ID_DP_DTO || 573 cs->id == CLOCK_SOURCE_ID_EXTERNAL) { 574 pll_settings->adjusted_pix_clk = clk_src->ext_clk_khz; 575 pll_settings->calculated_pix_clk = clk_src->ext_clk_khz; 576 pll_settings->actual_pix_clk = 577 pix_clk_params->requested_pix_clk; 578 return 0; 579 } 580 581 switch (cs->ctx->dce_version) { 582 case DCE_VERSION_8_0: 583 case DCE_VERSION_8_1: 584 case DCE_VERSION_8_3: 585 case DCE_VERSION_10_0: 586 case DCE_VERSION_11_0: 587 pll_calc_error = 588 dce110_get_pix_clk_dividers_helper(clk_src, 589 pll_settings, pix_clk_params); 590 break; 591 case DCE_VERSION_11_2: 592 case DCE_VERSION_12_0: 593 #if defined(CONFIG_DRM_AMD_DC_DCN1_0) 594 case DCN_VERSION_1_0: 595 #endif 596 597 dce112_get_pix_clk_dividers_helper(clk_src, 598 pll_settings, pix_clk_params); 599 break; 600 default: 601 break; 602 } 603 604 return pll_calc_error; 605 } 606 607 static uint32_t dce110_get_pll_pixel_rate_in_hz( 608 struct clock_source *cs, 609 struct pixel_clk_params *pix_clk_params, 610 struct pll_settings *pll_settings) 611 { 612 uint32_t inst = pix_clk_params->controller_id - CONTROLLER_ID_D0; 613 struct dc *dc_core = cs->ctx->dc; 614 struct dc_state *context = dc_core->current_state; 615 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[inst]; 616 617 /* This function need separate to different DCE version, before separate, just use pixel clock */ 618 return pipe_ctx->stream->phy_pix_clk; 619 620 } 621 622 static uint32_t dce110_get_dp_pixel_rate_from_combo_phy_pll( 623 struct clock_source *cs, 624 struct pixel_clk_params *pix_clk_params, 625 struct pll_settings *pll_settings) 626 { 627 uint32_t inst = pix_clk_params->controller_id - CONTROLLER_ID_D0; 628 struct dc *dc_core = cs->ctx->dc; 629 struct dc_state *context = dc_core->current_state; 630 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[inst]; 631 632 /* This function need separate to different DCE version, before separate, just use pixel clock */ 633 return pipe_ctx->stream->phy_pix_clk; 634 } 635 636 static uint32_t dce110_get_d_to_pixel_rate_in_hz( 637 struct clock_source *cs, 638 struct pixel_clk_params *pix_clk_params, 639 struct pll_settings *pll_settings) 640 { 641 uint32_t inst = pix_clk_params->controller_id - CONTROLLER_ID_D0; 642 struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(cs); 643 int dto_enabled = 0; 644 struct fixed31_32 pix_rate; 645 646 REG_GET(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, &dto_enabled); 647 648 if (dto_enabled) { 649 uint32_t phase = 0; 650 uint32_t modulo = 0; 651 REG_GET(PHASE[inst], DP_DTO0_PHASE, &phase); 652 REG_GET(MODULO[inst], DP_DTO0_MODULO, &modulo); 653 654 if (modulo == 0) { 655 return 0; 656 } 657 658 pix_rate = dal_fixed31_32_from_int(clk_src->ref_freq_khz); 659 pix_rate = dal_fixed31_32_mul_int(pix_rate, 1000); 660 pix_rate = dal_fixed31_32_mul_int(pix_rate, phase); 661 pix_rate = dal_fixed31_32_div_int(pix_rate, modulo); 662 663 return dal_fixed31_32_round(pix_rate); 664 } else { 665 return dce110_get_dp_pixel_rate_from_combo_phy_pll(cs, pix_clk_params, pll_settings); 666 } 667 } 668 669 static uint32_t dce110_get_pix_rate_in_hz( 670 struct clock_source *cs, 671 struct pixel_clk_params *pix_clk_params, 672 struct pll_settings *pll_settings) 673 { 674 uint32_t pix_rate = 0; 675 switch (pix_clk_params->signal_type) { 676 case SIGNAL_TYPE_DISPLAY_PORT: 677 case SIGNAL_TYPE_DISPLAY_PORT_MST: 678 case SIGNAL_TYPE_EDP: 679 case SIGNAL_TYPE_VIRTUAL: 680 pix_rate = dce110_get_d_to_pixel_rate_in_hz(cs, pix_clk_params, pll_settings); 681 break; 682 case SIGNAL_TYPE_HDMI_TYPE_A: 683 default: 684 pix_rate = dce110_get_pll_pixel_rate_in_hz(cs, pix_clk_params, pll_settings); 685 break; 686 } 687 688 return pix_rate; 689 } 690 691 static bool disable_spread_spectrum(struct dce110_clk_src *clk_src) 692 { 693 enum bp_result result; 694 struct bp_spread_spectrum_parameters bp_ss_params = {0}; 695 696 bp_ss_params.pll_id = clk_src->base.id; 697 698 /*Call ASICControl to process ATOMBIOS Exec table*/ 699 result = clk_src->bios->funcs->enable_spread_spectrum_on_ppll( 700 clk_src->bios, 701 &bp_ss_params, 702 false); 703 704 return result == BP_RESULT_OK; 705 } 706 707 static bool calculate_ss( 708 const struct pll_settings *pll_settings, 709 const struct spread_spectrum_data *ss_data, 710 struct delta_sigma_data *ds_data) 711 { 712 struct fixed32_32 fb_div; 713 struct fixed32_32 ss_amount; 714 struct fixed32_32 ss_nslip_amount; 715 struct fixed32_32 ss_ds_frac_amount; 716 struct fixed32_32 ss_step_size; 717 struct fixed32_32 modulation_time; 718 719 if (ds_data == NULL) 720 return false; 721 if (ss_data == NULL) 722 return false; 723 if (ss_data->percentage == 0) 724 return false; 725 if (pll_settings == NULL) 726 return false; 727 728 memset(ds_data, 0, sizeof(struct delta_sigma_data)); 729 730 /* compute SS_AMOUNT_FBDIV & SS_AMOUNT_NFRAC_SLIP & SS_AMOUNT_DSFRAC*/ 731 /* 6 decimal point support in fractional feedback divider */ 732 fb_div = dal_fixed32_32_from_fraction( 733 pll_settings->fract_feedback_divider, 1000000); 734 fb_div = dal_fixed32_32_add_int(fb_div, pll_settings->feedback_divider); 735 736 ds_data->ds_frac_amount = 0; 737 /*spreadSpectrumPercentage is in the unit of .01%, 738 * so have to divided by 100 * 100*/ 739 ss_amount = dal_fixed32_32_mul( 740 fb_div, dal_fixed32_32_from_fraction(ss_data->percentage, 741 100 * ss_data->percentage_divider)); 742 ds_data->feedback_amount = dal_fixed32_32_floor(ss_amount); 743 744 ss_nslip_amount = dal_fixed32_32_sub(ss_amount, 745 dal_fixed32_32_from_int(ds_data->feedback_amount)); 746 ss_nslip_amount = dal_fixed32_32_mul_int(ss_nslip_amount, 10); 747 ds_data->nfrac_amount = dal_fixed32_32_floor(ss_nslip_amount); 748 749 ss_ds_frac_amount = dal_fixed32_32_sub(ss_nslip_amount, 750 dal_fixed32_32_from_int(ds_data->nfrac_amount)); 751 ss_ds_frac_amount = dal_fixed32_32_mul_int(ss_ds_frac_amount, 65536); 752 ds_data->ds_frac_amount = dal_fixed32_32_floor(ss_ds_frac_amount); 753 754 /* compute SS_STEP_SIZE_DSFRAC */ 755 modulation_time = dal_fixed32_32_from_fraction( 756 pll_settings->reference_freq * 1000, 757 pll_settings->reference_divider * ss_data->modulation_freq_hz); 758 759 if (ss_data->flags.CENTER_SPREAD) 760 modulation_time = dal_fixed32_32_div_int(modulation_time, 4); 761 else 762 modulation_time = dal_fixed32_32_div_int(modulation_time, 2); 763 764 ss_step_size = dal_fixed32_32_div(ss_amount, modulation_time); 765 /* SS_STEP_SIZE_DSFRAC_DEC = Int(SS_STEP_SIZE * 2 ^ 16 * 10)*/ 766 ss_step_size = dal_fixed32_32_mul_int(ss_step_size, 65536 * 10); 767 ds_data->ds_frac_size = dal_fixed32_32_floor(ss_step_size); 768 769 return true; 770 } 771 772 static bool enable_spread_spectrum( 773 struct dce110_clk_src *clk_src, 774 enum signal_type signal, struct pll_settings *pll_settings) 775 { 776 struct bp_spread_spectrum_parameters bp_params = {0}; 777 struct delta_sigma_data d_s_data; 778 const struct spread_spectrum_data *ss_data = NULL; 779 780 ss_data = get_ss_data_entry( 781 clk_src, 782 signal, 783 pll_settings->calculated_pix_clk); 784 785 /* Pixel clock PLL has been programmed to generate desired pixel clock, 786 * now enable SS on pixel clock */ 787 /* TODO is it OK to return true not doing anything ??*/ 788 if (ss_data != NULL && pll_settings->ss_percentage != 0) { 789 if (calculate_ss(pll_settings, ss_data, &d_s_data)) { 790 bp_params.ds.feedback_amount = 791 d_s_data.feedback_amount; 792 bp_params.ds.nfrac_amount = 793 d_s_data.nfrac_amount; 794 bp_params.ds.ds_frac_size = d_s_data.ds_frac_size; 795 bp_params.ds_frac_amount = 796 d_s_data.ds_frac_amount; 797 bp_params.flags.DS_TYPE = 1; 798 bp_params.pll_id = clk_src->base.id; 799 bp_params.percentage = ss_data->percentage; 800 if (ss_data->flags.CENTER_SPREAD) 801 bp_params.flags.CENTER_SPREAD = 1; 802 if (ss_data->flags.EXTERNAL_SS) 803 bp_params.flags.EXTERNAL_SS = 1; 804 805 if (BP_RESULT_OK != 806 clk_src->bios->funcs-> 807 enable_spread_spectrum_on_ppll( 808 clk_src->bios, 809 &bp_params, 810 true)) 811 return false; 812 } else 813 return false; 814 } 815 return true; 816 } 817 818 static void dce110_program_pixel_clk_resync( 819 struct dce110_clk_src *clk_src, 820 enum signal_type signal_type, 821 enum dc_color_depth colordepth) 822 { 823 REG_UPDATE(RESYNC_CNTL, 824 DCCG_DEEP_COLOR_CNTL1, 0); 825 /* 826 24 bit mode: TMDS clock = 1.0 x pixel clock (1:1) 827 30 bit mode: TMDS clock = 1.25 x pixel clock (5:4) 828 36 bit mode: TMDS clock = 1.5 x pixel clock (3:2) 829 48 bit mode: TMDS clock = 2 x pixel clock (2:1) 830 */ 831 if (signal_type != SIGNAL_TYPE_HDMI_TYPE_A) 832 return; 833 834 switch (colordepth) { 835 case COLOR_DEPTH_888: 836 REG_UPDATE(RESYNC_CNTL, 837 DCCG_DEEP_COLOR_CNTL1, 0); 838 break; 839 case COLOR_DEPTH_101010: 840 REG_UPDATE(RESYNC_CNTL, 841 DCCG_DEEP_COLOR_CNTL1, 1); 842 break; 843 case COLOR_DEPTH_121212: 844 REG_UPDATE(RESYNC_CNTL, 845 DCCG_DEEP_COLOR_CNTL1, 2); 846 break; 847 case COLOR_DEPTH_161616: 848 REG_UPDATE(RESYNC_CNTL, 849 DCCG_DEEP_COLOR_CNTL1, 3); 850 break; 851 default: 852 break; 853 } 854 } 855 856 static void dce112_program_pixel_clk_resync( 857 struct dce110_clk_src *clk_src, 858 enum signal_type signal_type, 859 enum dc_color_depth colordepth, 860 bool enable_ycbcr420) 861 { 862 uint32_t deep_color_cntl = 0; 863 uint32_t double_rate_enable = 0; 864 865 /* 866 24 bit mode: TMDS clock = 1.0 x pixel clock (1:1) 867 30 bit mode: TMDS clock = 1.25 x pixel clock (5:4) 868 36 bit mode: TMDS clock = 1.5 x pixel clock (3:2) 869 48 bit mode: TMDS clock = 2 x pixel clock (2:1) 870 */ 871 if (signal_type == SIGNAL_TYPE_HDMI_TYPE_A) { 872 double_rate_enable = enable_ycbcr420 ? 1 : 0; 873 874 switch (colordepth) { 875 case COLOR_DEPTH_888: 876 deep_color_cntl = 0; 877 break; 878 case COLOR_DEPTH_101010: 879 deep_color_cntl = 1; 880 break; 881 case COLOR_DEPTH_121212: 882 deep_color_cntl = 2; 883 break; 884 case COLOR_DEPTH_161616: 885 deep_color_cntl = 3; 886 break; 887 default: 888 break; 889 } 890 } 891 892 if (clk_src->cs_mask->PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE) 893 REG_UPDATE_2(PIXCLK_RESYNC_CNTL, 894 PHYPLLA_DCCG_DEEP_COLOR_CNTL, deep_color_cntl, 895 PHYPLLA_PIXCLK_DOUBLE_RATE_ENABLE, double_rate_enable); 896 else 897 REG_UPDATE(PIXCLK_RESYNC_CNTL, 898 PHYPLLA_DCCG_DEEP_COLOR_CNTL, deep_color_cntl); 899 900 } 901 902 static bool dce110_program_pix_clk( 903 struct clock_source *clock_source, 904 struct pixel_clk_params *pix_clk_params, 905 struct pll_settings *pll_settings) 906 { 907 struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source); 908 struct bp_pixel_clock_parameters bp_pc_params = {0}; 909 910 #if defined(CONFIG_DRM_AMD_DC_DCN1_0) 911 if (IS_FPGA_MAXIMUS_DC(clock_source->ctx->dce_environment)) { 912 unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0; 913 unsigned dp_dto_ref_kHz = 700000; 914 unsigned clock_kHz = pll_settings->actual_pix_clk; 915 916 /* Set DTO values: phase = target clock, modulo = reference clock */ 917 REG_WRITE(PHASE[inst], clock_kHz); 918 REG_WRITE(MODULO[inst], dp_dto_ref_kHz); 919 920 /* Enable DTO */ 921 REG_UPDATE(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, 1); 922 return true; 923 } 924 #endif 925 /* First disable SS 926 * ATOMBIOS will enable by default SS on PLL for DP, 927 * do not disable it here 928 */ 929 if (clock_source->id != CLOCK_SOURCE_ID_EXTERNAL && 930 !dc_is_dp_signal(pix_clk_params->signal_type) && 931 clock_source->ctx->dce_version <= DCE_VERSION_11_0) 932 disable_spread_spectrum(clk_src); 933 934 /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/ 935 bp_pc_params.controller_id = pix_clk_params->controller_id; 936 bp_pc_params.pll_id = clock_source->id; 937 bp_pc_params.target_pixel_clock = pll_settings->actual_pix_clk; 938 bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id; 939 bp_pc_params.signal_type = pix_clk_params->signal_type; 940 941 switch (clock_source->ctx->dce_version) { 942 case DCE_VERSION_8_0: 943 case DCE_VERSION_8_1: 944 case DCE_VERSION_8_3: 945 case DCE_VERSION_10_0: 946 case DCE_VERSION_11_0: 947 bp_pc_params.reference_divider = pll_settings->reference_divider; 948 bp_pc_params.feedback_divider = pll_settings->feedback_divider; 949 bp_pc_params.fractional_feedback_divider = 950 pll_settings->fract_feedback_divider; 951 bp_pc_params.pixel_clock_post_divider = 952 pll_settings->pix_clk_post_divider; 953 bp_pc_params.flags.SET_EXTERNAL_REF_DIV_SRC = 954 pll_settings->use_external_clk; 955 956 if (clk_src->bios->funcs->set_pixel_clock( 957 clk_src->bios, &bp_pc_params) != BP_RESULT_OK) 958 return false; 959 /* Enable SS 960 * ATOMBIOS will enable by default SS for DP on PLL ( DP ID clock), 961 * based on HW display PLL team, SS control settings should be programmed 962 * during PLL Reset, but they do not have effect 963 * until SS_EN is asserted.*/ 964 if (clock_source->id != CLOCK_SOURCE_ID_EXTERNAL 965 && !dc_is_dp_signal(pix_clk_params->signal_type)) { 966 967 if (pix_clk_params->flags.ENABLE_SS) 968 if (!enable_spread_spectrum(clk_src, 969 pix_clk_params->signal_type, 970 pll_settings)) 971 return false; 972 973 /* Resync deep color DTO */ 974 dce110_program_pixel_clk_resync(clk_src, 975 pix_clk_params->signal_type, 976 pix_clk_params->color_depth); 977 } 978 979 break; 980 case DCE_VERSION_11_2: 981 case DCE_VERSION_12_0: 982 #if defined(CONFIG_DRM_AMD_DC_DCN1_0) 983 case DCN_VERSION_1_0: 984 #endif 985 986 if (clock_source->id != CLOCK_SOURCE_ID_DP_DTO) { 987 bp_pc_params.flags.SET_GENLOCK_REF_DIV_SRC = 988 pll_settings->use_external_clk; 989 bp_pc_params.flags.SET_XTALIN_REF_SRC = 990 !pll_settings->use_external_clk; 991 if (pix_clk_params->flags.SUPPORT_YCBCR420) { 992 bp_pc_params.flags.SUPPORT_YUV_420 = 1; 993 } 994 } 995 if (clk_src->bios->funcs->set_pixel_clock( 996 clk_src->bios, &bp_pc_params) != BP_RESULT_OK) 997 return false; 998 /* Resync deep color DTO */ 999 if (clock_source->id != CLOCK_SOURCE_ID_DP_DTO) 1000 dce112_program_pixel_clk_resync(clk_src, 1001 pix_clk_params->signal_type, 1002 pix_clk_params->color_depth, 1003 pix_clk_params->flags.SUPPORT_YCBCR420); 1004 break; 1005 default: 1006 break; 1007 } 1008 1009 return true; 1010 } 1011 1012 static bool dce110_clock_source_power_down( 1013 struct clock_source *clk_src) 1014 { 1015 struct dce110_clk_src *dce110_clk_src = TO_DCE110_CLK_SRC(clk_src); 1016 enum bp_result bp_result; 1017 struct bp_pixel_clock_parameters bp_pixel_clock_params = {0}; 1018 1019 if (clk_src->dp_clk_src) 1020 return true; 1021 1022 /* If Pixel Clock is 0 it means Power Down Pll*/ 1023 bp_pixel_clock_params.controller_id = CONTROLLER_ID_UNDEFINED; 1024 bp_pixel_clock_params.pll_id = clk_src->id; 1025 bp_pixel_clock_params.flags.FORCE_PROGRAMMING_OF_PLL = 1; 1026 1027 /*Call ASICControl to process ATOMBIOS Exec table*/ 1028 bp_result = dce110_clk_src->bios->funcs->set_pixel_clock( 1029 dce110_clk_src->bios, 1030 &bp_pixel_clock_params); 1031 1032 return bp_result == BP_RESULT_OK; 1033 } 1034 1035 /*****************************************/ 1036 /* Constructor */ 1037 /*****************************************/ 1038 static const struct clock_source_funcs dce110_clk_src_funcs = { 1039 .cs_power_down = dce110_clock_source_power_down, 1040 .program_pix_clk = dce110_program_pix_clk, 1041 .get_pix_clk_dividers = dce110_get_pix_clk_dividers, 1042 .get_pix_rate_in_hz = dce110_get_pix_rate_in_hz 1043 }; 1044 1045 static void get_ss_info_from_atombios( 1046 struct dce110_clk_src *clk_src, 1047 enum as_signal_type as_signal, 1048 struct spread_spectrum_data *spread_spectrum_data[], 1049 uint32_t *ss_entries_num) 1050 { 1051 enum bp_result bp_result = BP_RESULT_FAILURE; 1052 struct spread_spectrum_info *ss_info; 1053 struct spread_spectrum_data *ss_data; 1054 struct spread_spectrum_info *ss_info_cur; 1055 struct spread_spectrum_data *ss_data_cur; 1056 uint32_t i; 1057 struct calc_pll_clock_source *calc_pll_cs = &clk_src->calc_pll; 1058 if (ss_entries_num == NULL) { 1059 DC_LOG_SYNC( 1060 "Invalid entry !!!\n"); 1061 return; 1062 } 1063 if (spread_spectrum_data == NULL) { 1064 DC_LOG_SYNC( 1065 "Invalid array pointer!!!\n"); 1066 return; 1067 } 1068 1069 spread_spectrum_data[0] = NULL; 1070 *ss_entries_num = 0; 1071 1072 *ss_entries_num = clk_src->bios->funcs->get_ss_entry_number( 1073 clk_src->bios, 1074 as_signal); 1075 1076 if (*ss_entries_num == 0) 1077 return; 1078 1079 ss_info = kzalloc(sizeof(struct spread_spectrum_info) * (*ss_entries_num), 1080 GFP_KERNEL); 1081 ss_info_cur = ss_info; 1082 if (ss_info == NULL) 1083 return; 1084 1085 ss_data = kzalloc(sizeof(struct spread_spectrum_data) * (*ss_entries_num), 1086 GFP_KERNEL); 1087 if (ss_data == NULL) 1088 goto out_free_info; 1089 1090 for (i = 0, ss_info_cur = ss_info; 1091 i < (*ss_entries_num); 1092 ++i, ++ss_info_cur) { 1093 1094 bp_result = clk_src->bios->funcs->get_spread_spectrum_info( 1095 clk_src->bios, 1096 as_signal, 1097 i, 1098 ss_info_cur); 1099 1100 if (bp_result != BP_RESULT_OK) 1101 goto out_free_data; 1102 } 1103 1104 for (i = 0, ss_info_cur = ss_info, ss_data_cur = ss_data; 1105 i < (*ss_entries_num); 1106 ++i, ++ss_info_cur, ++ss_data_cur) { 1107 1108 if (ss_info_cur->type.STEP_AND_DELAY_INFO != false) { 1109 DC_LOG_SYNC( 1110 "Invalid ATOMBIOS SS Table!!!\n"); 1111 goto out_free_data; 1112 } 1113 1114 /* for HDMI check SS percentage, 1115 * if it is > 6 (0.06%), the ATOMBIOS table info is invalid*/ 1116 if (as_signal == AS_SIGNAL_TYPE_HDMI 1117 && ss_info_cur->spread_spectrum_percentage > 6){ 1118 /* invalid input, do nothing */ 1119 DC_LOG_SYNC( 1120 "Invalid SS percentage "); 1121 DC_LOG_SYNC( 1122 "for HDMI in ATOMBIOS info Table!!!\n"); 1123 continue; 1124 } 1125 if (ss_info_cur->spread_percentage_divider == 1000) { 1126 /* Keep previous precision from ATOMBIOS for these 1127 * in case new precision set by ATOMBIOS for these 1128 * (otherwise all code in DCE specific classes 1129 * for all previous ASICs would need 1130 * to be updated for SS calculations, 1131 * Audio SS compensation and DP DTO SS compensation 1132 * which assumes fixed SS percentage Divider = 100)*/ 1133 ss_info_cur->spread_spectrum_percentage /= 10; 1134 ss_info_cur->spread_percentage_divider = 100; 1135 } 1136 1137 ss_data_cur->freq_range_khz = ss_info_cur->target_clock_range; 1138 ss_data_cur->percentage = 1139 ss_info_cur->spread_spectrum_percentage; 1140 ss_data_cur->percentage_divider = 1141 ss_info_cur->spread_percentage_divider; 1142 ss_data_cur->modulation_freq_hz = 1143 ss_info_cur->spread_spectrum_range; 1144 1145 if (ss_info_cur->type.CENTER_MODE) 1146 ss_data_cur->flags.CENTER_SPREAD = 1; 1147 1148 if (ss_info_cur->type.EXTERNAL) 1149 ss_data_cur->flags.EXTERNAL_SS = 1; 1150 1151 } 1152 1153 *spread_spectrum_data = ss_data; 1154 kfree(ss_info); 1155 return; 1156 1157 out_free_data: 1158 kfree(ss_data); 1159 *ss_entries_num = 0; 1160 out_free_info: 1161 kfree(ss_info); 1162 } 1163 1164 static void ss_info_from_atombios_create( 1165 struct dce110_clk_src *clk_src) 1166 { 1167 get_ss_info_from_atombios( 1168 clk_src, 1169 AS_SIGNAL_TYPE_DISPLAY_PORT, 1170 &clk_src->dp_ss_params, 1171 &clk_src->dp_ss_params_cnt); 1172 get_ss_info_from_atombios( 1173 clk_src, 1174 AS_SIGNAL_TYPE_HDMI, 1175 &clk_src->hdmi_ss_params, 1176 &clk_src->hdmi_ss_params_cnt); 1177 get_ss_info_from_atombios( 1178 clk_src, 1179 AS_SIGNAL_TYPE_DVI, 1180 &clk_src->dvi_ss_params, 1181 &clk_src->dvi_ss_params_cnt); 1182 } 1183 1184 static bool calc_pll_max_vco_construct( 1185 struct calc_pll_clock_source *calc_pll_cs, 1186 struct calc_pll_clock_source_init_data *init_data) 1187 { 1188 uint32_t i; 1189 struct dc_firmware_info fw_info = { { 0 } }; 1190 if (calc_pll_cs == NULL || 1191 init_data == NULL || 1192 init_data->bp == NULL) 1193 return false; 1194 1195 if (init_data->bp->funcs->get_firmware_info( 1196 init_data->bp, 1197 &fw_info) != BP_RESULT_OK) 1198 return false; 1199 1200 calc_pll_cs->ctx = init_data->ctx; 1201 calc_pll_cs->ref_freq_khz = fw_info.pll_info.crystal_frequency; 1202 calc_pll_cs->min_vco_khz = 1203 fw_info.pll_info.min_output_pxl_clk_pll_frequency; 1204 calc_pll_cs->max_vco_khz = 1205 fw_info.pll_info.max_output_pxl_clk_pll_frequency; 1206 1207 if (init_data->max_override_input_pxl_clk_pll_freq_khz != 0) 1208 calc_pll_cs->max_pll_input_freq_khz = 1209 init_data->max_override_input_pxl_clk_pll_freq_khz; 1210 else 1211 calc_pll_cs->max_pll_input_freq_khz = 1212 fw_info.pll_info.max_input_pxl_clk_pll_frequency; 1213 1214 if (init_data->min_override_input_pxl_clk_pll_freq_khz != 0) 1215 calc_pll_cs->min_pll_input_freq_khz = 1216 init_data->min_override_input_pxl_clk_pll_freq_khz; 1217 else 1218 calc_pll_cs->min_pll_input_freq_khz = 1219 fw_info.pll_info.min_input_pxl_clk_pll_frequency; 1220 1221 calc_pll_cs->min_pix_clock_pll_post_divider = 1222 init_data->min_pix_clk_pll_post_divider; 1223 calc_pll_cs->max_pix_clock_pll_post_divider = 1224 init_data->max_pix_clk_pll_post_divider; 1225 calc_pll_cs->min_pll_ref_divider = 1226 init_data->min_pll_ref_divider; 1227 calc_pll_cs->max_pll_ref_divider = 1228 init_data->max_pll_ref_divider; 1229 1230 if (init_data->num_fract_fb_divider_decimal_point == 0 || 1231 init_data->num_fract_fb_divider_decimal_point_precision > 1232 init_data->num_fract_fb_divider_decimal_point) { 1233 DC_LOG_ERROR( 1234 "The dec point num or precision is incorrect!"); 1235 return false; 1236 } 1237 if (init_data->num_fract_fb_divider_decimal_point_precision == 0) { 1238 DC_LOG_ERROR( 1239 "Incorrect fract feedback divider precision num!"); 1240 return false; 1241 } 1242 1243 calc_pll_cs->fract_fb_divider_decimal_points_num = 1244 init_data->num_fract_fb_divider_decimal_point; 1245 calc_pll_cs->fract_fb_divider_precision = 1246 init_data->num_fract_fb_divider_decimal_point_precision; 1247 calc_pll_cs->fract_fb_divider_factor = 1; 1248 for (i = 0; i < calc_pll_cs->fract_fb_divider_decimal_points_num; ++i) 1249 calc_pll_cs->fract_fb_divider_factor *= 10; 1250 1251 calc_pll_cs->fract_fb_divider_precision_factor = 1; 1252 for ( 1253 i = 0; 1254 i < (calc_pll_cs->fract_fb_divider_decimal_points_num - 1255 calc_pll_cs->fract_fb_divider_precision); 1256 ++i) 1257 calc_pll_cs->fract_fb_divider_precision_factor *= 10; 1258 1259 return true; 1260 } 1261 1262 bool dce110_clk_src_construct( 1263 struct dce110_clk_src *clk_src, 1264 struct dc_context *ctx, 1265 struct dc_bios *bios, 1266 enum clock_source_id id, 1267 const struct dce110_clk_src_regs *regs, 1268 const struct dce110_clk_src_shift *cs_shift, 1269 const struct dce110_clk_src_mask *cs_mask) 1270 { 1271 struct dc_firmware_info fw_info = { { 0 } }; 1272 struct calc_pll_clock_source_init_data calc_pll_cs_init_data_hdmi; 1273 struct calc_pll_clock_source_init_data calc_pll_cs_init_data; 1274 1275 clk_src->base.ctx = ctx; 1276 clk_src->bios = bios; 1277 clk_src->base.id = id; 1278 clk_src->base.funcs = &dce110_clk_src_funcs; 1279 1280 clk_src->regs = regs; 1281 clk_src->cs_shift = cs_shift; 1282 clk_src->cs_mask = cs_mask; 1283 1284 if (clk_src->bios->funcs->get_firmware_info( 1285 clk_src->bios, &fw_info) != BP_RESULT_OK) { 1286 ASSERT_CRITICAL(false); 1287 goto unexpected_failure; 1288 } 1289 1290 clk_src->ext_clk_khz = 1291 fw_info.external_clock_source_frequency_for_dp; 1292 1293 switch (clk_src->base.ctx->dce_version) { 1294 case DCE_VERSION_8_0: 1295 case DCE_VERSION_8_1: 1296 case DCE_VERSION_8_3: 1297 case DCE_VERSION_10_0: 1298 case DCE_VERSION_11_0: 1299 1300 /* structure normally used with PLL ranges from ATOMBIOS; DS on by default */ 1301 calc_pll_cs_init_data.bp = bios; 1302 calc_pll_cs_init_data.min_pix_clk_pll_post_divider = 1; 1303 calc_pll_cs_init_data.max_pix_clk_pll_post_divider = 1304 clk_src->cs_mask->PLL_POST_DIV_PIXCLK; 1305 calc_pll_cs_init_data.min_pll_ref_divider = 1; 1306 calc_pll_cs_init_data.max_pll_ref_divider = clk_src->cs_mask->PLL_REF_DIV; 1307 /* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/ 1308 calc_pll_cs_init_data.min_override_input_pxl_clk_pll_freq_khz = 0; 1309 /* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/ 1310 calc_pll_cs_init_data.max_override_input_pxl_clk_pll_freq_khz = 0; 1311 /*numberOfFractFBDividerDecimalPoints*/ 1312 calc_pll_cs_init_data.num_fract_fb_divider_decimal_point = 1313 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM; 1314 /*number of decimal point to round off for fractional feedback divider value*/ 1315 calc_pll_cs_init_data.num_fract_fb_divider_decimal_point_precision = 1316 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM; 1317 calc_pll_cs_init_data.ctx = ctx; 1318 1319 /*structure for HDMI, no SS or SS% <= 0.06% for 27 MHz Ref clock */ 1320 calc_pll_cs_init_data_hdmi.bp = bios; 1321 calc_pll_cs_init_data_hdmi.min_pix_clk_pll_post_divider = 1; 1322 calc_pll_cs_init_data_hdmi.max_pix_clk_pll_post_divider = 1323 clk_src->cs_mask->PLL_POST_DIV_PIXCLK; 1324 calc_pll_cs_init_data_hdmi.min_pll_ref_divider = 1; 1325 calc_pll_cs_init_data_hdmi.max_pll_ref_divider = clk_src->cs_mask->PLL_REF_DIV; 1326 /* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/ 1327 calc_pll_cs_init_data_hdmi.min_override_input_pxl_clk_pll_freq_khz = 13500; 1328 /* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/ 1329 calc_pll_cs_init_data_hdmi.max_override_input_pxl_clk_pll_freq_khz = 27000; 1330 /*numberOfFractFBDividerDecimalPoints*/ 1331 calc_pll_cs_init_data_hdmi.num_fract_fb_divider_decimal_point = 1332 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM; 1333 /*number of decimal point to round off for fractional feedback divider value*/ 1334 calc_pll_cs_init_data_hdmi.num_fract_fb_divider_decimal_point_precision = 1335 FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM; 1336 calc_pll_cs_init_data_hdmi.ctx = ctx; 1337 1338 clk_src->ref_freq_khz = fw_info.pll_info.crystal_frequency; 1339 1340 if (clk_src->base.id == CLOCK_SOURCE_ID_EXTERNAL) 1341 return true; 1342 1343 /* PLL only from here on */ 1344 ss_info_from_atombios_create(clk_src); 1345 1346 if (!calc_pll_max_vco_construct( 1347 &clk_src->calc_pll, 1348 &calc_pll_cs_init_data)) { 1349 ASSERT_CRITICAL(false); 1350 goto unexpected_failure; 1351 } 1352 1353 1354 calc_pll_cs_init_data_hdmi. 1355 min_override_input_pxl_clk_pll_freq_khz = clk_src->ref_freq_khz/2; 1356 calc_pll_cs_init_data_hdmi. 1357 max_override_input_pxl_clk_pll_freq_khz = clk_src->ref_freq_khz; 1358 1359 1360 if (!calc_pll_max_vco_construct( 1361 &clk_src->calc_pll_hdmi, &calc_pll_cs_init_data_hdmi)) { 1362 ASSERT_CRITICAL(false); 1363 goto unexpected_failure; 1364 } 1365 break; 1366 default: 1367 break; 1368 } 1369 1370 return true; 1371 1372 unexpected_failure: 1373 return false; 1374 } 1375 1376