1 // SPDX-License-Identifier: MIT 2 // 3 // Copyright 2024 Advanced Micro Devices, Inc. 4 5 6 #include "dml2_internal_types.h" 7 #include "dml_top.h" 8 #include "dml2_core_dcn4_calcs.h" 9 #include "dml2_internal_shared_types.h" 10 #include "dml21_utils.h" 11 #include "dml21_translation_helper.h" 12 #include "dml2_dc_resource_mgmt.h" 13 14 static bool dml21_allocate_memory(struct dml2_context **dml_ctx) 15 { 16 *dml_ctx = (struct dml2_context *)kzalloc(sizeof(struct dml2_context), GFP_KERNEL); 17 if (!(*dml_ctx)) 18 return false; 19 20 (*dml_ctx)->v21.dml_init.dml2_instance = (struct dml2_instance *)kzalloc(sizeof(struct dml2_instance), GFP_KERNEL); 21 if (!((*dml_ctx)->v21.dml_init.dml2_instance)) 22 return false; 23 24 (*dml_ctx)->v21.mode_support.dml2_instance = (*dml_ctx)->v21.dml_init.dml2_instance; 25 (*dml_ctx)->v21.mode_programming.dml2_instance = (*dml_ctx)->v21.dml_init.dml2_instance; 26 27 (*dml_ctx)->v21.mode_support.display_config = &(*dml_ctx)->v21.display_config; 28 (*dml_ctx)->v21.mode_programming.display_config = (*dml_ctx)->v21.mode_support.display_config; 29 30 (*dml_ctx)->v21.mode_programming.programming = (struct dml2_display_cfg_programming *)kzalloc(sizeof(struct dml2_display_cfg_programming), GFP_KERNEL); 31 if (!((*dml_ctx)->v21.mode_programming.programming)) 32 return false; 33 34 return true; 35 } 36 37 static void dml21_apply_debug_options(const struct dc *in_dc, struct dml2_context *dml_ctx, const struct dml2_configuration_options *config) 38 { 39 bool disable_fams2; 40 struct dml2_pmo_options *pmo_options = &dml_ctx->v21.dml_init.options.pmo_options; 41 42 /* ODM options */ 43 pmo_options->disable_dyn_odm = !config->minimize_dispclk_using_odm; 44 pmo_options->disable_dyn_odm_for_multi_stream = true; 45 pmo_options->disable_dyn_odm_for_stream_with_svp = true; 46 47 /* UCLK P-State options */ 48 if (in_dc->debug.dml21_force_pstate_method) { 49 dml_ctx->config.pmo.force_pstate_method_enable = true; 50 dml_ctx->config.pmo.force_pstate_method_value = in_dc->debug.dml21_force_pstate_method_value; 51 } else { 52 dml_ctx->config.pmo.force_pstate_method_enable = false; 53 } 54 55 pmo_options->disable_vblank = ((in_dc->debug.dml21_disable_pstate_method_mask >> 1) & 1); 56 57 /* NOTE: DRR and SubVP Require FAMS2 */ 58 disable_fams2 = !in_dc->debug.fams2_config.bits.enable; 59 pmo_options->disable_svp = ((in_dc->debug.dml21_disable_pstate_method_mask >> 2) & 1) || 60 in_dc->debug.force_disable_subvp || 61 disable_fams2; 62 pmo_options->disable_drr_clamped = ((in_dc->debug.dml21_disable_pstate_method_mask >> 3) & 1) || 63 disable_fams2; 64 pmo_options->disable_drr_var = ((in_dc->debug.dml21_disable_pstate_method_mask >> 4) & 1) || 65 disable_fams2; 66 pmo_options->disable_fams2 = disable_fams2; 67 68 pmo_options->disable_drr_var_when_var_active = in_dc->debug.disable_fams_gaming; 69 } 70 71 static void dml21_init(const struct dc *in_dc, struct dml2_context **dml_ctx, const struct dml2_configuration_options *config) 72 { 73 switch (in_dc->ctx->dce_version) { 74 case DCN_VERSION_4_01: 75 case DCN_VERSION_3_2: // TODO : Temporary for N-1 validation. Remove this after N-1 validation phase is complete. 76 (*dml_ctx)->v21.dml_init.options.project_id = dml2_project_dcn4x_stage2_auto_drr_svp; 77 break; 78 default: 79 (*dml_ctx)->v21.dml_init.options.project_id = dml2_project_invalid; 80 } 81 82 (*dml_ctx)->architecture = dml2_architecture_21; 83 84 /* Store configuration options */ 85 (*dml_ctx)->config = *config; 86 87 /*Initialize SOCBB and DCNIP params */ 88 dml21_initialize_soc_bb_params(&(*dml_ctx)->v21.dml_init, config, in_dc); 89 dml21_initialize_ip_params(&(*dml_ctx)->v21.dml_init, config, in_dc); 90 dml21_apply_soc_bb_overrides(&(*dml_ctx)->v21.dml_init, config, in_dc); 91 92 /* apply debug overrides */ 93 dml21_apply_debug_options(in_dc, *dml_ctx, config); 94 95 /*Initialize DML21 instance */ 96 dml2_initialize_instance(&(*dml_ctx)->v21.dml_init); 97 } 98 99 bool dml21_create(const struct dc *in_dc, struct dml2_context **dml_ctx, const struct dml2_configuration_options *config) 100 { 101 /* Allocate memory for initializing DML21 instance */ 102 if (!dml21_allocate_memory(dml_ctx)) 103 return false; 104 105 dml21_init(in_dc, dml_ctx, config); 106 107 return true; 108 } 109 110 void dml21_destroy(struct dml2_context *dml2) 111 { 112 kfree(dml2->v21.dml_init.dml2_instance); 113 kfree(dml2->v21.mode_programming.programming); 114 } 115 116 static void dml21_calculate_rq_and_dlg_params(const struct dc *dc, struct dc_state *context, struct resource_context *out_new_hw_state, 117 struct dml2_context *in_ctx, unsigned int pipe_cnt) 118 { 119 unsigned int dml_prog_idx = 0, dc_pipe_index = 0, num_dpps_required = 0; 120 struct dml2_per_plane_programming *pln_prog = NULL; 121 struct dml2_per_stream_programming *stream_prog = NULL; 122 struct pipe_ctx *dc_main_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__]; 123 struct pipe_ctx *dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__] = {0}; 124 int num_pipes; 125 126 context->bw_ctx.bw.dcn.clk.dppclk_khz = 0; 127 128 /* copy global DCHUBBUB arbiter registers */ 129 memcpy(&context->bw_ctx.bw.dcn.arb_regs, &in_ctx->v21.mode_programming.programming->global_regs.arb_regs, sizeof(struct dml2_display_arb_regs)); 130 131 /* legacy only */ 132 context->bw_ctx.bw.dcn.compbuf_size_kb = (int)in_ctx->v21.mode_programming.programming->global_regs.arb_regs.compbuf_size * 64; 133 134 context->bw_ctx.bw.dcn.mall_ss_size_bytes = 0; 135 context->bw_ctx.bw.dcn.mall_ss_psr_active_size_bytes = 0; 136 context->bw_ctx.bw.dcn.mall_subvp_size_bytes = 0; 137 138 for (dml_prog_idx = 0; dml_prog_idx < DML2_MAX_PLANES; dml_prog_idx++) { 139 pln_prog = &in_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx]; 140 141 if (!pln_prog->plane_descriptor) 142 continue; 143 144 stream_prog = &in_ctx->v21.mode_programming.programming->stream_programming[pln_prog->plane_descriptor->stream_index]; 145 num_dpps_required = pln_prog->num_dpps_required; 146 147 if (num_dpps_required == 0) { 148 continue; 149 } 150 num_pipes = dml21_find_dc_pipes_for_plane(dc, context, in_ctx, dc_main_pipes, dc_phantom_pipes, dml_prog_idx); 151 152 if (num_pipes <= 0) 153 continue; 154 155 /* program each pipe */ 156 for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) { 157 dml21_program_dc_pipe(in_ctx, context, dc_main_pipes[dc_pipe_index], pln_prog, stream_prog); 158 159 if (pln_prog->phantom_plane.valid) { 160 dml21_program_dc_pipe(in_ctx, context, dc_phantom_pipes[dc_pipe_index], pln_prog, stream_prog); 161 } 162 } 163 } 164 165 /* assign global clocks */ 166 context->bw_ctx.bw.dcn.clk.bw_dppclk_khz = context->bw_ctx.bw.dcn.clk.dppclk_khz; 167 context->bw_ctx.bw.dcn.clk.bw_dispclk_khz = context->bw_ctx.bw.dcn.clk.dispclk_khz; 168 if (in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.num_clk_values > 1) { 169 context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = 170 in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.clk_values_khz[in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.num_clk_values] * 1000; 171 } else { 172 context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dispclk.clk_values_khz[0] * 1000; 173 } 174 175 if (in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.num_clk_values > 1) { 176 context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = 177 in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.clk_values_khz[in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.num_clk_values] * 1000; 178 } else { 179 context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = in_ctx->v21.dml_init.soc_bb.clk_table.dppclk.clk_values_khz[0] * 1000; 180 } 181 182 /* get global mall allocation */ 183 if (dc->res_pool->funcs->calculate_mall_ways_from_bytes) { 184 context->bw_ctx.bw.dcn.clk.num_ways = dc->res_pool->funcs->calculate_mall_ways_from_bytes(dc, context->bw_ctx.bw.dcn.mall_subvp_size_bytes); 185 } else { 186 context->bw_ctx.bw.dcn.clk.num_ways = 0; 187 } 188 } 189 190 static bool dml21_mode_check_and_programming(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx) 191 { 192 bool result = false; 193 struct dml2_build_mode_programming_in_out *mode_programming = &dml_ctx->v21.mode_programming; 194 195 memset(&dml_ctx->v21.display_config, 0, sizeof(struct dml2_display_cfg)); 196 memset(&dml_ctx->v21.dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping)); 197 memset(&dml_ctx->v21.mode_programming.dml2_instance->scratch.build_mode_programming_locals.mode_programming_params, 0, sizeof(struct dml2_core_mode_programming_in_out)); 198 199 if (!context || context->stream_count == 0) 200 return true; 201 202 /* scrub phantom's from current dc_state */ 203 dml_ctx->config.svp_pstate.callbacks.remove_phantom_streams_and_planes(in_dc, context); 204 dml_ctx->config.svp_pstate.callbacks.release_phantom_streams_and_planes(in_dc, context); 205 206 /* Populate stream, plane mappings and other fields in display config. */ 207 result = dml21_map_dc_state_into_dml_display_cfg(in_dc, context, dml_ctx); 208 if (!result) 209 return false; 210 211 result = dml2_build_mode_programming(mode_programming); 212 if (!result) 213 return false; 214 215 /* Check and map HW resources */ 216 if (result && !dml_ctx->config.skip_hw_state_mapping) { 217 dml21_map_hw_resources(dml_ctx); 218 dml2_map_dc_pipes(dml_ctx, context, NULL, &dml_ctx->v21.dml_to_dc_pipe_mapping, in_dc->current_state); 219 /* if subvp phantoms are present, expand them into dc context */ 220 dml21_handle_phantom_streams_planes(in_dc, context, dml_ctx); 221 } 222 223 /* Copy DML CLK, WM and REG outputs to bandwidth context */ 224 if (result && !dml_ctx->config.skip_hw_state_mapping) { 225 dml21_calculate_rq_and_dlg_params(in_dc, context, &context->res_ctx, dml_ctx, in_dc->res_pool->pipe_count); 226 dml21_copy_clocks_to_dc_state(dml_ctx, context); 227 dml21_extract_watermark_sets(in_dc, &context->bw_ctx.bw.dcn.watermarks, dml_ctx); 228 if (in_dc->ctx->dce_version == DCN_VERSION_3_2) { 229 dml21_extract_legacy_watermark_set(in_dc, &context->bw_ctx.bw.dcn.watermarks.a, DML2_DCHUB_WATERMARK_SET_A, dml_ctx); 230 dml21_extract_legacy_watermark_set(in_dc, &context->bw_ctx.bw.dcn.watermarks.b, DML2_DCHUB_WATERMARK_SET_A, dml_ctx); 231 dml21_extract_legacy_watermark_set(in_dc, &context->bw_ctx.bw.dcn.watermarks.c, DML2_DCHUB_WATERMARK_SET_A, dml_ctx); 232 dml21_extract_legacy_watermark_set(in_dc, &context->bw_ctx.bw.dcn.watermarks.d, DML2_DCHUB_WATERMARK_SET_A, dml_ctx); 233 } 234 235 dml21_build_fams2_programming(in_dc, context, dml_ctx); 236 } 237 238 return true; 239 } 240 241 static bool dml21_check_mode_support(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx) 242 { 243 bool is_supported = false; 244 struct dml2_initialize_instance_in_out *dml_init = &dml_ctx->v21.dml_init; 245 struct dml2_check_mode_supported_in_out *mode_support = &dml_ctx->v21.mode_support; 246 247 memset(&dml_ctx->v21.display_config, 0, sizeof(struct dml2_display_cfg)); 248 memset(&dml_ctx->v21.dml_to_dc_pipe_mapping, 0, sizeof(struct dml2_dml_to_dc_pipe_mapping)); 249 memset(&dml_ctx->v21.mode_programming.dml2_instance->scratch.check_mode_supported_locals.mode_support_params, 0, sizeof(struct dml2_core_mode_support_in_out)); 250 251 if (!context || context->stream_count == 0) 252 return true; 253 254 /* Scrub phantom's from current dc_state */ 255 dml_ctx->config.svp_pstate.callbacks.remove_phantom_streams_and_planes(in_dc, context); 256 dml_ctx->config.svp_pstate.callbacks.release_phantom_streams_and_planes(in_dc, context); 257 258 mode_support->dml2_instance = dml_init->dml2_instance; 259 dml21_map_dc_state_into_dml_display_cfg(in_dc, context, dml_ctx); 260 is_supported = dml2_check_mode_supported(mode_support); 261 if (!is_supported) 262 return false; 263 264 return true; 265 } 266 267 bool dml21_validate(const struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx, bool fast_validate) 268 { 269 bool out = false; 270 271 /* Use dml_validate_only for fast_validate path */ 272 if (fast_validate) { 273 out = dml21_check_mode_support(in_dc, context, dml_ctx); 274 } else 275 out = dml21_mode_check_and_programming(in_dc, context, dml_ctx); 276 return out; 277 } 278 279 void dml21_prepare_mcache_programming(struct dc *in_dc, struct dc_state *context, struct dml2_context *dml_ctx) 280 { 281 unsigned int num_pipes, dml_prog_idx, dml_phantom_prog_idx, dc_pipe_index; 282 struct pipe_ctx *dc_main_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__]; 283 struct pipe_ctx *dc_phantom_pipes[__DML2_WRAPPER_MAX_STREAMS_PLANES__] = {0}; 284 285 struct dml2_per_plane_programming *pln_prog = NULL; 286 struct dml2_plane_mcache_configuration_descriptor *mcache_config = NULL; 287 struct prepare_mcache_programming_locals *l = &dml_ctx->v21.scratch.prepare_mcache_locals; 288 289 if (context->stream_count == 0) { 290 return; 291 } 292 293 memset(&l->build_mcache_programming_params, 0, sizeof(struct dml2_build_mcache_programming_in_out)); 294 l->build_mcache_programming_params.dml2_instance = dml_ctx->v21.dml_init.dml2_instance; 295 296 /* phantom's start after main planes */ 297 dml_phantom_prog_idx = dml_ctx->v21.mode_programming.programming->display_config.num_planes; 298 299 /* Build mcache programming parameters per plane per pipe */ 300 for (dml_prog_idx = 0; dml_prog_idx < dml_ctx->v21.mode_programming.programming->display_config.num_planes; dml_prog_idx++) { 301 pln_prog = &dml_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx]; 302 303 mcache_config = &l->build_mcache_programming_params.mcache_configurations[dml_prog_idx]; 304 memset(mcache_config, 0, sizeof(struct dml2_plane_mcache_configuration_descriptor)); 305 mcache_config->plane_descriptor = pln_prog->plane_descriptor; 306 mcache_config->mcache_allocation = &context->bw_ctx.bw.dcn.mcache_allocations[dml_prog_idx]; 307 mcache_config->num_pipes = pln_prog->num_dpps_required; 308 l->build_mcache_programming_params.num_configurations++; 309 310 if (pln_prog->num_dpps_required == 0) { 311 continue; 312 } 313 314 num_pipes = dml21_find_dc_pipes_for_plane(in_dc, context, dml_ctx, dc_main_pipes, dc_phantom_pipes, dml_prog_idx); 315 316 if (num_pipes <= 0 || 317 dc_main_pipes[0]->stream == NULL || 318 dc_main_pipes[0]->plane_state == NULL) 319 continue; 320 321 /* get config for each pipe */ 322 for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) { 323 ASSERT(dc_main_pipes[dc_pipe_index]); 324 dml21_get_pipe_mcache_config(context, dc_main_pipes[dc_pipe_index], pln_prog, &mcache_config->pipe_configurations[dc_pipe_index]); 325 } 326 327 /* get config for each phantom pipe */ 328 if (pln_prog->phantom_plane.valid) { 329 mcache_config = &l->build_mcache_programming_params.mcache_configurations[dml_phantom_prog_idx]; 330 memset(mcache_config, 0, sizeof(struct dml2_plane_mcache_configuration_descriptor)); 331 mcache_config->plane_descriptor = pln_prog->plane_descriptor; 332 mcache_config->mcache_allocation = &context->bw_ctx.bw.dcn.mcache_allocations[dml_phantom_prog_idx]; 333 mcache_config->num_pipes = pln_prog->num_dpps_required; 334 l->build_mcache_programming_params.num_configurations++; 335 336 for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) { 337 ASSERT(dc_phantom_pipes[dc_pipe_index]); 338 dml21_get_pipe_mcache_config(context, dc_phantom_pipes[dc_pipe_index], pln_prog, &mcache_config->pipe_configurations[dc_pipe_index]); 339 } 340 341 /* increment phantom index */ 342 dml_phantom_prog_idx++; 343 } 344 } 345 346 /* Call to generate mcache programming per plane per pipe for the given display configuration */ 347 dml2_build_mcache_programming(&l->build_mcache_programming_params); 348 349 /* get per plane per pipe mcache programming */ 350 for (dml_prog_idx = 0; dml_prog_idx < dml_ctx->v21.mode_programming.programming->display_config.num_planes; dml_prog_idx++) { 351 pln_prog = &dml_ctx->v21.mode_programming.programming->plane_programming[dml_prog_idx]; 352 353 num_pipes = dml21_find_dc_pipes_for_plane(in_dc, context, dml_ctx, dc_main_pipes, dc_phantom_pipes, dml_prog_idx); 354 355 if (num_pipes <= 0 || 356 dc_main_pipes[0]->stream == NULL || 357 dc_main_pipes[0]->plane_state == NULL) 358 continue; 359 360 /* get config for each pipe */ 361 for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) { 362 ASSERT(dc_main_pipes[dc_pipe_index]); 363 if (l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_prog_idx][dc_pipe_index]) { 364 memcpy(&dc_main_pipes[dc_pipe_index]->mcache_regs, 365 l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_prog_idx][dc_pipe_index], 366 sizeof(struct dml2_hubp_pipe_mcache_regs)); 367 } 368 } 369 370 /* get config for each phantom pipe */ 371 if (pln_prog->phantom_plane.valid) { 372 for (dc_pipe_index = 0; dc_pipe_index < num_pipes; dc_pipe_index++) { 373 ASSERT(dc_phantom_pipes[dc_pipe_index]); 374 if (l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_phantom_prog_idx][dc_pipe_index]) { 375 memcpy(&dc_phantom_pipes[dc_pipe_index]->mcache_regs, 376 l->build_mcache_programming_params.per_plane_pipe_mcache_regs[dml_phantom_prog_idx][dc_pipe_index], 377 sizeof(struct dml2_hubp_pipe_mcache_regs)); 378 } 379 } 380 /* increment phantom index */ 381 dml_phantom_prog_idx++; 382 } 383 } 384 } 385 386 void dml21_copy(struct dml2_context *dst_dml_ctx, 387 struct dml2_context *src_dml_ctx) 388 { 389 /* Preserve references to internals */ 390 struct dml2_instance *dst_dml2_instance = dst_dml_ctx->v21.dml_init.dml2_instance; 391 struct dml2_display_cfg_programming *dst_dml2_programming = dst_dml_ctx->v21.mode_programming.programming; 392 393 /* Copy context */ 394 memcpy(dst_dml_ctx, src_dml_ctx, sizeof(struct dml2_context)); 395 396 /* Copy Internals */ 397 memcpy(dst_dml2_instance, src_dml_ctx->v21.dml_init.dml2_instance, sizeof(struct dml2_instance)); 398 memcpy(dst_dml2_programming, src_dml_ctx->v21.mode_programming.programming, sizeof(struct dml2_display_cfg_programming)); 399 400 /* Restore references to internals */ 401 dst_dml_ctx->v21.dml_init.dml2_instance = dst_dml2_instance; 402 403 dst_dml_ctx->v21.mode_support.dml2_instance = dst_dml2_instance; 404 dst_dml_ctx->v21.mode_programming.dml2_instance = dst_dml2_instance; 405 406 dst_dml_ctx->v21.mode_support.display_config = &dst_dml_ctx->v21.display_config; 407 dst_dml_ctx->v21.mode_programming.display_config = dst_dml_ctx->v21.mode_support.display_config; 408 409 dst_dml_ctx->v21.mode_programming.programming = dst_dml2_programming; 410 411 /* need to initialize copied instance for internal references to be correct */ 412 dml2_initialize_instance(&dst_dml_ctx->v21.dml_init); 413 } 414 415 bool dml21_create_copy(struct dml2_context **dst_dml_ctx, 416 struct dml2_context *src_dml_ctx) 417 { 418 /* Allocate memory for initializing DML21 instance */ 419 if (!dml21_allocate_memory(dst_dml_ctx)) 420 return false; 421 422 dml21_copy(*dst_dml_ctx, src_dml_ctx); 423 424 return true; 425 } 426 427 void dml21_reinit(const struct dc *in_dc, struct dml2_context **dml_ctx, const struct dml2_configuration_options *config) 428 { 429 dml21_init(in_dc, dml_ctx, config); 430 } 431 432