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