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 #include "dccg.h" 27 #include "clk_mgr_internal.h" 28 29 #include "dcn32/dcn32_clk_mgr_smu_msg.h" 30 #include "dcn20/dcn20_clk_mgr.h" 31 #include "dce100/dce_clk_mgr.h" 32 #include "dcn31/dcn31_clk_mgr.h" 33 #include "reg_helper.h" 34 #include "core_types.h" 35 #include "dm_helpers.h" 36 #include "dc_link_dp.h" 37 38 #include "atomfirmware.h" 39 #include "smu13_driver_if.h" 40 41 #include "dcn/dcn_3_2_0_offset.h" 42 #include "dcn/dcn_3_2_0_sh_mask.h" 43 44 #include "dcn32/dcn32_clk_mgr.h" 45 #include "dml/dcn32/dcn32_fpu.h" 46 47 #define DCN_BASE__INST0_SEG1 0x000000C0 48 49 #define mmCLK1_CLK_PLL_REQ 0x16E37 50 #define mmCLK1_CLK0_DFS_CNTL 0x16E69 51 #define mmCLK1_CLK1_DFS_CNTL 0x16E6C 52 #define mmCLK1_CLK2_DFS_CNTL 0x16E6F 53 #define mmCLK1_CLK3_DFS_CNTL 0x16E72 54 #define mmCLK1_CLK4_DFS_CNTL 0x16E75 55 56 #define CLK1_CLK_PLL_REQ__FbMult_int_MASK 0x000001ffUL 57 #define CLK1_CLK_PLL_REQ__PllSpineDiv_MASK 0x0000f000UL 58 #define CLK1_CLK_PLL_REQ__FbMult_frac_MASK 0xffff0000UL 59 #define CLK1_CLK_PLL_REQ__FbMult_int__SHIFT 0x00000000 60 #define CLK1_CLK_PLL_REQ__PllSpineDiv__SHIFT 0x0000000c 61 #define CLK1_CLK_PLL_REQ__FbMult_frac__SHIFT 0x00000010 62 63 #define mmCLK01_CLK0_CLK_PLL_REQ 0x16E37 64 #define mmCLK01_CLK0_CLK0_DFS_CNTL 0x16E64 65 #define mmCLK01_CLK0_CLK1_DFS_CNTL 0x16E67 66 #define mmCLK01_CLK0_CLK2_DFS_CNTL 0x16E6A 67 #define mmCLK01_CLK0_CLK3_DFS_CNTL 0x16E6D 68 #define mmCLK01_CLK0_CLK4_DFS_CNTL 0x16E70 69 70 #define CLK0_CLK_PLL_REQ__FbMult_int_MASK 0x000001ffL 71 #define CLK0_CLK_PLL_REQ__PllSpineDiv_MASK 0x0000f000L 72 #define CLK0_CLK_PLL_REQ__FbMult_frac_MASK 0xffff0000L 73 #define CLK0_CLK_PLL_REQ__FbMult_int__SHIFT 0x00000000 74 #define CLK0_CLK_PLL_REQ__PllSpineDiv__SHIFT 0x0000000c 75 #define CLK0_CLK_PLL_REQ__FbMult_frac__SHIFT 0x00000010 76 77 #undef FN 78 #define FN(reg_name, field_name) \ 79 clk_mgr->clk_mgr_shift->field_name, clk_mgr->clk_mgr_mask->field_name 80 81 #define REG(reg) \ 82 (clk_mgr->regs->reg) 83 84 #define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg 85 86 #define BASE(seg) BASE_INNER(seg) 87 88 #define SR(reg_name)\ 89 .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \ 90 reg ## reg_name 91 92 #define CLK_SR_DCN32(reg_name)\ 93 .reg_name = mm ## reg_name 94 95 static const struct clk_mgr_registers clk_mgr_regs_dcn32 = { 96 CLK_REG_LIST_DCN32() 97 }; 98 99 static const struct clk_mgr_shift clk_mgr_shift_dcn32 = { 100 CLK_COMMON_MASK_SH_LIST_DCN32(__SHIFT) 101 }; 102 103 static const struct clk_mgr_mask clk_mgr_mask_dcn32 = { 104 CLK_COMMON_MASK_SH_LIST_DCN32(_MASK) 105 }; 106 107 108 #define CLK_SR_DCN321(reg_name, block, inst)\ 109 .reg_name = mm ## block ## _ ## reg_name 110 111 static const struct clk_mgr_registers clk_mgr_regs_dcn321 = { 112 CLK_REG_LIST_DCN321() 113 }; 114 115 static const struct clk_mgr_shift clk_mgr_shift_dcn321 = { 116 CLK_COMMON_MASK_SH_LIST_DCN321(__SHIFT) 117 }; 118 119 static const struct clk_mgr_mask clk_mgr_mask_dcn321 = { 120 CLK_COMMON_MASK_SH_LIST_DCN321(_MASK) 121 }; 122 123 124 /* Query SMU for all clock states for a particular clock */ 125 static void dcn32_init_single_clock(struct clk_mgr_internal *clk_mgr, PPCLK_e clk, unsigned int *entry_0, 126 unsigned int *num_levels) 127 { 128 unsigned int i; 129 char *entry_i = (char *)entry_0; 130 131 uint32_t ret = dcn30_smu_get_dpm_freq_by_index(clk_mgr, clk, 0xFF); 132 133 if (ret & (1 << 31)) 134 /* fine-grained, only min and max */ 135 *num_levels = 2; 136 else 137 /* discrete, a number of fixed states */ 138 /* will set num_levels to 0 on failure */ 139 *num_levels = ret & 0xFF; 140 141 /* if the initial message failed, num_levels will be 0 */ 142 for (i = 0; i < *num_levels; i++) { 143 *((unsigned int *)entry_i) = (dcn30_smu_get_dpm_freq_by_index(clk_mgr, clk, i) & 0xFFFF); 144 entry_i += sizeof(clk_mgr->base.bw_params->clk_table.entries[0]); 145 } 146 } 147 148 static void dcn32_build_wm_range_table(struct clk_mgr_internal *clk_mgr) 149 { 150 DC_FP_START(); 151 dcn32_build_wm_range_table_fpu(clk_mgr); 152 DC_FP_END(); 153 } 154 155 void dcn32_init_clocks(struct clk_mgr *clk_mgr_base) 156 { 157 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 158 unsigned int num_levels; 159 struct clk_limit_num_entries *num_entries_per_clk = &clk_mgr_base->bw_params->clk_table.num_entries_per_clk; 160 unsigned int i; 161 162 memset(&(clk_mgr_base->clks), 0, sizeof(struct dc_clocks)); 163 clk_mgr_base->clks.p_state_change_support = true; 164 clk_mgr_base->clks.prev_p_state_change_support = true; 165 clk_mgr_base->clks.fclk_prev_p_state_change_support = true; 166 clk_mgr->smu_present = false; 167 clk_mgr->dpm_present = false; 168 169 if (!clk_mgr_base->bw_params) 170 return; 171 172 if (!clk_mgr_base->force_smu_not_present && dcn30_smu_get_smu_version(clk_mgr, &clk_mgr->smu_ver)) 173 clk_mgr->smu_present = true; 174 175 if (!clk_mgr->smu_present) 176 return; 177 178 dcn30_smu_check_driver_if_version(clk_mgr); 179 dcn30_smu_check_msg_header_version(clk_mgr); 180 181 /* DCFCLK */ 182 dcn32_init_single_clock(clk_mgr, PPCLK_DCFCLK, 183 &clk_mgr_base->bw_params->clk_table.entries[0].dcfclk_mhz, 184 &num_entries_per_clk->num_dcfclk_levels); 185 186 /* SOCCLK */ 187 dcn32_init_single_clock(clk_mgr, PPCLK_SOCCLK, 188 &clk_mgr_base->bw_params->clk_table.entries[0].socclk_mhz, 189 &num_entries_per_clk->num_socclk_levels); 190 191 /* DTBCLK */ 192 if (!clk_mgr->base.ctx->dc->debug.disable_dtb_ref_clk_switch) 193 dcn32_init_single_clock(clk_mgr, PPCLK_DTBCLK, 194 &clk_mgr_base->bw_params->clk_table.entries[0].dtbclk_mhz, 195 &num_entries_per_clk->num_dtbclk_levels); 196 197 /* DISPCLK */ 198 dcn32_init_single_clock(clk_mgr, PPCLK_DISPCLK, 199 &clk_mgr_base->bw_params->clk_table.entries[0].dispclk_mhz, 200 &num_entries_per_clk->num_dispclk_levels); 201 num_levels = num_entries_per_clk->num_dispclk_levels; 202 203 if (num_entries_per_clk->num_dcfclk_levels && 204 num_entries_per_clk->num_dtbclk_levels && 205 num_entries_per_clk->num_dispclk_levels) 206 clk_mgr->dpm_present = true; 207 208 if (clk_mgr_base->ctx->dc->debug.min_disp_clk_khz) { 209 for (i = 0; i < num_levels; i++) 210 if (clk_mgr_base->bw_params->clk_table.entries[i].dispclk_mhz 211 < khz_to_mhz_ceil(clk_mgr_base->ctx->dc->debug.min_disp_clk_khz)) 212 clk_mgr_base->bw_params->clk_table.entries[i].dispclk_mhz 213 = khz_to_mhz_ceil(clk_mgr_base->ctx->dc->debug.min_disp_clk_khz); 214 } 215 for (i = 0; i < num_levels; i++) 216 if (clk_mgr_base->bw_params->clk_table.entries[i].dispclk_mhz > 1950) 217 clk_mgr_base->bw_params->clk_table.entries[i].dispclk_mhz = 1950; 218 219 if (clk_mgr_base->ctx->dc->debug.min_dpp_clk_khz) { 220 for (i = 0; i < num_levels; i++) 221 if (clk_mgr_base->bw_params->clk_table.entries[i].dppclk_mhz 222 < khz_to_mhz_ceil(clk_mgr_base->ctx->dc->debug.min_dpp_clk_khz)) 223 clk_mgr_base->bw_params->clk_table.entries[i].dppclk_mhz 224 = khz_to_mhz_ceil(clk_mgr_base->ctx->dc->debug.min_dpp_clk_khz); 225 } 226 227 /* Get UCLK, update bounding box */ 228 clk_mgr_base->funcs->get_memclk_states_from_smu(clk_mgr_base); 229 230 DC_FP_START(); 231 /* WM range table */ 232 dcn32_build_wm_range_table(clk_mgr); 233 DC_FP_END(); 234 } 235 236 /* Since DPPCLK request to PMFW needs to be exact (due to DPP DTO programming), 237 * update DPPCLK to be the exact frequency that will be set after the DPPCLK 238 * divider is updated. This will prevent rounding issues that could cause DPP 239 * refclk and DPP DTO to not match up. 240 */ 241 static void dcn32_update_dppclk_dispclk_freq(struct clk_mgr_internal *clk_mgr, struct dc_clocks *new_clocks) 242 { 243 int dpp_divider = 0; 244 int disp_divider = 0; 245 246 if (new_clocks->dppclk_khz) { 247 dpp_divider = DENTIST_DIVIDER_RANGE_SCALE_FACTOR 248 * clk_mgr->base.dentist_vco_freq_khz / new_clocks->dppclk_khz; 249 new_clocks->dppclk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR * clk_mgr->base.dentist_vco_freq_khz) / dpp_divider; 250 } 251 if (new_clocks->dispclk_khz > 0) { 252 disp_divider = DENTIST_DIVIDER_RANGE_SCALE_FACTOR 253 * clk_mgr->base.dentist_vco_freq_khz / new_clocks->dispclk_khz; 254 new_clocks->dispclk_khz = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR * clk_mgr->base.dentist_vco_freq_khz) / disp_divider; 255 } 256 } 257 258 static void dcn32_update_clocks(struct clk_mgr *clk_mgr_base, 259 struct dc_state *context, 260 bool safe_to_lower) 261 { 262 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 263 struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk; 264 struct dc *dc = clk_mgr_base->ctx->dc; 265 int display_count; 266 bool update_dppclk = false; 267 bool update_dispclk = false; 268 bool enter_display_off = false; 269 bool dpp_clock_lowered = false; 270 struct dmcu *dmcu = clk_mgr_base->ctx->dc->res_pool->dmcu; 271 bool force_reset = false; 272 bool update_uclk = false, update_fclk = false; 273 bool p_state_change_support; 274 bool fclk_p_state_change_support; 275 int total_plane_count; 276 277 if (dc->work_arounds.skip_clock_update) 278 return; 279 280 if (clk_mgr_base->clks.dispclk_khz == 0 || 281 (dc->debug.force_clock_mode & 0x1)) { 282 /* This is from resume or boot up, if forced_clock cfg option used, 283 * we bypass program dispclk and DPPCLK, but need set them for S3. 284 */ 285 force_reset = true; 286 287 dcn2_read_clocks_from_hw_dentist(clk_mgr_base); 288 289 /* Force_clock_mode 0x1: force reset the clock even it is the same clock 290 * as long as it is in Passive level. 291 */ 292 } 293 display_count = clk_mgr_helper_get_active_display_cnt(dc, context); 294 295 if (display_count == 0) 296 enter_display_off = true; 297 298 if (clk_mgr->smu_present) { 299 if (enter_display_off == safe_to_lower) 300 dcn30_smu_set_num_of_displays(clk_mgr, display_count); 301 302 clk_mgr_base->clks.fclk_prev_p_state_change_support = clk_mgr_base->clks.fclk_p_state_change_support; 303 304 total_plane_count = clk_mgr_helper_get_active_plane_cnt(dc, context); 305 fclk_p_state_change_support = new_clocks->fclk_p_state_change_support || (total_plane_count == 0); 306 307 if (should_update_pstate_support(safe_to_lower, fclk_p_state_change_support, clk_mgr_base->clks.fclk_p_state_change_support)) { 308 clk_mgr_base->clks.fclk_p_state_change_support = fclk_p_state_change_support; 309 310 /* To enable FCLK P-state switching, send FCLK_PSTATE_SUPPORTED message to PMFW */ 311 if (clk_mgr_base->ctx->dce_version != DCN_VERSION_3_21 && clk_mgr_base->clks.fclk_p_state_change_support) { 312 /* Handle the code for sending a message to PMFW that FCLK P-state change is supported */ 313 dcn32_smu_send_fclk_pstate_message(clk_mgr, FCLK_PSTATE_SUPPORTED); 314 } 315 } 316 317 if (dc->debug.force_min_dcfclk_mhz > 0) 318 new_clocks->dcfclk_khz = (new_clocks->dcfclk_khz > (dc->debug.force_min_dcfclk_mhz * 1000)) ? 319 new_clocks->dcfclk_khz : (dc->debug.force_min_dcfclk_mhz * 1000); 320 321 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) { 322 clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz; 323 dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DCFCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dcfclk_khz)); 324 } 325 326 if (should_set_clock(safe_to_lower, new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) { 327 clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz; 328 dcn30_smu_set_min_deep_sleep_dcef_clk(clk_mgr, khz_to_mhz_ceil(clk_mgr_base->clks.dcfclk_deep_sleep_khz)); 329 } 330 331 if (should_set_clock(safe_to_lower, new_clocks->socclk_khz, clk_mgr_base->clks.socclk_khz)) 332 /* We don't actually care about socclk, don't notify SMU of hard min */ 333 clk_mgr_base->clks.socclk_khz = new_clocks->socclk_khz; 334 335 clk_mgr_base->clks.prev_p_state_change_support = clk_mgr_base->clks.p_state_change_support; 336 clk_mgr_base->clks.prev_num_ways = clk_mgr_base->clks.num_ways; 337 338 if (clk_mgr_base->clks.num_ways != new_clocks->num_ways && 339 clk_mgr_base->clks.num_ways < new_clocks->num_ways) { 340 clk_mgr_base->clks.num_ways = new_clocks->num_ways; 341 dcn32_smu_send_cab_for_uclk_message(clk_mgr, clk_mgr_base->clks.num_ways); 342 } 343 344 345 p_state_change_support = new_clocks->p_state_change_support || (total_plane_count == 0); 346 if (should_update_pstate_support(safe_to_lower, p_state_change_support, clk_mgr_base->clks.p_state_change_support)) { 347 clk_mgr_base->clks.p_state_change_support = p_state_change_support; 348 349 /* to disable P-State switching, set UCLK min = max */ 350 if (!clk_mgr_base->clks.p_state_change_support) 351 dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, 352 clk_mgr_base->bw_params->clk_table.entries[clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_memclk_levels - 1].memclk_mhz); 353 } 354 355 /* Always update saved value, even if new value not set due to P-State switching unsupported. Also check safe_to_lower for FCLK */ 356 if (safe_to_lower && (clk_mgr_base->clks.fclk_p_state_change_support != clk_mgr_base->clks.fclk_prev_p_state_change_support)) { 357 update_fclk = true; 358 } 359 360 if (clk_mgr_base->ctx->dce_version != DCN_VERSION_3_21 && !clk_mgr_base->clks.fclk_p_state_change_support && update_fclk) { 361 /* Handle code for sending a message to PMFW that FCLK P-state change is not supported */ 362 dcn32_smu_send_fclk_pstate_message(clk_mgr, FCLK_PSTATE_NOTSUPPORTED); 363 } 364 365 /* Always update saved value, even if new value not set due to P-State switching unsupported */ 366 if (should_set_clock(safe_to_lower, new_clocks->dramclk_khz, clk_mgr_base->clks.dramclk_khz)) { 367 clk_mgr_base->clks.dramclk_khz = new_clocks->dramclk_khz; 368 update_uclk = true; 369 } 370 371 /* set UCLK to requested value if P-State switching is supported, or to re-enable P-State switching */ 372 if (clk_mgr_base->clks.p_state_change_support && 373 (update_uclk || !clk_mgr_base->clks.prev_p_state_change_support)) 374 dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dramclk_khz)); 375 376 if (clk_mgr_base->clks.num_ways != new_clocks->num_ways && 377 clk_mgr_base->clks.num_ways > new_clocks->num_ways) { 378 clk_mgr_base->clks.num_ways = new_clocks->num_ways; 379 dcn32_smu_send_cab_for_uclk_message(clk_mgr, clk_mgr_base->clks.num_ways); 380 } 381 } 382 383 dcn32_update_dppclk_dispclk_freq(clk_mgr, new_clocks); 384 if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr_base->clks.dppclk_khz)) { 385 if (clk_mgr_base->clks.dppclk_khz > new_clocks->dppclk_khz) 386 dpp_clock_lowered = true; 387 388 clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz; 389 390 if (clk_mgr->smu_present && !dpp_clock_lowered) 391 dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DPPCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dppclk_khz)); 392 393 update_dppclk = true; 394 } 395 396 if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) { 397 clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz; 398 399 if (clk_mgr->smu_present) 400 dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DISPCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dispclk_khz)); 401 402 update_dispclk = true; 403 } 404 405 if (!new_clocks->dtbclk_en) { 406 new_clocks->ref_dtbclk_khz = clk_mgr_base->bw_params->clk_table.entries[0].dtbclk_mhz * 1000; 407 } 408 409 /* clock limits are received with MHz precision, divide by 1000 to prevent setting clocks at every call */ 410 if (!dc->debug.disable_dtb_ref_clk_switch && 411 should_set_clock(safe_to_lower, new_clocks->ref_dtbclk_khz / 1000, clk_mgr_base->clks.ref_dtbclk_khz / 1000)) { 412 /* DCCG requires KHz precision for DTBCLK */ 413 clk_mgr_base->clks.ref_dtbclk_khz = 414 dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DTBCLK, khz_to_mhz_ceil(new_clocks->ref_dtbclk_khz)); 415 } 416 417 if (dc->config.forced_clocks == false || (force_reset && safe_to_lower)) { 418 if (dpp_clock_lowered) { 419 /* if clock is being lowered, increase DTO before lowering refclk */ 420 dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); 421 dcn20_update_clocks_update_dentist(clk_mgr, context); 422 if (clk_mgr->smu_present) 423 dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_DPPCLK, khz_to_mhz_ceil(clk_mgr_base->clks.dppclk_khz)); 424 } else { 425 /* if clock is being raised, increase refclk before lowering DTO */ 426 if (update_dppclk || update_dispclk) 427 dcn20_update_clocks_update_dentist(clk_mgr, context); 428 /* There is a check inside dcn20_update_clocks_update_dpp_dto which ensures 429 * that we do not lower dto when it is not safe to lower. We do not need to 430 * compare the current and new dppclk before calling this function. 431 */ 432 dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower); 433 } 434 } 435 436 if (update_dispclk && dmcu && dmcu->funcs->is_dmcu_initialized(dmcu)) 437 /*update dmcu for wait_loop count*/ 438 dmcu->funcs->set_psr_wait_loop(dmcu, 439 clk_mgr_base->clks.dispclk_khz / 1000 / 7); 440 } 441 442 static uint32_t dcn32_get_vco_frequency_from_reg(struct clk_mgr_internal *clk_mgr) 443 { 444 struct fixed31_32 pll_req; 445 uint32_t pll_req_reg = 0; 446 447 /* get FbMult value */ 448 if (ASICREV_IS_GC_11_0_2(clk_mgr->base.ctx->asic_id.hw_internal_rev)) 449 pll_req_reg = REG_READ(CLK0_CLK_PLL_REQ); 450 else 451 pll_req_reg = REG_READ(CLK1_CLK_PLL_REQ); 452 453 /* set up a fixed-point number 454 * this works because the int part is on the right edge of the register 455 * and the frac part is on the left edge 456 */ 457 pll_req = dc_fixpt_from_int(pll_req_reg & clk_mgr->clk_mgr_mask->FbMult_int); 458 pll_req.value |= pll_req_reg & clk_mgr->clk_mgr_mask->FbMult_frac; 459 460 /* multiply by REFCLK period */ 461 pll_req = dc_fixpt_mul_int(pll_req, clk_mgr->dfs_ref_freq_khz); 462 463 return dc_fixpt_floor(pll_req); 464 } 465 466 static void dcn32_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass, 467 struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info) 468 { 469 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 470 uint32_t dprefclk_did = 0; 471 uint32_t dcfclk_did = 0; 472 uint32_t dtbclk_did = 0; 473 uint32_t dispclk_did = 0; 474 uint32_t dppclk_did = 0; 475 uint32_t target_div = 0; 476 477 if (ASICREV_IS_GC_11_0_2(clk_mgr->base.ctx->asic_id.hw_internal_rev)) { 478 /* DFS Slice 0 is used for DISPCLK */ 479 dispclk_did = REG_READ(CLK0_CLK0_DFS_CNTL); 480 /* DFS Slice 1 is used for DPPCLK */ 481 dppclk_did = REG_READ(CLK0_CLK1_DFS_CNTL); 482 /* DFS Slice 2 is used for DPREFCLK */ 483 dprefclk_did = REG_READ(CLK0_CLK2_DFS_CNTL); 484 /* DFS Slice 3 is used for DCFCLK */ 485 dcfclk_did = REG_READ(CLK0_CLK3_DFS_CNTL); 486 /* DFS Slice 4 is used for DTBCLK */ 487 dtbclk_did = REG_READ(CLK0_CLK4_DFS_CNTL); 488 } else { 489 /* DFS Slice 0 is used for DISPCLK */ 490 dispclk_did = REG_READ(CLK1_CLK0_DFS_CNTL); 491 /* DFS Slice 1 is used for DPPCLK */ 492 dppclk_did = REG_READ(CLK1_CLK1_DFS_CNTL); 493 /* DFS Slice 2 is used for DPREFCLK */ 494 dprefclk_did = REG_READ(CLK1_CLK2_DFS_CNTL); 495 /* DFS Slice 3 is used for DCFCLK */ 496 dcfclk_did = REG_READ(CLK1_CLK3_DFS_CNTL); 497 /* DFS Slice 4 is used for DTBCLK */ 498 dtbclk_did = REG_READ(CLK1_CLK4_DFS_CNTL); 499 } 500 501 /* Convert DISPCLK DFS Slice DID to divider*/ 502 target_div = dentist_get_divider_from_did(dispclk_did); 503 //Get dispclk in khz 504 regs_and_bypass->dispclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR 505 * clk_mgr->base.dentist_vco_freq_khz) / target_div; 506 507 /* Convert DISPCLK DFS Slice DID to divider*/ 508 target_div = dentist_get_divider_from_did(dppclk_did); 509 //Get dppclk in khz 510 regs_and_bypass->dppclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR 511 * clk_mgr->base.dentist_vco_freq_khz) / target_div; 512 513 /* Convert DPREFCLK DFS Slice DID to divider*/ 514 target_div = dentist_get_divider_from_did(dprefclk_did); 515 //Get dprefclk in khz 516 regs_and_bypass->dprefclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR 517 * clk_mgr->base.dentist_vco_freq_khz) / target_div; 518 519 /* Convert DCFCLK DFS Slice DID to divider*/ 520 target_div = dentist_get_divider_from_did(dcfclk_did); 521 //Get dcfclk in khz 522 regs_and_bypass->dcfclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR 523 * clk_mgr->base.dentist_vco_freq_khz) / target_div; 524 525 /* Convert DTBCLK DFS Slice DID to divider*/ 526 target_div = dentist_get_divider_from_did(dtbclk_did); 527 //Get dtbclk in khz 528 regs_and_bypass->dtbclk = (DENTIST_DIVIDER_RANGE_SCALE_FACTOR 529 * clk_mgr->base.dentist_vco_freq_khz) / target_div; 530 } 531 532 static void dcn32_clock_read_ss_info(struct clk_mgr_internal *clk_mgr) 533 { 534 struct dc_bios *bp = clk_mgr->base.ctx->dc_bios; 535 int ss_info_num = bp->funcs->get_ss_entry_number( 536 bp, AS_SIGNAL_TYPE_GPU_PLL); 537 538 if (ss_info_num) { 539 struct spread_spectrum_info info = { { 0 } }; 540 enum bp_result result = bp->funcs->get_spread_spectrum_info( 541 bp, AS_SIGNAL_TYPE_GPU_PLL, 0, &info); 542 543 /* SSInfo.spreadSpectrumPercentage !=0 would be sign 544 * that SS is enabled 545 */ 546 if (result == BP_RESULT_OK && 547 info.spread_spectrum_percentage != 0) { 548 clk_mgr->ss_on_dprefclk = true; 549 clk_mgr->dprefclk_ss_divider = info.spread_percentage_divider; 550 551 if (info.type.CENTER_MODE == 0) { 552 /* Currently for DP Reference clock we 553 * need only SS percentage for 554 * downspread 555 */ 556 clk_mgr->dprefclk_ss_percentage = 557 info.spread_spectrum_percentage; 558 } 559 } 560 } 561 } 562 static void dcn32_notify_wm_ranges(struct clk_mgr *clk_mgr_base) 563 { 564 unsigned int i; 565 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 566 WatermarksExternal_t *table = (WatermarksExternal_t *) clk_mgr->wm_range_table; 567 568 if (!clk_mgr->smu_present) 569 return; 570 571 if (!table) 572 return; 573 574 memset(table, 0, sizeof(*table)); 575 576 /* collect valid ranges, place in pmfw table */ 577 for (i = 0; i < WM_SET_COUNT; i++) 578 if (clk_mgr->base.bw_params->wm_table.nv_entries[i].valid) { 579 table->Watermarks.WatermarkRow[i].WmSetting = i; 580 table->Watermarks.WatermarkRow[i].Flags = clk_mgr->base.bw_params->wm_table.nv_entries[i].pmfw_breakdown.wm_type; 581 } 582 dcn30_smu_set_dram_addr_high(clk_mgr, clk_mgr->wm_range_table_addr >> 32); 583 dcn30_smu_set_dram_addr_low(clk_mgr, clk_mgr->wm_range_table_addr & 0xFFFFFFFF); 584 dcn32_smu_transfer_wm_table_dram_2_smu(clk_mgr); 585 } 586 587 /* Set min memclk to minimum, either constrained by the current mode or DPM0 */ 588 static void dcn32_set_hard_min_memclk(struct clk_mgr *clk_mgr_base, bool current_mode) 589 { 590 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 591 592 if (!clk_mgr->smu_present) 593 return; 594 595 if (current_mode) { 596 if (clk_mgr_base->clks.p_state_change_support) 597 dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, 598 khz_to_mhz_ceil(clk_mgr_base->clks.dramclk_khz)); 599 else 600 dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, 601 clk_mgr_base->bw_params->clk_table.entries[clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_memclk_levels - 1].memclk_mhz); 602 } else { 603 dcn32_smu_set_hard_min_by_freq(clk_mgr, PPCLK_UCLK, 604 clk_mgr_base->bw_params->clk_table.entries[0].memclk_mhz); 605 } 606 } 607 608 /* Set max memclk to highest DPM value */ 609 static void dcn32_set_hard_max_memclk(struct clk_mgr *clk_mgr_base) 610 { 611 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 612 613 if (!clk_mgr->smu_present) 614 return; 615 616 dcn30_smu_set_hard_max_by_freq(clk_mgr, PPCLK_UCLK, 617 clk_mgr_base->bw_params->clk_table.entries[clk_mgr_base->bw_params->clk_table.num_entries_per_clk.num_memclk_levels - 1].memclk_mhz); 618 } 619 620 /* Get current memclk states, update bounding box */ 621 static void dcn32_get_memclk_states_from_smu(struct clk_mgr *clk_mgr_base) 622 { 623 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 624 struct clk_limit_num_entries *num_entries_per_clk = &clk_mgr_base->bw_params->clk_table.num_entries_per_clk; 625 unsigned int num_levels; 626 627 if (!clk_mgr->smu_present) 628 return; 629 630 /* Refresh memclk and fclk states */ 631 dcn32_init_single_clock(clk_mgr, PPCLK_UCLK, 632 &clk_mgr_base->bw_params->clk_table.entries[0].memclk_mhz, 633 &num_entries_per_clk->num_memclk_levels); 634 635 /* memclk must have at least one level */ 636 num_entries_per_clk->num_memclk_levels = num_entries_per_clk->num_memclk_levels ? num_entries_per_clk->num_memclk_levels : 1; 637 638 dcn32_init_single_clock(clk_mgr, PPCLK_FCLK, 639 &clk_mgr_base->bw_params->clk_table.entries[0].fclk_mhz, 640 &num_entries_per_clk->num_fclk_levels); 641 642 if (num_entries_per_clk->num_memclk_levels >= num_entries_per_clk->num_fclk_levels) { 643 num_levels = num_entries_per_clk->num_memclk_levels; 644 } else { 645 num_levels = num_entries_per_clk->num_fclk_levels; 646 } 647 648 clk_mgr_base->bw_params->clk_table.num_entries = num_levels ? num_levels : 1; 649 650 if (clk_mgr->dpm_present && !num_levels) 651 clk_mgr->dpm_present = false; 652 653 if (!clk_mgr->dpm_present) 654 dcn32_patch_dpm_table(clk_mgr_base->bw_params); 655 656 DC_FP_START(); 657 /* Refresh bounding box */ 658 clk_mgr_base->ctx->dc->res_pool->funcs->update_bw_bounding_box( 659 clk_mgr->base.ctx->dc, clk_mgr_base->bw_params); 660 DC_FP_END(); 661 } 662 663 static bool dcn32_are_clock_states_equal(struct dc_clocks *a, 664 struct dc_clocks *b) 665 { 666 if (a->dispclk_khz != b->dispclk_khz) 667 return false; 668 else if (a->dppclk_khz != b->dppclk_khz) 669 return false; 670 else if (a->dcfclk_khz != b->dcfclk_khz) 671 return false; 672 else if (a->dcfclk_deep_sleep_khz != b->dcfclk_deep_sleep_khz) 673 return false; 674 else if (a->dramclk_khz != b->dramclk_khz) 675 return false; 676 else if (a->p_state_change_support != b->p_state_change_support) 677 return false; 678 else if (a->fclk_p_state_change_support != b->fclk_p_state_change_support) 679 return false; 680 681 return true; 682 } 683 684 static void dcn32_enable_pme_wa(struct clk_mgr *clk_mgr_base) 685 { 686 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 687 688 if (!clk_mgr->smu_present) 689 return; 690 691 dcn32_smu_set_pme_workaround(clk_mgr); 692 } 693 694 static bool dcn32_is_smu_present(struct clk_mgr *clk_mgr_base) 695 { 696 struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base); 697 return clk_mgr->smu_present; 698 } 699 700 701 static struct clk_mgr_funcs dcn32_funcs = { 702 .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz, 703 .get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz, 704 .update_clocks = dcn32_update_clocks, 705 .dump_clk_registers = dcn32_dump_clk_registers, 706 .init_clocks = dcn32_init_clocks, 707 .notify_wm_ranges = dcn32_notify_wm_ranges, 708 .set_hard_min_memclk = dcn32_set_hard_min_memclk, 709 .set_hard_max_memclk = dcn32_set_hard_max_memclk, 710 .get_memclk_states_from_smu = dcn32_get_memclk_states_from_smu, 711 .are_clock_states_equal = dcn32_are_clock_states_equal, 712 .enable_pme_wa = dcn32_enable_pme_wa, 713 .is_smu_present = dcn32_is_smu_present, 714 }; 715 716 void dcn32_clk_mgr_construct( 717 struct dc_context *ctx, 718 struct clk_mgr_internal *clk_mgr, 719 struct pp_smu_funcs *pp_smu, 720 struct dccg *dccg) 721 { 722 clk_mgr->base.ctx = ctx; 723 clk_mgr->base.funcs = &dcn32_funcs; 724 if (ASICREV_IS_GC_11_0_2(clk_mgr->base.ctx->asic_id.hw_internal_rev)) { 725 clk_mgr->regs = &clk_mgr_regs_dcn321; 726 clk_mgr->clk_mgr_shift = &clk_mgr_shift_dcn321; 727 clk_mgr->clk_mgr_mask = &clk_mgr_mask_dcn321; 728 } else { 729 clk_mgr->regs = &clk_mgr_regs_dcn32; 730 clk_mgr->clk_mgr_shift = &clk_mgr_shift_dcn32; 731 clk_mgr->clk_mgr_mask = &clk_mgr_mask_dcn32; 732 } 733 734 clk_mgr->dccg = dccg; 735 clk_mgr->dfs_bypass_disp_clk = 0; 736 737 clk_mgr->dprefclk_ss_percentage = 0; 738 clk_mgr->dprefclk_ss_divider = 1000; 739 clk_mgr->ss_on_dprefclk = false; 740 clk_mgr->dfs_ref_freq_khz = 100000; 741 742 /* Changed from DCN3.2_clock_frequency doc to match 743 * dcn32_dump_clk_registers from 4 * dentist_vco_freq_khz / 744 * dprefclk DID divider 745 */ 746 clk_mgr->base.dprefclk_khz = 716666; 747 if (ctx->dc->debug.disable_dtb_ref_clk_switch) { 748 //initialize DTB ref clock value if DPM disabled 749 if (ctx->dce_version == DCN_VERSION_3_21) 750 clk_mgr->base.clks.ref_dtbclk_khz = 477800; 751 else 752 clk_mgr->base.clks.ref_dtbclk_khz = 268750; 753 } 754 755 /* integer part is now VCO frequency in kHz */ 756 clk_mgr->base.dentist_vco_freq_khz = dcn32_get_vco_frequency_from_reg(clk_mgr); 757 758 /* in case we don't get a value from the register, use default */ 759 if (clk_mgr->base.dentist_vco_freq_khz == 0) 760 clk_mgr->base.dentist_vco_freq_khz = 4300000; /* Updated as per HW docs */ 761 762 if (ctx->dc->debug.disable_dtb_ref_clk_switch && 763 clk_mgr->base.clks.ref_dtbclk_khz != clk_mgr->base.boot_snapshot.dtbclk) { 764 clk_mgr->base.clks.ref_dtbclk_khz = clk_mgr->base.boot_snapshot.dtbclk; 765 } 766 767 if (clk_mgr->base.boot_snapshot.dprefclk != 0) { 768 clk_mgr->base.dprefclk_khz = clk_mgr->base.boot_snapshot.dprefclk; 769 } 770 dcn32_clock_read_ss_info(clk_mgr); 771 772 clk_mgr->dfs_bypass_enabled = false; 773 774 clk_mgr->smu_present = false; 775 776 clk_mgr->base.bw_params = kzalloc(sizeof(*clk_mgr->base.bw_params), GFP_KERNEL); 777 778 /* need physical address of table to give to PMFW */ 779 clk_mgr->wm_range_table = dm_helpers_allocate_gpu_mem(clk_mgr->base.ctx, 780 DC_MEM_ALLOC_TYPE_GART, sizeof(WatermarksExternal_t), 781 &clk_mgr->wm_range_table_addr); 782 } 783 784 void dcn32_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr) 785 { 786 if (clk_mgr->base.bw_params) 787 kfree(clk_mgr->base.bw_params); 788 789 if (clk_mgr->wm_range_table) 790 dm_helpers_free_gpu_mem(clk_mgr->base.ctx, DC_MEM_ALLOC_TYPE_GART, 791 clk_mgr->wm_range_table); 792 } 793 794