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 void dcn315_clk_mgr_helper_populate_bw_params( 462 struct clk_mgr_internal *clk_mgr, 463 struct integrated_info *bios_info, 464 const DpmClocks_315_t *clock_table) 465 { 466 int i; 467 struct clk_bw_params *bw_params = clk_mgr->base.bw_params; 468 uint32_t max_pstate = clock_table->NumDfPstatesEnabled - 1; 469 struct clk_limit_table_entry def_max = bw_params->clk_table.entries[bw_params->clk_table.num_entries - 1]; 470 471 /* For 315 we want to base clock table on dcfclk, need at least one entry regardless of pmfw table */ 472 for (i = 0; i < clock_table->NumDcfClkLevelsEnabled; i++) { 473 int j; 474 475 /* DF table is sorted with clocks decreasing */ 476 for (j = clock_table->NumDfPstatesEnabled - 2; j >= 0; j--) { 477 if (clock_table->DfPstateTable[j].Voltage <= clock_table->SocVoltage[i]) 478 max_pstate = j; 479 } 480 /* Max DCFCLK should match up with max pstate */ 481 if (i == clock_table->NumDcfClkLevelsEnabled - 1) 482 max_pstate = 0; 483 484 /* First search defaults for the clocks we don't read using closest lower or equal default dcfclk */ 485 for (j = bw_params->clk_table.num_entries - 1; j > 0; j--) 486 if (bw_params->clk_table.entries[j].dcfclk_mhz <= clock_table->DcfClocks[i]) 487 break; 488 bw_params->clk_table.entries[i].phyclk_mhz = bw_params->clk_table.entries[j].phyclk_mhz; 489 bw_params->clk_table.entries[i].phyclk_d18_mhz = bw_params->clk_table.entries[j].phyclk_d18_mhz; 490 bw_params->clk_table.entries[i].dtbclk_mhz = bw_params->clk_table.entries[j].dtbclk_mhz; 491 492 /* Now update clocks we do read */ 493 bw_params->clk_table.entries[i].fclk_mhz = clock_table->DfPstateTable[max_pstate].FClk; 494 bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[max_pstate].MemClk; 495 bw_params->clk_table.entries[i].voltage = clock_table->SocVoltage[i]; 496 bw_params->clk_table.entries[i].dcfclk_mhz = clock_table->DcfClocks[i]; 497 bw_params->clk_table.entries[i].socclk_mhz = clock_table->SocClocks[i]; 498 bw_params->clk_table.entries[i].dispclk_mhz = clock_table->DispClocks[i]; 499 bw_params->clk_table.entries[i].dppclk_mhz = clock_table->DppClocks[i]; 500 bw_params->clk_table.entries[i].wck_ratio = 1; 501 } 502 503 /* Make sure to include at least one entry */ 504 if (i == 0) { 505 bw_params->clk_table.entries[i].fclk_mhz = clock_table->DfPstateTable[0].FClk; 506 bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[0].MemClk; 507 bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[0].Voltage; 508 bw_params->clk_table.entries[i].dcfclk_mhz = clock_table->DcfClocks[0]; 509 bw_params->clk_table.entries[i].wck_ratio = 1; 510 i++; 511 } 512 bw_params->clk_table.num_entries = i; 513 514 /* Set any 0 clocks to max default setting. Not an issue for 515 * power since we aren't doing switching in such case anyway 516 */ 517 for (i = 0; i < bw_params->clk_table.num_entries; i++) { 518 if (!bw_params->clk_table.entries[i].fclk_mhz) { 519 bw_params->clk_table.entries[i].fclk_mhz = def_max.fclk_mhz; 520 bw_params->clk_table.entries[i].memclk_mhz = def_max.memclk_mhz; 521 bw_params->clk_table.entries[i].voltage = def_max.voltage; 522 } 523 if (!bw_params->clk_table.entries[i].dcfclk_mhz) 524 bw_params->clk_table.entries[i].dcfclk_mhz = def_max.dcfclk_mhz; 525 if (!bw_params->clk_table.entries[i].socclk_mhz) 526 bw_params->clk_table.entries[i].socclk_mhz = def_max.socclk_mhz; 527 if (!bw_params->clk_table.entries[i].dispclk_mhz) 528 bw_params->clk_table.entries[i].dispclk_mhz = def_max.dispclk_mhz; 529 if (!bw_params->clk_table.entries[i].dppclk_mhz) 530 bw_params->clk_table.entries[i].dppclk_mhz = def_max.dppclk_mhz; 531 if (!bw_params->clk_table.entries[i].phyclk_mhz) 532 bw_params->clk_table.entries[i].phyclk_mhz = def_max.phyclk_mhz; 533 if (!bw_params->clk_table.entries[i].phyclk_d18_mhz) 534 bw_params->clk_table.entries[i].phyclk_d18_mhz = def_max.phyclk_d18_mhz; 535 if (!bw_params->clk_table.entries[i].dtbclk_mhz) 536 bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz; 537 } 538 539 /* Make sure all highest default clocks are included*/ 540 ASSERT(bw_params->clk_table.entries[i-1].phyclk_mhz == def_max.phyclk_mhz); 541 ASSERT(bw_params->clk_table.entries[i-1].phyclk_d18_mhz == def_max.phyclk_d18_mhz); 542 ASSERT(bw_params->clk_table.entries[i-1].dtbclk_mhz == def_max.dtbclk_mhz); 543 ASSERT(bw_params->clk_table.entries[i-1].dcfclk_mhz); 544 bw_params->vram_type = bios_info->memory_type; 545 bw_params->num_channels = bios_info->ma_channel_number; 546 bw_params->dram_channel_width_bytes = bios_info->memory_type == 0x22 ? 8 : 4; 547 548 for (i = 0; i < WM_SET_COUNT; i++) { 549 bw_params->wm_table.entries[i].wm_inst = i; 550 551 if (i >= bw_params->clk_table.num_entries) { 552 bw_params->wm_table.entries[i].valid = false; 553 continue; 554 } 555 556 bw_params->wm_table.entries[i].wm_type = WM_TYPE_PSTATE_CHG; 557 bw_params->wm_table.entries[i].valid = true; 558 } 559 } 560 561 static void dcn315_enable_pme_wa(struct clk_mgr *clk_mgr_base) 562 { 563 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 564 565 dcn315_smu_enable_pme_wa(clk_mgr); 566 } 567 568 static struct clk_mgr_funcs dcn315_funcs = { 569 .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, 570 .get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz, 571 .update_clocks = dcn315_update_clocks, 572 .init_clocks = dcn31_init_clocks, 573 .enable_pme_wa = dcn315_enable_pme_wa, 574 .are_clock_states_equal = dcn31_are_clock_states_equal, 575 .notify_wm_ranges = dcn315_notify_wm_ranges 576 }; 577 extern struct clk_mgr_funcs dcn3_fpga_funcs; 578 579 void dcn315_clk_mgr_construct( 580 struct dc_context *ctx, 581 struct clk_mgr_dcn315 *clk_mgr, 582 struct pp_smu_funcs *pp_smu, 583 struct dccg *dccg) 584 { 585 struct dcn315_smu_dpm_clks smu_dpm_clks = { 0 }; 586 587 clk_mgr->base.base.ctx = ctx; 588 clk_mgr->base.base.funcs = &dcn315_funcs; 589 590 clk_mgr->base.pp_smu = pp_smu; 591 592 clk_mgr->base.dccg = dccg; 593 clk_mgr->base.dfs_bypass_disp_clk = 0; 594 595 clk_mgr->base.dprefclk_ss_percentage = 0; 596 clk_mgr->base.dprefclk_ss_divider = 1000; 597 clk_mgr->base.ss_on_dprefclk = false; 598 clk_mgr->base.dfs_ref_freq_khz = 48000; 599 600 clk_mgr->smu_wm_set.wm_set = (struct dcn315_watermarks *)dm_helpers_allocate_gpu_mem( 601 clk_mgr->base.base.ctx, 602 DC_MEM_ALLOC_TYPE_FRAME_BUFFER, 603 sizeof(struct dcn315_watermarks), 604 &clk_mgr->smu_wm_set.mc_address.quad_part); 605 606 if (!clk_mgr->smu_wm_set.wm_set) { 607 clk_mgr->smu_wm_set.wm_set = &dummy_wms; 608 clk_mgr->smu_wm_set.mc_address.quad_part = 0; 609 } 610 ASSERT(clk_mgr->smu_wm_set.wm_set); 611 612 smu_dpm_clks.dpm_clks = (DpmClocks_315_t *)dm_helpers_allocate_gpu_mem( 613 clk_mgr->base.base.ctx, 614 DC_MEM_ALLOC_TYPE_FRAME_BUFFER, 615 sizeof(DpmClocks_315_t), 616 &smu_dpm_clks.mc_address.quad_part); 617 618 if (smu_dpm_clks.dpm_clks == NULL) { 619 smu_dpm_clks.dpm_clks = &dummy_clocks; 620 smu_dpm_clks.mc_address.quad_part = 0; 621 } 622 623 ASSERT(smu_dpm_clks.dpm_clks); 624 625 if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) { 626 clk_mgr->base.base.funcs = &dcn3_fpga_funcs; 627 } else { 628 struct clk_log_info log_info = {0}; 629 630 clk_mgr->base.smu_ver = dcn315_smu_get_smu_version(&clk_mgr->base); 631 632 if (clk_mgr->base.smu_ver > 0) 633 clk_mgr->base.smu_present = true; 634 635 if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType) { 636 dcn315_bw_params.wm_table = lpddr5_wm_table; 637 } else { 638 dcn315_bw_params.wm_table = ddr5_wm_table; 639 } 640 /* Saved clocks configured at boot for debug purposes */ 641 dcn315_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, 642 &clk_mgr->base.base, &log_info); 643 644 } 645 646 clk_mgr->base.base.dprefclk_khz = 600000; 647 clk_mgr->base.base.dprefclk_khz = dcn315_smu_get_dpref_clk(&clk_mgr->base); 648 clk_mgr->base.base.clks.ref_dtbclk_khz = clk_mgr->base.base.dprefclk_khz; 649 dce_clock_read_ss_info(&clk_mgr->base); 650 clk_mgr->base.base.clks.ref_dtbclk_khz = dce_adjust_dp_ref_freq_for_ss(&clk_mgr->base, clk_mgr->base.base.dprefclk_khz); 651 652 clk_mgr->base.base.bw_params = &dcn315_bw_params; 653 654 if (clk_mgr->base.base.ctx->dc->debug.pstate_enabled) { 655 int i; 656 657 dcn315_get_dpm_table_from_smu(&clk_mgr->base, &smu_dpm_clks); 658 DC_LOG_SMU("NumDcfClkLevelsEnabled: %d\n" 659 "NumDispClkLevelsEnabled: %d\n" 660 "NumSocClkLevelsEnabled: %d\n" 661 "VcnClkLevelsEnabled: %d\n" 662 "NumDfPst atesEnabled: %d\n" 663 "MinGfxClk: %d\n" 664 "MaxGfxClk: %d\n", 665 smu_dpm_clks.dpm_clks->NumDcfClkLevelsEnabled, 666 smu_dpm_clks.dpm_clks->NumDispClkLevelsEnabled, 667 smu_dpm_clks.dpm_clks->NumSocClkLevelsEnabled, 668 smu_dpm_clks.dpm_clks->VcnClkLevelsEnabled, 669 smu_dpm_clks.dpm_clks->NumDfPstatesEnabled, 670 smu_dpm_clks.dpm_clks->MinGfxClk, 671 smu_dpm_clks.dpm_clks->MaxGfxClk); 672 for (i = 0; i < smu_dpm_clks.dpm_clks->NumDcfClkLevelsEnabled; i++) { 673 DC_LOG_SMU("smu_dpm_clks.dpm_clks->DcfClocks[%d] = %d\n", 674 i, 675 smu_dpm_clks.dpm_clks->DcfClocks[i]); 676 } 677 for (i = 0; i < smu_dpm_clks.dpm_clks->NumDispClkLevelsEnabled; i++) { 678 DC_LOG_SMU("smu_dpm_clks.dpm_clks->DispClocks[%d] = %d\n", 679 i, smu_dpm_clks.dpm_clks->DispClocks[i]); 680 } 681 for (i = 0; i < smu_dpm_clks.dpm_clks->NumSocClkLevelsEnabled; i++) { 682 DC_LOG_SMU("smu_dpm_clks.dpm_clks->SocClocks[%d] = %d\n", 683 i, smu_dpm_clks.dpm_clks->SocClocks[i]); 684 } 685 for (i = 0; i < NUM_SOC_VOLTAGE_LEVELS; i++) 686 DC_LOG_SMU("smu_dpm_clks.dpm_clks->SocVoltage[%d] = %d\n", 687 i, smu_dpm_clks.dpm_clks->SocVoltage[i]); 688 689 for (i = 0; i < NUM_DF_PSTATE_LEVELS; i++) { 690 DC_LOG_SMU("smu_dpm_clks.dpm_clks.DfPstateTable[%d].FClk = %d\n" 691 "smu_dpm_clks.dpm_clks->DfPstateTable[%d].MemClk= %d\n" 692 "smu_dpm_clks.dpm_clks->DfPstateTable[%d].Voltage = %d\n", 693 i, smu_dpm_clks.dpm_clks->DfPstateTable[i].FClk, 694 i, smu_dpm_clks.dpm_clks->DfPstateTable[i].MemClk, 695 i, smu_dpm_clks.dpm_clks->DfPstateTable[i].Voltage); 696 } 697 698 if (ctx->dc_bios && ctx->dc_bios->integrated_info) { 699 dcn315_clk_mgr_helper_populate_bw_params( 700 &clk_mgr->base, 701 ctx->dc_bios->integrated_info, 702 smu_dpm_clks.dpm_clks); 703 } 704 } 705 706 if (smu_dpm_clks.dpm_clks && smu_dpm_clks.mc_address.quad_part != 0) 707 dm_helpers_free_gpu_mem(clk_mgr->base.base.ctx, DC_MEM_ALLOC_TYPE_FRAME_BUFFER, 708 smu_dpm_clks.dpm_clks); 709 } 710 711 void dcn315_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int) 712 { 713 struct clk_mgr_dcn315 *clk_mgr = TO_CLK_MGR_DCN315(clk_mgr_int); 714 715 if (clk_mgr->smu_wm_set.wm_set && clk_mgr->smu_wm_set.mc_address.quad_part != 0) 716 dm_helpers_free_gpu_mem(clk_mgr_int->base.ctx, DC_MEM_ALLOC_TYPE_FRAME_BUFFER, 717 clk_mgr->smu_wm_set.wm_set); 718 } 719