1 /* 2 * Copyright 2021 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 28 #include "dccg.h" 29 #include "clk_mgr_internal.h" 30 31 // For dce12_get_dp_ref_freq_khz 32 #include "dce100/dce_clk_mgr.h" 33 // For dcn20_update_clocks_update_dpp_dto 34 #include "dcn20/dcn20_clk_mgr.h" 35 #include "dcn31/dcn31_clk_mgr.h" 36 #include "dcn315_clk_mgr.h" 37 38 #include "core_types.h" 39 #include "dcn315_smu.h" 40 #include "dm_helpers.h" 41 42 #include "dc_dmub_srv.h" 43 44 #include "logger_types.h" 45 #undef DC_LOGGER 46 #define DC_LOGGER \ 47 clk_mgr->base.base.ctx->logger 48 49 #include "dc_link_dp.h" 50 51 #define TO_CLK_MGR_DCN315(clk_mgr)\ 52 container_of(clk_mgr, struct clk_mgr_dcn315, base) 53 54 #define UNSUPPORTED_DCFCLK 10000000 55 #define MIN_DPP_DISP_CLK 100000 56 57 static int dcn315_get_active_display_cnt_wa( 58 struct dc *dc, 59 struct dc_state *context) 60 { 61 int i, display_count; 62 bool tmds_present = false; 63 64 display_count = 0; 65 for (i = 0; i < context->stream_count; i++) { 66 const struct dc_stream_state *stream = context->streams[i]; 67 68 if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A || 69 stream->signal == SIGNAL_TYPE_DVI_SINGLE_LINK || 70 stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) 71 tmds_present = true; 72 } 73 74 for (i = 0; i < dc->link_count; i++) { 75 const struct dc_link *link = dc->links[i]; 76 77 /* abusing the fact that the dig and phy are coupled to see if the phy is enabled */ 78 if (link->link_enc && link->link_enc->funcs->is_dig_enabled && 79 link->link_enc->funcs->is_dig_enabled(link->link_enc)) 80 display_count++; 81 } 82 83 /* WA for hang on HDMI after display off back back on*/ 84 if (display_count == 0 && tmds_present) 85 display_count = 1; 86 87 return display_count; 88 } 89 90 static void dcn315_disable_otg_wa(struct clk_mgr *clk_mgr_base, struct dc_state *context, bool disable) 91 { 92 struct dc *dc = clk_mgr_base->ctx->dc; 93 int i; 94 95 for (i = 0; i < dc->res_pool->pipe_count; ++i) { 96 struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i]; 97 98 if (pipe->top_pipe || pipe->prev_odm_pipe) 99 continue; 100 if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL || 101 dc_is_virtual_signal(pipe->stream->signal))) { 102 if (disable) { 103 pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg); 104 reset_sync_context_for_pipe(dc, context, i); 105 } else 106 pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg); 107 } 108 } 109 } 110 111 static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base, 112 struct dc_state *context, 113 bool safe_to_lower) 114 { 115 union dmub_rb_cmd cmd; 116 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 117 struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; 118 struct dc *dc = clk_mgr_base->ctx->dc; 119 int display_count; 120 bool update_dppclk = false; 121 bool update_dispclk = false; 122 bool dpp_clock_lowered = false; 123 124 if (dc->work_arounds.skip_clock_update) 125 return; 126 127 clk_mgr_base->clks.zstate_support = new_clocks->zstate_support; 128 /* 129 * if it is safe to lower, but we are already in the lower state, we don't have to do anything 130 * also if safe to lower is false, we just go in the higher state 131 */ 132 clk_mgr_base->clks.zstate_support = new_clocks->zstate_support; 133 if (safe_to_lower) { 134 /* check that we're not already in lower */ 135 if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) { 136 display_count = dcn315_get_active_display_cnt_wa(dc, context); 137 /* if we can go lower, go lower */ 138 if (display_count == 0) { 139 union display_idle_optimization_u idle_info = { 0 }; 140 idle_info.idle_info.df_request_disabled = 1; 141 idle_info.idle_info.phy_ref_clk_off = 1; 142 idle_info.idle_info.s0i2_rdy = 1; 143 dcn315_smu_set_display_idle_optimization(clk_mgr, idle_info.data); 144 /* update power state */ 145 clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER; 146 } 147 } 148 } else { 149 /* check that we're not already in D0 */ 150 if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_MISSION_MODE) { 151 union display_idle_optimization_u idle_info = { 0 }; 152 dcn315_smu_set_display_idle_optimization(clk_mgr, idle_info.data); 153 /* update power state */ 154 clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_MISSION_MODE; 155 } 156 } 157 158 /* Lock pstate by requesting unsupported dcfclk if change is unsupported */ 159 if (!new_clocks->p_state_change_support) 160 new_clocks->dcfclk_khz = UNSUPPORTED_DCFCLK; 161 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) { 162 clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz; 163 dcn315_smu_set_hard_min_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_khz); 164 } 165 166 if (should_set_clock(safe_to_lower, 167 new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) { 168 clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; 169 dcn315_smu_set_min_deep_sleep_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_deep_sleep_khz); 170 } 171 172 // workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow. 173 if (!IS_DIAG_DC(dc->ctx->dce_environment)) { 174 if (new_clocks->dppclk_khz < MIN_DPP_DISP_CLK) 175 new_clocks->dppclk_khz = MIN_DPP_DISP_CLK; 176 if (new_clocks->dispclk_khz < MIN_DPP_DISP_CLK) 177 new_clocks->dispclk_khz = MIN_DPP_DISP_CLK; 178 } 179 180 if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) { 181 if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz) 182 dpp_clock_lowered = true; 183 clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz; 184 update_dppclk = true; 185 } 186 187 if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { 188 /* No need to apply the w/a if we haven't taken over from bios yet */ 189 if (clk_mgr_base->clks.dispclk_khz) 190 dcn315_disable_otg_wa(clk_mgr_base, context, true); 191 192 clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; 193 dcn315_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz); 194 if (clk_mgr_base->clks.dispclk_khz) 195 dcn315_disable_otg_wa(clk_mgr_base, context, false); 196 197 update_dispclk = true; 198 } 199 200 if (dpp_clock_lowered) { 201 // increase per DPP DTO before lowering global dppclk 202 dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); 203 dcn315_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz); 204 } else { 205 // increase global DPPCLK before lowering per DPP DTO 206 if (update_dppclk || update_dispclk) 207 dcn315_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz); 208 // always update dtos unless clock is lowered and not safe to lower 209 if (new_clocks->dppclk_khz >= dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz) 210 dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); 211 } 212 213 // notify DMCUB of latest clocks 214 memset(&cmd, 0, sizeof(cmd)); 215 cmd.notify_clocks.header.type = DMUB_CMD__CLK_MGR; 216 cmd.notify_clocks.header.sub_type = DMUB_CMD__CLK_MGR_NOTIFY_CLOCKS; 217 cmd.notify_clocks.clocks.dcfclk_khz = clk_mgr_base->clks.dcfclk_khz; 218 cmd.notify_clocks.clocks.dcfclk_deep_sleep_khz = 219 clk_mgr_base->clks.dcfclk_deep_sleep_khz; 220 cmd.notify_clocks.clocks.dispclk_khz = clk_mgr_base->clks.dispclk_khz; 221 cmd.notify_clocks.clocks.dppclk_khz = clk_mgr_base->clks.dppclk_khz; 222 223 dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd); 224 dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv); 225 dc_dmub_srv_wait_idle(dc->ctx->dmub_srv); 226 } 227 228 static void dcn315_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass, 229 struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info) 230 { 231 return; 232 } 233 234 static struct clk_bw_params dcn315_bw_params = { 235 .vram_type = Ddr4MemType, 236 .num_channels = 2, 237 .clk_table = { 238 .entries = { 239 { 240 .voltage = 0, 241 .dispclk_mhz = 640, 242 .dppclk_mhz = 640, 243 .phyclk_mhz = 810, 244 .phyclk_d18_mhz = 667, 245 .dtbclk_mhz = 600, 246 }, 247 { 248 .voltage = 1, 249 .dispclk_mhz = 739, 250 .dppclk_mhz = 739, 251 .phyclk_mhz = 810, 252 .phyclk_d18_mhz = 667, 253 .dtbclk_mhz = 600, 254 }, 255 { 256 .voltage = 2, 257 .dispclk_mhz = 960, 258 .dppclk_mhz = 960, 259 .phyclk_mhz = 810, 260 .phyclk_d18_mhz = 667, 261 .dtbclk_mhz = 600, 262 }, 263 { 264 .voltage = 3, 265 .dispclk_mhz = 1200, 266 .dppclk_mhz = 1200, 267 .phyclk_mhz = 810, 268 .phyclk_d18_mhz = 667, 269 .dtbclk_mhz = 600, 270 }, 271 { 272 .voltage = 4, 273 .dispclk_mhz = 1372, 274 .dppclk_mhz = 1372, 275 .phyclk_mhz = 810, 276 .phyclk_d18_mhz = 667, 277 .dtbclk_mhz = 600, 278 }, 279 }, 280 .num_entries = 5, 281 }, 282 283 }; 284 285 static struct wm_table ddr5_wm_table = { 286 .entries = { 287 { 288 .wm_inst = WM_A, 289 .wm_type = WM_TYPE_PSTATE_CHG, 290 .pstate_latency_us = 129.0, 291 .sr_exit_time_us = 11.5, 292 .sr_enter_plus_exit_time_us = 14.5, 293 .valid = true, 294 }, 295 { 296 .wm_inst = WM_B, 297 .wm_type = WM_TYPE_PSTATE_CHG, 298 .pstate_latency_us = 129.0, 299 .sr_exit_time_us = 11.5, 300 .sr_enter_plus_exit_time_us = 14.5, 301 .valid = true, 302 }, 303 { 304 .wm_inst = WM_C, 305 .wm_type = WM_TYPE_PSTATE_CHG, 306 .pstate_latency_us = 129.0, 307 .sr_exit_time_us = 11.5, 308 .sr_enter_plus_exit_time_us = 14.5, 309 .valid = true, 310 }, 311 { 312 .wm_inst = WM_D, 313 .wm_type = WM_TYPE_PSTATE_CHG, 314 .pstate_latency_us = 129.0, 315 .sr_exit_time_us = 11.5, 316 .sr_enter_plus_exit_time_us = 14.5, 317 .valid = true, 318 }, 319 } 320 }; 321 322 static struct wm_table lpddr5_wm_table = { 323 .entries = { 324 { 325 .wm_inst = WM_A, 326 .wm_type = WM_TYPE_PSTATE_CHG, 327 .pstate_latency_us = 11.65333, 328 .sr_exit_time_us = 11.5, 329 .sr_enter_plus_exit_time_us = 14.5, 330 .valid = true, 331 }, 332 { 333 .wm_inst = WM_B, 334 .wm_type = WM_TYPE_PSTATE_CHG, 335 .pstate_latency_us = 11.65333, 336 .sr_exit_time_us = 11.5, 337 .sr_enter_plus_exit_time_us = 14.5, 338 .valid = true, 339 }, 340 { 341 .wm_inst = WM_C, 342 .wm_type = WM_TYPE_PSTATE_CHG, 343 .pstate_latency_us = 11.65333, 344 .sr_exit_time_us = 11.5, 345 .sr_enter_plus_exit_time_us = 14.5, 346 .valid = true, 347 }, 348 { 349 .wm_inst = WM_D, 350 .wm_type = WM_TYPE_PSTATE_CHG, 351 .pstate_latency_us = 11.65333, 352 .sr_exit_time_us = 11.5, 353 .sr_enter_plus_exit_time_us = 14.5, 354 .valid = true, 355 }, 356 } 357 }; 358 359 /* Temporary Place holder until we can get them from fuse */ 360 static DpmClocks_315_t dummy_clocks = { 0 }; 361 static struct dcn315_watermarks dummy_wms = { 0 }; 362 363 static void dcn315_build_watermark_ranges(struct clk_bw_params *bw_params, struct dcn315_watermarks *table) 364 { 365 int i, num_valid_sets; 366 367 num_valid_sets = 0; 368 369 for (i = 0; i < WM_SET_COUNT; i++) { 370 /* skip empty entries, the smu array has no holes*/ 371 if (!bw_params->wm_table.entries[i].valid) 372 continue; 373 374 table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmSetting = bw_params->wm_table.entries[i].wm_inst; 375 table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType = bw_params->wm_table.entries[i].wm_type; 376 /* We will not select WM based on fclk, so leave it as unconstrained */ 377 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0; 378 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF; 379 380 if (table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType == WM_TYPE_PSTATE_CHG) { 381 if (i == 0) 382 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk = 0; 383 else { 384 /* add 1 to make it non-overlapping with next lvl */ 385 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk = 386 bw_params->clk_table.entries[i - 1].dcfclk_mhz + 1; 387 } 388 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxMclk = 389 bw_params->clk_table.entries[i].dcfclk_mhz; 390 391 } else { 392 /* unconstrained for memory retraining */ 393 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0; 394 table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF; 395 396 /* Modify previous watermark range to cover up to max */ 397 table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF; 398 } 399 num_valid_sets++; 400 } 401 402 ASSERT(num_valid_sets != 0); /* Must have at least one set of valid watermarks */ 403 404 /* modify the min and max to make sure we cover the whole range*/ 405 table->WatermarkRow[WM_DCFCLK][0].MinMclk = 0; 406 table->WatermarkRow[WM_DCFCLK][0].MinClock = 0; 407 table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxMclk = 0xFFFF; 408 table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF; 409 410 /* This is for writeback only, does not matter currently as no writeback support*/ 411 table->WatermarkRow[WM_SOCCLK][0].WmSetting = WM_A; 412 table->WatermarkRow[WM_SOCCLK][0].MinClock = 0; 413 table->WatermarkRow[WM_SOCCLK][0].MaxClock = 0xFFFF; 414 table->WatermarkRow[WM_SOCCLK][0].MinMclk = 0; 415 table->WatermarkRow[WM_SOCCLK][0].MaxMclk = 0xFFFF; 416 } 417 418 static void dcn315_notify_wm_ranges(struct clk_mgr *clk_mgr_base) 419 { 420 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 421 struct clk_mgr_dcn315 *clk_mgr_dcn315 = TO_CLK_MGR_DCN315(clk_mgr); 422 struct dcn315_watermarks *table = clk_mgr_dcn315->smu_wm_set.wm_set; 423 424 if (!clk_mgr->smu_ver) 425 return; 426 427 if (!table || clk_mgr_dcn315->smu_wm_set.mc_address.quad_part == 0) 428 return; 429 430 memset(table, 0, sizeof(*table)); 431 432 dcn315_build_watermark_ranges(clk_mgr_base->bw_params, table); 433 434 dcn315_smu_set_dram_addr_high(clk_mgr, 435 clk_mgr_dcn315->smu_wm_set.mc_address.high_part); 436 dcn315_smu_set_dram_addr_low(clk_mgr, 437 clk_mgr_dcn315->smu_wm_set.mc_address.low_part); 438 dcn315_smu_transfer_wm_table_dram_2_smu(clk_mgr); 439 } 440 441 static void dcn315_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr, 442 struct dcn315_smu_dpm_clks *smu_dpm_clks) 443 { 444 DpmClocks_315_t *table = smu_dpm_clks->dpm_clks; 445 446 if (!clk_mgr->smu_ver) 447 return; 448 449 if (!table || smu_dpm_clks->mc_address.quad_part == 0) 450 return; 451 452 memset(table, 0, sizeof(*table)); 453 454 dcn315_smu_set_dram_addr_high(clk_mgr, 455 smu_dpm_clks->mc_address.high_part); 456 dcn315_smu_set_dram_addr_low(clk_mgr, 457 smu_dpm_clks->mc_address.low_part); 458 dcn315_smu_transfer_dpm_table_smu_2_dram(clk_mgr); 459 } 460 461 static uint32_t find_max_clk_value(const uint32_t clocks[], uint32_t num_clocks) 462 { 463 uint32_t max = 0; 464 int i; 465 466 for (i = 0; i < num_clocks; ++i) { 467 if (clocks[i] > max) 468 max = clocks[i]; 469 } 470 471 return max; 472 } 473 474 static void dcn315_clk_mgr_helper_populate_bw_params( 475 struct clk_mgr_internal *clk_mgr, 476 struct integrated_info *bios_info, 477 const DpmClocks_315_t *clock_table) 478 { 479 int i; 480 struct clk_bw_params *bw_params = clk_mgr->base.bw_params; 481 uint32_t max_pstate = 0, max_fclk = 0, min_pstate = 0; 482 struct clk_limit_table_entry def_max = bw_params->clk_table.entries[bw_params->clk_table.num_entries - 1]; 483 484 /* Find highest fclk pstate */ 485 for (i = 0; i < clock_table->NumDfPstatesEnabled; i++) { 486 if (clock_table->DfPstateTable[i].FClk > max_fclk) { 487 max_fclk = clock_table->DfPstateTable[i].FClk; 488 max_pstate = i; 489 } 490 } 491 492 /* For 315 we want to base clock table on dcfclk, need at least one entry regardless of pmfw table */ 493 for (i = 0; i < clock_table->NumDcfClkLevelsEnabled; i++) { 494 int j; 495 uint32_t min_fclk = clock_table->DfPstateTable[0].FClk; 496 497 for (j = 1; j < clock_table->NumDfPstatesEnabled; j++) { 498 if (clock_table->DfPstateTable[j].Voltage <= clock_table->SocVoltage[i] 499 && clock_table->DfPstateTable[j].FClk < min_fclk) { 500 min_fclk = clock_table->DfPstateTable[j].FClk; 501 min_pstate = j; 502 } 503 } 504 505 /* First search defaults for the clocks we don't read using closest lower or equal default dcfclk */ 506 for (j = bw_params->clk_table.num_entries - 1; j > 0; j--) 507 if (bw_params->clk_table.entries[j].dcfclk_mhz <= clock_table->DcfClocks[i]) 508 break; 509 bw_params->clk_table.entries[i].phyclk_mhz = bw_params->clk_table.entries[j].phyclk_mhz; 510 bw_params->clk_table.entries[i].phyclk_d18_mhz = bw_params->clk_table.entries[j].phyclk_d18_mhz; 511 bw_params->clk_table.entries[i].dtbclk_mhz = bw_params->clk_table.entries[j].dtbclk_mhz; 512 513 /* Now update clocks we do read */ 514 bw_params->clk_table.entries[i].fclk_mhz = min_fclk; 515 bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[min_pstate].MemClk; 516 bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[min_pstate].Voltage; 517 bw_params->clk_table.entries[i].dcfclk_mhz = clock_table->DcfClocks[i]; 518 bw_params->clk_table.entries[i].socclk_mhz = clock_table->SocClocks[i]; 519 bw_params->clk_table.entries[i].dispclk_mhz = clock_table->DispClocks[i]; 520 bw_params->clk_table.entries[i].dppclk_mhz = clock_table->DppClocks[i]; 521 bw_params->clk_table.entries[i].wck_ratio = 1; 522 } 523 524 /* Make sure to include at least one entry and highest pstate */ 525 if (max_pstate != min_pstate || i == 0) { 526 bw_params->clk_table.entries[i].fclk_mhz = max_fclk; 527 bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[max_pstate].MemClk; 528 bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[max_pstate].Voltage; 529 bw_params->clk_table.entries[i].dcfclk_mhz = find_max_clk_value(clock_table->DcfClocks, NUM_DCFCLK_DPM_LEVELS); 530 bw_params->clk_table.entries[i].wck_ratio = 1; 531 i++; 532 } 533 bw_params->clk_table.num_entries = i--; 534 535 /* Make sure all highest clocks are included*/ 536 bw_params->clk_table.entries[i].socclk_mhz = find_max_clk_value(clock_table->SocClocks, NUM_SOCCLK_DPM_LEVELS); 537 bw_params->clk_table.entries[i].dispclk_mhz = find_max_clk_value(clock_table->DispClocks, NUM_DISPCLK_DPM_LEVELS); 538 bw_params->clk_table.entries[i].dppclk_mhz = find_max_clk_value(clock_table->DppClocks, NUM_DPPCLK_DPM_LEVELS); 539 ASSERT(clock_table->DcfClocks[i] == find_max_clk_value(clock_table->DcfClocks, NUM_DCFCLK_DPM_LEVELS)); 540 bw_params->clk_table.entries[i].phyclk_mhz = def_max.phyclk_mhz; 541 bw_params->clk_table.entries[i].phyclk_d18_mhz = def_max.phyclk_d18_mhz; 542 bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz; 543 544 /* Set any 0 clocks to max default setting. Not an issue for 545 * power since we aren't doing switching in such case anyway 546 */ 547 for (i = 0; i < bw_params->clk_table.num_entries; i++) { 548 if (!bw_params->clk_table.entries[i].fclk_mhz) { 549 bw_params->clk_table.entries[i].fclk_mhz = def_max.fclk_mhz; 550 bw_params->clk_table.entries[i].memclk_mhz = def_max.memclk_mhz; 551 bw_params->clk_table.entries[i].voltage = def_max.voltage; 552 } 553 if (!bw_params->clk_table.entries[i].dcfclk_mhz) 554 bw_params->clk_table.entries[i].dcfclk_mhz = def_max.dcfclk_mhz; 555 if (!bw_params->clk_table.entries[i].socclk_mhz) 556 bw_params->clk_table.entries[i].socclk_mhz = def_max.socclk_mhz; 557 if (!bw_params->clk_table.entries[i].dispclk_mhz) 558 bw_params->clk_table.entries[i].dispclk_mhz = def_max.dispclk_mhz; 559 if (!bw_params->clk_table.entries[i].dppclk_mhz) 560 bw_params->clk_table.entries[i].dppclk_mhz = def_max.dppclk_mhz; 561 if (!bw_params->clk_table.entries[i].phyclk_mhz) 562 bw_params->clk_table.entries[i].phyclk_mhz = def_max.phyclk_mhz; 563 if (!bw_params->clk_table.entries[i].phyclk_d18_mhz) 564 bw_params->clk_table.entries[i].phyclk_d18_mhz = def_max.phyclk_d18_mhz; 565 if (!bw_params->clk_table.entries[i].dtbclk_mhz) 566 bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz; 567 } 568 ASSERT(bw_params->clk_table.entries[i-1].dcfclk_mhz); 569 bw_params->vram_type = bios_info->memory_type; 570 bw_params->num_channels = bios_info->ma_channel_number; 571 bw_params->dram_channel_width_bytes = bios_info->memory_type == 0x22 ? 8 : 4; 572 573 for (i = 0; i < WM_SET_COUNT; i++) { 574 bw_params->wm_table.entries[i].wm_inst = i; 575 576 if (i >= bw_params->clk_table.num_entries) { 577 bw_params->wm_table.entries[i].valid = false; 578 continue; 579 } 580 581 bw_params->wm_table.entries[i].wm_type = WM_TYPE_PSTATE_CHG; 582 bw_params->wm_table.entries[i].valid = true; 583 } 584 } 585 586 static void dcn315_enable_pme_wa(struct clk_mgr *clk_mgr_base) 587 { 588 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 589 590 dcn315_smu_enable_pme_wa(clk_mgr); 591 } 592 593 static struct clk_mgr_funcs dcn315_funcs = { 594 .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, 595 .get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz, 596 .update_clocks = dcn315_update_clocks, 597 .init_clocks = dcn31_init_clocks, 598 .enable_pme_wa = dcn315_enable_pme_wa, 599 .are_clock_states_equal = dcn31_are_clock_states_equal, 600 .notify_wm_ranges = dcn315_notify_wm_ranges 601 }; 602 extern struct clk_mgr_funcs dcn3_fpga_funcs; 603 604 void dcn315_clk_mgr_construct( 605 struct dc_context *ctx, 606 struct clk_mgr_dcn315 *clk_mgr, 607 struct pp_smu_funcs *pp_smu, 608 struct dccg *dccg) 609 { 610 struct dcn315_smu_dpm_clks smu_dpm_clks = { 0 }; 611 612 clk_mgr->base.base.ctx = ctx; 613 clk_mgr->base.base.funcs = &dcn315_funcs; 614 615 clk_mgr->base.pp_smu = pp_smu; 616 617 clk_mgr->base.dccg = dccg; 618 clk_mgr->base.dfs_bypass_disp_clk = 0; 619 620 clk_mgr->base.dprefclk_ss_percentage = 0; 621 clk_mgr->base.dprefclk_ss_divider = 1000; 622 clk_mgr->base.ss_on_dprefclk = false; 623 clk_mgr->base.dfs_ref_freq_khz = 48000; 624 625 clk_mgr->smu_wm_set.wm_set = (struct dcn315_watermarks *)dm_helpers_allocate_gpu_mem( 626 clk_mgr->base.base.ctx, 627 DC_MEM_ALLOC_TYPE_FRAME_BUFFER, 628 sizeof(struct dcn315_watermarks), 629 &clk_mgr->smu_wm_set.mc_address.quad_part); 630 631 if (!clk_mgr->smu_wm_set.wm_set) { 632 clk_mgr->smu_wm_set.wm_set = &dummy_wms; 633 clk_mgr->smu_wm_set.mc_address.quad_part = 0; 634 } 635 ASSERT(clk_mgr->smu_wm_set.wm_set); 636 637 smu_dpm_clks.dpm_clks = (DpmClocks_315_t *)dm_helpers_allocate_gpu_mem( 638 clk_mgr->base.base.ctx, 639 DC_MEM_ALLOC_TYPE_FRAME_BUFFER, 640 sizeof(DpmClocks_315_t), 641 &smu_dpm_clks.mc_address.quad_part); 642 643 if (smu_dpm_clks.dpm_clks == NULL) { 644 smu_dpm_clks.dpm_clks = &dummy_clocks; 645 smu_dpm_clks.mc_address.quad_part = 0; 646 } 647 648 ASSERT(smu_dpm_clks.dpm_clks); 649 650 if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) { 651 clk_mgr->base.base.funcs = &dcn3_fpga_funcs; 652 } else { 653 struct clk_log_info log_info = {0}; 654 655 clk_mgr->base.smu_ver = dcn315_smu_get_smu_version(&clk_mgr->base); 656 657 if (clk_mgr->base.smu_ver > 0) 658 clk_mgr->base.smu_present = true; 659 660 if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType) { 661 dcn315_bw_params.wm_table = lpddr5_wm_table; 662 } else { 663 dcn315_bw_params.wm_table = ddr5_wm_table; 664 } 665 /* Saved clocks configured at boot for debug purposes */ 666 dcn315_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, 667 &clk_mgr->base.base, &log_info); 668 669 } 670 671 clk_mgr->base.base.dprefclk_khz = 600000; 672 clk_mgr->base.base.dprefclk_khz = dcn315_smu_get_dpref_clk(&clk_mgr->base); 673 clk_mgr->base.base.clks.ref_dtbclk_khz = clk_mgr->base.base.dprefclk_khz; 674 dce_clock_read_ss_info(&clk_mgr->base); 675 clk_mgr->base.base.clks.ref_dtbclk_khz = dce_adjust_dp_ref_freq_for_ss(&clk_mgr->base, clk_mgr->base.base.dprefclk_khz); 676 677 clk_mgr->base.base.bw_params = &dcn315_bw_params; 678 679 if (clk_mgr->base.base.ctx->dc->debug.pstate_enabled) { 680 int i; 681 682 dcn315_get_dpm_table_from_smu(&clk_mgr->base, &smu_dpm_clks); 683 DC_LOG_SMU("NumDcfClkLevelsEnabled: %d\n" 684 "NumDispClkLevelsEnabled: %d\n" 685 "NumSocClkLevelsEnabled: %d\n" 686 "VcnClkLevelsEnabled: %d\n" 687 "NumDfPst atesEnabled: %d\n" 688 "MinGfxClk: %d\n" 689 "MaxGfxClk: %d\n", 690 smu_dpm_clks.dpm_clks->NumDcfClkLevelsEnabled, 691 smu_dpm_clks.dpm_clks->NumDispClkLevelsEnabled, 692 smu_dpm_clks.dpm_clks->NumSocClkLevelsEnabled, 693 smu_dpm_clks.dpm_clks->VcnClkLevelsEnabled, 694 smu_dpm_clks.dpm_clks->NumDfPstatesEnabled, 695 smu_dpm_clks.dpm_clks->MinGfxClk, 696 smu_dpm_clks.dpm_clks->MaxGfxClk); 697 for (i = 0; i < smu_dpm_clks.dpm_clks->NumDcfClkLevelsEnabled; i++) { 698 DC_LOG_SMU("smu_dpm_clks.dpm_clks->DcfClocks[%d] = %d\n", 699 i, 700 smu_dpm_clks.dpm_clks->DcfClocks[i]); 701 } 702 for (i = 0; i < smu_dpm_clks.dpm_clks->NumDispClkLevelsEnabled; i++) { 703 DC_LOG_SMU("smu_dpm_clks.dpm_clks->DispClocks[%d] = %d\n", 704 i, smu_dpm_clks.dpm_clks->DispClocks[i]); 705 } 706 for (i = 0; i < smu_dpm_clks.dpm_clks->NumSocClkLevelsEnabled; i++) { 707 DC_LOG_SMU("smu_dpm_clks.dpm_clks->SocClocks[%d] = %d\n", 708 i, smu_dpm_clks.dpm_clks->SocClocks[i]); 709 } 710 for (i = 0; i < NUM_SOC_VOLTAGE_LEVELS; i++) 711 DC_LOG_SMU("smu_dpm_clks.dpm_clks->SocVoltage[%d] = %d\n", 712 i, smu_dpm_clks.dpm_clks->SocVoltage[i]); 713 714 for (i = 0; i < NUM_DF_PSTATE_LEVELS; i++) { 715 DC_LOG_SMU("smu_dpm_clks.dpm_clks.DfPstateTable[%d].FClk = %d\n" 716 "smu_dpm_clks.dpm_clks->DfPstateTable[%d].MemClk= %d\n" 717 "smu_dpm_clks.dpm_clks->DfPstateTable[%d].Voltage = %d\n", 718 i, smu_dpm_clks.dpm_clks->DfPstateTable[i].FClk, 719 i, smu_dpm_clks.dpm_clks->DfPstateTable[i].MemClk, 720 i, smu_dpm_clks.dpm_clks->DfPstateTable[i].Voltage); 721 } 722 723 if (ctx->dc_bios && ctx->dc_bios->integrated_info) { 724 dcn315_clk_mgr_helper_populate_bw_params( 725 &clk_mgr->base, 726 ctx->dc_bios->integrated_info, 727 smu_dpm_clks.dpm_clks); 728 } 729 } 730 731 if (smu_dpm_clks.dpm_clks && smu_dpm_clks.mc_address.quad_part != 0) 732 dm_helpers_free_gpu_mem(clk_mgr->base.base.ctx, DC_MEM_ALLOC_TYPE_FRAME_BUFFER, 733 smu_dpm_clks.dpm_clks); 734 } 735 736 void dcn315_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int) 737 { 738 struct clk_mgr_dcn315 *clk_mgr = TO_CLK_MGR_DCN315(clk_mgr_int); 739 740 if (clk_mgr->smu_wm_set.wm_set && clk_mgr->smu_wm_set.mc_address.quad_part != 0) 741 dm_helpers_free_gpu_mem(clk_mgr_int->base.ctx, DC_MEM_ALLOC_TYPE_FRAME_BUFFER, 742 clk_mgr->smu_wm_set.wm_set); 743 } 744