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