1 /* 2 * Copyright 2022 Advanced Micro Devices, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20 * OTHER DEALINGS IN THE SOFTWARE. 21 * 22 * Authors: AMD 23 * 24 */ 25 26 27 #include "dcn35_clk_mgr.h" 28 29 #include "dccg.h" 30 #include "clk_mgr_internal.h" 31 32 // For dce12_get_dp_ref_freq_khz 33 #include "dce100/dce_clk_mgr.h" 34 35 // For dcn20_update_clocks_update_dpp_dto 36 #include "dcn20/dcn20_clk_mgr.h" 37 38 39 40 41 #include "reg_helper.h" 42 #include "core_types.h" 43 #include "dcn35_smu.h" 44 #include "dm_helpers.h" 45 46 /* TODO: remove this include once we ported over remaining clk mgr functions*/ 47 #include "dcn30/dcn30_clk_mgr.h" 48 #include "dcn31/dcn31_clk_mgr.h" 49 50 #include "dc_dmub_srv.h" 51 #include "link.h" 52 #include "logger_types.h" 53 #undef DC_LOGGER 54 #define DC_LOGGER \ 55 clk_mgr->base.base.ctx->logger 56 57 #define regCLK1_CLK_PLL_REQ 0x0237 58 #define regCLK1_CLK_PLL_REQ_BASE_IDX 0 59 60 #define CLK1_CLK_PLL_REQ__FbMult_int__SHIFT 0x0 61 #define CLK1_CLK_PLL_REQ__PllSpineDiv__SHIFT 0xc 62 #define CLK1_CLK_PLL_REQ__FbMult_frac__SHIFT 0x10 63 #define CLK1_CLK_PLL_REQ__FbMult_int_MASK 0x000001FFL 64 #define CLK1_CLK_PLL_REQ__PllSpineDiv_MASK 0x0000F000L 65 #define CLK1_CLK_PLL_REQ__FbMult_frac_MASK 0xFFFF0000L 66 67 #define regCLK1_CLK2_BYPASS_CNTL 0x029c 68 #define regCLK1_CLK2_BYPASS_CNTL_BASE_IDX 0 69 70 #define CLK1_CLK2_BYPASS_CNTL__CLK2_BYPASS_SEL__SHIFT 0x0 71 #define CLK1_CLK2_BYPASS_CNTL__CLK2_BYPASS_DIV__SHIFT 0x10 72 #define CLK1_CLK2_BYPASS_CNTL__CLK2_BYPASS_SEL_MASK 0x00000007L 73 #define CLK1_CLK2_BYPASS_CNTL__CLK2_BYPASS_DIV_MASK 0x000F0000L 74 75 #define REG(reg_name) \ 76 (ctx->clk_reg_offsets[reg ## reg_name ## _BASE_IDX] + reg ## reg_name) 77 78 #define TO_CLK_MGR_DCN35(clk_mgr)\ 79 container_of(clk_mgr, struct clk_mgr_dcn35, base) 80 81 static int dcn35_get_active_display_cnt_wa( 82 struct dc *dc, 83 struct dc_state *context) 84 { 85 int i, display_count; 86 bool tmds_present = false; 87 88 display_count = 0; 89 for (i = 0; i < context->stream_count; i++) { 90 const struct dc_stream_state *stream = context->streams[i]; 91 92 if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A || 93 stream->signal == SIGNAL_TYPE_DVI_SINGLE_LINK || 94 stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) 95 tmds_present = true; 96 } 97 98 for (i = 0; i < dc->link_count; i++) { 99 const struct dc_link *link = dc->links[i]; 100 101 /* abusing the fact that the dig and phy are coupled to see if the phy is enabled */ 102 if (link->link_enc && link->link_enc->funcs->is_dig_enabled && 103 link->link_enc->funcs->is_dig_enabled(link->link_enc)) 104 display_count++; 105 } 106 107 /* WA for hang on HDMI after display off back on*/ 108 if (display_count == 0 && tmds_present) 109 display_count = 1; 110 111 return display_count; 112 } 113 114 static void dcn35_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, 115 bool safe_to_lower, bool disable) 116 { 117 struct dc *dc = clk_mgr_base->ctx->dc; 118 int i; 119 120 for (i = 0; i < dc->res_pool->pipe_count; ++i) { 121 struct pipe_ctx *pipe = safe_to_lower 122 ? &context->res_ctx.pipe_ctx[i] 123 : &dc->current_state->res_ctx.pipe_ctx[i]; 124 125 if (pipe->top_pipe || pipe->prev_odm_pipe) 126 continue; 127 if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal) || 128 !pipe->stream->link_enc)) { 129 struct stream_encoder *stream_enc = pipe->stream_res.stream_enc; 130 131 if (disable) { 132 if (stream_enc && stream_enc->funcs->disable_fifo) 133 pipe->stream_res.stream_enc->funcs->disable_fifo(stream_enc); 134 135 if (pipe->stream_res.tg && pipe->stream_res.tg->funcs->immediate_disable_crtc) 136 pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg); 137 138 reset_sync_context_for_pipe(dc, context, i); 139 } else { 140 pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg); 141 142 if (stream_enc && stream_enc->funcs->enable_fifo) 143 pipe->stream_res.stream_enc->funcs->enable_fifo(stream_enc); 144 } 145 } 146 } 147 } 148 149 static void dcn35_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr, 150 struct dc_state *context, 151 int ref_dtbclk_khz) 152 { 153 struct dccg *dccg = clk_mgr->dccg; 154 uint32_t tg_mask = 0; 155 int i; 156 157 for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) { 158 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 159 struct dtbclk_dto_params dto_params = {0}; 160 161 /* use mask to program DTO once per tg */ 162 if (pipe_ctx->stream_res.tg && 163 !(tg_mask & (1 << pipe_ctx->stream_res.tg->inst))) { 164 tg_mask |= (1 << pipe_ctx->stream_res.tg->inst); 165 166 dto_params.otg_inst = pipe_ctx->stream_res.tg->inst; 167 dto_params.ref_dtbclk_khz = ref_dtbclk_khz; 168 169 dccg->funcs->set_dtbclk_dto(clk_mgr->dccg, &dto_params); 170 //dccg->funcs->set_audio_dtbclk_dto(clk_mgr->dccg, &dto_params); 171 } 172 } 173 } 174 175 static void dcn35_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr, 176 struct dc_state *context, bool safe_to_lower) 177 { 178 int i; 179 bool dppclk_active[MAX_PIPES] = {0}; 180 181 182 clk_mgr->dccg->ref_dppclk = clk_mgr->base.clks.dppclk_khz; 183 for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) { 184 int dpp_inst = 0, dppclk_khz, prev_dppclk_khz; 185 186 dppclk_khz = context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz; 187 188 if (context->res_ctx.pipe_ctx[i].plane_res.dpp) 189 dpp_inst = context->res_ctx.pipe_ctx[i].plane_res.dpp->inst; 190 else if (!context->res_ctx.pipe_ctx[i].plane_res.dpp && dppclk_khz == 0) { 191 /* dpp == NULL && dppclk_khz == 0 is valid because of pipe harvesting. 192 * In this case just continue in loop 193 */ 194 continue; 195 } else if (!context->res_ctx.pipe_ctx[i].plane_res.dpp && dppclk_khz > 0) { 196 /* The software state is not valid if dpp resource is NULL and 197 * dppclk_khz > 0. 198 */ 199 ASSERT(false); 200 continue; 201 } 202 203 prev_dppclk_khz = clk_mgr->dccg->pipe_dppclk_khz[i]; 204 205 if (safe_to_lower || prev_dppclk_khz < dppclk_khz) 206 clk_mgr->dccg->funcs->update_dpp_dto( 207 clk_mgr->dccg, dpp_inst, dppclk_khz); 208 dppclk_active[dpp_inst] = true; 209 } 210 if (safe_to_lower) 211 for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) { 212 struct dpp *old_dpp = clk_mgr->base.ctx->dc->current_state->res_ctx.pipe_ctx[i].plane_res.dpp; 213 214 if (old_dpp && !dppclk_active[old_dpp->inst]) 215 clk_mgr->dccg->funcs->update_dpp_dto(clk_mgr->dccg, old_dpp->inst, 0); 216 } 217 } 218 219 void dcn35_update_clocks(struct clk_mgr *clk_mgr_base, 220 struct dc_state *context, 221 bool safe_to_lower) 222 { 223 union dmub_rb_cmd cmd; 224 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 225 struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; 226 struct dc *dc = clk_mgr_base->ctx->dc; 227 int display_count; 228 bool update_dppclk = false; 229 bool update_dispclk = false; 230 bool dpp_clock_lowered = false; 231 232 if (dc->work_arounds.skip_clock_update) 233 return; 234 235 /* DTBCLK is fixed, so set a default if unspecified. */ 236 if (new_clocks->dtbclk_en && !new_clocks->ref_dtbclk_khz) 237 new_clocks->ref_dtbclk_khz = 600000; 238 239 /* 240 * if it is safe to lower, but we are already in the lower state, we don't have to do anything 241 * also if safe to lower is false, we just go in the higher state 242 */ 243 if (safe_to_lower) { 244 if (new_clocks->zstate_support != DCN_ZSTATE_SUPPORT_DISALLOW && 245 new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) { 246 dcn35_smu_set_zstate_support(clk_mgr, new_clocks->zstate_support); 247 dm_helpers_enable_periodic_detection(clk_mgr_base->ctx, true); 248 clk_mgr_base->clks.zstate_support = new_clocks->zstate_support; 249 } 250 251 if (clk_mgr_base->clks.dtbclk_en && !new_clocks->dtbclk_en) { 252 dcn35_smu_set_dtbclk(clk_mgr, false); 253 clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en; 254 } 255 /* check that we're not already in lower */ 256 if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) { 257 display_count = dcn35_get_active_display_cnt_wa(dc, context); 258 /* if we can go lower, go lower */ 259 if (display_count == 0) 260 clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER; 261 } 262 } else { 263 if (new_clocks->zstate_support == DCN_ZSTATE_SUPPORT_DISALLOW && 264 new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) { 265 dcn35_smu_set_zstate_support(clk_mgr, DCN_ZSTATE_SUPPORT_DISALLOW); 266 dm_helpers_enable_periodic_detection(clk_mgr_base->ctx, false); 267 clk_mgr_base->clks.zstate_support = new_clocks->zstate_support; 268 } 269 270 if (!clk_mgr_base->clks.dtbclk_en && new_clocks->dtbclk_en) { 271 dcn35_smu_set_dtbclk(clk_mgr, true); 272 clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en; 273 274 dcn35_update_clocks_update_dtb_dto(clk_mgr, context, new_clocks->ref_dtbclk_khz); 275 clk_mgr_base->clks.ref_dtbclk_khz = new_clocks->ref_dtbclk_khz; 276 } 277 278 /* check that we're not already in D0 */ 279 if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_MISSION_MODE) { 280 union display_idle_optimization_u idle_info = { 0 }; 281 282 dcn35_smu_set_display_idle_optimization(clk_mgr, idle_info.data); 283 /* update power state */ 284 clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_MISSION_MODE; 285 } 286 } 287 if (dc->debug.force_min_dcfclk_mhz > 0) 288 new_clocks->dcfclk_khz = (new_clocks->dcfclk_khz > (dc->debug.force_min_dcfclk_mhz * 1000)) ? 289 new_clocks->dcfclk_khz : (dc->debug.force_min_dcfclk_mhz * 1000); 290 291 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) { 292 clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz; 293 dcn35_smu_set_hard_min_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_khz); 294 } 295 296 if (should_set_clock(safe_to_lower, 297 new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) { 298 clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; 299 dcn35_smu_set_min_deep_sleep_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_deep_sleep_khz); 300 } 301 302 // workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow. 303 if (new_clocks->dppclk_khz < 100000) 304 new_clocks->dppclk_khz = 100000; 305 306 if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) { 307 if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz) 308 dpp_clock_lowered = true; 309 clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz; 310 update_dppclk = true; 311 } 312 313 if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { 314 dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, true); 315 316 clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; 317 dcn35_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); 318 dcn35_disable_otg_wa(clk_mgr_base, context, safe_to_lower, false); 319 320 update_dispclk = true; 321 } 322 323 /* clock limits are received with MHz precision, divide by 1000 to prevent setting clocks at every call */ 324 if (!dc->debug.disable_dtb_ref_clk_switch && 325 should_set_clock(safe_to_lower, new_clocks->ref_dtbclk_khz / 1000, 326 clk_mgr_base->clks.ref_dtbclk_khz / 1000)) { 327 dcn35_update_clocks_update_dtb_dto(clk_mgr, context, new_clocks->ref_dtbclk_khz); 328 clk_mgr_base->clks.ref_dtbclk_khz = new_clocks->ref_dtbclk_khz; 329 } 330 331 if (dpp_clock_lowered) { 332 // increase per DPP DTO before lowering global dppclk 333 dcn35_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); 334 dcn35_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz); 335 } else { 336 // increase global DPPCLK before lowering per DPP DTO 337 if (update_dppclk || update_dispclk) 338 dcn35_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz); 339 dcn35_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); 340 } 341 342 // notify DMCUB of latest clocks 343 memset(&cmd, 0, sizeof(cmd)); 344 cmd.notify_clocks.header.type = DMUB_CMD__CLK_MGR; 345 cmd.notify_clocks.header.sub_type = DMUB_CMD__CLK_MGR_NOTIFY_CLOCKS; 346 cmd.notify_clocks.clocks.dcfclk_khz = clk_mgr_base->clks.dcfclk_khz; 347 cmd.notify_clocks.clocks.dcfclk_deep_sleep_khz = 348 clk_mgr_base->clks.dcfclk_deep_sleep_khz; 349 cmd.notify_clocks.clocks.dispclk_khz = clk_mgr_base->clks.dispclk_khz; 350 cmd.notify_clocks.clocks.dppclk_khz = clk_mgr_base->clks.dppclk_khz; 351 352 dm_execute_dmub_cmd(dc->ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); 353 } 354 355 static int get_vco_frequency_from_reg(struct clk_mgr_internal *clk_mgr) 356 { 357 /* get FbMult value */ 358 struct fixed31_32 pll_req; 359 unsigned int fbmult_frac_val = 0; 360 unsigned int fbmult_int_val = 0; 361 struct dc_context *ctx = clk_mgr->base.ctx; 362 363 /* 364 * Register value of fbmult is in 8.16 format, we are converting to 314.32 365 * to leverage the fix point operations available in driver 366 */ 367 368 REG_GET(CLK1_CLK_PLL_REQ, FbMult_frac, &fbmult_frac_val); /* 16 bit fractional part*/ 369 REG_GET(CLK1_CLK_PLL_REQ, FbMult_int, &fbmult_int_val); /* 8 bit integer part */ 370 371 pll_req = dc_fixpt_from_int(fbmult_int_val); 372 373 /* 374 * since fractional part is only 16 bit in register definition but is 32 bit 375 * in our fix point definiton, need to shift left by 16 to obtain correct value 376 */ 377 pll_req.value |= fbmult_frac_val << 16; 378 379 /* multiply by REFCLK period */ 380 pll_req = dc_fixpt_mul_int(pll_req, clk_mgr->dfs_ref_freq_khz); 381 382 /* integer part is now VCO frequency in kHz */ 383 return dc_fixpt_floor(pll_req); 384 } 385 386 static void dcn35_enable_pme_wa(struct clk_mgr *clk_mgr_base) 387 { 388 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 389 390 dcn35_smu_enable_pme_wa(clk_mgr); 391 } 392 393 void dcn35_init_clocks(struct clk_mgr *clk_mgr) 394 { 395 uint32_t ref_dtbclk = clk_mgr->clks.ref_dtbclk_khz; 396 397 memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks)); 398 399 // Assumption is that boot state always supports pstate 400 clk_mgr->clks.ref_dtbclk_khz = ref_dtbclk; // restore ref_dtbclk 401 clk_mgr->clks.p_state_change_support = true; 402 clk_mgr->clks.prev_p_state_change_support = true; 403 clk_mgr->clks.pwr_state = DCN_PWR_STATE_UNKNOWN; 404 clk_mgr->clks.zstate_support = DCN_ZSTATE_SUPPORT_UNKNOWN; 405 } 406 407 bool dcn35_are_clock_states_equal(struct dc_clocks *a, 408 struct dc_clocks *b) 409 { 410 if (a->dispclk_khz != b->dispclk_khz) 411 return false; 412 else if (a->dppclk_khz != b->dppclk_khz) 413 return false; 414 else if (a->dcfclk_khz != b->dcfclk_khz) 415 return false; 416 else if (a->dcfclk_deep_sleep_khz != b->dcfclk_deep_sleep_khz) 417 return false; 418 else if (a->zstate_support != b->zstate_support) 419 return false; 420 else if (a->dtbclk_en != b->dtbclk_en) 421 return false; 422 423 return true; 424 } 425 426 static void dcn35_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass, 427 struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info) 428 { 429 430 } 431 432 static struct clk_bw_params dcn35_bw_params = { 433 .vram_type = Ddr4MemType, 434 .num_channels = 1, 435 .clk_table = { 436 .num_entries = 4, 437 }, 438 439 }; 440 441 static struct wm_table ddr5_wm_table = { 442 .entries = { 443 { 444 .wm_inst = WM_A, 445 .wm_type = WM_TYPE_PSTATE_CHG, 446 .pstate_latency_us = 11.72, 447 .sr_exit_time_us = 14.0, 448 .sr_enter_plus_exit_time_us = 16.0, 449 .valid = true, 450 }, 451 { 452 .wm_inst = WM_B, 453 .wm_type = WM_TYPE_PSTATE_CHG, 454 .pstate_latency_us = 11.72, 455 .sr_exit_time_us = 14.0, 456 .sr_enter_plus_exit_time_us = 16.0, 457 .valid = true, 458 }, 459 { 460 .wm_inst = WM_C, 461 .wm_type = WM_TYPE_PSTATE_CHG, 462 .pstate_latency_us = 11.72, 463 .sr_exit_time_us = 14.0, 464 .sr_enter_plus_exit_time_us = 16.0, 465 .valid = true, 466 }, 467 { 468 .wm_inst = WM_D, 469 .wm_type = WM_TYPE_PSTATE_CHG, 470 .pstate_latency_us = 11.72, 471 .sr_exit_time_us = 14.0, 472 .sr_enter_plus_exit_time_us = 16.0, 473 .valid = true, 474 }, 475 } 476 }; 477 478 static struct wm_table lpddr5_wm_table = { 479 .entries = { 480 { 481 .wm_inst = WM_A, 482 .wm_type = WM_TYPE_PSTATE_CHG, 483 .pstate_latency_us = 11.65333, 484 .sr_exit_time_us = 14.0, 485 .sr_enter_plus_exit_time_us = 16.0, 486 .valid = true, 487 }, 488 { 489 .wm_inst = WM_B, 490 .wm_type = WM_TYPE_PSTATE_CHG, 491 .pstate_latency_us = 11.65333, 492 .sr_exit_time_us = 14.0, 493 .sr_enter_plus_exit_time_us = 16.0, 494 .valid = true, 495 }, 496 { 497 .wm_inst = WM_C, 498 .wm_type = WM_TYPE_PSTATE_CHG, 499 .pstate_latency_us = 11.65333, 500 .sr_exit_time_us = 14.0, 501 .sr_enter_plus_exit_time_us = 16.0, 502 .valid = true, 503 }, 504 { 505 .wm_inst = WM_D, 506 .wm_type = WM_TYPE_PSTATE_CHG, 507 .pstate_latency_us = 11.65333, 508 .sr_exit_time_us = 14.0, 509 .sr_enter_plus_exit_time_us = 16.0, 510 .valid = true, 511 }, 512 } 513 }; 514 515 static DpmClocks_t_dcn35 dummy_clocks; 516 517 static struct dcn35_watermarks dummy_wms = { 0 }; 518 519 static void dcn35_build_watermark_ranges(struct clk_bw_params *bw_params, struct dcn35_watermarks *table) 520 { 521 int i, num_valid_sets; 522 523 num_valid_sets = 0; 524 525 for (i = 0; i < WM_SET_COUNT; i++) { 526 /* skip empty entries, the smu array has no holes*/ 527 if (!bw_params->wm_table.entries[i].valid) 528 continue; 529 530 table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmSetting = bw_params->wm_table.entries[i].wm_inst; 531 table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType = bw_params->wm_table.entries[i].wm_type; 532 /* We will not select WM based on fclk, so leave it as unconstrained */ 533 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0; 534 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF; 535 536 if (table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType == WM_TYPE_PSTATE_CHG) { 537 if (i == 0) 538 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk = 0; 539 else { 540 /* add 1 to make it non-overlapping with next lvl */ 541 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk = 542 bw_params->clk_table.entries[i - 1].dcfclk_mhz + 1; 543 } 544 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxMclk = 545 bw_params->clk_table.entries[i].dcfclk_mhz; 546 547 } else { 548 /* unconstrained for memory retraining */ 549 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0; 550 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF; 551 552 /* Modify previous watermark range to cover up to max */ 553 table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF; 554 } 555 num_valid_sets++; 556 } 557 558 ASSERT(num_valid_sets != 0); /* Must have at least one set of valid watermarks */ 559 560 /* modify the min and max to make sure we cover the whole range*/ 561 table->WatermarkRow[WM_DCFCLK][0].MinMclk = 0; 562 table->WatermarkRow[WM_DCFCLK][0].MinClock = 0; 563 table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxMclk = 0xFFFF; 564 table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF; 565 566 /* This is for writeback only, does not matter currently as no writeback support*/ 567 table->WatermarkRow[WM_SOCCLK][0].WmSetting = WM_A; 568 table->WatermarkRow[WM_SOCCLK][0].MinClock = 0; 569 table->WatermarkRow[WM_SOCCLK][0].MaxClock = 0xFFFF; 570 table->WatermarkRow[WM_SOCCLK][0].MinMclk = 0; 571 table->WatermarkRow[WM_SOCCLK][0].MaxMclk = 0xFFFF; 572 } 573 574 static void dcn35_notify_wm_ranges(struct clk_mgr *clk_mgr_base) 575 { 576 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 577 struct clk_mgr_dcn35 *clk_mgr_dcn35 = TO_CLK_MGR_DCN35(clk_mgr); 578 struct dcn35_watermarks *table = clk_mgr_dcn35->smu_wm_set.wm_set; 579 580 if (!clk_mgr->smu_ver) 581 return; 582 583 if (!table || clk_mgr_dcn35->smu_wm_set.mc_address.quad_part == 0) 584 return; 585 586 memset(table, 0, sizeof(*table)); 587 588 dcn35_build_watermark_ranges(clk_mgr_base->bw_params, table); 589 590 dcn35_smu_set_dram_addr_high(clk_mgr, 591 clk_mgr_dcn35->smu_wm_set.mc_address.high_part); 592 dcn35_smu_set_dram_addr_low(clk_mgr, 593 clk_mgr_dcn35->smu_wm_set.mc_address.low_part); 594 dcn35_smu_transfer_wm_table_dram_2_smu(clk_mgr); 595 } 596 597 static void dcn35_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr, 598 struct dcn35_smu_dpm_clks *smu_dpm_clks) 599 { 600 DpmClocks_t_dcn35 *table = smu_dpm_clks->dpm_clks; 601 602 if (!clk_mgr->smu_ver) 603 return; 604 605 if (!table || smu_dpm_clks->mc_address.quad_part == 0) 606 return; 607 608 memset(table, 0, sizeof(*table)); 609 610 dcn35_smu_set_dram_addr_high(clk_mgr, 611 smu_dpm_clks->mc_address.high_part); 612 dcn35_smu_set_dram_addr_low(clk_mgr, 613 smu_dpm_clks->mc_address.low_part); 614 dcn35_smu_transfer_dpm_table_smu_2_dram(clk_mgr); 615 } 616 617 static uint32_t find_max_clk_value(const uint32_t clocks[], uint32_t num_clocks) 618 { 619 uint32_t max = 0; 620 int i; 621 622 for (i = 0; i < num_clocks; ++i) { 623 if (clocks[i] > max) 624 max = clocks[i]; 625 } 626 627 return max; 628 } 629 630 static inline bool is_valid_clock_value(uint32_t clock_value) 631 { 632 return clock_value > 1 && clock_value < 100000; 633 } 634 635 static unsigned int convert_wck_ratio(uint8_t wck_ratio) 636 { 637 switch (wck_ratio) { 638 case WCK_RATIO_1_2: 639 return 2; 640 641 case WCK_RATIO_1_4: 642 return 4; 643 /* Find lowest DPM, FCLK is filled in reverse order*/ 644 645 default: 646 break; 647 } 648 649 return 1; 650 } 651 652 static inline uint32_t calc_dram_speed_mts(const MemPstateTable_t *entry) 653 { 654 return entry->UClk * convert_wck_ratio(entry->WckRatio) * 2; 655 } 656 657 static void dcn35_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk_mgr, 658 struct integrated_info *bios_info, 659 DpmClocks_t_dcn35 *clock_table) 660 { 661 struct clk_bw_params *bw_params = clk_mgr->base.bw_params; 662 struct clk_limit_table_entry def_max = bw_params->clk_table.entries[bw_params->clk_table.num_entries - 1]; 663 uint32_t max_fclk = 0, min_pstate = 0, max_dispclk = 0, max_dppclk = 0; 664 uint32_t max_pstate = 0, max_dram_speed_mts = 0, min_dram_speed_mts = 0; 665 int i; 666 667 /* Determine min/max p-state values. */ 668 for (i = 0; i < clock_table->NumMemPstatesEnabled; i++) { 669 uint32_t dram_speed_mts = calc_dram_speed_mts(&clock_table->MemPstateTable[i]); 670 671 if (is_valid_clock_value(dram_speed_mts) && dram_speed_mts > max_dram_speed_mts) { 672 max_dram_speed_mts = dram_speed_mts; 673 max_pstate = i; 674 } 675 } 676 677 min_dram_speed_mts = max_dram_speed_mts; 678 min_pstate = max_pstate; 679 680 for (i = 0; i < clock_table->NumMemPstatesEnabled; i++) { 681 uint32_t dram_speed_mts = calc_dram_speed_mts(&clock_table->MemPstateTable[i]); 682 683 if (is_valid_clock_value(dram_speed_mts) && dram_speed_mts < min_dram_speed_mts) { 684 min_dram_speed_mts = dram_speed_mts; 685 min_pstate = i; 686 } 687 } 688 689 /* We expect the table to contain at least one valid P-state entry. */ 690 ASSERT(clock_table->NumMemPstatesEnabled && 691 is_valid_clock_value(max_dram_speed_mts) && 692 is_valid_clock_value(min_dram_speed_mts)); 693 694 /* dispclk and dppclk can be max at any voltage, same number of levels for both */ 695 if (clock_table->NumDispClkLevelsEnabled <= NUM_DISPCLK_DPM_LEVELS && 696 clock_table->NumDispClkLevelsEnabled <= NUM_DPPCLK_DPM_LEVELS) { 697 max_dispclk = find_max_clk_value(clock_table->DispClocks, 698 clock_table->NumDispClkLevelsEnabled); 699 max_dppclk = find_max_clk_value(clock_table->DppClocks, 700 clock_table->NumDispClkLevelsEnabled); 701 } else { 702 /* Invalid number of entries in the table from PMFW. */ 703 ASSERT(0); 704 } 705 706 /* Base the clock table on dcfclk, need at least one entry regardless of pmfw table */ 707 ASSERT(clock_table->NumDcfClkLevelsEnabled > 0); 708 709 max_fclk = find_max_clk_value(clock_table->FclkClocks_Freq, clock_table->NumFclkLevelsEnabled); 710 711 for (i = 0; i < clock_table->NumDcfClkLevelsEnabled; i++) { 712 int j; 713 714 /* First search defaults for the clocks we don't read using closest lower or equal default dcfclk */ 715 for (j = bw_params->clk_table.num_entries - 1; j > 0; j--) 716 if (bw_params->clk_table.entries[j].dcfclk_mhz <= clock_table->DcfClocks[i]) 717 break; 718 719 bw_params->clk_table.entries[i].phyclk_mhz = bw_params->clk_table.entries[j].phyclk_mhz; 720 bw_params->clk_table.entries[i].phyclk_d18_mhz = bw_params->clk_table.entries[j].phyclk_d18_mhz; 721 bw_params->clk_table.entries[i].dtbclk_mhz = bw_params->clk_table.entries[j].dtbclk_mhz; 722 723 /* Now update clocks we do read */ 724 bw_params->clk_table.entries[i].memclk_mhz = clock_table->MemPstateTable[min_pstate].MemClk; 725 bw_params->clk_table.entries[i].voltage = clock_table->MemPstateTable[min_pstate].Voltage; 726 bw_params->clk_table.entries[i].dcfclk_mhz = clock_table->DcfClocks[i]; 727 bw_params->clk_table.entries[i].socclk_mhz = clock_table->SocClocks[i]; 728 bw_params->clk_table.entries[i].dispclk_mhz = max_dispclk; 729 bw_params->clk_table.entries[i].dppclk_mhz = max_dppclk; 730 bw_params->clk_table.entries[i].wck_ratio = 731 convert_wck_ratio(clock_table->MemPstateTable[min_pstate].WckRatio); 732 733 /* Dcfclk and Fclk are tied, but at a different ratio */ 734 bw_params->clk_table.entries[i].fclk_mhz = min(max_fclk, 2 * clock_table->DcfClocks[i]); 735 } 736 737 /* Make sure to include at least one entry at highest pstate */ 738 if (max_pstate != min_pstate || i == 0) { 739 if (i > MAX_NUM_DPM_LVL - 1) 740 i = MAX_NUM_DPM_LVL - 1; 741 742 bw_params->clk_table.entries[i].fclk_mhz = max_fclk; 743 bw_params->clk_table.entries[i].memclk_mhz = clock_table->MemPstateTable[max_pstate].MemClk; 744 bw_params->clk_table.entries[i].voltage = clock_table->MemPstateTable[max_pstate].Voltage; 745 bw_params->clk_table.entries[i].dcfclk_mhz = 746 find_max_clk_value(clock_table->DcfClocks, NUM_DCFCLK_DPM_LEVELS); 747 bw_params->clk_table.entries[i].socclk_mhz = 748 find_max_clk_value(clock_table->SocClocks, NUM_SOCCLK_DPM_LEVELS); 749 bw_params->clk_table.entries[i].dispclk_mhz = max_dispclk; 750 bw_params->clk_table.entries[i].dppclk_mhz = max_dppclk; 751 bw_params->clk_table.entries[i].wck_ratio = convert_wck_ratio( 752 clock_table->MemPstateTable[max_pstate].WckRatio); 753 i++; 754 } 755 bw_params->clk_table.num_entries = i--; 756 757 /* Make sure all highest clocks are included*/ 758 bw_params->clk_table.entries[i].socclk_mhz = 759 find_max_clk_value(clock_table->SocClocks, NUM_SOCCLK_DPM_LEVELS); 760 bw_params->clk_table.entries[i].dispclk_mhz = 761 find_max_clk_value(clock_table->DispClocks, NUM_DISPCLK_DPM_LEVELS); 762 bw_params->clk_table.entries[i].dppclk_mhz = 763 find_max_clk_value(clock_table->DppClocks, NUM_DPPCLK_DPM_LEVELS); 764 bw_params->clk_table.entries[i].fclk_mhz = 765 find_max_clk_value(clock_table->FclkClocks_Freq, NUM_FCLK_DPM_LEVELS); 766 ASSERT(clock_table->DcfClocks[i] == find_max_clk_value(clock_table->DcfClocks, NUM_DCFCLK_DPM_LEVELS)); 767 bw_params->clk_table.entries[i].phyclk_mhz = def_max.phyclk_mhz; 768 bw_params->clk_table.entries[i].phyclk_d18_mhz = def_max.phyclk_d18_mhz; 769 bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz; 770 bw_params->clk_table.num_entries_per_clk.num_dcfclk_levels = clock_table->NumDcfClkLevelsEnabled; 771 bw_params->clk_table.num_entries_per_clk.num_dispclk_levels = clock_table->NumDispClkLevelsEnabled; 772 bw_params->clk_table.num_entries_per_clk.num_dppclk_levels = clock_table->NumDispClkLevelsEnabled; 773 bw_params->clk_table.num_entries_per_clk.num_fclk_levels = clock_table->NumFclkLevelsEnabled; 774 bw_params->clk_table.num_entries_per_clk.num_memclk_levels = clock_table->NumMemPstatesEnabled; 775 bw_params->clk_table.num_entries_per_clk.num_socclk_levels = clock_table->NumSocClkLevelsEnabled; 776 777 /* 778 * Set any 0 clocks to max default setting. Not an issue for 779 * power since we aren't doing switching in such case anyway 780 */ 781 for (i = 0; i < bw_params->clk_table.num_entries; i++) { 782 if (!bw_params->clk_table.entries[i].fclk_mhz) { 783 bw_params->clk_table.entries[i].fclk_mhz = def_max.fclk_mhz; 784 bw_params->clk_table.entries[i].memclk_mhz = def_max.memclk_mhz; 785 bw_params->clk_table.entries[i].voltage = def_max.voltage; 786 } 787 if (!bw_params->clk_table.entries[i].dcfclk_mhz) 788 bw_params->clk_table.entries[i].dcfclk_mhz = def_max.dcfclk_mhz; 789 if (!bw_params->clk_table.entries[i].socclk_mhz) 790 bw_params->clk_table.entries[i].socclk_mhz = def_max.socclk_mhz; 791 if (!bw_params->clk_table.entries[i].dispclk_mhz) 792 bw_params->clk_table.entries[i].dispclk_mhz = def_max.dispclk_mhz; 793 if (!bw_params->clk_table.entries[i].dppclk_mhz) 794 bw_params->clk_table.entries[i].dppclk_mhz = def_max.dppclk_mhz; 795 if (!bw_params->clk_table.entries[i].fclk_mhz) 796 bw_params->clk_table.entries[i].fclk_mhz = def_max.fclk_mhz; 797 if (!bw_params->clk_table.entries[i].phyclk_mhz) 798 bw_params->clk_table.entries[i].phyclk_mhz = def_max.phyclk_mhz; 799 if (!bw_params->clk_table.entries[i].phyclk_d18_mhz) 800 bw_params->clk_table.entries[i].phyclk_d18_mhz = def_max.phyclk_d18_mhz; 801 if (!bw_params->clk_table.entries[i].dtbclk_mhz) 802 bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz; 803 } 804 ASSERT(bw_params->clk_table.entries[i-1].dcfclk_mhz); 805 bw_params->vram_type = bios_info->memory_type; 806 bw_params->dram_channel_width_bytes = bios_info->memory_type == 0x22 ? 8 : 4; 807 bw_params->num_channels = bios_info->ma_channel_number ? bios_info->ma_channel_number : 4; 808 809 for (i = 0; i < WM_SET_COUNT; i++) { 810 bw_params->wm_table.entries[i].wm_inst = i; 811 812 if (i >= bw_params->clk_table.num_entries) { 813 bw_params->wm_table.entries[i].valid = false; 814 continue; 815 } 816 817 bw_params->wm_table.entries[i].wm_type = WM_TYPE_PSTATE_CHG; 818 bw_params->wm_table.entries[i].valid = true; 819 } 820 } 821 822 static void dcn35_set_low_power_state(struct clk_mgr *clk_mgr_base) 823 { 824 int display_count; 825 struct dc *dc = clk_mgr_base->ctx->dc; 826 struct dc_state *context = dc->current_state; 827 828 if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) { 829 display_count = dcn35_get_active_display_cnt_wa(dc, context); 830 /* if we can go lower, go lower */ 831 if (display_count == 0) 832 clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER; 833 } 834 } 835 836 static void dcn35_set_idle_state(struct clk_mgr *clk_mgr_base, bool allow_idle) 837 { 838 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 839 struct dc *dc = clk_mgr_base->ctx->dc; 840 uint32_t val = dcn35_smu_read_ips_scratch(clk_mgr); 841 842 if (dc->config.disable_ips == DMUB_IPS_ENABLE || 843 dc->config.disable_ips == DMUB_IPS_DISABLE_DYNAMIC) { 844 val = val & ~DMUB_IPS1_ALLOW_MASK; 845 val = val & ~DMUB_IPS2_ALLOW_MASK; 846 } else if (dc->config.disable_ips == DMUB_IPS_DISABLE_IPS1) { 847 val |= DMUB_IPS1_ALLOW_MASK; 848 val |= DMUB_IPS2_ALLOW_MASK; 849 } else if (dc->config.disable_ips == DMUB_IPS_DISABLE_IPS2) { 850 val = val & ~DMUB_IPS1_ALLOW_MASK; 851 val |= DMUB_IPS2_ALLOW_MASK; 852 } else if (dc->config.disable_ips == DMUB_IPS_DISABLE_IPS2_Z10) { 853 val = val & ~DMUB_IPS1_ALLOW_MASK; 854 val = val & ~DMUB_IPS2_ALLOW_MASK; 855 } 856 857 if (!allow_idle) { 858 val |= DMUB_IPS1_ALLOW_MASK; 859 val |= DMUB_IPS2_ALLOW_MASK; 860 } 861 862 dcn35_smu_write_ips_scratch(clk_mgr, val); 863 } 864 865 static void dcn35_exit_low_power_state(struct clk_mgr *clk_mgr_base) 866 { 867 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 868 869 //SMU optimization is performed part of low power state exit. 870 dcn35_smu_exit_low_power_state(clk_mgr); 871 872 } 873 874 static bool dcn35_is_ips_supported(struct clk_mgr *clk_mgr_base) 875 { 876 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 877 bool ips_supported = true; 878 879 ips_supported = dcn35_smu_get_ips_supported(clk_mgr) ? true : false; 880 881 return ips_supported; 882 } 883 884 static uint32_t dcn35_get_idle_state(struct clk_mgr *clk_mgr_base) 885 { 886 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 887 888 return dcn35_smu_read_ips_scratch(clk_mgr); 889 } 890 891 static void dcn35_init_clocks_fpga(struct clk_mgr *clk_mgr) 892 { 893 dcn35_init_clocks(clk_mgr); 894 895 /* TODO: Implement the functions and remove the ifndef guard */ 896 } 897 898 static void dcn35_update_clocks_fpga(struct clk_mgr *clk_mgr, 899 struct dc_state *context, 900 bool safe_to_lower) 901 { 902 struct clk_mgr_internal *clk_mgr_int = TO_CLK_MGR_INTERNAL(clk_mgr); 903 struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; 904 int fclk_adj = new_clocks->fclk_khz; 905 906 /* TODO: remove this after correctly set by DML */ 907 new_clocks->dcfclk_khz = 400000; 908 new_clocks->socclk_khz = 400000; 909 910 /* Min fclk = 1.2GHz since all the extra scemi logic seems to run off of it */ 911 //int fclk_adj = new_clocks->fclk_khz > 1200000 ? new_clocks->fclk_khz : 1200000; 912 new_clocks->fclk_khz = 4320000; 913 914 if (should_set_clock(safe_to_lower, new_clocks->phyclk_khz, clk_mgr->clks.phyclk_khz)) { 915 clk_mgr->clks.phyclk_khz = new_clocks->phyclk_khz; 916 } 917 918 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr->clks.dcfclk_khz)) { 919 clk_mgr->clks.dcfclk_khz = new_clocks->dcfclk_khz; 920 } 921 922 if (should_set_clock(safe_to_lower, 923 new_clocks->dcfclk_deep_sleep_khz, clk_mgr->clks.dcfclk_deep_sleep_khz)) { 924 clk_mgr->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; 925 } 926 927 if (should_set_clock(safe_to_lower, new_clocks->socclk_khz, clk_mgr->clks.socclk_khz)) { 928 clk_mgr->clks.socclk_khz = new_clocks->socclk_khz; 929 } 930 931 if (should_set_clock(safe_to_lower, new_clocks->dramclk_khz, clk_mgr->clks.dramclk_khz)) { 932 clk_mgr->clks.dramclk_khz = new_clocks->dramclk_khz; 933 } 934 935 if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->clks.dppclk_khz)) { 936 clk_mgr->clks.dppclk_khz = new_clocks->dppclk_khz; 937 } 938 939 if (should_set_clock(safe_to_lower, fclk_adj, clk_mgr->clks.fclk_khz)) { 940 clk_mgr->clks.fclk_khz = fclk_adj; 941 } 942 943 if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr->clks.dispclk_khz)) { 944 clk_mgr->clks.dispclk_khz = new_clocks->dispclk_khz; 945 } 946 947 /* Both fclk and ref_dppclk run on the same scemi clock. 948 * So take the higher value since the DPP DTO is typically programmed 949 * such that max dppclk is 1:1 with ref_dppclk. 950 */ 951 if (clk_mgr->clks.fclk_khz > clk_mgr->clks.dppclk_khz) 952 clk_mgr->clks.dppclk_khz = clk_mgr->clks.fclk_khz; 953 if (clk_mgr->clks.dppclk_khz > clk_mgr->clks.fclk_khz) 954 clk_mgr->clks.fclk_khz = clk_mgr->clks.dppclk_khz; 955 956 // Both fclk and ref_dppclk run on the same scemi clock. 957 clk_mgr_int->dccg->ref_dppclk = clk_mgr->clks.fclk_khz; 958 959 /* TODO: set dtbclk in correct place */ 960 clk_mgr->clks.dtbclk_en = true; 961 dm_set_dcn_clocks(clk_mgr->ctx, &clk_mgr->clks); 962 dcn35_update_clocks_update_dpp_dto(clk_mgr_int, context, safe_to_lower); 963 964 dcn35_update_clocks_update_dtb_dto(clk_mgr_int, context, clk_mgr->clks.ref_dtbclk_khz); 965 } 966 967 static struct clk_mgr_funcs dcn35_funcs = { 968 .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, 969 .get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz, 970 .update_clocks = dcn35_update_clocks, 971 .init_clocks = dcn35_init_clocks, 972 .enable_pme_wa = dcn35_enable_pme_wa, 973 .are_clock_states_equal = dcn35_are_clock_states_equal, 974 .notify_wm_ranges = dcn35_notify_wm_ranges, 975 .set_low_power_state = dcn35_set_low_power_state, 976 .exit_low_power_state = dcn35_exit_low_power_state, 977 .is_ips_supported = dcn35_is_ips_supported, 978 .set_idle_state = dcn35_set_idle_state, 979 .get_idle_state = dcn35_get_idle_state 980 }; 981 982 struct clk_mgr_funcs dcn35_fpga_funcs = { 983 .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, 984 .update_clocks = dcn35_update_clocks_fpga, 985 .init_clocks = dcn35_init_clocks_fpga, 986 .get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz, 987 }; 988 989 void dcn35_clk_mgr_construct( 990 struct dc_context *ctx, 991 struct clk_mgr_dcn35 *clk_mgr, 992 struct pp_smu_funcs *pp_smu, 993 struct dccg *dccg) 994 { 995 struct dcn35_smu_dpm_clks smu_dpm_clks = { 0 }; 996 struct clk_log_info log_info = {0}; 997 clk_mgr->base.base.ctx = ctx; 998 clk_mgr->base.base.funcs = &dcn35_funcs; 999 1000 clk_mgr->base.pp_smu = pp_smu; 1001 1002 clk_mgr->base.dccg = dccg; 1003 clk_mgr->base.dfs_bypass_disp_clk = 0; 1004 1005 clk_mgr->base.dprefclk_ss_percentage = 0; 1006 clk_mgr->base.dprefclk_ss_divider = 1000; 1007 clk_mgr->base.ss_on_dprefclk = false; 1008 clk_mgr->base.dfs_ref_freq_khz = 48000; 1009 1010 clk_mgr->smu_wm_set.wm_set = (struct dcn35_watermarks *)dm_helpers_allocate_gpu_mem( 1011 clk_mgr->base.base.ctx, 1012 DC_MEM_ALLOC_TYPE_FRAME_BUFFER, 1013 sizeof(struct dcn35_watermarks), 1014 &clk_mgr->smu_wm_set.mc_address.quad_part); 1015 1016 if (!clk_mgr->smu_wm_set.wm_set) { 1017 clk_mgr->smu_wm_set.wm_set = &dummy_wms; 1018 clk_mgr->smu_wm_set.mc_address.quad_part = 0; 1019 } 1020 ASSERT(clk_mgr->smu_wm_set.wm_set); 1021 1022 smu_dpm_clks.dpm_clks = (DpmClocks_t_dcn35 *)dm_helpers_allocate_gpu_mem( 1023 clk_mgr->base.base.ctx, 1024 DC_MEM_ALLOC_TYPE_FRAME_BUFFER, 1025 sizeof(DpmClocks_t_dcn35), 1026 &smu_dpm_clks.mc_address.quad_part); 1027 1028 if (smu_dpm_clks.dpm_clks == NULL) { 1029 smu_dpm_clks.dpm_clks = &dummy_clocks; 1030 smu_dpm_clks.mc_address.quad_part = 0; 1031 } 1032 1033 ASSERT(smu_dpm_clks.dpm_clks); 1034 1035 clk_mgr->base.smu_ver = dcn35_smu_get_smu_version(&clk_mgr->base); 1036 1037 if (clk_mgr->base.smu_ver) 1038 clk_mgr->base.smu_present = true; 1039 1040 /* TODO: Check we get what we expect during bringup */ 1041 clk_mgr->base.base.dentist_vco_freq_khz = get_vco_frequency_from_reg(&clk_mgr->base); 1042 1043 if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType) { 1044 dcn35_bw_params.wm_table = lpddr5_wm_table; 1045 } else { 1046 dcn35_bw_params.wm_table = ddr5_wm_table; 1047 } 1048 /* Saved clocks configured at boot for debug purposes */ 1049 dcn35_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, &clk_mgr->base.base, &log_info); 1050 1051 clk_mgr->base.base.dprefclk_khz = dcn35_smu_get_dprefclk(&clk_mgr->base); 1052 clk_mgr->base.base.clks.ref_dtbclk_khz = 600000; 1053 1054 dce_clock_read_ss_info(&clk_mgr->base); 1055 /*when clk src is from FCH, it could have ss, same clock src as DPREF clk*/ 1056 1057 clk_mgr->base.base.bw_params = &dcn35_bw_params; 1058 1059 if (clk_mgr->base.base.ctx->dc->debug.pstate_enabled) { 1060 int i; 1061 dcn35_get_dpm_table_from_smu(&clk_mgr->base, &smu_dpm_clks); 1062 DC_LOG_SMU("NumDcfClkLevelsEnabled: %d\n" 1063 "NumDispClkLevelsEnabled: %d\n" 1064 "NumSocClkLevelsEnabled: %d\n" 1065 "VcnClkLevelsEnabled: %d\n" 1066 "FClkLevelsEnabled: %d\n" 1067 "NumMemPstatesEnabled: %d\n" 1068 "MinGfxClk: %d\n" 1069 "MaxGfxClk: %d\n", 1070 smu_dpm_clks.dpm_clks->NumDcfClkLevelsEnabled, 1071 smu_dpm_clks.dpm_clks->NumDispClkLevelsEnabled, 1072 smu_dpm_clks.dpm_clks->NumSocClkLevelsEnabled, 1073 smu_dpm_clks.dpm_clks->VcnClkLevelsEnabled, 1074 smu_dpm_clks.dpm_clks->NumFclkLevelsEnabled, 1075 smu_dpm_clks.dpm_clks->NumMemPstatesEnabled, 1076 smu_dpm_clks.dpm_clks->MinGfxClk, 1077 smu_dpm_clks.dpm_clks->MaxGfxClk); 1078 for (i = 0; i < smu_dpm_clks.dpm_clks->NumDcfClkLevelsEnabled; i++) { 1079 DC_LOG_SMU("smu_dpm_clks.dpm_clks->DcfClocks[%d] = %d\n", 1080 i, 1081 smu_dpm_clks.dpm_clks->DcfClocks[i]); 1082 } 1083 for (i = 0; i < smu_dpm_clks.dpm_clks->NumDispClkLevelsEnabled; i++) { 1084 DC_LOG_SMU("smu_dpm_clks.dpm_clks->DispClocks[%d] = %d\n", 1085 i, smu_dpm_clks.dpm_clks->DispClocks[i]); 1086 } 1087 for (i = 0; i < smu_dpm_clks.dpm_clks->NumSocClkLevelsEnabled; i++) { 1088 DC_LOG_SMU("smu_dpm_clks.dpm_clks->SocClocks[%d] = %d\n", 1089 i, smu_dpm_clks.dpm_clks->SocClocks[i]); 1090 } 1091 for (i = 0; i < smu_dpm_clks.dpm_clks->NumFclkLevelsEnabled; i++) { 1092 DC_LOG_SMU("smu_dpm_clks.dpm_clks->FclkClocks_Freq[%d] = %d\n", 1093 i, smu_dpm_clks.dpm_clks->FclkClocks_Freq[i]); 1094 DC_LOG_SMU("smu_dpm_clks.dpm_clks->FclkClocks_Voltage[%d] = %d\n", 1095 i, smu_dpm_clks.dpm_clks->FclkClocks_Voltage[i]); 1096 } 1097 for (i = 0; i < smu_dpm_clks.dpm_clks->NumSocClkLevelsEnabled; i++) 1098 DC_LOG_SMU("smu_dpm_clks.dpm_clks->SocVoltage[%d] = %d\n", 1099 i, smu_dpm_clks.dpm_clks->SocVoltage[i]); 1100 1101 for (i = 0; i < smu_dpm_clks.dpm_clks->NumMemPstatesEnabled; i++) { 1102 DC_LOG_SMU("smu_dpm_clks.dpm_clks.MemPstateTable[%d].UClk = %d\n" 1103 "smu_dpm_clks.dpm_clks->MemPstateTable[%d].MemClk= %d\n" 1104 "smu_dpm_clks.dpm_clks->MemPstateTable[%d].Voltage = %d\n", 1105 i, smu_dpm_clks.dpm_clks->MemPstateTable[i].UClk, 1106 i, smu_dpm_clks.dpm_clks->MemPstateTable[i].MemClk, 1107 i, smu_dpm_clks.dpm_clks->MemPstateTable[i].Voltage); 1108 } 1109 1110 if (ctx->dc_bios && ctx->dc_bios->integrated_info && ctx->dc->config.use_default_clock_table == false) { 1111 dcn35_clk_mgr_helper_populate_bw_params( 1112 &clk_mgr->base, 1113 ctx->dc_bios->integrated_info, 1114 smu_dpm_clks.dpm_clks); 1115 } 1116 } 1117 1118 if (smu_dpm_clks.dpm_clks && smu_dpm_clks.mc_address.quad_part != 0) 1119 dm_helpers_free_gpu_mem(clk_mgr->base.base.ctx, DC_MEM_ALLOC_TYPE_FRAME_BUFFER, 1120 smu_dpm_clks.dpm_clks); 1121 1122 if (ctx->dc->config.disable_ips != DMUB_IPS_DISABLE_ALL) { 1123 bool ips_support = false; 1124 1125 /*avoid call pmfw at init*/ 1126 ips_support = dcn35_smu_get_ips_supported(&clk_mgr->base); 1127 if (ips_support) { 1128 ctx->dc->debug.ignore_pg = false; 1129 ctx->dc->debug.disable_dpp_power_gate = false; 1130 ctx->dc->debug.disable_hubp_power_gate = false; 1131 ctx->dc->debug.disable_dsc_power_gate = false; 1132 } else { 1133 /*let's reset the config control flag*/ 1134 ctx->dc->config.disable_ips = DMUB_IPS_DISABLE_ALL; /*pmfw not support it, disable it all*/ 1135 } 1136 } 1137 } 1138 1139 void dcn35_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int) 1140 { 1141 struct clk_mgr_dcn35 *clk_mgr = TO_CLK_MGR_DCN35(clk_mgr_int); 1142 1143 if (clk_mgr->smu_wm_set.wm_set && clk_mgr->smu_wm_set.mc_address.quad_part != 0) 1144 dm_helpers_free_gpu_mem(clk_mgr_int->base.ctx, DC_MEM_ALLOC_TYPE_FRAME_BUFFER, 1145 clk_mgr->smu_wm_set.wm_set); 1146 } 1147