1 // SPDX-License-Identifier: MIT 2 // 3 // Copyright 2026 Advanced Micro Devices, Inc. 4 5 #include "dcn42_clk_mgr.h" 6 7 #include "dccg.h" 8 #include "clk_mgr_internal.h" 9 10 // For dce12_get_dp_ref_freq_khz 11 #include "dce100/dce_clk_mgr.h" 12 13 // For dcn20_update_clocks_update_dpp_dto 14 #include "dcn20/dcn20_clk_mgr.h" 15 16 17 18 19 #include "reg_helper.h" 20 #include "core_types.h" 21 #include "dcn42_smu.h" 22 #include "dm_helpers.h" 23 24 /* TODO: remove this include once we ported over remaining clk mgr functions*/ 25 #include "dcn30/dcn30_clk_mgr.h" 26 #include "dcn31/dcn31_clk_mgr.h" 27 28 #include "dcn35/dcn35_clk_mgr.h" 29 30 #include "dc_dmub_srv.h" 31 #include "link_service.h" 32 #include "logger_types.h" 33 34 #include "clk/clk_15_0_0_offset.h" 35 #include "clk/clk_15_0_0_sh_mask.h" 36 #include "dcn/dcn_4_2_0_offset.h" 37 #include "dcn/dcn_4_2_0_sh_mask.h" 38 39 40 #undef DC_LOGGER 41 #define DC_LOGGER \ 42 dc_logger 43 #define DC_LOGGER_INIT(logger) \ 44 struct dal_logger *dc_logger = logger 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 // for DCN register access 54 #define DCN_BASE__INST0_SEG0 0x00000012 55 #define DCN_BASE__INST0_SEG1 0x000000C0 56 57 #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg 58 59 #define BASE(seg) BASE_INNER(seg) 60 61 #define SR(reg_name) \ 62 .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + reg ## reg_name 63 64 // for CLKIP register access 65 #define CLK_BASE__INST0_SEG0 0x00016C00 66 67 #define CLK_BASE_INNER(seg) \ 68 CLK_BASE__INST0_SEG ## seg 69 70 #define CLK_SR_DCN42(reg_name) \ 71 .reg_name = CLK_BASE(reg ## reg_name ## _BASE_IDX) + reg ## reg_name 72 73 static const struct clk_mgr_registers clk_mgr_regs_dcn42 = { 74 CLK_REG_LIST_DCN42() 75 }; 76 77 static const struct clk_mgr_shift clk_mgr_shift_dcn42 = { 78 CLK_COMMON_MASK_SH_LIST_DCN42(__SHIFT) 79 }; 80 81 static const struct clk_mgr_mask clk_mgr_mask_dcn42 = { 82 CLK_COMMON_MASK_SH_LIST_DCN42(_MASK) 83 }; 84 85 #define TO_CLK_MGR_DCN42(clk_mgr_int)\ 86 container_of(clk_mgr_int, struct clk_mgr_dcn42, base) 87 88 bool dcn42_has_active_display(struct dc *dc, const struct dc_state *context) 89 { 90 int i, active_count = 0; 91 92 for (i = 0; i < context->stream_count; i++) { 93 const struct dc_stream_state *stream = context->streams[i]; 94 95 /* Checking stream / link detection ensuring that PHY is active*/ 96 if (dc_is_hdmi_signal(stream->signal) || 97 dc_is_dvi_signal(stream->signal) || 98 (dc_is_dp_signal(stream->signal) && !stream->dpms_off)) 99 active_count++; 100 } 101 102 for (i = 0; i < dc->link_count; i++) { 103 const struct dc_link *link = dc->links[i]; 104 105 /* abusing the fact that the dig and phy are coupled to see if the phy is enabled */ 106 if (link->link_enc && link->link_enc->funcs->is_dig_enabled && 107 link->link_enc->funcs->is_dig_enabled(link->link_enc)) 108 active_count++; 109 } 110 111 return active_count > 0; 112 } 113 114 static uint32_t dcn42_get_clock_freq_from_clkip(struct clk_mgr *clk_mgr_base, enum clock_type clock) 115 { 116 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 117 uint64_t clock_freq_mhz = 0; 118 uint32_t timer_threshold = 0; 119 120 // always safer to read the timer threshold instead of using cached value 121 REG_GET(CLK8_CLK_TICK_CNT_CONFIG_REG, TIMER_THRESHOLD, &timer_threshold); 122 123 if (timer_threshold == 0) { 124 BREAK_TO_DEBUGGER(); 125 return 0; 126 } 127 128 switch (clock) { 129 case clock_type_dispclk: 130 clock_freq_mhz = REG_READ(CLK8_CLK0_CURRENT_CNT); 131 break; 132 case clock_type_dppclk: 133 clock_freq_mhz = REG_READ(CLK8_CLK1_CURRENT_CNT); 134 break; 135 case clock_type_dprefclk: 136 clock_freq_mhz = REG_READ(CLK8_CLK2_CURRENT_CNT); 137 break; 138 case clock_type_dcfclk: 139 clock_freq_mhz = REG_READ(CLK8_CLK3_CURRENT_CNT); 140 break; 141 case clock_type_dtbclk: 142 clock_freq_mhz = REG_READ(CLK8_CLK4_CURRENT_CNT); 143 break; 144 default: 145 break; 146 } 147 148 clock_freq_mhz *= DCN42_CLKIP_REFCLK; 149 clock_freq_mhz = div_u64(clock_freq_mhz, timer_threshold); 150 151 // there are no DCN clocks over 0xFFFFFFFF MHz 152 ASSERT(clock_freq_mhz <= 0xFFFFFFFF); 153 154 return (uint32_t)clock_freq_mhz; 155 } 156 157 void dcn42_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr, 158 struct dc_state *context, 159 int ref_dtbclk_khz) 160 { 161 (void)clk_mgr; 162 (void)context; 163 (void)ref_dtbclk_khz; 164 /* DCN42 does not implement set_dtbclk_dto function, so this is a no-op */ 165 } 166 167 void dcn42_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr, 168 struct dc_state *context, bool safe_to_lower) 169 { 170 uint32_t i; 171 bool dppclk_active[MAX_PIPES] = {0}; 172 173 174 clk_mgr->dccg->ref_dppclk = clk_mgr->base.clks.dppclk_khz; 175 for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) { 176 int dpp_inst = 0, dppclk_khz, prev_dppclk_khz; 177 178 dppclk_khz = context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz; 179 180 if (context->res_ctx.pipe_ctx[i].plane_res.dpp) 181 dpp_inst = context->res_ctx.pipe_ctx[i].plane_res.dpp->inst; 182 else if (!context->res_ctx.pipe_ctx[i].plane_res.dpp && dppclk_khz == 0) { 183 /* dpp == NULL && dppclk_khz == 0 is valid because of pipe harvesting. 184 * In this case just continue in loop 185 */ 186 continue; 187 } else if (!context->res_ctx.pipe_ctx[i].plane_res.dpp && dppclk_khz > 0) { 188 /* The software state is not valid if dpp resource is NULL and 189 * dppclk_khz > 0. 190 */ 191 ASSERT(false); 192 continue; 193 } 194 195 prev_dppclk_khz = clk_mgr->dccg->pipe_dppclk_khz[i]; 196 197 if (safe_to_lower || prev_dppclk_khz < dppclk_khz) 198 clk_mgr->dccg->funcs->update_dpp_dto( 199 clk_mgr->dccg, dpp_inst, dppclk_khz); 200 dppclk_active[dpp_inst] = true; 201 } 202 if (safe_to_lower) 203 for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) { 204 struct dpp *old_dpp = clk_mgr->base.ctx->dc->current_state->res_ctx.pipe_ctx[i].plane_res.dpp; 205 206 if (old_dpp && !dppclk_active[old_dpp->inst]) 207 clk_mgr->dccg->funcs->update_dpp_dto(clk_mgr->dccg, old_dpp->inst, 0); 208 } 209 } 210 211 void dcn42_update_clocks(struct clk_mgr *clk_mgr_base, 212 struct dc_state *context, 213 bool safe_to_lower) 214 { 215 union dmub_rb_cmd cmd; 216 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 217 struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; 218 struct dc *dc = clk_mgr_base->ctx->dc; 219 bool update_dppclk = false; 220 bool update_dispclk = false; 221 bool dpp_clock_lowered = false; 222 bool has_active_display; 223 224 if (dc->work_arounds.skip_clock_update) 225 return; 226 227 has_active_display = dcn42_has_active_display(dc, context); 228 229 if (new_clocks->dtbclk_en && new_clocks->ref_dtbclk_khz < 590000) 230 new_clocks->ref_dtbclk_khz = 600000; 231 /* 232 * if it is safe to lower, but we are already in the lower state, we don't have to do anything 233 * also if safe to lower is false, we just go in the higher state 234 */ 235 if (safe_to_lower) { 236 if (new_clocks->zstate_support != DCN_ZSTATE_SUPPORT_DISALLOW && 237 new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) { 238 dcn42_smu_set_zstate_support(clk_mgr, new_clocks->zstate_support); 239 clk_mgr_base->clks.zstate_support = new_clocks->zstate_support; 240 } 241 242 if (clk_mgr_base->clks.dtbclk_en && !new_clocks->dtbclk_en) { 243 if (clk_mgr->base.ctx->dc->config.allow_0_dtb_clk) 244 dcn42_smu_set_dtbclk(clk_mgr, false); 245 clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en; 246 } 247 /* check that we're not already in lower */ 248 if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) { 249 /* if we can go lower, go lower */ 250 if (has_active_display == false) 251 clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER; 252 } 253 } else { 254 if (new_clocks->zstate_support == DCN_ZSTATE_SUPPORT_DISALLOW && 255 new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) { 256 dcn42_smu_set_zstate_support(clk_mgr, DCN_ZSTATE_SUPPORT_DISALLOW); 257 clk_mgr_base->clks.zstate_support = new_clocks->zstate_support; 258 } 259 /* Only attempt to enable dtbclk if currently disabled AND new state requests it. 260 * For dcn42b (no dtbclk hardware), init_clk_states sets dtbclk_en=false and 261 * new_clocks->dtbclk_en should always be false, so this block never executes. 262 */ 263 if (!clk_mgr_base->clks.dtbclk_en && new_clocks->dtbclk_en) { 264 int actual_dtbclk = 0; 265 266 dcn42_update_clocks_update_dtb_dto(clk_mgr, context, new_clocks->ref_dtbclk_khz); 267 dcn42_smu_set_dtbclk(clk_mgr, true); 268 actual_dtbclk = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dtbclk); 269 270 if (actual_dtbclk > 590000) { 271 clk_mgr_base->clks.ref_dtbclk_khz = new_clocks->ref_dtbclk_khz; 272 clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en; 273 } 274 } 275 276 /* check that we're not already in D0 */ 277 if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_MISSION_MODE) { 278 union display_idle_optimization_u idle_info = { 0 }; 279 280 dcn42_smu_set_display_idle_optimization(clk_mgr, idle_info.data); 281 /* update power state */ 282 clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_MISSION_MODE; 283 } 284 } 285 if (dc->debug.force_min_dcfclk_mhz > 0) { 286 int force_min_dcfclk_khz = dc->debug.force_min_dcfclk_mhz * 1000; 287 288 new_clocks->dcfclk_khz = (new_clocks->dcfclk_khz > force_min_dcfclk_khz) ? 289 new_clocks->dcfclk_khz : force_min_dcfclk_khz; 290 } 291 292 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) { 293 clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz; 294 clk_mgr_base->clks.fclk_khz = new_clocks->fclk_khz; 295 clk_mgr_base->clks.dramclk_khz = new_clocks->dramclk_khz; 296 dcn42_smu_set_hard_min_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_khz); 297 } 298 299 if (should_set_clock(safe_to_lower, 300 new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) { 301 clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; 302 303 /* Clamp the requested clock to PMFW based on DCN limit. */ 304 if (dc->debug.min_deep_sleep_dcfclk_khz > 0 && 305 clk_mgr_base->clks.dcfclk_deep_sleep_khz < (int)dc->debug.min_deep_sleep_dcfclk_khz) 306 clk_mgr_base->clks.dcfclk_deep_sleep_khz = (int)dc->debug.min_deep_sleep_dcfclk_khz; 307 308 dcn42_smu_set_min_deep_sleep_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_deep_sleep_khz); 309 } 310 311 // workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow. 312 if (new_clocks->dppclk_khz < 100000) 313 new_clocks->dppclk_khz = 100000; 314 315 if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) { 316 if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz) 317 dpp_clock_lowered = true; 318 clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz; 319 update_dppclk = true; 320 } 321 322 if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz) && 323 (new_clocks->dispclk_khz > 0 || (safe_to_lower && has_active_display == false))) { 324 uint32_t requested_dispclk_khz = new_clocks->dispclk_khz; 325 326 dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, true); 327 328 /* Clamp the requested clock to PMFW based on their limit. */ 329 if (dc->debug.min_disp_clk_khz > 0 && requested_dispclk_khz < (uint32_t)dc->debug.min_disp_clk_khz) 330 requested_dispclk_khz = (uint32_t)dc->debug.min_disp_clk_khz; 331 332 dcn42_smu_set_dispclk(clk_mgr, requested_dispclk_khz); 333 clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; 334 dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, false); 335 336 update_dispclk = true; 337 } 338 339 /* clock limits are received with MHz precision, divide by 1000 to prevent setting clocks at every call */ 340 if (!dc->debug.disable_dtb_ref_clk_switch && new_clocks->dtbclk_en && 341 should_set_clock(safe_to_lower, new_clocks->ref_dtbclk_khz / 1000, 342 clk_mgr_base->clks.ref_dtbclk_khz / 1000)) { 343 dcn42_update_clocks_update_dtb_dto(clk_mgr, context, new_clocks->ref_dtbclk_khz); 344 clk_mgr_base->clks.ref_dtbclk_khz = new_clocks->ref_dtbclk_khz; 345 } 346 347 if (dpp_clock_lowered) { 348 // increase per DPP DTO before lowering global dppclk 349 dcn42_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); 350 dcn42_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz); 351 } else { 352 // increase global DPPCLK before lowering per DPP DTO 353 if (update_dppclk || update_dispclk) 354 dcn42_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz); 355 dcn42_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); 356 } 357 // notify DMCUB of latest clocks 358 memset(&cmd, 0, sizeof(cmd)); 359 cmd.notify_clocks.header.type = DMUB_CMD__CLK_MGR; 360 cmd.notify_clocks.header.sub_type = DMUB_CMD__CLK_MGR_NOTIFY_CLOCKS; 361 cmd.notify_clocks.clocks.dcfclk_khz = clk_mgr_base->clks.dcfclk_khz; 362 cmd.notify_clocks.clocks.dcfclk_deep_sleep_khz = 363 clk_mgr_base->clks.dcfclk_deep_sleep_khz; 364 cmd.notify_clocks.clocks.dispclk_khz = clk_mgr_base->clks.dispclk_khz; 365 cmd.notify_clocks.clocks.dppclk_khz = clk_mgr_base->clks.dppclk_khz; 366 367 dc_wake_and_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 368 } 369 370 371 void dcn42_enable_pme_wa(struct clk_mgr *clk_mgr_base) 372 { 373 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 374 375 dcn42_smu_enable_pme_wa(clk_mgr); 376 } 377 378 379 bool dcn42_are_clock_states_equal(struct dc_clocks *a, 380 struct dc_clocks *b) 381 { 382 if (a->dispclk_khz != b->dispclk_khz) 383 return false; 384 else if (a->dppclk_khz != b->dppclk_khz) 385 return false; 386 else if (a->dcfclk_khz != b->dcfclk_khz) 387 return false; 388 else if (a->dcfclk_deep_sleep_khz != b->dcfclk_deep_sleep_khz) 389 return false; 390 else if (a->zstate_support != b->zstate_support) 391 return false; 392 else if (a->dtbclk_en != b->dtbclk_en) 393 return false; 394 395 return true; 396 } 397 398 static void dcn42_dump_clk_registers_internal(struct dcn42_clk_internal *internal, struct clk_mgr *clk_mgr_base) 399 { 400 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 401 402 REG_GET(CLK8_CLK_TICK_CNT_CONFIG_REG, TIMER_THRESHOLD, &internal->CLK8_CLK_TICK_CNT__TIMER_THRESHOLD); 403 404 // read dcf deep sleep divider 405 internal->CLK8_CLK0_DS_CNTL = REG_READ(CLK8_CLK0_DS_CNTL); 406 internal->CLK8_CLK3_DS_CNTL = REG_READ(CLK8_CLK3_DS_CNTL); 407 // read dispclk 408 internal->CLK8_CLK0_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dispclk); 409 internal->CLK8_CLK0_BYPASS_CNTL = REG_READ(CLK8_CLK0_BYPASS_CNTL); 410 // read dppclk 411 internal->CLK8_CLK1_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dppclk); 412 internal->CLK8_CLK1_BYPASS_CNTL = REG_READ(CLK8_CLK1_BYPASS_CNTL); 413 // read dprefclk 414 internal->CLK8_CLK2_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dprefclk); 415 internal->CLK8_CLK2_BYPASS_CNTL = REG_READ(CLK8_CLK2_BYPASS_CNTL); 416 // read dcfclk 417 internal->CLK8_CLK3_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dcfclk); 418 internal->CLK8_CLK3_BYPASS_CNTL = REG_READ(CLK8_CLK3_BYPASS_CNTL); 419 // read dtbclk 420 internal->CLK8_CLK4_CURRENT_CNT = dcn42_get_clock_freq_from_clkip(clk_mgr_base, clock_type_dtbclk); 421 internal->CLK8_CLK4_BYPASS_CNTL = REG_READ(CLK8_CLK4_BYPASS_CNTL); 422 } 423 424 static void dcn42_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass, 425 struct clk_mgr_dcn42 *clk_mgr) 426 { 427 struct dcn42_clk_internal internal = {0}; 428 char *bypass_clks[5] = {"0x0 DFS", "0x1 REFCLK", "0x2 ERROR", "0x3 400 FCH", "0x4 600 FCH"}; 429 430 DC_LOGGER_INIT(clk_mgr->base.base.ctx->logger); 431 (void)dc_logger; 432 433 dcn42_dump_clk_registers_internal(&internal, &clk_mgr->base.base); 434 regs_and_bypass->timer_threshold = internal.CLK8_CLK_TICK_CNT__TIMER_THRESHOLD; 435 regs_and_bypass->dcfclk = internal.CLK8_CLK3_CURRENT_CNT / 10; 436 regs_and_bypass->dcf_deep_sleep_divider = internal.CLK8_CLK3_DS_CNTL / 10; 437 regs_and_bypass->dcf_deep_sleep_allow = internal.CLK8_CLK3_DS_CNTL & 0x10; /*bit 4: CLK0_ALLOW_DS*/ 438 regs_and_bypass->dprefclk = internal.CLK8_CLK2_CURRENT_CNT / 10; 439 regs_and_bypass->dispclk = internal.CLK8_CLK0_CURRENT_CNT / 10; 440 regs_and_bypass->dppclk = internal.CLK8_CLK1_CURRENT_CNT / 10; 441 regs_and_bypass->dtbclk = internal.CLK8_CLK4_CURRENT_CNT / 10; 442 443 regs_and_bypass->dispclk_bypass = get_reg_field_value(internal.CLK8_CLK0_BYPASS_CNTL, CLK8_CLK0_BYPASS_CNTL, CLK0_BYPASS_SEL); 444 regs_and_bypass->dppclk_bypass = get_reg_field_value(internal.CLK8_CLK1_BYPASS_CNTL, CLK8_CLK1_BYPASS_CNTL, CLK1_BYPASS_SEL); 445 regs_and_bypass->dprefclk_bypass = get_reg_field_value(internal.CLK8_CLK2_BYPASS_CNTL, CLK8_CLK2_BYPASS_CNTL, CLK2_BYPASS_SEL); 446 regs_and_bypass->dcfclk_bypass = get_reg_field_value(internal.CLK8_CLK3_BYPASS_CNTL, CLK8_CLK3_BYPASS_CNTL, CLK3_BYPASS_SEL); 447 448 if (clk_mgr->base.base.ctx->dc->debug.pstate_enabled) { 449 DC_LOG_SMU("clk_type,clk_value,deepsleep_cntl,deepsleep_allow,bypass\n"); 450 451 DC_LOG_SMU("dcfclk,%d,%d,%d,%s\n", 452 regs_and_bypass->dcfclk, 453 regs_and_bypass->dcf_deep_sleep_divider, 454 regs_and_bypass->dcf_deep_sleep_allow, 455 bypass_clks[(int) regs_and_bypass->dcfclk_bypass]); 456 457 DC_LOG_SMU("dprefclk,%d,N/A,N/A,%s\n", 458 regs_and_bypass->dprefclk, 459 bypass_clks[(int) regs_and_bypass->dprefclk_bypass]); 460 461 DC_LOG_SMU("dispclk,%d,N/A,N/A,%s\n", 462 regs_and_bypass->dispclk, 463 bypass_clks[(int) regs_and_bypass->dispclk_bypass]); 464 465 //split 466 DC_LOG_SMU("SPLIT\n"); 467 468 // REGISTER VALUES 469 DC_LOG_SMU("reg_name,value,clk_type\n"); 470 DC_LOG_SMU("CLK1_CLK3_CURRENT_CNT,%d,dcfclk\n", 471 internal.CLK8_CLK3_CURRENT_CNT); 472 473 DC_LOG_SMU("CLK1_CLK3_DS_CNTL,%d,dcf_deep_sleep_divider\n", 474 internal.CLK8_CLK3_DS_CNTL); 475 476 DC_LOG_SMU("CLK1_CLK3_ALLOW_DS,%d,dcf_deep_sleep_allow\n", 477 (internal.CLK8_CLK3_DS_CNTL & 0x10)); 478 479 DC_LOG_SMU("CLK1_CLK2_CURRENT_CNT,%d,dprefclk\n", 480 internal.CLK8_CLK2_CURRENT_CNT); 481 482 DC_LOG_SMU("CLK1_CLK0_CURRENT_CNT,%d,dispclk\n", 483 internal.CLK8_CLK0_CURRENT_CNT); 484 485 DC_LOG_SMU("CLK1_CLK1_CURRENT_CNT,%d,dppclk\n", 486 internal.CLK8_CLK1_CURRENT_CNT); 487 488 DC_LOG_SMU("CLK1_CLK4_CURRENT_CNT,%d,dtbclk\n", 489 internal.CLK8_CLK4_CURRENT_CNT); 490 491 DC_LOG_SMU("CLK1_CLK3_BYPASS_CNTL,%d,dcfclk_bypass\n", 492 internal.CLK8_CLK3_BYPASS_CNTL); 493 494 DC_LOG_SMU("CLK1_CLK2_BYPASS_CNTL,%d,dprefclk_bypass\n", 495 internal.CLK8_CLK2_BYPASS_CNTL); 496 497 DC_LOG_SMU("CLK1_CLK0_BYPASS_CNTL,%d,dispclk_bypass\n", 498 internal.CLK8_CLK0_BYPASS_CNTL); 499 500 DC_LOG_SMU("CLK1_CLK1_BYPASS_CNTL,%d,dppclk_bypass\n", 501 internal.CLK8_CLK1_BYPASS_CNTL); 502 } 503 } 504 505 bool dcn42_is_spll_ssc_enabled(struct clk_mgr *clk_mgr_base) 506 { 507 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 508 struct dc_context *ctx = clk_mgr->base.ctx; 509 510 511 if (ctx->dc->config.ignore_dpref_ss) { 512 /*revert bios's ss info for test only*/ 513 return (clk_mgr->dprefclk_ss_percentage == 0); 514 } 515 /*need to update after BU*/ 516 return false; 517 } 518 519 static void init_clk_states(struct clk_mgr *clk_mgr) 520 { 521 uint32_t ref_dtbclk = clk_mgr->clks.ref_dtbclk_khz; 522 523 memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks)); 524 525 clk_mgr->clks.dtbclk_en = true; // request DTBCLK disable on first commit 526 clk_mgr->clks.ref_dtbclk_khz = ref_dtbclk; // restore ref_dtbclk 527 clk_mgr->clks.p_state_change_support = true; 528 clk_mgr->clks.prev_p_state_change_support = true; 529 clk_mgr->clks.pwr_state = DCN_PWR_STATE_UNKNOWN; 530 clk_mgr->clks.zstate_support = DCN_ZSTATE_SUPPORT_UNKNOWN; 531 } 532 533 void dcn42_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr, 534 struct dcn42_smu_dpm_clks *smu_dpm_clks) 535 { 536 DpmClocks_t_dcn42 *table = smu_dpm_clks->dpm_clks; 537 538 if (!clk_mgr->smu_ver) 539 return; 540 541 if (!table || smu_dpm_clks->mc_address.quad_part == 0) 542 return; 543 544 memset(table, 0, sizeof(*table)); 545 546 dcn42_smu_set_dram_addr_high(clk_mgr, 547 smu_dpm_clks->mc_address.high_part); 548 dcn42_smu_set_dram_addr_low(clk_mgr, 549 smu_dpm_clks->mc_address.low_part); 550 dcn42_smu_transfer_dpm_table_smu_2_dram(clk_mgr); 551 } 552 553 void dcn42_init_single_clock(unsigned int *entry_0, 554 uint32_t *smu_entry_0, 555 uint8_t num_levels) 556 { 557 int i; 558 char *entry_i = (char *)entry_0; 559 560 ASSERT(num_levels <= MAX_NUM_DPM_LVL); 561 if (num_levels > MAX_NUM_DPM_LVL) 562 num_levels = MAX_NUM_DPM_LVL; 563 564 565 for (i = 0; i < num_levels; i++) { 566 *((unsigned int *)entry_i) = smu_entry_0[i]; 567 entry_i += sizeof(struct clk_limit_table_entry); 568 } 569 } 570 571 unsigned int dcn42_convert_wck_ratio(uint8_t wck_ratio) 572 { 573 switch (wck_ratio) { 574 case WCK_RATIO_1_2: 575 return 2; 576 577 case WCK_RATIO_1_4: 578 return 4; 579 580 default: 581 break; 582 } 583 584 return 1; 585 } 586 587 void dcn42_init_clocks(struct clk_mgr *clk_mgr_base) 588 { 589 struct clk_mgr_internal *clk_mgr_int = TO_CLK_MGR_INTERNAL(clk_mgr_base); 590 struct clk_mgr_dcn42 *clk_mgr = TO_CLK_MGR_DCN42(clk_mgr_int); 591 592 DC_LOGGER_INIT(clk_mgr_base->ctx->logger); 593 (void)dc_logger; 594 595 init_clk_states(clk_mgr_base); 596 597 // to adjust dp_dto reference clock if ssc is enable otherwise to apply dprefclk 598 if (dcn42_is_spll_ssc_enabled(clk_mgr_base)) 599 clk_mgr_base->dp_dto_source_clock_in_khz = 600 dce_adjust_dp_ref_freq_for_ss(clk_mgr_int, clk_mgr_base->dprefclk_khz); 601 else 602 clk_mgr_base->dp_dto_source_clock_in_khz = clk_mgr_base->dprefclk_khz; 603 604 DC_LOG_SMU("dp_dto_source_clock %d, dprefclk %d\n", clk_mgr_base->dp_dto_source_clock_in_khz, clk_mgr_base->dprefclk_khz); 605 dcn42_dump_clk_registers(&clk_mgr_base->boot_snapshot, clk_mgr); 606 607 clk_mgr_base->clks.ref_dtbclk_khz = clk_mgr_base->boot_snapshot.dtbclk * 10; 608 clk_mgr_base->clks.dtbclk_en = clk_mgr_base->boot_snapshot.dtbclk > 59000; 609 } 610 611 static struct clk_bw_params dcn42_bw_params = { 612 .vram_type = Ddr4MemType, 613 .num_channels = 1, 614 .clk_table = { 615 .num_entries = 4, 616 }, 617 618 }; 619 620 struct dcn42_ss_info_table dcn42_ss_info_table = { 621 .ss_divider = 1000, 622 .ss_percentage = {0, 0, 375, 375, 375} 623 }; 624 625 static void dcn42_read_ss_info_from_lut(struct clk_mgr_internal *clk_mgr) 626 { 627 uint32_t clock_source; 628 629 clock_source = (REG_READ(CLK8_CLK2_BYPASS_CNTL) & CLK8_CLK2_BYPASS_CNTL__CLK2_BYPASS_SEL_MASK); 630 // If it's DFS mode, clock_source is 0. 631 if (dcn42_is_spll_ssc_enabled(&clk_mgr->base) && (clock_source < ARRAY_SIZE(dcn42_ss_info_table.ss_percentage))) { 632 clk_mgr->dprefclk_ss_percentage = dcn42_ss_info_table.ss_percentage[clock_source]; 633 634 if (clk_mgr->dprefclk_ss_percentage != 0) { 635 clk_mgr->ss_on_dprefclk = true; 636 clk_mgr->dprefclk_ss_divider = dcn42_ss_info_table.ss_divider; 637 } 638 } 639 } 640 641 void dcn42_build_watermark_ranges(struct clk_bw_params *bw_params, struct dcn42_watermarks *table) 642 { 643 uint8_t i, num_valid_sets; 644 645 num_valid_sets = 0; 646 647 for (i = 0; i < WM_SET_COUNT; i++) { 648 /* skip empty entries, the smu array has no holes*/ 649 if (!bw_params->wm_table.entries[i].valid) 650 continue; 651 652 table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmSetting = 653 (uint8_t)bw_params->wm_table.entries[i].wm_inst; 654 table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType = 655 (uint8_t)bw_params->wm_table.entries[i].wm_type; 656 /* We will not select WM based on fclk, so leave it as unconstrained */ 657 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0; 658 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF; 659 660 if (table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType == WM_TYPE_PSTATE_CHG) { 661 if (i == 0) 662 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk = 0; 663 else { 664 /* add 1 to make it non-overlapping with next lvl */ 665 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk = 666 (uint16_t)(bw_params->clk_table.entries[i - 1].dcfclk_mhz + 1); 667 } 668 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxMclk = 669 (uint16_t)bw_params->clk_table.entries[i].dcfclk_mhz; 670 671 } else { 672 /* unconstrained for memory retraining */ 673 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0; 674 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF; 675 676 /* Modify previous watermark range to cover up to max */ 677 if (num_valid_sets > 0) 678 table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF; 679 } 680 num_valid_sets++; 681 } 682 683 ASSERT(num_valid_sets != 0); /* Must have at least one set of valid watermarks */ 684 685 /* modify the min and max to make sure we cover the whole range*/ 686 table->WatermarkRow[WM_DCFCLK][0].MinMclk = 0; 687 table->WatermarkRow[WM_DCFCLK][0].MinClock = 0; 688 table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxMclk = 0xFFFF; 689 table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF; 690 691 /* This is for writeback only, does not matter currently as no writeback support*/ 692 table->WatermarkRow[WM_SOCCLK][0].WmSetting = WM_A; 693 table->WatermarkRow[WM_SOCCLK][0].MinClock = 0; 694 table->WatermarkRow[WM_SOCCLK][0].MaxClock = 0xFFFF; 695 table->WatermarkRow[WM_SOCCLK][0].MinMclk = 0; 696 table->WatermarkRow[WM_SOCCLK][0].MaxMclk = 0xFFFF; 697 } 698 699 void dcn42_notify_wm_ranges(struct clk_mgr *clk_mgr_base) 700 { 701 unsigned int i = 0; 702 struct dcn42_watermarks *table = NULL; 703 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 704 struct clk_mgr_dcn42 *clk_mgr_dcn42 = TO_CLK_MGR_DCN42(clk_mgr); 705 706 if (!clk_mgr->smu_ver) 707 return; 708 /*send once already skip*/ 709 if (clk_mgr_base->bw_params->wm_table.entries[WM_A].valid == true) 710 return; 711 clk_mgr_dcn42->smu_wm_set.wm_set = (struct dcn42_watermarks *)dm_helpers_allocate_gpu_mem( 712 clk_mgr->base.ctx, 713 DC_MEM_ALLOC_TYPE_GART, 714 sizeof(struct dcn42_watermarks), 715 &clk_mgr_dcn42->smu_wm_set.mc_address.quad_part); 716 717 ASSERT(clk_mgr_dcn42->smu_wm_set.wm_set); 718 719 table = clk_mgr_dcn42->smu_wm_set.wm_set; 720 721 if (!table || clk_mgr_dcn42->smu_wm_set.mc_address.quad_part == 0) 722 return; 723 724 memset(table, 0, sizeof(*table)); 725 /*same as previous asic, set wm valid before building watermark ranges*/ 726 for (i = 0; i < WM_SET_COUNT; i++) { 727 clk_mgr_base->bw_params->wm_table.entries[i].wm_inst = i; 728 729 if (i >= clk_mgr_base->bw_params->clk_table.num_entries) { 730 clk_mgr_base->bw_params->wm_table.entries[i].valid = false; 731 continue; 732 } 733 clk_mgr_base->bw_params->wm_table.entries[i].wm_type = WM_TYPE_PSTATE_CHG; 734 clk_mgr_base->bw_params->wm_table.entries[i].valid = true; 735 } 736 /* build watermark_range will check this valid range*/ 737 dcn42_build_watermark_ranges(clk_mgr_base->bw_params, table); 738 739 dcn42_smu_set_dram_addr_high(clk_mgr, 740 clk_mgr_dcn42->smu_wm_set.mc_address.high_part); 741 dcn42_smu_set_dram_addr_low(clk_mgr, 742 clk_mgr_dcn42->smu_wm_set.mc_address.low_part); 743 dcn42_smu_transfer_wm_table_dram_2_smu(clk_mgr); 744 745 if (clk_mgr_dcn42->smu_wm_set.wm_set && clk_mgr_dcn42->smu_wm_set.mc_address.quad_part != 0) { 746 dm_helpers_free_gpu_mem(clk_mgr->base.ctx, DC_MEM_ALLOC_TYPE_GART, 747 clk_mgr_dcn42->smu_wm_set.wm_set); 748 clk_mgr_dcn42->smu_wm_set.wm_set = NULL; 749 clk_mgr_dcn42->smu_wm_set.mc_address.quad_part = 0; 750 } 751 752 } 753 754 void dcn42_set_low_power_state(struct clk_mgr *clk_mgr_base) 755 { 756 struct dc *dc = clk_mgr_base->ctx->dc; 757 struct dc_state *context = dc->current_state; 758 759 if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) { 760 /* if we can go lower, go lower */ 761 if (dcn42_has_active_display(dc, context) == false) 762 clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER; 763 } 764 765 if (clk_mgr_base->clks.pwr_state == DCN_PWR_STATE_LOW_POWER) { 766 union display_idle_optimization_u idle_info = { 0 }; 767 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 768 769 idle_info.idle_info.df_request_disabled = 1; 770 idle_info.idle_info.phy_ref_clk_off = 1; 771 idle_info.idle_info.s0i2_rdy = 1; 772 dcn42_smu_set_display_idle_optimization(clk_mgr, idle_info.data); 773 } 774 } 775 776 void dcn42_exit_low_power_state(struct clk_mgr *clk_mgr_base) 777 { 778 (void)clk_mgr_base; 779 780 } 781 782 static void dcn42_init_clocks_fpga(struct clk_mgr *clk_mgr) 783 { 784 init_clk_states(clk_mgr); 785 786 } 787 788 void dcn42_update_clocks_fpga(struct clk_mgr *clk_mgr, 789 struct dc_state *context, 790 bool safe_to_lower) 791 { 792 struct clk_mgr_internal *clk_mgr_int = TO_CLK_MGR_INTERNAL(clk_mgr); 793 struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; 794 int fclk_adj = new_clocks->fclk_khz; 795 796 /* TODO: remove this after correctly set by DML */ 797 new_clocks->dcfclk_khz = 400000; 798 new_clocks->socclk_khz = 400000; 799 800 /* Min fclk = 1.2GHz since all the extra scemi logic seems to run off of it */ 801 //int fclk_adj = new_clocks->fclk_khz > 1200000 ? new_clocks->fclk_khz : 1200000; 802 new_clocks->fclk_khz = 4320000; 803 804 if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, clk_mgr->clks.phyclk_khz)) 805 clk_mgr->clks.phyclk_khz = new_clocks->phyclk_khz; 806 807 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr->clks.dcfclk_khz)) 808 clk_mgr->clks.dcfclk_khz = new_clocks->dcfclk_khz; 809 810 if (should_set_clock(safe_to_lower, 811 new_clocks->dcfclk_deep_sleep_khz, clk_mgr->clks.dcfclk_deep_sleep_khz)) 812 clk_mgr->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; 813 814 if (should_set_clock(safe_to_lower, new_clocks->socclk_khz, clk_mgr->clks.socclk_khz)) 815 clk_mgr->clks.socclk_khz = new_clocks->socclk_khz; 816 817 if (should_set_clock(safe_to_lower, new_clocks->dramclk_khz, clk_mgr->clks.dramclk_khz)) 818 clk_mgr->clks.dramclk_khz = new_clocks->dramclk_khz; 819 820 if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->clks.dppclk_khz)) 821 clk_mgr->clks.dppclk_khz = new_clocks->dppclk_khz; 822 823 if (should_set_clock(safe_to_lower, fclk_adj, clk_mgr->clks.fclk_khz)) 824 clk_mgr->clks.fclk_khz = fclk_adj; 825 826 if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr->clks.dispclk_khz)) 827 clk_mgr->clks.dispclk_khz = new_clocks->dispclk_khz; 828 829 /* Both fclk and ref_dppclk run on the same scemi clock. 830 * So take the higher value since the DPP DTO is typically programmed 831 * such that max dppclk is 1:1 with ref_dppclk. 832 */ 833 if (clk_mgr->clks.fclk_khz > clk_mgr->clks.dppclk_khz) 834 clk_mgr->clks.dppclk_khz = clk_mgr->clks.fclk_khz; 835 if (clk_mgr->clks.dppclk_khz > clk_mgr->clks.fclk_khz) 836 clk_mgr->clks.fclk_khz = clk_mgr->clks.dppclk_khz; 837 838 // Both fclk and ref_dppclk run on the same scemi clock. 839 clk_mgr_int->dccg->ref_dppclk = clk_mgr->clks.fclk_khz; 840 841 dm_set_dcn_clocks(clk_mgr->ctx, &clk_mgr->clks); 842 if (clk_mgr->clks.dtbclk_en) { 843 dcn42_update_clocks_update_dtb_dto(clk_mgr_int, context, clk_mgr->clks.ref_dtbclk_khz); 844 } else { 845 clk_mgr->clks.ref_dtbclk_khz = 0; 846 } 847 dcn42_update_clocks_update_dpp_dto(clk_mgr_int, context, safe_to_lower); 848 } 849 850 unsigned int dcn42_get_max_clock_khz(struct clk_mgr *clk_mgr_base, enum clk_type clk_type) 851 { 852 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 853 854 unsigned int num_clk_levels; 855 856 switch (clk_type) { 857 case CLK_TYPE_DISPCLK: 858 num_clk_levels = clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dispclk_levels; 859 return num_clk_levels ? 860 clk_mgr->base.bw_params->clk_table.entries[num_clk_levels - 1].dispclk_mhz * 1000 : 861 clk_mgr->base.boot_snapshot.dispclk; 862 case CLK_TYPE_DPPCLK: 863 num_clk_levels = clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dppclk_levels; 864 return num_clk_levels ? 865 clk_mgr->base.bw_params->clk_table.entries[num_clk_levels - 1].dppclk_mhz * 1000 : 866 clk_mgr->base.boot_snapshot.dppclk; 867 case CLK_TYPE_DSCCLK: 868 num_clk_levels = clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dispclk_levels; 869 return num_clk_levels ? 870 clk_mgr->base.bw_params->clk_table.entries[num_clk_levels - 1].dispclk_mhz * 1000 / 3 : 871 clk_mgr->base.boot_snapshot.dispclk / 3; 872 default: 873 break; 874 } 875 876 return 0; 877 } 878 879 int dcn42_get_dispclk_from_dentist(struct clk_mgr *clk_mgr_base) 880 { 881 (void)clk_mgr_base; 882 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 883 uint32_t dispclk_wdivider; 884 unsigned int disp_divider; 885 886 REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, &dispclk_wdivider); 887 disp_divider = dentist_get_divider_from_did(dispclk_wdivider); 888 889 /* Return DISPCLK freq in Khz */ 890 if (disp_divider) 891 return (DENTIST_DIVIDER_RANGE_SCALE_FACTOR * clk_mgr->base.dentist_vco_freq_khz) / disp_divider; 892 893 return 0; 894 } 895 bool dcn42_is_smu_present(struct clk_mgr *clk_mgr_base) 896 { 897 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 898 return clk_mgr->smu_present; 899 } 900 901 void dcn42_get_smu_clocks(struct clk_mgr_internal *clk_mgr_int) 902 { 903 struct clk_mgr *clk_mgr_base = &clk_mgr_int->base; 904 struct dcn42_smu_dpm_clks smu_dpm_clks = { 0 }; 905 906 DC_LOGGER_INIT(clk_mgr_base->ctx->logger); 907 (void)dc_logger; 908 909 smu_dpm_clks.dpm_clks = (DpmClocks_t_dcn42 *)dm_helpers_allocate_gpu_mem( 910 clk_mgr_base->ctx, 911 DC_MEM_ALLOC_TYPE_GART, 912 sizeof(DpmClocks_t_dcn42), 913 &smu_dpm_clks.mc_address.quad_part); 914 915 ASSERT(smu_dpm_clks.dpm_clks); 916 if (clk_mgr_base->ctx->dc->debug.pstate_enabled && smu_dpm_clks.mc_address.quad_part != 0) { 917 int i; 918 DpmClocks_t_dcn42 *dpm_clks = smu_dpm_clks.dpm_clks; 919 920 dcn42_get_dpm_table_from_smu(clk_mgr_int, &smu_dpm_clks); 921 DC_LOG_SMU("NumDcfClkLevelsEnabled: %d\n" 922 "NumDispClkLevelsEnabled: %d\n" 923 "NumSocClkLevelsEnabled: %d\n" 924 "VcnClkLevelsEnabled: %d\n" 925 "FClkLevelsEnabled: %d\n" 926 "NumMemPstatesEnabled: %d\n" 927 "MinGfxClk: %d\n" 928 "MaxGfxClk: %d\n", 929 dpm_clks->NumDcfClkLevelsEnabled, 930 dpm_clks->NumDispClkLevelsEnabled, 931 dpm_clks->NumSocClkLevelsEnabled, 932 dpm_clks->VcnClkLevelsEnabled, 933 dpm_clks->NumFclkLevelsEnabled, 934 dpm_clks->NumMemPstatesEnabled, 935 dpm_clks->MinGfxClk, 936 dpm_clks->MaxGfxClk); 937 938 for (i = 0; i < NUM_DCFCLK_DPM_LEVELS; i++) { 939 DC_LOG_SMU("dpm_clks->DcfClocks[%d] = %d\n", 940 i, 941 dpm_clks->DcfClocks[i]); 942 } 943 for (i = 0; i < NUM_DISPCLK_DPM_LEVELS; i++) { 944 DC_LOG_SMU("dpm_clks->DispClocks[%d] = %d\n", 945 i, dpm_clks->DispClocks[i]); 946 } 947 for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) { 948 DC_LOG_SMU("dpm_clks->SocClocks[%d] = %d\n", 949 i, dpm_clks->SocClocks[i]); 950 } 951 for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) { 952 DC_LOG_SMU("dpm_clks->FclkClocks_Freq[%d] = %d\n", 953 i, dpm_clks->FclkClocks_Freq[i]); 954 DC_LOG_SMU("dpm_clks->FclkClocks_Voltage[%d] = %d\n", 955 i, dpm_clks->FclkClocks_Voltage[i]); 956 } 957 for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) 958 DC_LOG_SMU("dpm_clks->SocVoltage[%d] = %d\n", 959 i, dpm_clks->SocVoltage[i]); 960 961 for (i = 0; i < NUM_MEM_PSTATE_LEVELS; i++) { 962 DC_LOG_SMU("dpm_clks.MemPstateTable[%d].UClk = %d\n" 963 "dpm_clks->MemPstateTable[%d].MemClk= %d\n" 964 "dpm_clks->MemPstateTable[%d].Voltage = %d\n", 965 i, dpm_clks->MemPstateTable[i].UClk, 966 i, dpm_clks->MemPstateTable[i].MemClk, 967 i, dpm_clks->MemPstateTable[i].Voltage); 968 } 969 970 if (clk_mgr_base->ctx->dc_bios->integrated_info && clk_mgr_base->ctx->dc->config.use_default_clock_table == false) { 971 /* DCFCLK */ 972 dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].dcfclk_mhz, 973 dpm_clks->DcfClocks, 974 dpm_clks->NumDcfClkLevelsEnabled); 975 clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dcfclk_levels = dpm_clks->NumDcfClkLevelsEnabled; 976 977 /* SOCCLK */ 978 dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].socclk_mhz, 979 dpm_clks->SocClocks, 980 dpm_clks->NumSocClkLevelsEnabled); 981 clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_socclk_levels = dpm_clks->NumSocClkLevelsEnabled; 982 983 /* DISPCLK */ 984 dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].dispclk_mhz, 985 dpm_clks->DispClocks, 986 dpm_clks->NumDispClkLevelsEnabled); 987 clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dispclk_levels = dpm_clks->NumDispClkLevelsEnabled; 988 989 /* DPPCLK */ 990 dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].dppclk_mhz, 991 dpm_clks->DppClocks, 992 dpm_clks->NumDispClkLevelsEnabled); 993 clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dppclk_levels = dpm_clks->NumDispClkLevelsEnabled; 994 995 /* FCLK */ 996 dcn42_init_single_clock(&clk_mgr_base->bw_params->clk_table.entries[0].fclk_mhz, 997 dpm_clks->FclkClocks_Freq, 998 NUM_FCLK_DPM_LEVELS); 999 clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_fclk_levels = dpm_clks->NumFclkLevelsEnabled; 1000 clk_mgr_base->bw_params->clk_table.num_entries = dpm_clks->NumFclkLevelsEnabled; 1001 1002 /* Memory Pstate table is in reverse order*/ 1003 ASSERT(dpm_clks->NumMemPstatesEnabled <= NUM_MEM_PSTATE_LEVELS); 1004 if (dpm_clks->NumMemPstatesEnabled > NUM_MEM_PSTATE_LEVELS) 1005 dpm_clks->NumMemPstatesEnabled = NUM_MEM_PSTATE_LEVELS; 1006 for (i = 0; i < dpm_clks->NumMemPstatesEnabled; i++) { 1007 clk_mgr_base->bw_params->clk_table.entries[dpm_clks->NumMemPstatesEnabled - 1 - i].memclk_mhz = dpm_clks->MemPstateTable[i].MemClk; 1008 clk_mgr_base->bw_params->clk_table.entries[dpm_clks->NumMemPstatesEnabled - 1 - i].wck_ratio = dcn42_convert_wck_ratio(dpm_clks->MemPstateTable[i].WckRatio) ; 1009 } 1010 clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_memclk_levels = dpm_clks->NumMemPstatesEnabled; 1011 1012 /* DTBCLK*/ 1013 clk_mgr_base->bw_params->clk_table.entries[0].dtbclk_mhz = 600; /* Fixed on platform */ 1014 clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dtbclk_levels = 1; 1015 } 1016 } 1017 if (smu_dpm_clks.dpm_clks && smu_dpm_clks.mc_address.quad_part != 0) 1018 dm_helpers_free_gpu_mem(clk_mgr_base->ctx, DC_MEM_ALLOC_TYPE_GART, 1019 smu_dpm_clks.dpm_clks); 1020 } 1021 1022 static struct clk_mgr_funcs dcn42_funcs = { 1023 .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, 1024 .get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz, 1025 .update_clocks = dcn42_update_clocks, 1026 .init_clocks = dcn42_init_clocks, 1027 .enable_pme_wa = dcn42_enable_pme_wa, 1028 .are_clock_states_equal = dcn42_are_clock_states_equal, 1029 .notify_wm_ranges = NULL, 1030 .set_low_power_state = dcn42_set_low_power_state, 1031 .exit_low_power_state = dcn42_exit_low_power_state, 1032 .get_max_clock_khz = dcn42_get_max_clock_khz, 1033 .get_dispclk_from_dentist = dcn42_get_dispclk_from_dentist, 1034 .is_smu_present = dcn42_is_smu_present, 1035 }; 1036 1037 struct clk_mgr_funcs dcn42_fpga_funcs = { 1038 .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, 1039 .update_clocks = dcn42_update_clocks_fpga, 1040 .init_clocks = dcn42_init_clocks_fpga, 1041 .get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz, 1042 }; 1043 1044 void dcn42_clk_mgr_construct( 1045 struct dc_context *ctx, 1046 struct clk_mgr_dcn42 *clk_mgr, 1047 struct pp_smu_funcs *pp_smu, 1048 struct dccg *dccg) 1049 { 1050 clk_mgr->base.base.ctx = ctx; 1051 clk_mgr->base.base.funcs = &dcn42_funcs; 1052 clk_mgr->base.regs = &clk_mgr_regs_dcn42; 1053 clk_mgr->base.clk_mgr_shift = &clk_mgr_shift_dcn42; 1054 clk_mgr->base.clk_mgr_mask = &clk_mgr_mask_dcn42; 1055 1056 clk_mgr->base.pp_smu = pp_smu; 1057 1058 clk_mgr->base.dccg = dccg; 1059 clk_mgr->base.dfs_bypass_disp_clk = 0; 1060 1061 clk_mgr->base.dprefclk_ss_percentage = 0; 1062 clk_mgr->base.dprefclk_ss_divider = 1000; 1063 clk_mgr->base.ss_on_dprefclk = false; 1064 clk_mgr->base.dfs_ref_freq_khz = 48000; /*sync with pmfw*/ 1065 clk_mgr->base.base.clks.ref_dtbclk_khz = 600000; 1066 1067 /* Changed from DCN3.2_clock_frequency doc to match 1068 * dcn32_dump_clk_registers from 4 * dentist_vco_freq_khz / 1069 * dprefclk DID divider 1070 */ 1071 clk_mgr->base.base.dprefclk_khz = 600000; 1072 1073 clk_mgr->base.smu_present = false; 1074 clk_mgr->base.smu_ver = dcn42_smu_get_pmfw_version(&clk_mgr->base); 1075 if (clk_mgr->base.smu_ver && clk_mgr->base.smu_ver != -1) 1076 clk_mgr->base.smu_present = true; 1077 1078 if (ctx->dc_bios->integrated_info) { 1079 clk_mgr->base.base.dentist_vco_freq_khz = ctx->dc_bios->integrated_info->dentist_vco_freq; 1080 1081 dcn42_bw_params.vram_type = ctx->dc_bios->integrated_info->memory_type; 1082 dcn42_bw_params.dram_channel_width_bytes = ctx->dc_bios->integrated_info->memory_type == 0x22 ? 8 : 4; 1083 dcn42_bw_params.num_channels = ctx->dc_bios->integrated_info->ma_channel_number ? ctx->dc_bios->integrated_info->ma_channel_number : 2; 1084 if (clk_mgr->base.smu_present) { 1085 clk_mgr->base.base.clks.ref_dtbclk_khz = dcn42_smu_get_dtbclk(&clk_mgr->base); 1086 clk_mgr->base.base.dprefclk_khz = dcn42_smu_get_dprefclk(&clk_mgr->base); 1087 } 1088 clk_mgr->base.base.bw_params = &dcn42_bw_params; 1089 1090 if (clk_mgr->base.smu_present) 1091 dcn42_get_smu_clocks(&clk_mgr->base); 1092 } 1093 /* in case we don't get a value from the BIOS, use default */ 1094 if (clk_mgr->base.base.dentist_vco_freq_khz == 0) 1095 clk_mgr->base.base.dentist_vco_freq_khz = 3000000; /* 3000MHz */ 1096 1097 /* Saved clocks configured at boot for debug purposes */ 1098 dcn42_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, clk_mgr); 1099 1100 dce_clock_read_ss_info(&clk_mgr->base); 1101 /*when clk src is from FCH, it could have ss, same clock src as DPREF clk*/ 1102 1103 dcn42_read_ss_info_from_lut(&clk_mgr->base); 1104 1105 clk_mgr->base.base.bw_params = &dcn42_bw_params; 1106 if (clk_mgr->base.smu_present) 1107 dcn42_get_smu_clocks(&clk_mgr->base); 1108 } 1109 1110 void dcn42_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int) 1111 { 1112 struct clk_mgr_dcn42 *clk_mgr = TO_CLK_MGR_DCN42(clk_mgr_int); 1113 1114 if (clk_mgr->smu_wm_set.wm_set && clk_mgr->smu_wm_set.mc_address.quad_part != 0) { 1115 dm_helpers_free_gpu_mem(clk_mgr_int->base.ctx, DC_MEM_ALLOC_TYPE_GART, 1116 clk_mgr->smu_wm_set.wm_set); 1117 clk_mgr->smu_wm_set.wm_set = NULL; 1118 clk_mgr->smu_wm_set.mc_address.quad_part = 0; 1119 } 1120 } 1121