1 /* SPDX-License-Identifier: MIT */ 2 /* 3 * Copyright 2023 Advanced Micro Devices, Inc. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in 13 * all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 21 * OTHER DEALINGS IN THE SOFTWARE. 22 * 23 * Authors: AMD 24 * 25 */ 26 27 #include "display_mode_core.h" 28 #include "dml2_internal_types.h" 29 #include "dml2_utils.h" 30 #include "dml2_policy.h" 31 #include "dml2_translation_helper.h" 32 #include "dml2_mall_phantom.h" 33 #include "dml2_dc_resource_mgmt.h" 34 #include "dml21_wrapper.h" 35 36 37 static void initialize_dml2_ip_params(struct dml2_context *dml2, const struct dc *in_dc, struct ip_params_st *out) 38 { 39 if (dml2->config.use_native_soc_bb_construction) 40 dml2_init_ip_params(dml2, in_dc, out); 41 else 42 dml2_translate_ip_params(in_dc, out); 43 } 44 45 static void initialize_dml2_soc_bbox(struct dml2_context *dml2, const struct dc *in_dc, struct soc_bounding_box_st *out) 46 { 47 if (dml2->config.use_native_soc_bb_construction) 48 dml2_init_socbb_params(dml2, in_dc, out); 49 else 50 dml2_translate_socbb_params(in_dc, out); 51 } 52 53 static void initialize_dml2_soc_states(struct dml2_context *dml2, 54 const struct dc *in_dc, const struct soc_bounding_box_st *in_bbox, struct soc_states_st *out) 55 { 56 if (dml2->config.use_native_soc_bb_construction) 57 dml2_init_soc_states(dml2, in_dc, in_bbox, out); 58 else 59 dml2_translate_soc_states(in_dc, out, in_dc->dml.soc.num_states); 60 } 61 62 static void map_hw_resources(struct dml2_context *dml2, 63 struct dml_display_cfg_st *in_out_display_cfg, struct dml_mode_support_info_st *mode_support_info) 64 { 65 unsigned int num_pipes = 0; 66 int i, j; 67 68 for (i = 0; i < __DML_NUM_PLANES__; i++) { 69 in_out_display_cfg->hw.ODMMode[i] = mode_support_info->ODMMode[i]; 70 in_out_display_cfg->hw.DPPPerSurface[i] = mode_support_info->DPPPerSurface[i]; 71 in_out_display_cfg->hw.DSCEnabled[i] = mode_support_info->DSCEnabled[i]; 72 in_out_display_cfg->hw.NumberOfDSCSlices[i] = mode_support_info->NumberOfDSCSlices[i]; 73 in_out_display_cfg->hw.DLGRefClkFreqMHz = 24; 74 if (dml2->v20.dml_core_ctx.project != dml_project_dcn35 && 75 dml2->v20.dml_core_ctx.project != dml_project_dcn351) { 76 /*dGPU default as 50Mhz*/ 77 in_out_display_cfg->hw.DLGRefClkFreqMHz = 50; 78 } 79 for (j = 0; j < mode_support_info->DPPPerSurface[i]; j++) { 80 if (i >= __DML2_WRAPPER_MAX_STREAMS_PLANES__) { 81 dml_print("DML::%s: Index out of bounds: i=%d, __DML2_WRAPPER_MAX_STREAMS_PLANES__=%d\n", 82 __func__, i, __DML2_WRAPPER_MAX_STREAMS_PLANES__); 83 break; 84 } 85 dml2->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_stream_id[num_pipes] = dml2->v20.scratch.dml_to_dc_pipe_mapping.disp_cfg_to_stream_id[i]; 86 dml2->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_stream_id_valid[num_pipes] = true; 87 dml2->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_id[num_pipes] = dml2->v20.scratch.dml_to_dc_pipe_mapping.disp_cfg_to_plane_id[i]; 88 dml2->v20.scratch.dml_to_dc_pipe_mapping.dml_pipe_idx_to_plane_id_valid[num_pipes] = true; 89 num_pipes++; 90 } 91 } 92 } 93 94 static unsigned int pack_and_call_dml_mode_support_ex(struct dml2_context *dml2, 95 const struct dml_display_cfg_st *display_cfg, 96 struct dml_mode_support_info_st *evaluation_info) 97 { 98 struct dml2_wrapper_scratch *s = &dml2->v20.scratch; 99 100 s->mode_support_params.mode_lib = &dml2->v20.dml_core_ctx; 101 s->mode_support_params.in_display_cfg = display_cfg; 102 s->mode_support_params.out_evaluation_info = evaluation_info; 103 104 memset(evaluation_info, 0, sizeof(struct dml_mode_support_info_st)); 105 s->mode_support_params.out_lowest_state_idx = 0; 106 107 return dml_mode_support_ex(&s->mode_support_params); 108 } 109 110 static bool optimize_configuration(struct dml2_context *dml2, struct dml2_wrapper_optimize_configuration_params *p) 111 { 112 int unused_dpps = p->ip_params->max_num_dpp; 113 int i, j; 114 int odms_needed, refresh_rate_hz, dpps_needed, subvp_height, pstate_width_fw_delay_lines, surface_count; 115 int subvp_timing_to_add, new_timing_index, subvp_surface_to_add, new_surface_index; 116 float frame_time_sec, max_frame_time_sec; 117 int largest_blend_and_timing = 0; 118 bool optimization_done = false; 119 120 for (i = 0; i < (int) p->cur_display_config->num_timings; i++) { 121 if (p->cur_display_config->plane.BlendingAndTiming[i] > largest_blend_and_timing) 122 largest_blend_and_timing = p->cur_display_config->plane.BlendingAndTiming[i]; 123 } 124 125 if (p->new_policy != p->cur_policy) 126 *p->new_policy = *p->cur_policy; 127 128 if (p->new_display_config != p->cur_display_config) 129 *p->new_display_config = *p->cur_display_config; 130 131 // Optimize P-State Support 132 if (dml2->config.use_native_pstate_optimization) { 133 if (p->cur_mode_support_info->DRAMClockChangeSupport[0] == dml_dram_clock_change_unsupported) { 134 // Find a display with < 120Hz refresh rate with maximal refresh rate that's not already subvp 135 subvp_timing_to_add = -1; 136 subvp_surface_to_add = -1; 137 max_frame_time_sec = 0; 138 surface_count = 0; 139 for (i = 0; i < (int) p->cur_display_config->num_timings; i++) { 140 refresh_rate_hz = (int)div_u64((unsigned long long) p->cur_display_config->timing.PixelClock[i] * 1000 * 1000, 141 (p->cur_display_config->timing.HTotal[i] * p->cur_display_config->timing.VTotal[i])); 142 if (refresh_rate_hz < 120) { 143 // Check its upstream surfaces to see if this one could be converted to subvp. 144 dpps_needed = 0; 145 for (j = 0; j < (int) p->cur_display_config->num_surfaces; j++) { 146 if (p->cur_display_config->plane.BlendingAndTiming[j] == i && 147 p->cur_display_config->plane.UseMALLForPStateChange[j] == dml_use_mall_pstate_change_disable) { 148 dpps_needed += p->cur_mode_support_info->DPPPerSurface[j]; 149 subvp_surface_to_add = j; 150 surface_count++; 151 } 152 } 153 154 if (surface_count == 1 && dpps_needed > 0 && dpps_needed <= unused_dpps) { 155 frame_time_sec = (float)1 / refresh_rate_hz; 156 if (frame_time_sec > max_frame_time_sec) { 157 max_frame_time_sec = frame_time_sec; 158 subvp_timing_to_add = i; 159 } 160 } 161 } 162 } 163 if (subvp_timing_to_add >= 0) { 164 new_timing_index = p->new_display_config->num_timings++; 165 new_surface_index = p->new_display_config->num_surfaces++; 166 // Add a phantom pipe reflecting the main pipe's timing 167 dml2_util_copy_dml_timing(&p->new_display_config->timing, new_timing_index, subvp_timing_to_add); 168 169 pstate_width_fw_delay_lines = (int)(((double)(p->config->svp_pstate.subvp_fw_processing_delay_us + 170 p->config->svp_pstate.subvp_pstate_allow_width_us) / 1000000) * 171 (p->new_display_config->timing.PixelClock[subvp_timing_to_add] * 1000 * 1000) / 172 (double)p->new_display_config->timing.HTotal[subvp_timing_to_add]); 173 174 subvp_height = p->cur_mode_support_info->SubViewportLinesNeededInMALL[subvp_timing_to_add] + pstate_width_fw_delay_lines; 175 176 p->new_display_config->timing.VActive[new_timing_index] = subvp_height; 177 p->new_display_config->timing.VTotal[new_timing_index] = subvp_height + 178 p->new_display_config->timing.VTotal[subvp_timing_to_add] - p->new_display_config->timing.VActive[subvp_timing_to_add]; 179 180 p->new_display_config->output.OutputDisabled[new_timing_index] = true; 181 182 p->new_display_config->plane.UseMALLForPStateChange[subvp_surface_to_add] = dml_use_mall_pstate_change_sub_viewport; 183 184 dml2_util_copy_dml_plane(&p->new_display_config->plane, new_surface_index, subvp_surface_to_add); 185 dml2_util_copy_dml_surface(&p->new_display_config->surface, new_surface_index, subvp_surface_to_add); 186 187 p->new_display_config->plane.ViewportHeight[new_surface_index] = subvp_height; 188 p->new_display_config->plane.ViewportHeightChroma[new_surface_index] = subvp_height; 189 p->new_display_config->plane.ViewportStationary[new_surface_index] = false; 190 191 p->new_display_config->plane.UseMALLForStaticScreen[new_surface_index] = dml_use_mall_static_screen_disable; 192 p->new_display_config->plane.UseMALLForPStateChange[new_surface_index] = dml_use_mall_pstate_change_phantom_pipe; 193 194 p->new_display_config->plane.NumberOfCursors[new_surface_index] = 0; 195 196 p->new_policy->ImmediateFlipRequirement[new_surface_index] = dml_immediate_flip_not_required; 197 198 p->new_display_config->plane.BlendingAndTiming[new_surface_index] = new_timing_index; 199 200 optimization_done = true; 201 } 202 } 203 } 204 205 // Optimize Clocks 206 if (!optimization_done) { 207 if (largest_blend_and_timing == 0 && p->cur_policy->ODMUse[0] == dml_odm_use_policy_combine_as_needed && dml2->config.minimize_dispclk_using_odm) { 208 odms_needed = dml2_util_get_maximum_odm_combine_for_output(dml2->config.optimize_odm_4to1, 209 p->cur_display_config->output.OutputEncoder[0], p->cur_mode_support_info->DSCEnabled[0]) - 1; 210 211 if (odms_needed <= unused_dpps) { 212 unused_dpps -= odms_needed; 213 214 if (odms_needed == 1) { 215 p->new_policy->ODMUse[0] = dml_odm_use_policy_combine_2to1; 216 optimization_done = true; 217 } else if (odms_needed == 3) { 218 p->new_policy->ODMUse[0] = dml_odm_use_policy_combine_4to1; 219 optimization_done = true; 220 } else 221 optimization_done = false; 222 } 223 } 224 } 225 226 return optimization_done; 227 } 228 229 static int calculate_lowest_supported_state_for_temp_read(struct dml2_context *dml2, struct dc_state *display_state) 230 { 231 struct dml2_calculate_lowest_supported_state_for_temp_read_scratch *s = &dml2->v20.scratch.dml2_calculate_lowest_supported_state_for_temp_read_scratch; 232 struct dml2_wrapper_scratch *s_global = &dml2->v20.scratch; 233 234 unsigned int dml_result = 0; 235 int result = -1, i, j; 236 237 build_unoptimized_policy_settings(dml2->v20.dml_core_ctx.project, &dml2->v20.dml_core_ctx.policy); 238 239 /* Zero out before each call before proceeding */ 240 memset(s, 0, sizeof(struct dml2_calculate_lowest_supported_state_for_temp_read_scratch)); 241 memset(&s_global->mode_support_params, 0, sizeof(struct dml_mode_support_ex_params_st)); 242 memset(&s_global->dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping)); 243 244 for (i = 0; i < dml2->config.dcn_pipe_count; i++) { 245 /* Calling resource_build_scaling_params will populate the pipe params 246 * with the necessary information needed for correct DML calculations 247 * This is also done in DML1 driver code path and hence display_state 248 * cannot be const. 249 */ 250 struct pipe_ctx *pipe = &display_state->res_ctx.pipe_ctx[i]; 251 252 if (pipe->plane_state) { 253 if (!dml2->config.callbacks.build_scaling_params(pipe)) { 254 ASSERT(false); 255 return false; 256 } 257 } 258 } 259 260 map_dc_state_into_dml_display_cfg(dml2, display_state, &s->cur_display_config); 261 262 for (i = 0; i < dml2->v20.dml_core_ctx.states.num_states; i++) { 263 s->uclk_change_latencies[i] = dml2->v20.dml_core_ctx.states.state_array[i].dram_clock_change_latency_us; 264 } 265 266 for (i = 0; i < 4; i++) { 267 for (j = 0; j < dml2->v20.dml_core_ctx.states.num_states; j++) { 268 dml2->v20.dml_core_ctx.states.state_array[j].dram_clock_change_latency_us = s_global->dummy_pstate_table[i].dummy_pstate_latency_us; 269 } 270 271 dml_result = pack_and_call_dml_mode_support_ex(dml2, &s->cur_display_config, &s->evaluation_info); 272 273 if (dml_result && s->evaluation_info.DRAMClockChangeSupport[0] == dml_dram_clock_change_vactive) { 274 map_hw_resources(dml2, &s->cur_display_config, &s->evaluation_info); 275 dml_result = dml_mode_programming(&dml2->v20.dml_core_ctx, s_global->mode_support_params.out_lowest_state_idx, &s->cur_display_config, true); 276 277 ASSERT(dml_result); 278 279 dml2_extract_watermark_set(&dml2->v20.g6_temp_read_watermark_set, &dml2->v20.dml_core_ctx); 280 dml2->v20.g6_temp_read_watermark_set.cstate_pstate.fclk_pstate_change_ns = dml2->v20.g6_temp_read_watermark_set.cstate_pstate.pstate_change_ns; 281 282 result = s_global->mode_support_params.out_lowest_state_idx; 283 284 while (dml2->v20.dml_core_ctx.states.state_array[result].dram_speed_mts < s_global->dummy_pstate_table[i].dram_speed_mts) 285 result++; 286 287 break; 288 } 289 } 290 291 for (i = 0; i < dml2->v20.dml_core_ctx.states.num_states; i++) { 292 dml2->v20.dml_core_ctx.states.state_array[i].dram_clock_change_latency_us = s->uclk_change_latencies[i]; 293 } 294 295 return result; 296 } 297 298 static void copy_dummy_pstate_table(struct dummy_pstate_entry *dest, struct dummy_pstate_entry *src, unsigned int num_entries) 299 { 300 for (int i = 0; i < num_entries; i++) { 301 dest[i] = src[i]; 302 } 303 } 304 305 static bool are_timings_requiring_odm_doing_blending(const struct dml_display_cfg_st *display_cfg, 306 const struct dml_mode_support_info_st *evaluation_info) 307 { 308 unsigned int planes_per_timing[__DML_NUM_PLANES__] = {0}; 309 int i; 310 311 for (i = 0; i < display_cfg->num_surfaces; i++) 312 planes_per_timing[display_cfg->plane.BlendingAndTiming[i]]++; 313 314 for (i = 0; i < __DML_NUM_PLANES__; i++) { 315 if (planes_per_timing[i] > 1 && evaluation_info->ODMMode[i] != dml_odm_mode_bypass) 316 return true; 317 } 318 319 return false; 320 } 321 322 static bool does_configuration_meet_sw_policies(struct dml2_context *ctx, const struct dml_display_cfg_st *display_cfg, 323 const struct dml_mode_support_info_st *evaluation_info) 324 { 325 bool pass = true; 326 327 if (!ctx->config.enable_windowed_mpo_odm) { 328 if (are_timings_requiring_odm_doing_blending(display_cfg, evaluation_info)) 329 pass = false; 330 } 331 332 return pass; 333 } 334 335 static bool dml_mode_support_wrapper(struct dml2_context *dml2, 336 struct dc_state *display_state) 337 { 338 struct dml2_wrapper_scratch *s = &dml2->v20.scratch; 339 unsigned int result = 0, i; 340 unsigned int optimized_result = true; 341 342 build_unoptimized_policy_settings(dml2->v20.dml_core_ctx.project, &dml2->v20.dml_core_ctx.policy); 343 344 /* Zero out before each call before proceeding */ 345 memset(&s->cur_display_config, 0, sizeof(struct dml_display_cfg_st)); 346 memset(&s->mode_support_params, 0, sizeof(struct dml_mode_support_ex_params_st)); 347 memset(&s->dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping)); 348 memset(&s->optimize_configuration_params, 0, sizeof(struct dml2_wrapper_optimize_configuration_params)); 349 350 for (i = 0; i < dml2->config.dcn_pipe_count; i++) { 351 /* Calling resource_build_scaling_params will populate the pipe params 352 * with the necessary information needed for correct DML calculations 353 * This is also done in DML1 driver code path and hence display_state 354 * cannot be const. 355 */ 356 struct pipe_ctx *pipe = &display_state->res_ctx.pipe_ctx[i]; 357 358 if (pipe->plane_state) { 359 if (!dml2->config.callbacks.build_scaling_params(pipe)) { 360 ASSERT(false); 361 return false; 362 } 363 } 364 } 365 366 map_dc_state_into_dml_display_cfg(dml2, display_state, &s->cur_display_config); 367 if (!dml2->config.skip_hw_state_mapping) 368 dml2_apply_det_buffer_allocation_policy(dml2, &s->cur_display_config); 369 370 result = pack_and_call_dml_mode_support_ex(dml2, 371 &s->cur_display_config, 372 &s->mode_support_info); 373 374 if (result) 375 result = does_configuration_meet_sw_policies(dml2, &s->cur_display_config, &s->mode_support_info); 376 377 // Try to optimize 378 if (result) { 379 s->cur_policy = dml2->v20.dml_core_ctx.policy; 380 s->optimize_configuration_params.dml_core_ctx = &dml2->v20.dml_core_ctx; 381 s->optimize_configuration_params.config = &dml2->config; 382 s->optimize_configuration_params.ip_params = &dml2->v20.dml_core_ctx.ip; 383 s->optimize_configuration_params.cur_display_config = &s->cur_display_config; 384 s->optimize_configuration_params.cur_mode_support_info = &s->mode_support_info; 385 s->optimize_configuration_params.cur_policy = &s->cur_policy; 386 s->optimize_configuration_params.new_display_config = &s->new_display_config; 387 s->optimize_configuration_params.new_policy = &s->new_policy; 388 389 while (optimized_result && optimize_configuration(dml2, &s->optimize_configuration_params)) { 390 dml2->v20.dml_core_ctx.policy = s->new_policy; 391 optimized_result = pack_and_call_dml_mode_support_ex(dml2, 392 &s->new_display_config, 393 &s->mode_support_info); 394 395 if (optimized_result) 396 optimized_result = does_configuration_meet_sw_policies(dml2, &s->new_display_config, &s->mode_support_info); 397 398 // If the new optimized state is supposed, then set current = new 399 if (optimized_result) { 400 s->cur_display_config = s->new_display_config; 401 s->cur_policy = s->new_policy; 402 } else { 403 // Else, restore policy to current 404 dml2->v20.dml_core_ctx.policy = s->cur_policy; 405 } 406 } 407 408 // Optimize ended with a failed config, so we need to restore DML state to last passing 409 if (!optimized_result) { 410 result = pack_and_call_dml_mode_support_ex(dml2, 411 &s->cur_display_config, 412 &s->mode_support_info); 413 } 414 } 415 416 if (result) 417 map_hw_resources(dml2, &s->cur_display_config, &s->mode_support_info); 418 419 return result; 420 } 421 422 static int find_drr_eligible_stream(struct dc_state *display_state) 423 { 424 int i; 425 426 for (i = 0; i < display_state->stream_count; i++) { 427 if (dc_state_get_stream_subvp_type(display_state, display_state->streams[i]) == SUBVP_NONE 428 && display_state->streams[i]->ignore_msa_timing_param) { 429 // Use ignore_msa_timing_param flag to identify as DRR 430 return i; 431 } 432 } 433 434 return -1; 435 } 436 437 static bool optimize_pstate_with_svp_and_drr(struct dml2_context *dml2, struct dc_state *display_state) 438 { 439 struct dml2_wrapper_scratch *s = &dml2->v20.scratch; 440 bool pstate_optimization_done = false; 441 bool pstate_optimization_success = false; 442 bool result = false; 443 int drr_display_index = 0, non_svp_streams = 0; 444 bool force_svp = dml2->config.svp_pstate.force_enable_subvp; 445 bool advanced_pstate_switching = false; 446 447 display_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = false; 448 display_state->bw_ctx.bw.dcn.legacy_svp_drr_stream_index_valid = false; 449 450 result = dml_mode_support_wrapper(dml2, display_state); 451 452 if (!result) { 453 pstate_optimization_done = true; 454 } else if (!advanced_pstate_switching || 455 (s->mode_support_info.DRAMClockChangeSupport[0] != dml_dram_clock_change_unsupported && !force_svp)) { 456 pstate_optimization_success = true; 457 pstate_optimization_done = true; 458 } 459 460 if (display_state->stream_count == 1 && dml2->config.callbacks.can_support_mclk_switch_using_fw_based_vblank_stretch(dml2->config.callbacks.dc, display_state)) { 461 display_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = true; 462 463 result = dml_mode_support_wrapper(dml2, display_state); 464 } else { 465 non_svp_streams = display_state->stream_count; 466 467 while (!pstate_optimization_done) { 468 result = dml_mode_programming(&dml2->v20.dml_core_ctx, s->mode_support_params.out_lowest_state_idx, &s->cur_display_config, true); 469 470 // Always try adding SVP first 471 if (result) 472 result = dml2_svp_add_phantom_pipe_to_dc_state(dml2, display_state, &s->mode_support_info); 473 else 474 pstate_optimization_done = true; 475 476 477 if (result) { 478 result = dml_mode_support_wrapper(dml2, display_state); 479 } else { 480 pstate_optimization_done = true; 481 } 482 483 if (result) { 484 non_svp_streams--; 485 486 if (s->mode_support_info.DRAMClockChangeSupport[0] != dml_dram_clock_change_unsupported) { 487 if (dml2_svp_validate_static_schedulability(dml2, display_state, s->mode_support_info.DRAMClockChangeSupport[0])) { 488 pstate_optimization_success = true; 489 pstate_optimization_done = true; 490 } else { 491 pstate_optimization_success = false; 492 pstate_optimization_done = false; 493 } 494 } else { 495 drr_display_index = find_drr_eligible_stream(display_state); 496 497 // If there is only 1 remaining non SubVP pipe that is DRR, check static 498 // schedulability for SubVP + DRR. 499 if (non_svp_streams == 1 && drr_display_index >= 0) { 500 if (dml2_svp_drr_schedulable(dml2, display_state, &display_state->streams[drr_display_index]->timing)) { 501 display_state->bw_ctx.bw.dcn.legacy_svp_drr_stream_index_valid = true; 502 display_state->bw_ctx.bw.dcn.legacy_svp_drr_stream_index = drr_display_index; 503 result = dml_mode_support_wrapper(dml2, display_state); 504 } 505 506 if (result && s->mode_support_info.DRAMClockChangeSupport[0] != dml_dram_clock_change_unsupported) { 507 pstate_optimization_success = true; 508 pstate_optimization_done = true; 509 } else { 510 pstate_optimization_success = false; 511 pstate_optimization_done = false; 512 } 513 } 514 515 if (pstate_optimization_success) { 516 pstate_optimization_done = true; 517 } else { 518 pstate_optimization_done = false; 519 } 520 } 521 } 522 } 523 } 524 525 if (!pstate_optimization_success) { 526 dml2_svp_remove_all_phantom_pipes(dml2, display_state); 527 display_state->bw_ctx.bw.dcn.clk.fw_based_mclk_switching = false; 528 display_state->bw_ctx.bw.dcn.legacy_svp_drr_stream_index_valid = false; 529 result = dml_mode_support_wrapper(dml2, display_state); 530 } 531 532 return result; 533 } 534 535 static bool call_dml_mode_support_and_programming(struct dc_state *context) 536 { 537 unsigned int result = 0; 538 unsigned int min_state; 539 int min_state_for_g6_temp_read = 0; 540 struct dml2_context *dml2 = context->bw_ctx.dml2; 541 struct dml2_wrapper_scratch *s = &dml2->v20.scratch; 542 543 min_state_for_g6_temp_read = calculate_lowest_supported_state_for_temp_read(dml2, context); 544 545 ASSERT(min_state_for_g6_temp_read >= 0); 546 547 if (!dml2->config.use_native_pstate_optimization) { 548 result = optimize_pstate_with_svp_and_drr(dml2, context); 549 } else { 550 result = dml_mode_support_wrapper(dml2, context); 551 } 552 553 /* Upon trying to sett certain frequencies in FRL, min_state_for_g6_temp_read is reported as -1. This leads to an invalid value of min_state causing crashes later on. 554 * Use the default logic for min_state only when min_state_for_g6_temp_read is a valid value. In other cases, use the value calculated by the DML directly. 555 */ 556 if (min_state_for_g6_temp_read >= 0) 557 min_state = min_state_for_g6_temp_read > s->mode_support_params.out_lowest_state_idx ? min_state_for_g6_temp_read : s->mode_support_params.out_lowest_state_idx; 558 else 559 min_state = s->mode_support_params.out_lowest_state_idx; 560 561 if (result) 562 result = dml_mode_programming(&dml2->v20.dml_core_ctx, min_state, &s->cur_display_config, true); 563 564 return result; 565 } 566 567 static bool dml2_validate_and_build_resource(const struct dc *in_dc, struct dc_state *context) 568 { 569 struct dml2_context *dml2 = context->bw_ctx.dml2; 570 struct dml2_wrapper_scratch *s = &dml2->v20.scratch; 571 struct dml2_dcn_clocks out_clks; 572 unsigned int result = 0; 573 bool need_recalculation = false; 574 uint32_t cstate_enter_plus_exit_z8_ns; 575 576 if (context->stream_count == 0) { 577 unsigned int lowest_state_idx = 0; 578 579 out_clks.p_state_supported = true; 580 out_clks.dispclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dispclk_mhz * 1000; 581 out_clks.dcfclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dcfclk_mhz * 1000; 582 out_clks.fclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].fabricclk_mhz * 1000; 583 out_clks.uclk_mts = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dram_speed_mts; 584 out_clks.phyclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].phyclk_mhz * 1000; 585 out_clks.socclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].socclk_mhz * 1000; 586 out_clks.ref_dtbclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dtbclk_mhz * 1000; 587 context->bw_ctx.bw.dcn.clk.dtbclk_en = false; 588 dml2_copy_clocks_to_dc_state(&out_clks, context); 589 return true; 590 } 591 592 /* Zero out before each call before proceeding */ 593 memset(&dml2->v20.scratch, 0, sizeof(struct dml2_wrapper_scratch)); 594 memset(&dml2->v20.dml_core_ctx.policy, 0, sizeof(struct dml_mode_eval_policy_st)); 595 memset(&dml2->v20.dml_core_ctx.ms, 0, sizeof(struct mode_support_st)); 596 memset(&dml2->v20.dml_core_ctx.mp, 0, sizeof(struct mode_program_st)); 597 598 /* Initialize DET scratch */ 599 dml2_initialize_det_scratch(dml2); 600 601 copy_dummy_pstate_table(s->dummy_pstate_table, in_dc->clk_mgr->bw_params->dummy_pstate_table, 4); 602 603 result = call_dml_mode_support_and_programming(context); 604 /* Call map dc pipes to map the pipes based on the DML output. For correctly determining if recalculation 605 * is required or not, the resource context needs to correctly reflect the number of active pipes. We would 606 * only know the correct number if active pipes after dml2_map_dc_pipes is called. 607 */ 608 if (result && !dml2->config.skip_hw_state_mapping) 609 dml2_map_dc_pipes(dml2, context, &s->cur_display_config, &s->dml_to_dc_pipe_mapping, in_dc->current_state); 610 611 /* Verify and update DET Buffer configuration if needed. dml2_verify_det_buffer_configuration will check if DET Buffer 612 * size needs to be updated. If yes it will update the DETOverride variable and set need_recalculation flag to true. 613 * Based on that flag, run mode support again. Verification needs to be run after dml_mode_programming because the getters 614 * return correct det buffer values only after dml_mode_programming is called. 615 */ 616 if (result && !dml2->config.skip_hw_state_mapping) { 617 need_recalculation = dml2_verify_det_buffer_configuration(dml2, context, &dml2->det_helper_scratch); 618 if (need_recalculation) { 619 /* Engage the DML again if recalculation is required. */ 620 call_dml_mode_support_and_programming(context); 621 if (!dml2->config.skip_hw_state_mapping) { 622 dml2_map_dc_pipes(dml2, context, &s->cur_display_config, &s->dml_to_dc_pipe_mapping, in_dc->current_state); 623 } 624 need_recalculation = dml2_verify_det_buffer_configuration(dml2, context, &dml2->det_helper_scratch); 625 ASSERT(need_recalculation == false); 626 } 627 } 628 629 if (result) { 630 unsigned int lowest_state_idx = s->mode_support_params.out_lowest_state_idx; 631 double min_fclk_mhz_for_urgent_workaround = (double)dml2->config.min_fclk_for_urgent_workaround_khz / 1000.0; 632 double max_frac_urgent = (double)dml2->config.max_frac_urgent_for_min_fclk_x1000 / 1000.0; 633 634 if (min_fclk_mhz_for_urgent_workaround > 0.0 && max_frac_urgent > 0.0 && 635 (dml2->v20.dml_core_ctx.mp.FractionOfUrgentBandwidth > max_frac_urgent || 636 dml2->v20.dml_core_ctx.mp.FractionOfUrgentBandwidthImmediateFlip > max_frac_urgent)) { 637 unsigned int forced_lowest_state_idx = lowest_state_idx; 638 639 while (forced_lowest_state_idx < dml2->v20.dml_core_ctx.states.num_states && 640 dml2->v20.dml_core_ctx.states.state_array[forced_lowest_state_idx].fabricclk_mhz <= min_fclk_mhz_for_urgent_workaround) { 641 forced_lowest_state_idx += 1; 642 } 643 lowest_state_idx = forced_lowest_state_idx; 644 } 645 646 out_clks.dispclk_khz = (unsigned int)dml2->v20.dml_core_ctx.mp.Dispclk_calculated * 1000; 647 out_clks.p_state_supported = s->mode_support_info.DRAMClockChangeSupport[0] != dml_dram_clock_change_unsupported; 648 if (in_dc->config.use_default_clock_table && 649 (lowest_state_idx < dml2->v20.dml_core_ctx.states.num_states - 1)) { 650 lowest_state_idx = dml2->v20.dml_core_ctx.states.num_states - 1; 651 out_clks.dispclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dispclk_mhz * 1000; 652 } 653 654 out_clks.dcfclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dcfclk_mhz * 1000; 655 out_clks.fclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].fabricclk_mhz * 1000; 656 out_clks.uclk_mts = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dram_speed_mts; 657 out_clks.phyclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].phyclk_mhz * 1000; 658 out_clks.socclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].socclk_mhz * 1000; 659 out_clks.ref_dtbclk_khz = (unsigned int)dml2->v20.dml_core_ctx.states.state_array[lowest_state_idx].dtbclk_mhz * 1000; 660 context->bw_ctx.bw.dcn.clk.dtbclk_en = is_dtbclk_required(in_dc, context); 661 662 if (!dml2->config.skip_hw_state_mapping) { 663 /* Call dml2_calculate_rq_and_dlg_params */ 664 dml2_calculate_rq_and_dlg_params(in_dc, context, &context->res_ctx, dml2, in_dc->res_pool->pipe_count); 665 } 666 667 dml2_copy_clocks_to_dc_state(&out_clks, context); 668 dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.a, &dml2->v20.dml_core_ctx); 669 dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.b, &dml2->v20.dml_core_ctx); 670 memcpy(&context->bw_ctx.bw.dcn.watermarks.c, &dml2->v20.g6_temp_read_watermark_set, sizeof(context->bw_ctx.bw.dcn.watermarks.c)); 671 dml2_extract_watermark_set(&context->bw_ctx.bw.dcn.watermarks.d, &dml2->v20.dml_core_ctx); 672 dml2_extract_writeback_wm(context, &dml2->v20.dml_core_ctx); 673 //copy for deciding zstate use 674 context->bw_ctx.dml.vba.StutterPeriod = context->bw_ctx.dml2->v20.dml_core_ctx.mp.StutterPeriod; 675 676 cstate_enter_plus_exit_z8_ns = context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns; 677 678 if (context->bw_ctx.dml.vba.StutterPeriod < in_dc->debug.minimum_z8_residency_time && 679 cstate_enter_plus_exit_z8_ns < in_dc->debug.minimum_z8_residency_time * 1000) 680 cstate_enter_plus_exit_z8_ns = in_dc->debug.minimum_z8_residency_time * 1000; 681 682 context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns = cstate_enter_plus_exit_z8_ns; 683 } 684 685 return result; 686 } 687 688 static bool dml2_validate_only(struct dc_state *context) 689 { 690 struct dml2_context *dml2; 691 unsigned int result = 0; 692 693 if (!context || context->stream_count == 0) 694 return true; 695 696 dml2 = context->bw_ctx.dml2; 697 698 /* Zero out before each call before proceeding */ 699 memset(&dml2->v20.scratch, 0, sizeof(struct dml2_wrapper_scratch)); 700 memset(&dml2->v20.dml_core_ctx.policy, 0, sizeof(struct dml_mode_eval_policy_st)); 701 memset(&dml2->v20.dml_core_ctx.ms, 0, sizeof(struct mode_support_st)); 702 memset(&dml2->v20.dml_core_ctx.mp, 0, sizeof(struct mode_program_st)); 703 704 build_unoptimized_policy_settings(dml2->v20.dml_core_ctx.project, &dml2->v20.dml_core_ctx.policy); 705 706 map_dc_state_into_dml_display_cfg(dml2, context, &dml2->v20.scratch.cur_display_config); 707 708 result = pack_and_call_dml_mode_support_ex(dml2, 709 &dml2->v20.scratch.cur_display_config, 710 &dml2->v20.scratch.mode_support_info); 711 712 if (result) 713 result = does_configuration_meet_sw_policies(dml2, &dml2->v20.scratch.cur_display_config, &dml2->v20.scratch.mode_support_info); 714 715 return (result == 1) ? true : false; 716 } 717 718 static void dml2_apply_debug_options(const struct dc *dc, struct dml2_context *dml2) 719 { 720 if (dc->debug.override_odm_optimization) { 721 dml2->config.minimize_dispclk_using_odm = dc->debug.minimize_dispclk_using_odm; 722 } 723 } 724 725 bool dml2_validate(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml2, bool fast_validate) 726 { 727 bool out = false; 728 729 if (!dml2) 730 return false; 731 dml2_apply_debug_options(in_dc, dml2); 732 733 /* DML2.1 validation path */ 734 if (dml2->architecture == dml2_architecture_21) { 735 out = dml21_validate(in_dc, context, dml2, fast_validate); 736 return out; 737 } 738 739 /* Use dml_validate_only for fast_validate path */ 740 if (fast_validate) 741 out = dml2_validate_only(context); 742 else 743 out = dml2_validate_and_build_resource(in_dc, context); 744 return out; 745 } 746 747 static inline struct dml2_context *dml2_allocate_memory(void) 748 { 749 return (struct dml2_context *) kzalloc(sizeof(struct dml2_context), GFP_KERNEL); 750 } 751 752 static void dml2_init(const struct dc *in_dc, const struct dml2_configuration_options *config, struct dml2_context **dml2) 753 { 754 // TODO : Temporarily add DCN_VERSION_3_2 for N-1 validation. Remove DCN_VERSION_3_2 after N-1 validation phase is complete. 755 if ((in_dc->debug.using_dml21) && (in_dc->ctx->dce_version == DCN_VERSION_4_01 || in_dc->ctx->dce_version == DCN_VERSION_3_2)) { 756 dml21_reinit(in_dc, dml2, config); 757 return; 758 } 759 760 // Store config options 761 (*dml2)->config = *config; 762 763 switch (in_dc->ctx->dce_version) { 764 case DCN_VERSION_3_5: 765 (*dml2)->v20.dml_core_ctx.project = dml_project_dcn35; 766 break; 767 case DCN_VERSION_3_51: 768 (*dml2)->v20.dml_core_ctx.project = dml_project_dcn351; 769 break; 770 case DCN_VERSION_3_2: 771 (*dml2)->v20.dml_core_ctx.project = dml_project_dcn32; 772 break; 773 case DCN_VERSION_3_21: 774 (*dml2)->v20.dml_core_ctx.project = dml_project_dcn321; 775 break; 776 case DCN_VERSION_4_01: 777 (*dml2)->v20.dml_core_ctx.project = dml_project_dcn401; 778 break; 779 default: 780 (*dml2)->v20.dml_core_ctx.project = dml_project_default; 781 break; 782 } 783 784 initialize_dml2_ip_params(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.ip); 785 786 initialize_dml2_soc_bbox(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.soc); 787 788 initialize_dml2_soc_states(*dml2, in_dc, &(*dml2)->v20.dml_core_ctx.soc, &(*dml2)->v20.dml_core_ctx.states); 789 } 790 791 bool dml2_create(const struct dc *in_dc, const struct dml2_configuration_options *config, struct dml2_context **dml2) 792 { 793 // TODO : Temporarily add DCN_VERSION_3_2 for N-1 validation. Remove DCN_VERSION_3_2 after N-1 validation phase is complete. 794 if ((in_dc->debug.using_dml21) && (in_dc->ctx->dce_version == DCN_VERSION_4_01 || in_dc->ctx->dce_version == DCN_VERSION_3_2)) { 795 return dml21_create(in_dc, dml2, config); 796 } 797 798 // Allocate Mode Lib Ctx 799 *dml2 = dml2_allocate_memory(); 800 801 if (!(*dml2)) 802 return false; 803 804 dml2_init(in_dc, config, dml2); 805 806 return true; 807 } 808 809 void dml2_destroy(struct dml2_context *dml2) 810 { 811 if (!dml2) 812 return; 813 814 if (dml2->architecture == dml2_architecture_21) 815 dml21_destroy(dml2); 816 kfree(dml2); 817 } 818 819 void dml2_extract_dram_and_fclk_change_support(struct dml2_context *dml2, 820 unsigned int *fclk_change_support, unsigned int *dram_clk_change_support) 821 { 822 *fclk_change_support = (unsigned int) dml2->v20.dml_core_ctx.ms.support.FCLKChangeSupport[0]; 823 *dram_clk_change_support = (unsigned int) dml2->v20.dml_core_ctx.ms.support.DRAMClockChangeSupport[0]; 824 } 825 826 void dml2_copy(struct dml2_context *dst_dml2, 827 struct dml2_context *src_dml2) 828 { 829 if (src_dml2->architecture == dml2_architecture_21) { 830 dml21_copy(dst_dml2, src_dml2); 831 return; 832 } 833 /* copy Mode Lib Ctx */ 834 memcpy(dst_dml2, src_dml2, sizeof(struct dml2_context)); 835 } 836 837 bool dml2_create_copy(struct dml2_context **dst_dml2, 838 struct dml2_context *src_dml2) 839 { 840 if (src_dml2->architecture == dml2_architecture_21) 841 return dml21_create_copy(dst_dml2, src_dml2); 842 /* Allocate Mode Lib Ctx */ 843 *dst_dml2 = dml2_allocate_memory(); 844 845 if (!(*dst_dml2)) 846 return false; 847 848 /* copy Mode Lib Ctx */ 849 dml2_copy(*dst_dml2, src_dml2); 850 851 return true; 852 } 853 854 void dml2_reinit(const struct dc *in_dc, 855 const struct dml2_configuration_options *config, 856 struct dml2_context **dml2) 857 { 858 // TODO : Temporarily add DCN_VERSION_3_2 for N-1 validation. Remove DCN_VERSION_3_2 after N-1 validation phase is complete. 859 if ((in_dc->debug.using_dml21) && (in_dc->ctx->dce_version == DCN_VERSION_4_01 || in_dc->ctx->dce_version == DCN_VERSION_3_2)) { 860 dml21_reinit(in_dc, dml2, config); 861 return; 862 } 863 864 dml2_init(in_dc, config, dml2); 865 } 866