FILE
dcn401_clk_mgr.c
File preview with syntax highlighting.
linux-6.19.14/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn401/dcn401_clk_mgr.c
1// SPDX-License-Identifier: MIT 2// 3// Copyright 2024 Advanced Micro Devices, Inc. 4 5#include "dccg.h" 6#include "clk_mgr_internal.h" 7#include "dcn401/dcn401_clk_mgr_smu_msg.h" 8#include "dcn20/dcn20_clk_mgr.h" 9#include "dce100/dce_clk_mgr.h" 10#include "dcn31/dcn31_clk_mgr.h" 11#include "dcn32/dcn32_clk_mgr.h" 12#include "dcn401/dcn401_clk_mgr.h" 13#include "reg_helper.h" 14#include "core_types.h" 15#include "dm_helpers.h" 16#include "link_service.h" 17#include "dc_state_priv.h" 18#include "atomfirmware.h" 19 20#include "dcn401_smu14_driver_if.h" 21 22#include "dcn/dcn_4_1_0_offset.h" 23#include "dcn/dcn_4_1_0_sh_mask.h" 24 25#define DCN_BASE__INST0_SEG1 0x000000C0 26 27#define mmCLK01_CLK0_CLK_PLL_REQ 0x16E37 28#define mmCLK01_CLK0_CLK0_DFS_CNTL 0x16E69 29#define mmCLK01_CLK0_CLK1_DFS_CNTL 0x16E6C 30#define mmCLK01_CLK0_CLK2_DFS_CNTL 0x16E6F 31#define mmCLK01_CLK0_CLK3_DFS_CNTL 0x16E72 32#define mmCLK01_CLK0_CLK4_DFS_CNTL 0x16E75 33#define mmCLK20_CLK2_CLK2_DFS_CNTL 0x1B051 34 35#define CLK0_CLK_PLL_REQ__FbMult_int_MASK 0x000001ffUL 36#define CLK0_CLK_PLL_REQ__PllSpineDiv_MASK 0x0000f000UL 37#define CLK0_CLK_PLL_REQ__FbMult_frac_MASK 0xffff0000UL 38#define CLK0_CLK_PLL_REQ__FbMult_int__SHIFT 0x00000000 39#define CLK0_CLK_PLL_REQ__PllSpineDiv__SHIFT 0x0000000c 40#define CLK0_CLK_PLL_REQ__FbMult_frac__SHIFT 0x00000010 41 42#undef FN 43#define FN(reg_name, field_name) \ 44 clk_mgr->clk_mgr_shift->field_name, clk_mgr->clk_mgr_mask->field_name 45 46#define REG(reg) \ 47 (clk_mgr->regs->reg) 48 49#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg 50 51#define BASE(seg) BASE_INNER(seg) 52 53#define SR(reg_name)\ 54 .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ 55 reg ## reg_name 56 57#define CLK_SR_DCN401(reg_name, block, inst)\ 58 .reg_name = mm ## block ## _ ## reg_name 59 60static const struct clk_mgr_registers clk_mgr_regs_dcn401 = { 61 CLK_REG_LIST_DCN401() 62}; 63 64static const struct clk_mgr_shift clk_mgr_shift_dcn401 = { 65 CLK_COMMON_MASK_SH_LIST_DCN401(__SHIFT) 66}; 67 68static const struct clk_mgr_mask clk_mgr_mask_dcn401 = { 69 CLK_COMMON_MASK_SH_LIST_DCN401(_MASK) 70}; 71 72#define TO_DCN401_CLK_MGR(clk_mgr)\ 73 container_of(clk_mgr, struct dcn401_clk_mgr, base) 74 75static bool dcn401_is_ppclk_dpm_enabled(struct clk_mgr_internal *clk_mgr, PPCLK_e clk) 76{ 77 bool ppclk_dpm_enabled = false; 78 79 switch (clk) { 80 case PPCLK_SOCCLK: 81 ppclk_dpm_enabled = 82 clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_socclk_levels > 1; 83 break; 84 case PPCLK_UCLK: 85 ppclk_dpm_enabled = 86 clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_memclk_levels > 1; 87 break; 88 case PPCLK_FCLK: 89 ppclk_dpm_enabled = 90 clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_fclk_levels > 1; 91 break; 92 case PPCLK_DISPCLK: 93 ppclk_dpm_enabled = 94 clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dispclk_levels > 1; 95 break; 96 case PPCLK_DPPCLK: 97 ppclk_dpm_enabled = 98 clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dppclk_levels > 1; 99 break; 100 case PPCLK_DPREFCLK: 101 ppclk_dpm_enabled = false; 102 break; 103 case PPCLK_DCFCLK: 104 ppclk_dpm_enabled = 105 clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dcfclk_levels > 1; 106 break; 107 case PPCLK_DTBCLK: 108 ppclk_dpm_enabled = 109 clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dtbclk_levels > 1; 110 break; 111 default: 112 ppclk_dpm_enabled = false; 113 } 114 115 ppclk_dpm_enabled &= clk_mgr->smu_present; 116 117 return ppclk_dpm_enabled; 118} 119 120static bool dcn401_is_ppclk_idle_dpm_enabled(struct clk_mgr_internal *clk_mgr, PPCLK_e clk) 121{ 122 bool ppclk_idle_dpm_enabled = false; 123 124 switch (clk) { 125 case PPCLK_UCLK: 126 case PPCLK_FCLK: 127 if (ASICREV_IS_GC_12_0_0_A0(clk_mgr->base.ctx->asic_id.hw_internal_rev) && 128 clk_mgr->smu_ver >= 0x681800) { 129 ppclk_idle_dpm_enabled = true; 130 } else if (ASICREV_IS_GC_12_0_1_A0(clk_mgr->base.ctx->asic_id.hw_internal_rev) && 131 clk_mgr->smu_ver >= 0x661300) { 132 ppclk_idle_dpm_enabled = true; 133 } 134 break; 135 default: 136 ppclk_idle_dpm_enabled = false; 137 } 138 139 ppclk_idle_dpm_enabled &= clk_mgr->smu_present; 140 141 return ppclk_idle_dpm_enabled; 142} 143 144static bool dcn401_is_df_throttle_opt_enabled(struct clk_mgr_internal *clk_mgr) 145{ 146 bool is_df_throttle_opt_enabled = false; 147 148 if (ASICREV_IS_GC_12_0_1_A0(clk_mgr->base.ctx->asic_id.hw_internal_rev) && 149 clk_mgr->smu_ver >= 0x663500) { 150 is_df_throttle_opt_enabled = !clk_mgr->base.ctx->dc->debug.force_subvp_df_throttle; 151 } 152 153 is_df_throttle_opt_enabled &= clk_mgr->smu_present; 154 155 return is_df_throttle_opt_enabled; 156} 157 158/* Query SMU for all clock states for a particular clock */ 159static void dcn401_init_single_clock(struct clk_mgr_internal *clk_mgr, PPCLK_e clk, unsigned int *entry_0, 160 unsigned int *num_levels) 161{ 162 unsigned int i; 163 char *entry_i = (char *)entry_0; 164 165 uint32_t ret = dcn401_smu_get_dpm_freq_by_index(clk_mgr, clk, 0xFF); 166 167 if (ret & (1 << 31)) 168 /* fine-grained, only min and max */ 169 *num_levels = 2; 170 else 171 /* discrete, a number of fixed states */ 172 /* will set num_levels to 0 on failure */ 173 *num_levels = ret & 0xFF; 174 175 /* if the initial message failed, num_levels will be 0 */ 176 for (i = 0; i < *num_levels && i < ARRAY_SIZE(clk_mgr->base.bw_params->clk_table.entries); i++) { 177 *((unsigned int *)entry_i) = (dcn401_smu_get_dpm_freq_by_index(clk_mgr, clk, i) & 0xFFFF); 178 entry_i += sizeof(clk_mgr->base.bw_params->clk_table.entries[0]); 179 } 180} 181 182static void dcn401_build_wm_range_table(struct clk_mgr *clk_mgr) 183{ 184 /* For min clocks use as reported by PM FW and report those as min */ 185 uint16_t min_uclk_mhz = clk_mgr->bw_params->clk_table.entries[0].memclk_mhz; 186 uint16_t min_dcfclk_mhz = clk_mgr->bw_params->clk_table.entries[0].dcfclk_mhz; 187 188 /* Set A - Normal - default values */ 189 clk_mgr->bw_params->wm_table.nv_entries[WM_A].valid = true; 190 clk_mgr->bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.wm_type = WATERMARKS_CLOCK_RANGE; 191 clk_mgr->bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.min_dcfclk = min_dcfclk_mhz; 192 clk_mgr->bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.max_dcfclk = 0xFFFF; 193 clk_mgr->bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.min_uclk = min_uclk_mhz; 194 clk_mgr->bw_params->wm_table.nv_entries[WM_A].pmfw_breakdown.max_uclk = 0xFFFF; 195 196 /* Set B - Unused on dcn4 */ 197 clk_mgr->bw_params->wm_table.nv_entries[WM_B].valid = false; 198 199 /* Set 1A - Dummy P-State - P-State latency set to "dummy p-state" value */ 200 /* 'DalDummyClockChangeLatencyNs' registry key option set to 0x7FFFFFFF can be used to disable Set C for dummy p-state */ 201 if (clk_mgr->ctx->dc->bb_overrides.dummy_clock_change_latency_ns != 0x7FFFFFFF) { 202 clk_mgr->bw_params->wm_table.nv_entries[WM_1A].valid = true; 203 clk_mgr->bw_params->wm_table.nv_entries[WM_1A].pmfw_breakdown.wm_type = WATERMARKS_DUMMY_PSTATE; 204 clk_mgr->bw_params->wm_table.nv_entries[WM_1A].pmfw_breakdown.min_dcfclk = min_dcfclk_mhz; 205 clk_mgr->bw_params->wm_table.nv_entries[WM_1A].pmfw_breakdown.max_dcfclk = 0xFFFF; 206 clk_mgr->bw_params->wm_table.nv_entries[WM_1A].pmfw_breakdown.min_uclk = min_uclk_mhz; 207 clk_mgr->bw_params->wm_table.nv_entries[WM_1A].pmfw_breakdown.max_uclk = 0xFFFF; 208 } else { 209 clk_mgr->bw_params->wm_table.nv_entries[WM_1A].valid = false; 210 } 211 212 /* Set 1B - Unused on dcn4 */ 213 clk_mgr->bw_params->wm_table.nv_entries[WM_1B].valid = false; 214} 215 216void dcn401_init_clocks(struct clk_mgr *clk_mgr_base) 217{ 218 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 219 struct clk_limit_num_entries *num_entries_per_clk; 220 unsigned int i; 221 222 if (!clk_mgr_base->bw_params) 223 return; 224 225 num_entries_per_clk = &clk_mgr_base->bw_params->clk_table.num_entries_per_clk; 226 227 memset(&(clk_mgr_base->clks), 0, sizeof(struct dc_clocks)); 228 clk_mgr_base->clks.p_state_change_support = true; 229 clk_mgr_base->clks.prev_p_state_change_support = true; 230 clk_mgr_base->clks.fclk_prev_p_state_change_support = true; 231 clk_mgr->smu_present = false; 232 clk_mgr->dpm_present = false; 233 234 if (!clk_mgr_base->force_smu_not_present && dcn401_smu_get_smu_version(clk_mgr, &clk_mgr->smu_ver)) 235 clk_mgr->smu_present = true; 236 237 if (!clk_mgr->smu_present) 238 return; 239 240 dcn401_smu_check_driver_if_version(clk_mgr); 241 dcn401_smu_check_msg_header_version(clk_mgr); 242 243 /* DCFCLK */ 244 dcn401_init_single_clock(clk_mgr, PPCLK_DCFCLK, 245 &clk_mgr_base->bw_params->clk_table.entries[0].dcfclk_mhz, 246 &num_entries_per_clk->num_dcfclk_levels); 247 clk_mgr_base->bw_params->dc_mode_limit.dcfclk_mhz = dcn401_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_DCFCLK); 248 if (num_entries_per_clk->num_dcfclk_levels && clk_mgr_base->bw_params->dc_mode_limit.dcfclk_mhz == 249 clk_mgr_base->bw_params->clk_table.entries[num_entries_per_clk->num_dcfclk_levels - 1].dcfclk_mhz) 250 clk_mgr_base->bw_params->dc_mode_limit.dcfclk_mhz = 0; 251 252 /* SOCCLK */ 253 dcn401_init_single_clock(clk_mgr, PPCLK_SOCCLK, 254 &clk_mgr_base->bw_params->clk_table.entries[0].socclk_mhz, 255 &num_entries_per_clk->num_socclk_levels); 256 clk_mgr_base->bw_params->dc_mode_limit.socclk_mhz = dcn401_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_SOCCLK); 257 if (num_entries_per_clk->num_socclk_levels && clk_mgr_base->bw_params->dc_mode_limit.socclk_mhz == 258 clk_mgr_base->bw_params->clk_table.entries[num_entries_per_clk->num_socclk_levels - 1].socclk_mhz) 259 clk_mgr_base->bw_params->dc_mode_limit.socclk_mhz = 0; 260 261 /* DTBCLK */ 262 if (!clk_mgr->base.ctx->dc->debug.disable_dtb_ref_clk_switch) { 263 dcn401_init_single_clock(clk_mgr, PPCLK_DTBCLK, 264 &clk_mgr_base->bw_params->clk_table.entries[0].dtbclk_mhz, 265 &num_entries_per_clk->num_dtbclk_levels); 266 clk_mgr_base->bw_params->dc_mode_limit.dtbclk_mhz = dcn401_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_DTBCLK); 267 if (num_entries_per_clk->num_dtbclk_levels && clk_mgr_base->bw_params->dc_mode_limit.dtbclk_mhz == 268 clk_mgr_base->bw_params->clk_table.entries[num_entries_per_clk->num_dtbclk_levels - 1].dtbclk_mhz) 269 clk_mgr_base->bw_params->dc_mode_limit.dtbclk_mhz = 0; 270 } 271 272 /* DISPCLK */ 273 dcn401_init_single_clock(clk_mgr, PPCLK_DISPCLK, 274 &clk_mgr_base->bw_params->clk_table.entries[0].dispclk_mhz, 275 &num_entries_per_clk->num_dispclk_levels); 276 clk_mgr_base->bw_params->dc_mode_limit.dispclk_mhz = dcn401_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_DISPCLK); 277 if (num_entries_per_clk->num_dispclk_levels && clk_mgr_base->bw_params->dc_mode_limit.dispclk_mhz == 278 clk_mgr_base->bw_params->clk_table.entries[num_entries_per_clk->num_dispclk_levels - 1].dispclk_mhz) 279 clk_mgr_base->bw_params->dc_mode_limit.dispclk_mhz = 0; 280 281 /* DPPCLK */ 282 dcn401_init_single_clock(clk_mgr, PPCLK_DPPCLK, 283 &clk_mgr_base->bw_params->clk_table.entries[0].dppclk_mhz, 284 &num_entries_per_clk->num_dppclk_levels); 285 286 if (num_entries_per_clk->num_dcfclk_levels && 287 num_entries_per_clk->num_dtbclk_levels && 288 num_entries_per_clk->num_dispclk_levels) 289 clk_mgr->dpm_present = true; 290 291 if (clk_mgr_base->ctx->dc->debug.min_disp_clk_khz) { 292 for (i = 0; i < num_entries_per_clk->num_dispclk_levels; i++) 293 if (clk_mgr_base->bw_params->clk_table.entries[i].dispclk_mhz 294 < khz_to_mhz_ceil(clk_mgr_base->ctx->dc->debug.min_disp_clk_khz)) 295 clk_mgr_base->bw_params->clk_table.entries[i].dispclk_mhz 296 = khz_to_mhz_ceil(clk_mgr_base->ctx->dc->debug.min_disp_clk_khz); 297 } 298 299 if (clk_mgr_base->ctx->dc->debug.min_dpp_clk_khz) { 300 for (i = 0; i < num_entries_per_clk->num_dppclk_levels; i++) 301 if (clk_mgr_base->bw_params->clk_table.entries[i].dppclk_mhz 302 < khz_to_mhz_ceil(clk_mgr_base->ctx->dc->debug.min_dpp_clk_khz)) 303 clk_mgr_base->bw_params->clk_table.entries[i].dppclk_mhz 304 = khz_to_mhz_ceil(clk_mgr_base->ctx->dc->debug.min_dpp_clk_khz); 305 } 306 307 /* Get UCLK, update bounding box */ 308 clk_mgr_base->funcs->get_memclk_states_from_smu(clk_mgr_base); 309 310 /* WM range table */ 311 dcn401_build_wm_range_table(clk_mgr_base); 312} 313 314bool dcn401_is_dc_mode_present(struct clk_mgr *clk_mgr_base) 315{ 316 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 317 318 return clk_mgr->smu_present && clk_mgr->dpm_present && 319 ((clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dcfclk_levels && 320 clk_mgr_base->bw_params->dc_mode_limit.dcfclk_mhz) || 321 (clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dispclk_levels && 322 clk_mgr_base->bw_params->dc_mode_limit.dispclk_mhz) || 323 (clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_dtbclk_levels && 324 clk_mgr_base->bw_params->dc_mode_limit.dtbclk_mhz) || 325 (clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_fclk_levels && 326 clk_mgr_base->bw_params->dc_mode_limit.fclk_mhz) || 327 (clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_memclk_levels && 328 clk_mgr_base->bw_params->dc_mode_limit.memclk_mhz) || 329 (clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_socclk_levels && 330 clk_mgr_base->bw_params->dc_mode_limit.socclk_mhz)); 331} 332 333static void dcn401_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass, 334 struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info) 335{ 336 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 337 uint32_t dprefclk_did = 0; 338 uint32_t dcfclk_did = 0; 339 uint32_t dtbclk_did = 0; 340 uint32_t dispclk_did = 0; 341 uint32_t dppclk_did = 0; 342 uint32_t fclk_did = 0; 343 uint32_t target_div = 0; 344 345 /* DFS Slice 0 is used for DISPCLK */ 346 dispclk_did = REG_READ(CLK0_CLK0_DFS_CNTL); 347 /* DFS Slice 1 is used for DPPCLK */ 348 dppclk_did = REG_READ(CLK0_CLK1_DFS_CNTL); 349 /* DFS Slice 2 is used for DPREFCLK */ 350 dprefclk_did = REG_READ(CLK0_CLK2_DFS_CNTL); 351 /* DFS Slice 3 is used for DCFCLK */ 352 dcfclk_did = REG_READ(CLK0_CLK3_DFS_CNTL); 353 /* DFS Slice 4 is used for DTBCLK */ 354 dtbclk_did = REG_READ(CLK0_CLK4_DFS_CNTL); 355 /* DFS Slice _ is used for FCLK */ 356 fclk_did = REG_READ(CLK2_CLK2_DFS_CNTL); 357 358 /* Convert DISPCLK DFS Slice DID to divider*/ 359 target_div = dentist_get_divider_from_did(dispclk_did); 360 //Get dispclk in khz 361 regs_and_bypass->dispclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR 362 * clk_mgr->base.dentist_vco_freq_khz) / target_div; 363 364 /* Convert DISPCLK DFS Slice DID to divider*/ 365 target_div = dentist_get_divider_from_did(dppclk_did); 366 //Get dppclk in khz 367 regs_and_bypass->dppclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR 368 * clk_mgr->base.dentist_vco_freq_khz) / target_div; 369 370 /* Convert DPREFCLK DFS Slice DID to divider*/ 371 target_div = dentist_get_divider_from_did(dprefclk_did); 372 //Get dprefclk in khz 373 regs_and_bypass->dprefclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR 374 * clk_mgr->base.dentist_vco_freq_khz) / target_div; 375 376 /* Convert DCFCLK DFS Slice DID to divider*/ 377 target_div = dentist_get_divider_from_did(dcfclk_did); 378 //Get dcfclk in khz 379 regs_and_bypass->dcfclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR 380 * clk_mgr->base.dentist_vco_freq_khz) / target_div; 381 382 /* Convert DTBCLK DFS Slice DID to divider*/ 383 target_div = dentist_get_divider_from_did(dtbclk_did); 384 //Get dtbclk in khz 385 regs_and_bypass->dtbclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR 386 * clk_mgr->base.dentist_vco_freq_khz) / target_div; 387 388 /* Convert DTBCLK DFS Slice DID to divider*/ 389 target_div = dentist_get_divider_from_did(fclk_did); 390 //Get fclk in khz 391 regs_and_bypass->fclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR 392 * clk_mgr->base.dentist_vco_freq_khz) / target_div; 393} 394 395static bool dcn401_check_native_scaling(struct pipe_ctx *pipe) 396{ 397 bool is_native_scaling = false; 398 int width = pipe->plane_state->src_rect.width; 399 int height = pipe->plane_state->src_rect.height; 400 401 if (pipe->stream->timing.h_addressable == width && 402 pipe->stream->timing.v_addressable == height && 403 pipe->plane_state->dst_rect.width == width && 404 pipe->plane_state->dst_rect.height == height) 405 is_native_scaling = true; 406 407 return is_native_scaling; 408} 409 410static void dcn401_auto_dpm_test_log( 411 struct dc_clocks *new_clocks, 412 struct clk_mgr_internal *clk_mgr, 413 struct dc_state *context) 414{ 415 unsigned int mall_ss_size_bytes; 416 int dramclk_khz_override, fclk_khz_override, num_fclk_levels; 417 418 struct pipe_ctx *pipe_ctx_list[MAX_PIPES]; 419 int active_pipe_count = 0; 420 421 for (int i = 0; i < MAX_PIPES; i++) { 422 struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 423 424 if (pipe_ctx->stream && dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM) { 425 pipe_ctx_list[active_pipe_count] = pipe_ctx; 426 active_pipe_count++; 427 } 428 } 429 430 msleep(5); 431 432 mall_ss_size_bytes = context->bw_ctx.bw.dcn.mall_ss_size_bytes; 433 434 struct clk_log_info log_info = {0}; 435 struct clk_state_registers_and_bypass clk_register_dump; 436 437 dcn401_dump_clk_registers(&clk_register_dump, &clk_mgr->base, &log_info); 438 439 // Overrides for these clocks in case there is no p_state change support 440 dramclk_khz_override = new_clocks->dramclk_khz; 441 fclk_khz_override = new_clocks->fclk_khz; 442 443 num_fclk_levels = clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_fclk_levels - 1; 444 445 if (!new_clocks->p_state_change_support) 446 dramclk_khz_override = clk_mgr->base.bw_params->max_memclk_mhz * 1000; 447 448 if (!new_clocks->fclk_p_state_change_support) 449 fclk_khz_override = clk_mgr->base.bw_params->clk_table.entries[num_fclk_levels].fclk_mhz * 1000; 450 451 452 //////////////////////////////////////////////////////////////////////////// 453 // IMPORTANT: When adding more clocks to these logs, do NOT put a newline 454 // anywhere other than at the very end of the string. 455 // 456 // Formatting example (make sure to have " - " between each entry): 457 // 458 // AutoDPMTest: clk1:%d - clk2:%d - clk3:%d - clk4:%d\n" 459 //////////////////////////////////////////////////////////////////////////// 460 if (active_pipe_count > 0 && 461 new_clocks->dramclk_khz > 0 && 462 new_clocks->fclk_khz > 0 && 463 new_clocks->dcfclk_khz > 0 && 464 new_clocks->dppclk_khz > 0) { 465 466 uint32_t pix_clk_list[MAX_PIPES] = {0}; 467 int p_state_list[MAX_PIPES] = {0}; 468 int disp_src_width_list[MAX_PIPES] = {0}; 469 int disp_src_height_list[MAX_PIPES] = {0}; 470 uint64_t disp_src_refresh_list[MAX_PIPES] = {0}; 471 bool is_scaled_list[MAX_PIPES] = {0}; 472 473 for (int i = 0; i < active_pipe_count; i++) { 474 struct pipe_ctx *curr_pipe_ctx = pipe_ctx_list[i]; 475 uint64_t refresh_rate; 476 477 pix_clk_list[i] = curr_pipe_ctx->stream->timing.pix_clk_100hz; 478 p_state_list[i] = curr_pipe_ctx->p_state_type; 479 480 refresh_rate = (curr_pipe_ctx->stream->timing.pix_clk_100hz * (uint64_t)100 + 481 curr_pipe_ctx->stream->timing.v_total 482 * (uint64_t) curr_pipe_ctx->stream->timing.h_total - (uint64_t)1); 483 refresh_rate = div_u64(refresh_rate, curr_pipe_ctx->stream->timing.v_total); 484 refresh_rate = div_u64(refresh_rate, curr_pipe_ctx->stream->timing.h_total); 485 disp_src_refresh_list[i] = refresh_rate; 486 487 if (curr_pipe_ctx->plane_state) { 488 is_scaled_list[i] = !(dcn401_check_native_scaling(curr_pipe_ctx)); 489 disp_src_width_list[i] = curr_pipe_ctx->plane_state->src_rect.width; 490 disp_src_height_list[i] = curr_pipe_ctx->plane_state->src_rect.height; 491 } 492 } 493 494 DC_LOG_AUTO_DPM_TEST("AutoDPMTest: dramclk:%d - fclk:%d - " 495 "dcfclk:%d - dppclk:%d - dispclk_hw:%d - " 496 "dppclk_hw:%d - dprefclk_hw:%d - dcfclk_hw:%d - " 497 "dtbclk_hw:%d - fclk_hw:%d - pix_clk_0:%d - pix_clk_1:%d - " 498 "pix_clk_2:%d - pix_clk_3:%d - mall_ss_size:%d - p_state_type_0:%d - " 499 "p_state_type_1:%d - p_state_type_2:%d - p_state_type_3:%d - " 500 "pix_width_0:%d - pix_height_0:%d - refresh_rate_0:%lld - is_scaled_0:%d - " 501 "pix_width_1:%d - pix_height_1:%d - refresh_rate_1:%lld - is_scaled_1:%d - " 502 "pix_width_2:%d - pix_height_2:%d - refresh_rate_2:%lld - is_scaled_2:%d - " 503 "pix_width_3:%d - pix_height_3:%d - refresh_rate_3:%lld - is_scaled_3:%d - LOG_END\n", 504 dramclk_khz_override, 505 fclk_khz_override, 506 new_clocks->dcfclk_khz, 507 new_clocks->dppclk_khz, 508 clk_register_dump.dispclk, 509 clk_register_dump.dppclk, 510 clk_register_dump.dprefclk, 511 clk_register_dump.dcfclk, 512 clk_register_dump.dtbclk, 513 clk_register_dump.fclk, 514 pix_clk_list[0], pix_clk_list[1], pix_clk_list[3], pix_clk_list[2], 515 mall_ss_size_bytes, 516 p_state_list[0], p_state_list[1], p_state_list[2], p_state_list[3], 517 disp_src_width_list[0], disp_src_height_list[0], disp_src_refresh_list[0], is_scaled_list[0], 518 disp_src_width_list[1], disp_src_height_list[1], disp_src_refresh_list[1], is_scaled_list[1], 519 disp_src_width_list[2], disp_src_height_list[2], disp_src_refresh_list[2], is_scaled_list[2], 520 disp_src_width_list[3], disp_src_height_list[3], disp_src_refresh_list[3], is_scaled_list[3]); 521 } 522} 523 524static void dcn401_update_clocks_update_dtb_dto(struct clk_mgr_internal *clk_mgr, 525 struct dc_state *context, 526 int ref_dtbclk_khz) 527{ 528 int i; 529 struct dccg *dccg = clk_mgr->dccg; 530 struct pipe_ctx *otg_master; 531 bool use_hpo_encoder; 532 533 534 for (i = 0; i < context->stream_count; i++) { 535 otg_master = resource_get_otg_master_for_stream( 536 &context->res_ctx, context->streams[i]); 537 ASSERT(otg_master); 538 ASSERT(otg_master->clock_source); 539 ASSERT(otg_master->clock_source->funcs->program_pix_clk); 540 ASSERT(otg_master->stream_res.pix_clk_params.controller_id >= CONTROLLER_ID_D0); 541 542 use_hpo_encoder = dccg->ctx->dc->link_srv->dp_is_128b_132b_signal(otg_master); 543 if (!use_hpo_encoder) 544 continue; 545 546 if (otg_master->stream_res.pix_clk_params.controller_id > CONTROLLER_ID_UNDEFINED) 547 otg_master->clock_source->funcs->program_pix_clk( 548 otg_master->clock_source, 549 &otg_master->stream_res.pix_clk_params, 550 dccg->ctx->dc->link_srv->dp_get_encoding_format( 551 &otg_master->link_config.dp_link_settings), 552 &otg_master->pll_settings); 553 } 554} 555 556static void dcn401_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr, 557 struct dc_state *context, bool safe_to_lower, int ref_dppclk_khz) 558{ 559 int i; 560 561 clk_mgr->dccg->ref_dppclk = ref_dppclk_khz; 562 for (i = 0; i < clk_mgr->base.ctx->dc->res_pool->pipe_count; i++) { 563 int dpp_inst = 0, dppclk_khz, prev_dppclk_khz; 564 565 dppclk_khz = context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz; 566 567 if (context->res_ctx.pipe_ctx[i].plane_res.dpp) 568 dpp_inst = context->res_ctx.pipe_ctx[i].plane_res.dpp->inst; 569 else if (!context->res_ctx.pipe_ctx[i].plane_res.dpp && dppclk_khz == 0) { 570 /* dpp == NULL && dppclk_khz == 0 is valid because of pipe harvesting. 571 * In this case just continue in loop 572 */ 573 continue; 574 } else if (!context->res_ctx.pipe_ctx[i].plane_res.dpp && dppclk_khz > 0) { 575 /* The software state is not valid if dpp resource is NULL and 576 * dppclk_khz > 0. 577 */ 578 ASSERT(false); 579 continue; 580 } 581 582 prev_dppclk_khz = clk_mgr->dccg->pipe_dppclk_khz[i]; 583 584 if (safe_to_lower || prev_dppclk_khz < dppclk_khz) 585 clk_mgr->dccg->funcs->update_dpp_dto( 586 clk_mgr->dccg, dpp_inst, dppclk_khz); 587 } 588} 589 590static int dcn401_set_hard_min_by_freq_optimized(struct clk_mgr_internal *clk_mgr, PPCLK_e clk, int requested_clk_khz) 591{ 592 if (!clk_mgr->smu_present || !dcn401_is_ppclk_dpm_enabled(clk_mgr, clk)) 593 return 0; 594 595 /* 596 * SMU set hard min interface takes requested clock in mhz and return 597 * actual clock configured in khz. If we floor requested clk to mhz, 598 * there is a chance that the actual clock configured in khz is less 599 * than requested. If we ceil it to mhz, there is a chance that it 600 * unnecessarily dumps up to a higher dpm level, which burns more power. 601 * The solution is to set by flooring it to mhz first. If the actual 602 * clock returned is less than requested, then we will ceil the 603 * requested value to mhz and call it again. 604 */ 605 int actual_clk_khz = dcn401_smu_set_hard_min_by_freq(clk_mgr, clk, khz_to_mhz_floor(requested_clk_khz)); 606 607 if (actual_clk_khz < requested_clk_khz) 608 actual_clk_khz = dcn401_smu_set_hard_min_by_freq(clk_mgr, clk, khz_to_mhz_ceil(requested_clk_khz)); 609 610 return actual_clk_khz; 611} 612 613static void dcn401_update_clocks_update_dentist( 614 struct clk_mgr_internal *clk_mgr, 615 struct dc_state *context) 616{ 617 uint32_t new_disp_divider = 0; 618 uint32_t new_dispclk_wdivider = 0; 619 uint32_t dentist_dispclk_wdivider_readback = 0; 620 struct dc *dc = clk_mgr->base.ctx->dc; 621 622 if (clk_mgr->base.clks.dispclk_khz == 0) 623 return; 624 625 new_disp_divider = DENTIST_DIVIDER_RANGE_SCALE_FACTOR 626 * clk_mgr->base.dentist_vco_freq_khz / clk_mgr->base.clks.dispclk_khz; 627 628 new_dispclk_wdivider = dentist_get_did_from_divider(new_disp_divider); 629 630 if (dc->debug.override_dispclk_programming) { 631 REG_GET(DENTIST_DISPCLK_CNTL, 632 DENTIST_DISPCLK_WDIVIDER, &dentist_dispclk_wdivider_readback); 633 634 if (dentist_dispclk_wdivider_readback > new_dispclk_wdivider) { 635 REG_UPDATE(DENTIST_DISPCLK_CNTL, 636 DENTIST_DISPCLK_WDIVIDER, new_dispclk_wdivider); 637 REG_WAIT(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_CHG_DONE, 1, 50, 2000); 638 } 639 } 640 641} 642 643static void dcn401_execute_block_sequence(struct clk_mgr *clk_mgr_base, unsigned int num_steps) 644{ 645 struct clk_mgr_internal *clk_mgr_internal = TO_CLK_MGR_INTERNAL(clk_mgr_base); 646 struct dcn401_clk_mgr *clk_mgr401 = TO_DCN401_CLK_MGR(clk_mgr_internal); 647 648 unsigned int i; 649 union dcn401_clk_mgr_block_sequence_params *params; 650 651 /* execute sequence */ 652 for (i = 0; i < num_steps; i++) { 653 params = &clk_mgr401->block_sequence[i].params; 654 655 switch (clk_mgr401->block_sequence[i].func) { 656 case CLK_MGR401_READ_CLOCKS_FROM_DENTIST: 657 dcn2_read_clocks_from_hw_dentist(clk_mgr_base); 658 break; 659 case CLK_MGR401_UPDATE_NUM_DISPLAYS: 660 dcn401_smu_set_num_of_displays(clk_mgr_internal, 661 params->update_num_displays_params.num_displays); 662 break; 663 case CLK_MGR401_UPDATE_HARDMIN_PPCLK: 664 if (params->update_hardmin_params.response) 665 *params->update_hardmin_params.response = dcn401_smu_set_hard_min_by_freq( 666 clk_mgr_internal, 667 params->update_hardmin_params.ppclk, 668 params->update_hardmin_params.freq_mhz); 669 else 670 dcn401_smu_set_hard_min_by_freq(clk_mgr_internal, 671 params->update_hardmin_params.ppclk, 672 params->update_hardmin_params.freq_mhz); 673 break; 674 case CLK_MGR401_UPDATE_HARDMIN_PPCLK_OPTIMIZED: 675 if (params->update_hardmin_optimized_params.response) 676 *params->update_hardmin_optimized_params.response = dcn401_set_hard_min_by_freq_optimized( 677 clk_mgr_internal, 678 params->update_hardmin_optimized_params.ppclk, 679 params->update_hardmin_optimized_params.freq_khz); 680 else 681 dcn401_set_hard_min_by_freq_optimized(clk_mgr_internal, 682 params->update_hardmin_optimized_params.ppclk, 683 params->update_hardmin_optimized_params.freq_khz); 684 break; 685 case CLK_MGR401_UPDATE_ACTIVE_HARDMINS: 686 dcn401_smu_set_active_uclk_fclk_hardmin( 687 clk_mgr_internal, 688 params->update_idle_hardmin_params.uclk_mhz, 689 params->update_idle_hardmin_params.fclk_mhz); 690 break; 691 case CLK_MGR401_UPDATE_IDLE_HARDMINS: 692 dcn401_smu_set_idle_uclk_fclk_hardmin( 693 clk_mgr_internal, 694 params->update_idle_hardmin_params.uclk_mhz, 695 params->update_idle_hardmin_params.fclk_mhz); 696 break; 697 case CLK_MGR401_UPDATE_SUBVP_HARDMINS: 698 dcn401_smu_set_subvp_uclk_fclk_hardmin( 699 clk_mgr_internal, 700 params->update_idle_hardmin_params.uclk_mhz, 701 params->update_idle_hardmin_params.fclk_mhz); 702 break; 703 case CLK_MGR401_UPDATE_DEEP_SLEEP_DCFCLK: 704 dcn401_smu_set_min_deep_sleep_dcef_clk( 705 clk_mgr_internal, 706 params->update_deep_sleep_dcfclk_params.freq_mhz); 707 break; 708 case CLK_MGR401_UPDATE_FCLK_PSTATE_SUPPORT: 709 dcn401_smu_send_fclk_pstate_message( 710 clk_mgr_internal, 711 params->update_pstate_support_params.support); 712 break; 713 case CLK_MGR401_UPDATE_UCLK_PSTATE_SUPPORT: 714 dcn401_smu_send_uclk_pstate_message( 715 clk_mgr_internal, 716 params->update_pstate_support_params.support); 717 break; 718 case CLK_MGR401_UPDATE_CAB_FOR_UCLK: 719 dcn401_smu_send_cab_for_uclk_message( 720 clk_mgr_internal, 721 params->update_cab_for_uclk_params.num_ways); 722 break; 723 case CLK_MGR401_UPDATE_WAIT_FOR_DMUB_ACK: 724 dcn401_smu_wait_for_dmub_ack_mclk( 725 clk_mgr_internal, 726 params->update_wait_for_dmub_ack_params.enable); 727 break; 728 case CLK_MGR401_INDICATE_DRR_STATUS: 729 dcn401_smu_indicate_drr_status( 730 clk_mgr_internal, 731 params->indicate_drr_status_params.mod_drr_for_pstate); 732 break; 733 case CLK_MGR401_UPDATE_DPPCLK_DTO: 734 dcn401_update_clocks_update_dpp_dto( 735 clk_mgr_internal, 736 params->update_dppclk_dto_params.context, 737 params->update_dppclk_dto_params.safe_to_lower, 738 *params->update_dppclk_dto_params.ref_dppclk_khz); 739 break; 740 case CLK_MGR401_UPDATE_DTBCLK_DTO: 741 dcn401_update_clocks_update_dtb_dto( 742 clk_mgr_internal, 743 params->update_dtbclk_dto_params.context, 744 *params->update_dtbclk_dto_params.ref_dtbclk_khz); 745 break; 746 case CLK_MGR401_UPDATE_DENTIST: 747 dcn401_update_clocks_update_dentist( 748 clk_mgr_internal, 749 params->update_dentist_params.context); 750 break; 751 case CLK_MGR401_UPDATE_PSR_WAIT_LOOP: 752 params->update_psr_wait_loop_params.dmcu->funcs->set_psr_wait_loop( 753 params->update_psr_wait_loop_params.dmcu, 754 params->update_psr_wait_loop_params.wait); 755 break; 756 default: 757 /* this should never happen */ 758 BREAK_TO_DEBUGGER(); 759 break; 760 } 761 } 762} 763 764static unsigned int dcn401_build_update_bandwidth_clocks_sequence( 765 struct clk_mgr *clk_mgr_base, 766 struct dc_state *context, 767 struct dc_clocks *new_clocks, 768 bool safe_to_lower) 769{ 770 struct clk_mgr_internal *clk_mgr_internal = TO_CLK_MGR_INTERNAL(clk_mgr_base); 771 struct dcn401_clk_mgr *clk_mgr401 = TO_DCN401_CLK_MGR(clk_mgr_internal); 772 struct dc *dc = clk_mgr_base->ctx->dc; 773 struct dcn401_clk_mgr_block_sequence *block_sequence = clk_mgr401->block_sequence; 774 bool enter_display_off = false; 775 bool update_active_fclk = false; 776 bool update_active_uclk = false; 777 bool update_idle_fclk = false; 778 bool update_idle_uclk = false; 779 bool update_subvp_prefetch_dramclk = false; 780 bool update_subvp_prefetch_fclk = false; 781 bool is_idle_dpm_enabled = dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_UCLK) && 782 dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_FCLK) && 783 dcn401_is_ppclk_idle_dpm_enabled(clk_mgr_internal, PPCLK_UCLK) && 784 dcn401_is_ppclk_idle_dpm_enabled(clk_mgr_internal, PPCLK_FCLK); 785 bool is_df_throttle_opt_enabled = is_idle_dpm_enabled && 786 dcn401_is_df_throttle_opt_enabled(clk_mgr_internal); 787 int total_plane_count = clk_mgr_helper_get_active_plane_cnt(dc, context); 788 int active_uclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.dramclk_khz); 789 int active_fclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.fclk_khz); 790 int idle_uclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.idle_dramclk_khz); 791 int idle_fclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.idle_fclk_khz); 792 int subvp_prefetch_dramclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.subvp_prefetch_dramclk_khz); 793 int subvp_prefetch_fclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.subvp_prefetch_fclk_khz); 794 795 unsigned int num_steps = 0; 796 797 int display_count; 798 bool fclk_p_state_change_support, uclk_p_state_change_support; 799 800 /* CLK_MGR401_UPDATE_NUM_DISPLAYS */ 801 if (clk_mgr_internal->smu_present) { 802 display_count = clk_mgr_helper_get_active_display_cnt(dc, context); 803 804 if (display_count == 0) 805 enter_display_off = true; 806 807 if (enter_display_off == safe_to_lower) { 808 block_sequence[num_steps].params.update_num_displays_params.num_displays = display_count; 809 block_sequence[num_steps].func = CLK_MGR401_UPDATE_NUM_DISPLAYS; 810 num_steps++; 811 } 812 } 813 814 /* CLK_MGR401_UPDATE_FCLK_PSTATE_SUPPORT */ 815 clk_mgr_base->clks.fclk_prev_p_state_change_support = clk_mgr_base->clks.fclk_p_state_change_support; 816 fclk_p_state_change_support = new_clocks->fclk_p_state_change_support || (total_plane_count == 0); 817 if (should_update_pstate_support(safe_to_lower, fclk_p_state_change_support, clk_mgr_base->clks.fclk_prev_p_state_change_support)) { 818 clk_mgr_base->clks.fclk_p_state_change_support = fclk_p_state_change_support; 819 update_active_fclk = true; 820 update_idle_fclk = true; 821 822 /* To enable FCLK P-state switching, send PSTATE_SUPPORTED message to PMFW (message not supported on DCN401)*/ 823 // if (clk_mgr_base->clks.fclk_p_state_change_support) { 824 // /* Handle the code for sending a message to PMFW that FCLK P-state change is supported */ 825 // if (dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_FCLK)) { 826 // block_sequence[num_steps].params.update_pstate_support_params.support = true; 827 // block_sequence[num_steps].func = CLK_MGR401_UPDATE_FCLK_PSTATE_SUPPORT; 828 // num_steps++; 829 // } 830 // } 831 } 832 833 if (!clk_mgr_base->clks.fclk_p_state_change_support && dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_FCLK)) { 834 /* when P-State switching disabled, set UCLK min = max */ 835 idle_fclk_mhz = 836 clk_mgr_base->bw_params->clk_table.entries[clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_fclk_levels - 1].fclk_mhz; 837 active_fclk_mhz = idle_fclk_mhz; 838 } 839 840 /* UPDATE DCFCLK */ 841 if (dc->debug.force_min_dcfclk_mhz > 0) 842 new_clocks->dcfclk_khz = (new_clocks->dcfclk_khz > (dc->debug.force_min_dcfclk_mhz * 1000)) ? 843 new_clocks->dcfclk_khz : (dc->debug.force_min_dcfclk_mhz * 1000); 844 845 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) { 846 clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz; 847 if (dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_DCFCLK)) { 848 block_sequence[num_steps].params.update_hardmin_params.ppclk = PPCLK_DCFCLK; 849 block_sequence[num_steps].params.update_hardmin_params.freq_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.dcfclk_khz); 850 block_sequence[num_steps].params.update_hardmin_params.response = NULL; 851 block_sequence[num_steps].func = CLK_MGR401_UPDATE_HARDMIN_PPCLK; 852 num_steps++; 853 } 854 } 855 856 /* CLK_MGR401_UPDATE_DEEP_SLEEP_DCFCLK */ 857 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) { 858 clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; 859 if (dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_DCFCLK)) { 860 block_sequence[num_steps].params.update_deep_sleep_dcfclk_params.freq_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.dcfclk_deep_sleep_khz); 861 block_sequence[num_steps].func = CLK_MGR401_UPDATE_DEEP_SLEEP_DCFCLK; 862 num_steps++; 863 } 864 } 865 866 /* SOCCLK */ 867 if (should_set_clock(safe_to_lower, new_clocks->socclk_khz, clk_mgr_base->clks.socclk_khz)) 868 /* We don't actually care about socclk, don't notify SMU of hard min */ 869 clk_mgr_base->clks.socclk_khz = new_clocks->socclk_khz; 870 871 /* UCLK */ 872 if (new_clocks->fw_based_mclk_switching != clk_mgr_base->clks.fw_based_mclk_switching && 873 new_clocks->fw_based_mclk_switching) { 874 /* enable FAMS features */ 875 clk_mgr_base->clks.fw_based_mclk_switching = new_clocks->fw_based_mclk_switching; 876 877 block_sequence[num_steps].params.update_wait_for_dmub_ack_params.enable = clk_mgr_base->clks.fw_based_mclk_switching; 878 block_sequence[num_steps].func = CLK_MGR401_UPDATE_WAIT_FOR_DMUB_ACK; 879 num_steps++; 880 881 block_sequence[num_steps].params.indicate_drr_status_params.mod_drr_for_pstate = clk_mgr_base->clks.fw_based_mclk_switching; 882 block_sequence[num_steps].func = CLK_MGR401_INDICATE_DRR_STATUS; 883 num_steps++; 884 } 885 886 /* CLK_MGR401_UPDATE_CAB_FOR_UCLK */ 887 clk_mgr_base->clks.prev_num_ways = clk_mgr_base->clks.num_ways; 888 if (clk_mgr_base->clks.num_ways != new_clocks->num_ways && 889 clk_mgr_base->clks.num_ways < new_clocks->num_ways) { 890 /* increase num ways for subvp */ 891 clk_mgr_base->clks.num_ways = new_clocks->num_ways; 892 if (dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_UCLK)) { 893 block_sequence[num_steps].params.update_cab_for_uclk_params.num_ways = clk_mgr_base->clks.num_ways; 894 block_sequence[num_steps].func = CLK_MGR401_UPDATE_CAB_FOR_UCLK; 895 num_steps++; 896 } 897 } 898 899 clk_mgr_base->clks.prev_p_state_change_support = clk_mgr_base->clks.p_state_change_support; 900 uclk_p_state_change_support = new_clocks->p_state_change_support || (total_plane_count == 0); 901 if (should_update_pstate_support(safe_to_lower, uclk_p_state_change_support, clk_mgr_base->clks.prev_p_state_change_support)) { 902 clk_mgr_base->clks.p_state_change_support = uclk_p_state_change_support; 903 update_active_uclk = true; 904 update_idle_uclk = true; 905 906 if (clk_mgr_base->clks.p_state_change_support) { 907 /* enable UCLK switching */ 908 if (dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_UCLK)) { 909 block_sequence[num_steps].params.update_pstate_support_params.support = true; 910 block_sequence[num_steps].func = CLK_MGR401_UPDATE_UCLK_PSTATE_SUPPORT; 911 num_steps++; 912 } 913 } 914 } 915 916 if (!clk_mgr_base->clks.p_state_change_support && dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_UCLK)) { 917 /* when P-State switching disabled, set UCLK min = max */ 918 if (dc->clk_mgr->dc_mode_softmax_enabled) { 919 /* will never have the functional UCLK min above the softmax 920 * since we calculate mode support based on softmax being the max UCLK 921 * frequency. 922 */ 923 active_uclk_mhz = clk_mgr_base->bw_params->dc_mode_softmax_memclk; 924 } else { 925 active_uclk_mhz = clk_mgr_base->bw_params->max_memclk_mhz; 926 } 927 idle_uclk_mhz = active_uclk_mhz; 928 } 929 930 /* Always update saved value, even if new value not set due to P-State switching unsupported */ 931 if (should_set_clock(safe_to_lower, new_clocks->dramclk_khz, clk_mgr_base->clks.dramclk_khz)) { 932 clk_mgr_base->clks.dramclk_khz = new_clocks->dramclk_khz; 933 934 if (clk_mgr_base->clks.p_state_change_support) { 935 update_active_uclk = true; 936 active_uclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.dramclk_khz); 937 } 938 } 939 940 if (should_set_clock(safe_to_lower, new_clocks->idle_dramclk_khz, clk_mgr_base->clks.idle_dramclk_khz)) { 941 clk_mgr_base->clks.idle_dramclk_khz = new_clocks->idle_dramclk_khz; 942 943 if (clk_mgr_base->clks.p_state_change_support) { 944 update_idle_uclk = true; 945 idle_uclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.idle_dramclk_khz); 946 } 947 } 948 949 if (should_set_clock(safe_to_lower, new_clocks->subvp_prefetch_dramclk_khz, clk_mgr_base->clks.subvp_prefetch_dramclk_khz)) { 950 clk_mgr_base->clks.subvp_prefetch_dramclk_khz = new_clocks->subvp_prefetch_dramclk_khz; 951 update_subvp_prefetch_dramclk = true; 952 subvp_prefetch_dramclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.subvp_prefetch_dramclk_khz); 953 } 954 955 /* FCLK */ 956 /* Always update saved value, even if new value not set due to P-State switching unsupported */ 957 if (should_set_clock(safe_to_lower, new_clocks->fclk_khz, clk_mgr_base->clks.fclk_khz)) { 958 clk_mgr_base->clks.fclk_khz = new_clocks->fclk_khz; 959 960 if (clk_mgr_base->clks.fclk_p_state_change_support) { 961 update_active_fclk = true; 962 active_fclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.fclk_khz); 963 } 964 } 965 966 if (should_set_clock(safe_to_lower, new_clocks->idle_fclk_khz, clk_mgr_base->clks.idle_fclk_khz)) { 967 clk_mgr_base->clks.idle_fclk_khz = new_clocks->idle_fclk_khz; 968 969 if (clk_mgr_base->clks.fclk_p_state_change_support) { 970 update_idle_fclk = true; 971 idle_fclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.idle_fclk_khz); 972 } 973 } 974 975 if (should_set_clock(safe_to_lower, new_clocks->subvp_prefetch_fclk_khz, clk_mgr_base->clks.subvp_prefetch_fclk_khz)) { 976 clk_mgr_base->clks.subvp_prefetch_fclk_khz = new_clocks->subvp_prefetch_fclk_khz; 977 update_subvp_prefetch_fclk = true; 978 subvp_prefetch_fclk_mhz = khz_to_mhz_ceil(clk_mgr_base->clks.subvp_prefetch_fclk_khz); 979 } 980 981 /* When idle DPM is enabled, need to send active and idle hardmins separately */ 982 /* CLK_MGR401_UPDATE_ACTIVE_HARDMINS */ 983 if ((update_active_uclk || update_active_fclk) && is_idle_dpm_enabled) { 984 block_sequence[num_steps].params.update_idle_hardmin_params.uclk_mhz = active_uclk_mhz; 985 block_sequence[num_steps].params.update_idle_hardmin_params.fclk_mhz = active_fclk_mhz; 986 block_sequence[num_steps].func = CLK_MGR401_UPDATE_ACTIVE_HARDMINS; 987 num_steps++; 988 } 989 990 /* CLK_MGR401_UPDATE_IDLE_HARDMINS */ 991 if ((update_idle_uclk || update_idle_fclk) && is_idle_dpm_enabled) { 992 block_sequence[num_steps].params.update_idle_hardmin_params.uclk_mhz = idle_uclk_mhz; 993 block_sequence[num_steps].params.update_idle_hardmin_params.fclk_mhz = idle_fclk_mhz; 994 block_sequence[num_steps].func = CLK_MGR401_UPDATE_IDLE_HARDMINS; 995 num_steps++; 996 } 997 998 /* CLK_MGR401_UPDATE_SUBVP_HARDMINS */ 999 if ((update_subvp_prefetch_dramclk || update_subvp_prefetch_fclk) && is_df_throttle_opt_enabled) { 1000 block_sequence[num_steps].params.update_idle_hardmin_params.uclk_mhz = subvp_prefetch_dramclk_mhz; 1001 block_sequence[num_steps].params.update_idle_hardmin_params.fclk_mhz = subvp_prefetch_fclk_mhz; 1002 block_sequence[num_steps].func = CLK_MGR401_UPDATE_SUBVP_HARDMINS; 1003 num_steps++; 1004 } 1005 1006 /* set UCLK to requested value if P-State switching is supported, or to re-enable P-State switching */ 1007 if (update_active_uclk || update_idle_uclk) { 1008 if (!is_idle_dpm_enabled) { 1009 block_sequence[num_steps].params.update_hardmin_params.ppclk = PPCLK_UCLK; 1010 block_sequence[num_steps].params.update_hardmin_params.freq_mhz = active_uclk_mhz; 1011 block_sequence[num_steps].params.update_hardmin_params.response = NULL; 1012 block_sequence[num_steps].func = CLK_MGR401_UPDATE_HARDMIN_PPCLK; 1013 num_steps++; 1014 } 1015 1016 /* disable UCLK P-State support if needed */ 1017 if (!uclk_p_state_change_support && 1018 should_update_pstate_support(safe_to_lower, uclk_p_state_change_support, clk_mgr_base->clks.prev_p_state_change_support) && 1019 dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_UCLK)) { 1020 block_sequence[num_steps].params.update_pstate_support_params.support = false; 1021 block_sequence[num_steps].func = CLK_MGR401_UPDATE_UCLK_PSTATE_SUPPORT; 1022 num_steps++; 1023 } 1024 } 1025 1026 /* set FCLK to requested value if P-State switching is supported, or to re-enable P-State switching */ 1027 if (update_active_fclk || update_idle_fclk) { 1028 /* No need to send active FCLK hardmin, automatically set based on DCFCLK */ 1029 // if (!is_idle_dpm_enabled) { 1030 // block_sequence[*num_steps].update_hardmin_params.clk_mgr = clk_mgr; 1031 // block_sequence[*num_steps].update_hardmin_params.ppclk = PPCLK_FCLK; 1032 // block_sequence[*num_steps].update_hardmin_params.freq_mhz = active_fclk_mhz; 1033 // block_sequence[*num_steps].update_hardmin_params.response = NULL; 1034 // block_sequence[*num_steps].func = CLK_MGR401_UPDATE_HARDMIN_PPCLK; 1035 // (*num_steps)++; 1036 // } 1037 1038 /* disable FCLK P-State support if needed (message not supported on DCN401)*/ 1039 // if (!fclk_p_state_change_support && 1040 // should_update_pstate_support(safe_to_lower, fclk_p_state_change_support, clk_mgr_base->clks.fclk_prev_p_state_change_support) && 1041 // dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_FCLK)) { 1042 // block_sequence[num_steps].params.update_pstate_support_params.support = false; 1043 // block_sequence[num_steps].func = CLK_MGR401_UPDATE_FCLK_PSTATE_SUPPORT; 1044 // num_steps++; 1045 // } 1046 } 1047 1048 if (new_clocks->fw_based_mclk_switching != clk_mgr_base->clks.fw_based_mclk_switching && 1049 safe_to_lower && !new_clocks->fw_based_mclk_switching) { 1050 /* disable FAMS features */ 1051 clk_mgr_base->clks.fw_based_mclk_switching = new_clocks->fw_based_mclk_switching; 1052 1053 block_sequence[num_steps].params.update_wait_for_dmub_ack_params.enable = clk_mgr_base->clks.fw_based_mclk_switching; 1054 block_sequence[num_steps].func = CLK_MGR401_UPDATE_WAIT_FOR_DMUB_ACK; 1055 num_steps++; 1056 1057 block_sequence[num_steps].params.indicate_drr_status_params.mod_drr_for_pstate = clk_mgr_base->clks.fw_based_mclk_switching; 1058 block_sequence[num_steps].func = CLK_MGR401_INDICATE_DRR_STATUS; 1059 num_steps++; 1060 } 1061 1062 /* CLK_MGR401_UPDATE_CAB_FOR_UCLK */ 1063 if (clk_mgr_base->clks.num_ways != new_clocks->num_ways && 1064 safe_to_lower && clk_mgr_base->clks.num_ways > new_clocks->num_ways) { 1065 /* decrease num ways for subvp */ 1066 clk_mgr_base->clks.num_ways = new_clocks->num_ways; 1067 if (dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_UCLK)) { 1068 block_sequence[num_steps].params.update_cab_for_uclk_params.num_ways = clk_mgr_base->clks.num_ways; 1069 block_sequence[num_steps].func = CLK_MGR401_UPDATE_CAB_FOR_UCLK; 1070 num_steps++; 1071 } 1072 } 1073 1074 return num_steps; 1075} 1076 1077static unsigned int dcn401_build_update_display_clocks_sequence( 1078 struct clk_mgr *clk_mgr_base, 1079 struct dc_state *context, 1080 struct dc_clocks *new_clocks, 1081 bool safe_to_lower) 1082{ 1083 struct clk_mgr_internal *clk_mgr_internal = TO_CLK_MGR_INTERNAL(clk_mgr_base); 1084 struct dcn401_clk_mgr *clk_mgr401 = TO_DCN401_CLK_MGR(clk_mgr_internal); 1085 struct dc *dc = clk_mgr_base->ctx->dc; 1086 struct dmcu *dmcu = clk_mgr_base->ctx->dc->res_pool->dmcu; 1087 struct dcn401_clk_mgr_block_sequence *block_sequence = clk_mgr401->block_sequence; 1088 bool force_reset = false; 1089 bool update_dispclk = false; 1090 bool update_dppclk = false; 1091 bool dppclk_lowered = false; 1092 1093 unsigned int num_steps = 0; 1094 1095 /* CLK_MGR401_READ_CLOCKS_FROM_DENTIST */ 1096 if (clk_mgr_base->clks.dispclk_khz == 0 || 1097 (dc->debug.force_clock_mode & 0x1)) { 1098 /* This is from resume or boot up, if forced_clock cfg option used, 1099 * we bypass program dispclk and DPPCLK, but need set them for S3. 1100 * Force_clock_mode 0x1: force reset the clock even it is the same clock 1101 * as long as it is in Passive level. 1102 */ 1103 force_reset = true; 1104 1105 clk_mgr_base->clks.dispclk_khz = clk_mgr_base->boot_snapshot.dispclk; 1106 clk_mgr_base->clks.actual_dispclk_khz = clk_mgr_base->clks.dispclk_khz; 1107 1108 clk_mgr_base->clks.dppclk_khz = clk_mgr_base->boot_snapshot.dppclk; 1109 clk_mgr_base->clks.actual_dppclk_khz = clk_mgr_base->clks.dppclk_khz; 1110 } 1111 1112 /* DTBCLK */ 1113 if (!new_clocks->dtbclk_en && dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_DTBCLK)) { 1114 new_clocks->ref_dtbclk_khz = clk_mgr_base->bw_params->clk_table.entries[0].dtbclk_mhz * 1000; 1115 } 1116 1117 /* clock limits are received with MHz precision, divide by 1000 to prevent setting clocks at every call */ 1118 if (!dc->debug.disable_dtb_ref_clk_switch && 1119 should_set_clock(safe_to_lower, new_clocks->ref_dtbclk_khz / 1000, clk_mgr_base->clks.ref_dtbclk_khz / 1000) && //TODO these should be ceiled 1120 dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_DTBCLK)) { 1121 /* DCCG requires KHz precision for DTBCLK */ 1122 block_sequence[num_steps].params.update_hardmin_params.ppclk = PPCLK_DTBCLK; 1123 block_sequence[num_steps].params.update_hardmin_params.freq_mhz = khz_to_mhz_ceil(new_clocks->ref_dtbclk_khz); 1124 block_sequence[num_steps].params.update_hardmin_params.response = &clk_mgr_base->clks.ref_dtbclk_khz; 1125 block_sequence[num_steps].func = CLK_MGR401_UPDATE_HARDMIN_PPCLK; 1126 num_steps++; 1127 1128 /* Update DTO in DCCG */ 1129 block_sequence[num_steps].params.update_dtbclk_dto_params.context = context; 1130 block_sequence[num_steps].params.update_dtbclk_dto_params.ref_dtbclk_khz = &clk_mgr_base->clks.ref_dtbclk_khz; 1131 block_sequence[num_steps].func = CLK_MGR401_UPDATE_DTBCLK_DTO; 1132 num_steps++; 1133 } 1134 1135 if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr_base->clks.dppclk_khz)) { 1136 if (clk_mgr_base->clks.dppclk_khz > new_clocks->dppclk_khz) 1137 dppclk_lowered = true; 1138 1139 clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz; 1140 clk_mgr_base->clks.actual_dppclk_khz = new_clocks->dppclk_khz; 1141 1142 update_dppclk = true; 1143 } 1144 1145 if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { 1146 clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; 1147 1148 block_sequence[num_steps].params.update_hardmin_optimized_params.ppclk = PPCLK_DISPCLK; 1149 block_sequence[num_steps].params.update_hardmin_optimized_params.freq_khz = clk_mgr_base->clks.dispclk_khz; 1150 block_sequence[num_steps].params.update_hardmin_optimized_params.response = &clk_mgr_base->clks.actual_dispclk_khz; 1151 block_sequence[num_steps].func = CLK_MGR401_UPDATE_HARDMIN_PPCLK_OPTIMIZED; 1152 num_steps++; 1153 1154 update_dispclk = true; 1155 } 1156 1157 if (dc->config.forced_clocks == false || (force_reset && safe_to_lower)) { 1158 if (dppclk_lowered) { 1159 /* if clock is being lowered, increase DTO before lowering refclk */ 1160 block_sequence[num_steps].params.update_dppclk_dto_params.context = context; 1161 block_sequence[num_steps].params.update_dppclk_dto_params.ref_dppclk_khz = &clk_mgr_base->clks.dppclk_khz; 1162 block_sequence[num_steps].params.update_dppclk_dto_params.safe_to_lower = safe_to_lower; 1163 block_sequence[num_steps].func = CLK_MGR401_UPDATE_DPPCLK_DTO; 1164 num_steps++; 1165 1166 block_sequence[num_steps].params.update_dentist_params.context = context; 1167 block_sequence[num_steps].func = CLK_MGR401_UPDATE_DENTIST; 1168 num_steps++; 1169 1170 if (dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_DPPCLK)) { 1171 block_sequence[num_steps].params.update_hardmin_optimized_params.ppclk = PPCLK_DPPCLK; 1172 block_sequence[num_steps].params.update_hardmin_optimized_params.freq_khz = clk_mgr_base->clks.dppclk_khz; 1173 block_sequence[num_steps].params.update_hardmin_optimized_params.response = &clk_mgr_base->clks.actual_dppclk_khz; 1174 block_sequence[num_steps].func = CLK_MGR401_UPDATE_HARDMIN_PPCLK_OPTIMIZED; 1175 num_steps++; 1176 1177 block_sequence[num_steps].params.update_dppclk_dto_params.context = context; 1178 block_sequence[num_steps].params.update_dppclk_dto_params.ref_dppclk_khz = &clk_mgr_base->clks.actual_dppclk_khz; 1179 block_sequence[num_steps].params.update_dppclk_dto_params.safe_to_lower = safe_to_lower; 1180 block_sequence[num_steps].func = CLK_MGR401_UPDATE_DPPCLK_DTO; 1181 num_steps++; 1182 } 1183 } else { 1184 /* if clock is being raised, increase refclk before lowering DTO */ 1185 if (update_dppclk && dcn401_is_ppclk_dpm_enabled(clk_mgr_internal, PPCLK_DPPCLK)) { 1186 block_sequence[num_steps].params.update_hardmin_optimized_params.ppclk = PPCLK_DPPCLK; 1187 block_sequence[num_steps].params.update_hardmin_optimized_params.freq_khz = clk_mgr_base->clks.dppclk_khz; 1188 block_sequence[num_steps].params.update_hardmin_optimized_params.response = &clk_mgr_base->clks.actual_dppclk_khz; 1189 block_sequence[num_steps].func = CLK_MGR401_UPDATE_HARDMIN_PPCLK_OPTIMIZED; 1190 num_steps++; 1191 } 1192 1193 if (update_dppclk || update_dispclk) { 1194 block_sequence[num_steps].params.update_dentist_params.context = context; 1195 block_sequence[num_steps].func = CLK_MGR401_UPDATE_DENTIST; 1196 num_steps++; 1197 } 1198 1199 block_sequence[num_steps].params.update_dppclk_dto_params.context = context; 1200 block_sequence[num_steps].params.update_dppclk_dto_params.ref_dppclk_khz = &clk_mgr_base->clks.actual_dppclk_khz; 1201 block_sequence[num_steps].params.update_dppclk_dto_params.safe_to_lower = safe_to_lower; 1202 block_sequence[num_steps].func = CLK_MGR401_UPDATE_DPPCLK_DTO; 1203 num_steps++; 1204 } 1205 } 1206 1207 if (update_dispclk && dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) { 1208 /*update dmcu for wait_loop count*/ 1209 block_sequence[num_steps].params.update_psr_wait_loop_params.dmcu = dmcu; 1210 block_sequence[num_steps].params.update_psr_wait_loop_params.wait = clk_mgr_base->clks.dispclk_khz / 1000 / 7; 1211 block_sequence[num_steps].func = CLK_MGR401_UPDATE_PSR_WAIT_LOOP; 1212 num_steps++; 1213 } 1214 1215 return num_steps; 1216} 1217 1218static void dcn401_update_clocks(struct clk_mgr *clk_mgr_base, 1219 struct dc_state *context, 1220 bool safe_to_lower) 1221{ 1222 struct dc *dc = clk_mgr_base->ctx->dc; 1223 1224 unsigned int num_steps = 0; 1225 1226 /* build bandwidth related clocks update sequence */ 1227 num_steps = dcn401_build_update_bandwidth_clocks_sequence(clk_mgr_base, 1228 context, 1229 &context->bw_ctx.bw.dcn.clk, 1230 safe_to_lower); 1231 1232 /* execute sequence */ 1233 dcn401_execute_block_sequence(clk_mgr_base, num_steps); 1234 1235 /* build display related clocks update sequence */ 1236 num_steps = dcn401_build_update_display_clocks_sequence(clk_mgr_base, 1237 context, 1238 &context->bw_ctx.bw.dcn.clk, 1239 safe_to_lower); 1240 1241 /* execute sequence */ 1242 dcn401_execute_block_sequence(clk_mgr_base, num_steps); 1243 1244 if (dc->config.enable_auto_dpm_test_logs) 1245 dcn401_auto_dpm_test_log(&context->bw_ctx.bw.dcn.clk, TO_CLK_MGR_INTERNAL(clk_mgr_base), context); 1246 1247} 1248 1249 1250static uint32_t dcn401_get_vco_frequency_from_reg(struct clk_mgr_internal *clk_mgr) 1251{ 1252 struct fixed31_32 pll_req; 1253 uint32_t pll_req_reg = 0; 1254 1255 /* get FbMult value */ 1256 pll_req_reg = REG_READ(CLK0_CLK_PLL_REQ); 1257 1258 /* set up a fixed-point number 1259 * this works because the int part is on the right edge of the register 1260 * and the frac part is on the left edge 1261 */ 1262 pll_req = dc_fixpt_from_int(pll_req_reg & clk_mgr->clk_mgr_mask->FbMult_int); 1263 pll_req.value |= pll_req_reg & clk_mgr->clk_mgr_mask->FbMult_frac; 1264 1265 /* multiply by REFCLK period */ 1266 pll_req = dc_fixpt_mul_int(pll_req, clk_mgr->dfs_ref_freq_khz); 1267 1268 return dc_fixpt_floor(pll_req); 1269} 1270 1271static void dcn401_clock_read_ss_info(struct clk_mgr_internal *clk_mgr) 1272{ 1273 struct dc_bios *bp = clk_mgr->base.ctx->dc_bios; 1274 int ss_info_num = bp->funcs->get_ss_entry_number( 1275 bp, AS_SIGNAL_TYPE_GPU_PLL); 1276 1277 if (ss_info_num) { 1278 struct spread_spectrum_info info = { { 0 } }; 1279 enum bp_result result = bp->funcs->get_spread_spectrum_info( 1280 bp, AS_SIGNAL_TYPE_GPU_PLL, 0, &info); 1281 1282 /* SSInfo.spreadSpectrumPercentage !=0 would be sign 1283 * that SS is enabled 1284 */ 1285 if (result == BP_RESULT_OK && 1286 info.spread_spectrum_percentage != 0) { 1287 clk_mgr->ss_on_dprefclk = true; 1288 clk_mgr->dprefclk_ss_divider = info.spread_percentage_divider; 1289 1290 if (info.type.CENTER_MODE == 0) { 1291 /* Currently for DP Reference clock we 1292 * need only SS percentage for 1293 * downspread 1294 */ 1295 clk_mgr->dprefclk_ss_percentage = 1296 info.spread_spectrum_percentage; 1297 } 1298 } 1299 } 1300} 1301static void dcn401_notify_wm_ranges(struct clk_mgr *clk_mgr_base) 1302{ 1303 unsigned int i; 1304 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 1305 WatermarksExternal_t *table = (WatermarksExternal_t *) clk_mgr->wm_range_table; 1306 1307 if (!clk_mgr->smu_present) 1308 return; 1309 1310 if (!table) 1311 return; 1312 1313 memset(table, 0, sizeof(*table)); 1314 1315 /* collect valid ranges, place in pmfw table */ 1316 for (i = 0; i < WM_SET_COUNT; i++) 1317 if (clk_mgr->base.bw_params->wm_table.nv_entries[i].valid) { 1318 table->Watermarks.WatermarkRow[i].WmSetting = i; 1319 table->Watermarks.WatermarkRow[i].Flags = clk_mgr->base.bw_params->wm_table.nv_entries[i].pmfw_breakdown.wm_type; 1320 } 1321 dcn401_smu_set_dram_addr_high(clk_mgr, clk_mgr->wm_range_table_addr >> 32); 1322 dcn401_smu_set_dram_addr_low(clk_mgr, clk_mgr->wm_range_table_addr & 0xFFFFFFFF); 1323 dcn401_smu_transfer_wm_table_dram_2_smu(clk_mgr); 1324} 1325 1326/* Set min memclk to minimum, either constrained by the current mode or DPM0 */ 1327static void dcn401_set_hard_min_memclk(struct clk_mgr *clk_mgr_base, bool current_mode) 1328{ 1329 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 1330 const struct dc *dc = clk_mgr->base.ctx->dc; 1331 struct dc_state *context = dc->current_state; 1332 struct dc_clocks new_clocks; 1333 int num_steps; 1334 1335 if (!clk_mgr->smu_present || !dcn401_is_ppclk_dpm_enabled(clk_mgr, PPCLK_UCLK)) 1336 return; 1337 1338 /* build clock update */ 1339 memcpy(&new_clocks, &clk_mgr_base->clks, sizeof(struct dc_clocks)); 1340 1341 if (current_mode) { 1342 new_clocks.dramclk_khz = context->bw_ctx.bw.dcn.clk.dramclk_khz; 1343 new_clocks.idle_dramclk_khz = context->bw_ctx.bw.dcn.clk.idle_dramclk_khz; 1344 new_clocks.p_state_change_support = context->bw_ctx.bw.dcn.clk.p_state_change_support; 1345 } else { 1346 new_clocks.dramclk_khz = clk_mgr_base->bw_params->clk_table.entries[0].memclk_mhz * 1000; 1347 new_clocks.idle_dramclk_khz = new_clocks.dramclk_khz; 1348 new_clocks.p_state_change_support = true; 1349 } 1350 1351 num_steps = dcn401_build_update_bandwidth_clocks_sequence(clk_mgr_base, 1352 context, 1353 &new_clocks, 1354 true); 1355 1356 /* execute sequence */ 1357 dcn401_execute_block_sequence(clk_mgr_base, num_steps); 1358} 1359 1360static int dcn401_get_hard_min_memclk(struct clk_mgr *clk_mgr_base) 1361{ 1362 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 1363 1364 return clk_mgr->base.ctx->dc->current_state->bw_ctx.bw.dcn.clk.dramclk_khz; 1365} 1366 1367static int dcn401_get_hard_min_fclk(struct clk_mgr *clk_mgr_base) 1368{ 1369 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 1370 1371 return clk_mgr->base.ctx->dc->current_state->bw_ctx.bw.dcn.clk.fclk_khz; 1372} 1373 1374/* Get current memclk states, update bounding box */ 1375static void dcn401_get_memclk_states_from_smu(struct clk_mgr *clk_mgr_base) 1376{ 1377 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 1378 struct clk_limit_num_entries *num_entries_per_clk = &clk_mgr_base->bw_params->clk_table.num_entries_per_clk; 1379 unsigned int num_levels; 1380 1381 if (!clk_mgr->smu_present) 1382 return; 1383 1384 /* Refresh memclk and fclk states */ 1385 dcn401_init_single_clock(clk_mgr, PPCLK_UCLK, 1386 &clk_mgr_base->bw_params->clk_table.entries[0].memclk_mhz, 1387 &num_entries_per_clk->num_memclk_levels); 1388 if (num_entries_per_clk->num_memclk_levels) { 1389 clk_mgr_base->bw_params->max_memclk_mhz = 1390 clk_mgr_base->bw_params->clk_table.entries[num_entries_per_clk->num_memclk_levels - 1].memclk_mhz; 1391 } 1392 1393 clk_mgr_base->bw_params->dc_mode_limit.memclk_mhz = dcn401_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_UCLK); 1394 if (num_entries_per_clk->num_memclk_levels && clk_mgr_base->bw_params->dc_mode_limit.memclk_mhz == 1395 clk_mgr_base->bw_params->clk_table.entries[num_entries_per_clk->num_memclk_levels - 1].memclk_mhz) 1396 clk_mgr_base->bw_params->dc_mode_limit.memclk_mhz = 0; 1397 clk_mgr_base->bw_params->dc_mode_softmax_memclk = clk_mgr_base->bw_params->dc_mode_limit.memclk_mhz; 1398 1399 dcn401_init_single_clock(clk_mgr, PPCLK_FCLK, 1400 &clk_mgr_base->bw_params->clk_table.entries[0].fclk_mhz, 1401 &num_entries_per_clk->num_fclk_levels); 1402 clk_mgr_base->bw_params->dc_mode_limit.fclk_mhz = dcn401_smu_get_dc_mode_max_dpm_freq(clk_mgr, PPCLK_FCLK); 1403 if (num_entries_per_clk->num_fclk_levels && clk_mgr_base->bw_params->dc_mode_limit.fclk_mhz == 1404 clk_mgr_base->bw_params->clk_table.entries[num_entries_per_clk->num_fclk_levels - 1].fclk_mhz) 1405 clk_mgr_base->bw_params->dc_mode_limit.fclk_mhz = 0; 1406 1407 num_levels = max(num_entries_per_clk->num_memclk_levels, num_entries_per_clk->num_fclk_levels); 1408 1409 clk_mgr_base->bw_params->clk_table.num_entries = num_levels ? num_levels : 1; 1410 1411 if (clk_mgr->dpm_present && !num_levels) 1412 clk_mgr->dpm_present = false; 1413 1414 clk_mgr_base->bw_params->num_channels = dcn401_smu_get_num_of_umc_channels(clk_mgr); 1415 if (clk_mgr_base->ctx->dc_bios) { 1416 /* use BIOS values if none provided by PMFW */ 1417 if (clk_mgr_base->bw_params->num_channels == 0) { 1418 clk_mgr_base->bw_params->num_channels = clk_mgr_base->ctx->dc_bios->vram_info.num_chans; 1419 } 1420 clk_mgr_base->bw_params->dram_channel_width_bytes = clk_mgr_base->ctx->dc_bios->vram_info.dram_channel_width_bytes; 1421 } 1422 1423 /* Refresh bounding box */ 1424 clk_mgr_base->ctx->dc->res_pool->funcs->update_bw_bounding_box( 1425 clk_mgr->base.ctx->dc, clk_mgr_base->bw_params); 1426} 1427 1428static bool dcn401_are_clock_states_equal(struct dc_clocks *a, 1429 struct dc_clocks *b) 1430{ 1431 if (a->dispclk_khz != b->dispclk_khz) 1432 return false; 1433 else if (a->dppclk_khz != b->dppclk_khz) 1434 return false; 1435 else if (a->dcfclk_khz != b->dcfclk_khz) 1436 return false; 1437 else if (a->dcfclk_deep_sleep_khz != b->dcfclk_deep_sleep_khz) 1438 return false; 1439 else if (a->dramclk_khz != b->dramclk_khz) 1440 return false; 1441 else if (a->p_state_change_support != b->p_state_change_support) 1442 return false; 1443 else if (a->fclk_p_state_change_support != b->fclk_p_state_change_support) 1444 return false; 1445 1446 return true; 1447} 1448 1449static void dcn401_enable_pme_wa(struct clk_mgr *clk_mgr_base) 1450{ 1451 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 1452 1453 if (!clk_mgr->smu_present) 1454 return; 1455 1456 dcn401_smu_set_pme_workaround(clk_mgr); 1457} 1458 1459static bool dcn401_is_smu_present(struct clk_mgr *clk_mgr_base) 1460{ 1461 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 1462 return clk_mgr->smu_present; 1463} 1464 1465 1466static int dcn401_get_dtb_ref_freq_khz(struct clk_mgr *clk_mgr_base) 1467{ 1468 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 1469 1470 int dtb_ref_clk_khz = 0; 1471 1472 if (clk_mgr->smu_present && dcn401_is_ppclk_dpm_enabled(clk_mgr, PPCLK_DTBCLK)) { 1473 /* DPM enabled, use currently set value */ 1474 dtb_ref_clk_khz = clk_mgr_base->clks.ref_dtbclk_khz; 1475 } else { 1476 /* DPM disabled, so use boot snapshot */ 1477 dtb_ref_clk_khz = clk_mgr_base->boot_snapshot.dtbclk; 1478 } 1479 1480 return dtb_ref_clk_khz; 1481} 1482 1483static int dcn401_get_dispclk_from_dentist(struct clk_mgr *clk_mgr_base) 1484{ 1485 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 1486 uint32_t dispclk_wdivider; 1487 int disp_divider; 1488 1489 REG_GET(DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER, &dispclk_wdivider); 1490 disp_divider = dentist_get_divider_from_did(dispclk_wdivider); 1491 1492 /* Return DISPCLK freq in Khz */ 1493 if (disp_divider) 1494 return (DENTIST_DIVIDER_RANGE_SCALE_FACTOR * clk_mgr->base.dentist_vco_freq_khz) / disp_divider; 1495 1496 return 0; 1497} 1498 1499unsigned int dcn401_get_max_clock_khz(struct clk_mgr *clk_mgr_base, enum clk_type clk_type) 1500{ 1501 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 1502 1503 unsigned int num_clk_levels; 1504 1505 switch (clk_type) { 1506 case CLK_TYPE_DISPCLK: 1507 num_clk_levels = clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dispclk_levels; 1508 return dcn401_is_ppclk_dpm_enabled(clk_mgr, PPCLK_DISPCLK) ? 1509 clk_mgr->base.bw_params->clk_table.entries[num_clk_levels - 1].dispclk_mhz * 1000 : 1510 clk_mgr->base.boot_snapshot.dispclk; 1511 case CLK_TYPE_DPPCLK: 1512 num_clk_levels = clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dppclk_levels; 1513 return dcn401_is_ppclk_dpm_enabled(clk_mgr, PPCLK_DPPCLK) ? 1514 clk_mgr->base.bw_params->clk_table.entries[num_clk_levels - 1].dppclk_mhz * 1000 : 1515 clk_mgr->base.boot_snapshot.dppclk; 1516 case CLK_TYPE_DSCCLK: 1517 num_clk_levels = clk_mgr->base.bw_params->clk_table.num_entries_per_clk.num_dispclk_levels; 1518 return dcn401_is_ppclk_dpm_enabled(clk_mgr, PPCLK_DISPCLK) ? 1519 clk_mgr->base.bw_params->clk_table.entries[num_clk_levels - 1].dispclk_mhz * 1000 / 3 : 1520 clk_mgr->base.boot_snapshot.dispclk / 3; 1521 default: 1522 break; 1523 } 1524 1525 return 0; 1526} 1527 1528static struct clk_mgr_funcs dcn401_funcs = { 1529 .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, 1530 .get_dtb_ref_clk_frequency = dcn401_get_dtb_ref_freq_khz, 1531 .update_clocks = dcn401_update_clocks, 1532 .dump_clk_registers = dcn401_dump_clk_registers, 1533 .init_clocks = dcn401_init_clocks, 1534 .notify_wm_ranges = dcn401_notify_wm_ranges, 1535 .set_hard_min_memclk = dcn401_set_hard_min_memclk, 1536 .get_memclk_states_from_smu = dcn401_get_memclk_states_from_smu, 1537 .are_clock_states_equal = dcn401_are_clock_states_equal, 1538 .enable_pme_wa = dcn401_enable_pme_wa, 1539 .is_smu_present = dcn401_is_smu_present, 1540 .get_dispclk_from_dentist = dcn401_get_dispclk_from_dentist, 1541 .get_hard_min_memclk = dcn401_get_hard_min_memclk, 1542 .get_hard_min_fclk = dcn401_get_hard_min_fclk, 1543 .is_dc_mode_present = dcn401_is_dc_mode_present, 1544 .get_max_clock_khz = dcn401_get_max_clock_khz, 1545}; 1546 1547struct clk_mgr_internal *dcn401_clk_mgr_construct( 1548 struct dc_context *ctx, 1549 struct dccg *dccg) 1550{ 1551 struct clk_log_info log_info = {0}; 1552 struct dcn401_clk_mgr *clk_mgr401 = kzalloc(sizeof(struct dcn401_clk_mgr), GFP_KERNEL); 1553 struct clk_mgr_internal *clk_mgr; 1554 1555 if (!clk_mgr401) 1556 return NULL; 1557 1558 clk_mgr = &clk_mgr401->base; 1559 clk_mgr->base.ctx = ctx; 1560 clk_mgr->base.funcs = &dcn401_funcs; 1561 clk_mgr->regs = &clk_mgr_regs_dcn401; 1562 clk_mgr->clk_mgr_shift = &clk_mgr_shift_dcn401; 1563 clk_mgr->clk_mgr_mask = &clk_mgr_mask_dcn401; 1564 1565 clk_mgr->dccg = dccg; 1566 clk_mgr->dfs_bypass_disp_clk = 0; 1567 1568 clk_mgr->dprefclk_ss_percentage = 0; 1569 clk_mgr->dprefclk_ss_divider = 1000; 1570 clk_mgr->ss_on_dprefclk = false; 1571 clk_mgr->dfs_ref_freq_khz = 100000; 1572 1573 /* Changed from DCN3.2_clock_frequency doc to match 1574 * dcn401_dump_clk_registers from 4 * dentist_vco_freq_khz / 1575 * dprefclk DID divider 1576 */ 1577 clk_mgr->base.dprefclk_khz = 720000; //TODO update from VBIOS 1578 1579 /* integer part is now VCO frequency in kHz */ 1580 clk_mgr->base.dentist_vco_freq_khz = dcn401_get_vco_frequency_from_reg(clk_mgr); 1581 1582 /* in case we don't get a value from the register, use default */ 1583 if (clk_mgr->base.dentist_vco_freq_khz == 0) 1584 clk_mgr->base.dentist_vco_freq_khz = 4500000; //TODO Update from VBIOS 1585 1586 dcn401_dump_clk_registers(&clk_mgr->base.boot_snapshot, &clk_mgr->base, &log_info); 1587 1588 if (ctx->dc->debug.disable_dtb_ref_clk_switch && 1589 clk_mgr->base.clks.ref_dtbclk_khz != clk_mgr->base.boot_snapshot.dtbclk) { 1590 clk_mgr->base.clks.ref_dtbclk_khz = clk_mgr->base.boot_snapshot.dtbclk; 1591 } 1592 1593 if (clk_mgr->base.boot_snapshot.dprefclk != 0) { 1594 clk_mgr->base.dprefclk_khz = clk_mgr->base.boot_snapshot.dprefclk; 1595 } 1596 dcn401_clock_read_ss_info(clk_mgr); 1597 1598 clk_mgr->dfs_bypass_enabled = false; 1599 1600 clk_mgr->smu_present = false; 1601 1602 clk_mgr->base.bw_params = kzalloc(sizeof(*clk_mgr->base.bw_params), GFP_KERNEL); 1603 if (!clk_mgr->base.bw_params) { 1604 BREAK_TO_DEBUGGER(); 1605 kfree(clk_mgr401); 1606 return NULL; 1607 } 1608 1609 /* need physical address of table to give to PMFW */ 1610 clk_mgr->wm_range_table = dm_helpers_allocate_gpu_mem(clk_mgr->base.ctx, 1611 DC_MEM_ALLOC_TYPE_GART, sizeof(WatermarksExternal_t), 1612 &clk_mgr->wm_range_table_addr); 1613 if (!clk_mgr->wm_range_table) { 1614 BREAK_TO_DEBUGGER(); 1615 kfree(clk_mgr->base.bw_params); 1616 kfree(clk_mgr401); 1617 return NULL; 1618 } 1619 1620 return &clk_mgr401->base; 1621} 1622 1623void dcn401_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr) 1624{ 1625 kfree(clk_mgr->base.bw_params); 1626 1627 if (clk_mgr->wm_range_table) 1628 dm_helpers_free_gpu_mem(clk_mgr->base.ctx, DC_MEM_ALLOC_TYPE_GART, 1629 clk_mgr->wm_range_table); 1630} 1631
~/
Read-only file preview.