1264790Sbapt/* $NetBSD: amdgpu_dcn20_clk_mgr.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $ */ 2264790Sbapt 3264790Sbapt/* 4264790Sbapt * Copyright 2018 Advanced Micro Devices, Inc. 5264790Sbapt * 6264790Sbapt * Permission is hereby granted, free of charge, to any person obtaining a 7264790Sbapt * copy of this software and associated documentation files (the "Software"), 8264790Sbapt * to deal in the Software without restriction, including without limitation 9264790Sbapt * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10264790Sbapt * and/or sell copies of the Software, and to permit persons to whom the 11264790Sbapt * Software is furnished to do so, subject to the following conditions: 12264790Sbapt * 13264790Sbapt * The above copyright notice and this permission notice shall be included in 14264790Sbapt * all copies or substantial portions of the Software. 15264790Sbapt * 16264790Sbapt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17264790Sbapt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18264790Sbapt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19264790Sbapt * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20264790Sbapt * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21264790Sbapt * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22264790Sbapt * OTHER DEALINGS IN THE SOFTWARE. 23264790Sbapt * 24264790Sbapt * Authors: AMD 25264790Sbapt * 26264790Sbapt */ 27264790Sbapt 28264790Sbapt#include <sys/cdefs.h> 29264790Sbapt__KERNEL_RCSID(0, "$NetBSD: amdgpu_dcn20_clk_mgr.c,v 1.2 2021/12/18 23:45:02 riastradh Exp $"); 30264790Sbapt 31264790Sbapt#include "dccg.h" 32264790Sbapt#include "clk_mgr_internal.h" 33 34#include "dce100/dce_clk_mgr.h" 35#include "dcn20_clk_mgr.h" 36#include "reg_helper.h" 37#include "core_types.h" 38#include "dm_helpers.h" 39 40#include "navi10_ip_offset.h" 41#include "dcn/dcn_2_0_0_offset.h" 42#include "dcn/dcn_2_0_0_sh_mask.h" 43#include "clk/clk_11_0_0_offset.h" 44#include "clk/clk_11_0_0_sh_mask.h" 45 46#undef FN 47#define FN(reg_name, field_name) \ 48 clk_mgr->clk_mgr_shift->field_name, clk_mgr->clk_mgr_mask->field_name 49 50#define REG(reg) \ 51 (clk_mgr->regs->reg) 52 53#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg 54 55#define BASE(seg) BASE_INNER(seg) 56 57#define SR(reg_name)\ 58 .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ 59 mm ## reg_name 60 61#define CLK_BASE_INNER(seg) \ 62 CLK_BASE__INST0_SEG ## seg 63 64 65static const struct clk_mgr_registers clk_mgr_regs = { 66 CLK_REG_LIST_NV10() 67}; 68 69static const struct clk_mgr_shift clk_mgr_shift = { 70 CLK_MASK_SH_LIST_NV10(__SHIFT) 71}; 72 73static const struct clk_mgr_mask clk_mgr_mask = { 74 CLK_MASK_SH_LIST_NV10(_MASK) 75}; 76 77uint32_t dentist_get_did_from_divider(int divider) 78{ 79 uint32_t divider_id; 80 81 /* we want to floor here to get higher clock than required rather than lower */ 82 if (divider < DENTIST_DIVIDER_RANGE_2_START) { 83 if (divider < DENTIST_DIVIDER_RANGE_1_START) 84 divider_id = DENTIST_BASE_DID_1; 85 else 86 divider_id = DENTIST_BASE_DID_1 87 + (divider - DENTIST_DIVIDER_RANGE_1_START) 88 / DENTIST_DIVIDER_RANGE_1_STEP; 89 } else if (divider < DENTIST_DIVIDER_RANGE_3_START) { 90 divider_id = DENTIST_BASE_DID_2 91 + (divider - DENTIST_DIVIDER_RANGE_2_START) 92 / DENTIST_DIVIDER_RANGE_2_STEP; 93 } else if (divider < DENTIST_DIVIDER_RANGE_4_START) { 94 divider_id = DENTIST_BASE_DID_3 95 + (divider - DENTIST_DIVIDER_RANGE_3_START) 96 / DENTIST_DIVIDER_RANGE_3_STEP; 97 } else { 98 divider_id = DENTIST_BASE_DID_4 99 + (divider - DENTIST_DIVIDER_RANGE_4_START) 100 / DENTIST_DIVIDER_RANGE_4_STEP; 101 if (divider_id > DENTIST_MAX_DID) 102 divider_id = DENTIST_MAX_DID; 103 } 104 105 return divider_id; 106} 107 108void dcn20_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr, 109 struct dc_state *context, bool safe_to_lower) 110{ 111 int i; 112 113 clk_mgr->dccg->ref_dppclk = clk_mgr->base.clks.dppclk_khz; 114 for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) { 115 int dpp_inst, dppclk_khz, prev_dppclk_khz; 116 117 /* Loop index will match dpp->inst if resource exists, 118 * and we want to avoid dependency on dpp object 119 */ 120 dpp_inst = i; 121 dppclk_khz = context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz; 122 123 prev_dppclk_khz = clk_mgr->base.ctx->dc->current_state->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz; 124 125 if ((prev_dppclk_khz > dppclk_khz && safe_to_lower) || prev_dppclk_khz < dppclk_khz) { 126 clk_mgr->dccg->funcs->update_dpp_dto( 127 clk_mgr->dccg, dpp_inst, dppclk_khz); 128 } 129 } 130} 131 132void dcn20_update_clocks_update_dentist(struct clk_mgr_internal *clk_mgr) 133{ 134 int dpp_divider = DENTIST_DIVIDER_RANGE_SCALE_FACTOR 135 * clk_mgr->base.dentist_vco_freq_khz / clk_mgr->base.clks.dppclk_khz; 136 int disp_divider = DENTIST_DIVIDER_RANGE_SCALE_FACTOR 137 * clk_mgr->base.dentist_vco_freq_khz / clk_mgr->base.clks.dispclk_khz; 138 139 uint32_t dppclk_wdivider = dentist_get_did_from_divider(dpp_divider); 140 uint32_t dispclk_wdivider = dentist_get_did_from_divider(disp_divider); 141 142 REG_UPDATE(DENTIST_DISPCLK_CNTL, 143 DENTIST_DISPCLK_WDIVIDER, dispclk_wdivider); 144// REG_WAIT(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, 1, 5, 100); 145 REG_UPDATE(DENTIST_DISPCLK_CNTL, 146 DENTIST_DPPCLK_WDIVIDER, dppclk_wdivider); 147 REG_WAIT(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_CHG_DONE, 1, 5, 100); 148} 149 150 151void dcn2_update_clocks(struct clk_mgr *clk_mgr_base, 152 struct dc_state *context, 153 bool safe_to_lower) 154{ 155 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 156 struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; 157 struct dc *dc = clk_mgr_base->ctx->dc; 158 struct pp_smu_funcs_nv *pp_smu = NULL; 159 int display_count; 160 bool update_dppclk = false; 161 bool update_dispclk = false; 162 bool enter_display_off = false; 163 bool dpp_clock_lowered = false; 164 struct dmcu *dmcu = clk_mgr_base->ctx->dc->res_pool->dmcu; 165 bool force_reset = false; 166 167 if (dc->work_arounds.skip_clock_update) 168 return; 169 170 if (clk_mgr_base->clks.dispclk_khz == 0 || 171 dc->debug.force_clock_mode & 0x1) { 172 //this is from resume or boot up, if forced_clock cfg option used, we bypass program dispclk and DPPCLK, but need set them for S3. 173 force_reset = true; 174 175 dcn2_read_clocks_from_hw_dentist(clk_mgr_base); 176 177 //force_clock_mode 0x1: force reset the clock even it is the same clock as long as it is in Passive level. 178 } 179 display_count = clk_mgr_helper_get_active_display_cnt(dc, context); 180 if (dc->res_pool->pp_smu) 181 pp_smu = &dc->res_pool->pp_smu->nv_funcs; 182 183 if (display_count == 0) 184 enter_display_off = true; 185 186 if (enter_display_off == safe_to_lower) { 187 if (pp_smu && pp_smu->set_display_count) 188 pp_smu->set_display_count(&pp_smu->pp_smu, display_count); 189 } 190 191 if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, clk_mgr_base->clks.phyclk_khz)) { 192 clk_mgr_base->clks.phyclk_khz = new_clocks->phyclk_khz; 193 if (pp_smu && pp_smu->set_voltage_by_freq) 194 pp_smu->set_voltage_by_freq(&pp_smu->pp_smu, PP_SMU_NV_PHYCLK, clk_mgr_base->clks.phyclk_khz / 1000); 195 } 196 197 198 if (dc->debug.force_min_dcfclk_mhz > 0) 199 new_clocks->dcfclk_khz = (new_clocks->dcfclk_khz > (dc->debug.force_min_dcfclk_mhz * 1000)) ? 200 new_clocks->dcfclk_khz : (dc->debug.force_min_dcfclk_mhz * 1000); 201 202 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) { 203 clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz; 204 if (pp_smu && pp_smu->set_hard_min_dcfclk_by_freq) 205 pp_smu->set_hard_min_dcfclk_by_freq(&pp_smu->pp_smu, clk_mgr_base->clks.dcfclk_khz / 1000); 206 } 207 208 if (should_set_clock(safe_to_lower, 209 new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) { 210 clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; 211 if (pp_smu && pp_smu->set_min_deep_sleep_dcfclk) 212 pp_smu->set_min_deep_sleep_dcfclk(&pp_smu->pp_smu, clk_mgr_base->clks.dcfclk_deep_sleep_khz / 1000); 213 } 214 215 if (should_set_clock(safe_to_lower, new_clocks->socclk_khz, clk_mgr_base->clks.socclk_khz)) { 216 clk_mgr_base->clks.socclk_khz = new_clocks->socclk_khz; 217 if (pp_smu && pp_smu->set_hard_min_socclk_by_freq) 218 pp_smu->set_hard_min_socclk_by_freq(&pp_smu->pp_smu, clk_mgr_base->clks.socclk_khz / 1000); 219 } 220 221 if (should_update_pstate_support(safe_to_lower, new_clocks->p_state_change_support, clk_mgr_base->clks.p_state_change_support)) { 222 clk_mgr_base->clks.prev_p_state_change_support = clk_mgr_base->clks.p_state_change_support; 223 clk_mgr_base->clks.p_state_change_support = new_clocks->p_state_change_support; 224 if (pp_smu && pp_smu->set_pstate_handshake_support) 225 pp_smu->set_pstate_handshake_support(&pp_smu->pp_smu, clk_mgr_base->clks.p_state_change_support); 226 } 227 228 if (should_set_clock(safe_to_lower, new_clocks->dramclk_khz, clk_mgr_base->clks.dramclk_khz)) { 229 clk_mgr_base->clks.dramclk_khz = new_clocks->dramclk_khz; 230 if (pp_smu && pp_smu->set_hard_min_uclk_by_freq) 231 pp_smu->set_hard_min_uclk_by_freq(&pp_smu->pp_smu, clk_mgr_base->clks.dramclk_khz / 1000); 232 } 233 234 if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) { 235 if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz) 236 dpp_clock_lowered = true; 237 clk_mgr->base.clks.dppclk_khz = new_clocks->dppclk_khz; 238 239 if (pp_smu && pp_smu->set_voltage_by_freq) 240 pp_smu->set_voltage_by_freq(&pp_smu->pp_smu, PP_SMU_NV_PIXELCLK, clk_mgr_base->clks.dppclk_khz / 1000); 241 242 update_dppclk = true; 243 } 244 245 if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { 246 clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; 247 if (pp_smu && pp_smu->set_voltage_by_freq) 248 pp_smu->set_voltage_by_freq(&pp_smu->pp_smu, PP_SMU_NV_DISPCLK, clk_mgr_base->clks.dispclk_khz / 1000); 249 250 update_dispclk = true; 251 } 252 253 if (dc->config.forced_clocks == false || (force_reset && safe_to_lower)) { 254 if (dpp_clock_lowered) { 255 // if clock is being lowered, increase DTO before lowering refclk 256 dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); 257 dcn20_update_clocks_update_dentist(clk_mgr); 258 } else { 259 // if clock is being raised, increase refclk before lowering DTO 260 if (update_dppclk || update_dispclk) 261 dcn20_update_clocks_update_dentist(clk_mgr); 262 // always update dtos unless clock is lowered and not safe to lower 263 if (new_clocks->dppclk_khz >= dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz) 264 dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); 265 } 266 } 267 268 if (update_dispclk && 269 dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) { 270 /*update dmcu for wait_loop count*/ 271 dmcu->funcs->set_psr_wait_loop(dmcu, 272 clk_mgr_base->clks.dispclk_khz / 1000 / 7); 273 } 274} 275 276void dcn2_update_clocks_fpga(struct clk_mgr *clk_mgr, 277 struct dc_state *context, 278 bool safe_to_lower) 279{ 280 struct clk_mgr_internal *clk_mgr_int = TO_CLK_MGR_INTERNAL(clk_mgr); 281 282 struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; 283 /* Min fclk = 1.2GHz since all the extra scemi logic seems to run off of it */ 284 int fclk_adj = new_clocks->fclk_khz > 1200000 ? new_clocks->fclk_khz : 1200000; 285 286 if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, clk_mgr->clks.phyclk_khz)) { 287 clk_mgr->clks.phyclk_khz = new_clocks->phyclk_khz; 288 } 289 290 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr->clks.dcfclk_khz)) { 291 clk_mgr->clks.dcfclk_khz = new_clocks->dcfclk_khz; 292 } 293 294 if (should_set_clock(safe_to_lower, 295 new_clocks->dcfclk_deep_sleep_khz, clk_mgr->clks.dcfclk_deep_sleep_khz)) { 296 clk_mgr->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; 297 } 298 299 if (should_set_clock(safe_to_lower, new_clocks->socclk_khz, clk_mgr->clks.socclk_khz)) { 300 clk_mgr->clks.socclk_khz = new_clocks->socclk_khz; 301 } 302 303 if (should_set_clock(safe_to_lower, new_clocks->dramclk_khz, clk_mgr->clks.dramclk_khz)) { 304 clk_mgr->clks.dramclk_khz = new_clocks->dramclk_khz; 305 } 306 307 if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->clks.dppclk_khz)) { 308 clk_mgr->clks.dppclk_khz = new_clocks->dppclk_khz; 309 } 310 311 if (should_set_clock(safe_to_lower, fclk_adj, clk_mgr->clks.fclk_khz)) { 312 clk_mgr->clks.fclk_khz = fclk_adj; 313 } 314 315 if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr->clks.dispclk_khz)) { 316 clk_mgr->clks.dispclk_khz = new_clocks->dispclk_khz; 317 } 318 319 /* Both fclk and ref_dppclk run on the same scemi clock. 320 * So take the higher value since the DPP DTO is typically programmed 321 * such that max dppclk is 1:1 with ref_dppclk. 322 */ 323 if (clk_mgr->clks.fclk_khz > clk_mgr->clks.dppclk_khz) 324 clk_mgr->clks.dppclk_khz = clk_mgr->clks.fclk_khz; 325 if (clk_mgr->clks.dppclk_khz > clk_mgr->clks.fclk_khz) 326 clk_mgr->clks.fclk_khz = clk_mgr->clks.dppclk_khz; 327 328 // Both fclk and ref_dppclk run on the same scemi clock. 329 clk_mgr_int->dccg->ref_dppclk = clk_mgr->clks.fclk_khz; 330 331 dm_set_dcn_clocks(clk_mgr->ctx, &clk_mgr->clks); 332} 333 334void dcn2_init_clocks(struct clk_mgr *clk_mgr) 335{ 336 memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks)); 337 // Assumption is that boot state always supports pstate 338 clk_mgr->clks.p_state_change_support = true; 339 clk_mgr->clks.prev_p_state_change_support = true; 340} 341 342void dcn2_enable_pme_wa(struct clk_mgr *clk_mgr_base) 343{ 344 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 345 struct pp_smu_funcs_nv *pp_smu = NULL; 346 347 if (clk_mgr->pp_smu) { 348 pp_smu = &clk_mgr->pp_smu->nv_funcs; 349 350 if (pp_smu->set_pme_wa_enable) 351 pp_smu->set_pme_wa_enable(&pp_smu->pp_smu); 352 } 353} 354 355 356void dcn2_read_clocks_from_hw_dentist(struct clk_mgr *clk_mgr_base) 357{ 358 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 359 uint32_t dispclk_wdivider; 360 uint32_t dppclk_wdivider; 361 int disp_divider; 362 int dpp_divider; 363 364 REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, &dispclk_wdivider); 365 REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DPPCLK_WDIVIDER, &dppclk_wdivider); 366 367 disp_divider = dentist_get_divider_from_did(dispclk_wdivider); 368 dpp_divider = dentist_get_divider_from_did(dispclk_wdivider); 369 370 if (disp_divider && dpp_divider) { 371 /* Calculate the current DFS clock, in kHz.*/ 372 clk_mgr_base->clks.dispclk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR 373 * clk_mgr->base.dentist_vco_freq_khz) / disp_divider; 374 375 clk_mgr_base->clks.dppclk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR 376 * clk_mgr->base.dentist_vco_freq_khz) / dpp_divider; 377 } 378 379} 380 381void dcn2_get_clock(struct clk_mgr *clk_mgr, 382 struct dc_state *context, 383 enum dc_clock_type clock_type, 384 struct dc_clock_config *clock_cfg) 385{ 386 387 if (clock_type == DC_CLOCK_TYPE_DISPCLK) { 388 clock_cfg->max_clock_khz = context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz; 389 clock_cfg->min_clock_khz = DCN_MINIMUM_DISPCLK_Khz; 390 clock_cfg->current_clock_khz = clk_mgr->clks.dispclk_khz; 391 clock_cfg->bw_requirequired_clock_khz = context->bw_ctx.bw.dcn.clk.bw_dispclk_khz; 392 } 393 if (clock_type == DC_CLOCK_TYPE_DPPCLK) { 394 clock_cfg->max_clock_khz = context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz; 395 clock_cfg->min_clock_khz = DCN_MINIMUM_DPPCLK_Khz; 396 clock_cfg->current_clock_khz = clk_mgr->clks.dppclk_khz; 397 clock_cfg->bw_requirequired_clock_khz = context->bw_ctx.bw.dcn.clk.bw_dppclk_khz; 398 } 399} 400 401static bool dcn2_are_clock_states_equal(struct dc_clocks *a, 402 struct dc_clocks *b) 403{ 404 if (a->dispclk_khz != b->dispclk_khz) 405 return false; 406 else if (a->dppclk_khz != b->dppclk_khz) 407 return false; 408 else if (a->dcfclk_khz != b->dcfclk_khz) 409 return false; 410 else if (a->socclk_khz != b->socclk_khz) 411 return false; 412 else if (a->dcfclk_deep_sleep_khz != b->dcfclk_deep_sleep_khz) 413 return false; 414 else if (a->phyclk_khz != b->phyclk_khz) 415 return false; 416 else if (a->dramclk_khz != b->dramclk_khz) 417 return false; 418 else if (a->p_state_change_support != b->p_state_change_support) 419 return false; 420 421 return true; 422} 423 424static struct clk_mgr_funcs dcn2_funcs = { 425 .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, 426 .update_clocks = dcn2_update_clocks, 427 .init_clocks = dcn2_init_clocks, 428 .enable_pme_wa = dcn2_enable_pme_wa, 429 .get_clock = dcn2_get_clock, 430 .are_clock_states_equal = dcn2_are_clock_states_equal, 431}; 432 433 434void dcn20_clk_mgr_construct( 435 struct dc_context *ctx, 436 struct clk_mgr_internal *clk_mgr, 437 struct pp_smu_funcs *pp_smu, 438 struct dccg *dccg) 439{ 440 clk_mgr->base.ctx = ctx; 441 clk_mgr->pp_smu = pp_smu; 442 clk_mgr->base.funcs = &dcn2_funcs; 443 clk_mgr->regs = &clk_mgr_regs; 444 clk_mgr->clk_mgr_shift = &clk_mgr_shift; 445 clk_mgr->clk_mgr_mask = &clk_mgr_mask; 446 447 clk_mgr->dccg = dccg; 448 clk_mgr->dfs_bypass_disp_clk = 0; 449 450 clk_mgr->dprefclk_ss_percentage = 0; 451 clk_mgr->dprefclk_ss_divider = 1000; 452 clk_mgr->ss_on_dprefclk = false; 453 454 clk_mgr->base.dprefclk_khz = 700000; // 700 MHz planned if VCO is 3.85 GHz, will be retrieved 455 456 if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) { 457 dcn2_funcs.update_clocks = dcn2_update_clocks_fpga; 458 clk_mgr->base.dentist_vco_freq_khz = 3850000; 459 460 } else { 461 /* DFS Slice 2 should be used for DPREFCLK */ 462 int dprefclk_did = REG_READ(CLK3_CLK2_DFS_CNTL); 463 /* Convert DPREFCLK DFS Slice DID to actual divider*/ 464 int target_div = dentist_get_divider_from_did(dprefclk_did); 465 466 /* get FbMult value */ 467 uint32_t pll_req_reg = REG_READ(CLK3_CLK_PLL_REQ); 468 struct fixed31_32 pll_req; 469 470 /* set up a fixed-point number 471 * this works because the int part is on the right edge of the register 472 * and the frac part is on the left edge 473 */ 474 475 pll_req = dc_fixpt_from_int(pll_req_reg & clk_mgr->clk_mgr_mask->FbMult_int); 476 pll_req.value |= pll_req_reg & clk_mgr->clk_mgr_mask->FbMult_frac; 477 478 /* multiply by REFCLK period */ 479 pll_req = dc_fixpt_mul_int(pll_req, 100000); 480 481 /* integer part is now VCO frequency in kHz */ 482 clk_mgr->base.dentist_vco_freq_khz = dc_fixpt_floor(pll_req); 483 484 /* in case we don't get a value from the register, use default */ 485 if (clk_mgr->base.dentist_vco_freq_khz == 0) 486 clk_mgr->base.dentist_vco_freq_khz = 3850000; 487 488 /* Calculate the DPREFCLK in kHz.*/ 489 clk_mgr->base.dprefclk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR 490 * clk_mgr->base.dentist_vco_freq_khz) / target_div; 491 } 492 //Integrated_info table does not exist on dGPU projects so should not be referenced 493 //anywhere in code for dGPUs. 494 //Also there is no plan for now that DFS BYPASS will be used on NV10/12/14. 495 clk_mgr->dfs_bypass_enabled = false; 496 497 dce_clock_read_ss_info(clk_mgr); 498} 499 500