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