1 // SPDX-License-Identifier: MIT 2 // 3 // Copyright 2024 Advanced Micro Devices, Inc. 4 5 #include "dml2_internal_shared_types.h" 6 #include "dml2_core_shared_types.h" 7 #include "dml2_core_dcn4.h" 8 #include "dml2_core_dcn4_calcs.h" 9 #include "dml2_debug.h" 10 #include "lib_float_math.h" 11 12 static const struct dml2_core_ip_params core_dcn4_ip_caps_base = { 13 // Hardcoded values for DCN3x 14 .vblank_nom_default_us = 668, 15 .remote_iommu_outstanding_translations = 256, 16 .rob_buffer_size_kbytes = 128, 17 .config_return_buffer_size_in_kbytes = 1280, 18 .config_return_buffer_segment_size_in_kbytes = 64, 19 .compressed_buffer_segment_size_in_kbytes = 64, 20 .dpte_buffer_size_in_pte_reqs_luma = 68, 21 .dpte_buffer_size_in_pte_reqs_chroma = 36, 22 .pixel_chunk_size_kbytes = 8, 23 .alpha_pixel_chunk_size_kbytes = 4, 24 .min_pixel_chunk_size_bytes = 1024, 25 .writeback_chunk_size_kbytes = 8, 26 .line_buffer_size_bits = 1171920, 27 .max_line_buffer_lines = 32, 28 .writeback_interface_buffer_size_kbytes = 90, 29 //Number of pipes after DCN Pipe harvesting 30 .max_num_dpp = 4, 31 .max_num_otg = 4, 32 .max_num_wb = 1, 33 .max_dchub_pscl_bw_pix_per_clk = 4, 34 .max_pscl_lb_bw_pix_per_clk = 2, 35 .max_lb_vscl_bw_pix_per_clk = 4, 36 .max_vscl_hscl_bw_pix_per_clk = 4, 37 .max_hscl_ratio = 6, 38 .max_vscl_ratio = 6, 39 .max_hscl_taps = 8, 40 .max_vscl_taps = 8, 41 .dispclk_ramp_margin_percent = 1, 42 .dppclk_delay_subtotal = 47, 43 .dppclk_delay_scl = 50, 44 .dppclk_delay_scl_lb_only = 16, 45 .dppclk_delay_cnvc_formatter = 28, 46 .dppclk_delay_cnvc_cursor = 6, 47 .cursor_buffer_size = 24, 48 .cursor_chunk_size = 2, 49 .dispclk_delay_subtotal = 125, 50 .max_inter_dcn_tile_repeaters = 8, 51 .writeback_max_hscl_ratio = 1, 52 .writeback_max_vscl_ratio = 1, 53 .writeback_min_hscl_ratio = 1, 54 .writeback_min_vscl_ratio = 1, 55 .writeback_max_hscl_taps = 1, 56 .writeback_max_vscl_taps = 1, 57 .writeback_line_buffer_buffer_size = 0, 58 .num_dsc = 4, 59 .maximum_dsc_bits_per_component = 12, 60 .maximum_pixels_per_line_per_dsc_unit = 5760, 61 .dsc422_native_support = true, 62 .dcc_supported = true, 63 .ptoi_supported = false, 64 65 .cursor_64bpp_support = true, 66 .dynamic_metadata_vm_enabled = false, 67 68 .max_num_dp2p0_outputs = 4, 69 .max_num_dp2p0_streams = 4, 70 .imall_supported = 1, 71 .max_flip_time_us = 80, 72 .max_flip_time_lines = 32, 73 .words_per_channel = 16, 74 75 .subvp_fw_processing_delay_us = 15, 76 .subvp_pstate_allow_width_us = 20, 77 .subvp_swath_height_margin_lines = 16, 78 }; 79 patch_ip_caps_with_explicit_ip_params(struct dml2_ip_capabilities * ip_caps,const struct dml2_core_ip_params * ip_params)80 static void patch_ip_caps_with_explicit_ip_params(struct dml2_ip_capabilities *ip_caps, const struct dml2_core_ip_params *ip_params) 81 { 82 ip_caps->pipe_count = ip_params->max_num_dpp; 83 ip_caps->otg_count = ip_params->max_num_otg; 84 ip_caps->num_dsc = ip_params->num_dsc; 85 ip_caps->max_num_dp2p0_streams = ip_params->max_num_dp2p0_streams; 86 ip_caps->max_num_dp2p0_outputs = ip_params->max_num_dp2p0_outputs; 87 ip_caps->max_num_hdmi_frl_outputs = ip_params->max_num_hdmi_frl_outputs; 88 ip_caps->rob_buffer_size_kbytes = ip_params->rob_buffer_size_kbytes; 89 ip_caps->config_return_buffer_size_in_kbytes = ip_params->config_return_buffer_size_in_kbytes; 90 ip_caps->config_return_buffer_segment_size_in_kbytes = ip_params->config_return_buffer_segment_size_in_kbytes; 91 ip_caps->meta_fifo_size_in_kentries = ip_params->meta_fifo_size_in_kentries; 92 ip_caps->compressed_buffer_segment_size_in_kbytes = ip_params->compressed_buffer_segment_size_in_kbytes; 93 ip_caps->max_flip_time_us = ip_params->max_flip_time_us; 94 ip_caps->max_flip_time_lines = ip_params->max_flip_time_lines; 95 ip_caps->hostvm_mode = ip_params->hostvm_mode; 96 97 // FIXME_STAGE2: cleanup after adding all dv override to ip_caps 98 ip_caps->subvp_drr_scheduling_margin_us = 100; 99 ip_caps->subvp_prefetch_end_to_mall_start_us = 15; 100 ip_caps->subvp_fw_processing_delay = 16; 101 102 } 103 patch_ip_params_with_ip_caps(struct dml2_core_ip_params * ip_params,const struct dml2_ip_capabilities * ip_caps)104 static void patch_ip_params_with_ip_caps(struct dml2_core_ip_params *ip_params, const struct dml2_ip_capabilities *ip_caps) 105 { 106 ip_params->max_num_dpp = ip_caps->pipe_count; 107 ip_params->max_num_otg = ip_caps->otg_count; 108 ip_params->num_dsc = ip_caps->num_dsc; 109 ip_params->max_num_dp2p0_streams = ip_caps->max_num_dp2p0_streams; 110 ip_params->max_num_dp2p0_outputs = ip_caps->max_num_dp2p0_outputs; 111 ip_params->max_num_hdmi_frl_outputs = ip_caps->max_num_hdmi_frl_outputs; 112 ip_params->rob_buffer_size_kbytes = ip_caps->rob_buffer_size_kbytes; 113 ip_params->config_return_buffer_size_in_kbytes = ip_caps->config_return_buffer_size_in_kbytes; 114 ip_params->config_return_buffer_segment_size_in_kbytes = ip_caps->config_return_buffer_segment_size_in_kbytes; 115 ip_params->meta_fifo_size_in_kentries = ip_caps->meta_fifo_size_in_kentries; 116 ip_params->compressed_buffer_segment_size_in_kbytes = ip_caps->compressed_buffer_segment_size_in_kbytes; 117 ip_params->max_flip_time_us = ip_caps->max_flip_time_us; 118 ip_params->max_flip_time_lines = ip_caps->max_flip_time_lines; 119 ip_params->hostvm_mode = ip_caps->hostvm_mode; 120 } 121 core_dcn4_initialize(struct dml2_core_initialize_in_out * in_out)122 bool core_dcn4_initialize(struct dml2_core_initialize_in_out *in_out) 123 { 124 struct dml2_core_instance *core = in_out->instance; 125 126 if (!in_out->minimum_clock_table) 127 return false; 128 else 129 core->minimum_clock_table = in_out->minimum_clock_table; 130 131 if (in_out->explicit_ip_bb && in_out->explicit_ip_bb_size > 0) { 132 memcpy(&core->clean_me_up.mode_lib.ip, in_out->explicit_ip_bb, in_out->explicit_ip_bb_size); 133 134 // FIXME_STAGE2: 135 // DV still uses stage1 ip_param_st for each variant, need to patch the ip_caps with ip_param info 136 // Should move DV to use ip_caps but need move more overrides to ip_caps 137 patch_ip_caps_with_explicit_ip_params(in_out->ip_caps, in_out->explicit_ip_bb); 138 core->clean_me_up.mode_lib.ip.subvp_pstate_allow_width_us = core_dcn4_ip_caps_base.subvp_pstate_allow_width_us; 139 core->clean_me_up.mode_lib.ip.subvp_fw_processing_delay_us = core_dcn4_ip_caps_base.subvp_pstate_allow_width_us; 140 core->clean_me_up.mode_lib.ip.subvp_swath_height_margin_lines = core_dcn4_ip_caps_base.subvp_swath_height_margin_lines; 141 } else { 142 memcpy(&core->clean_me_up.mode_lib.ip, &core_dcn4_ip_caps_base, sizeof(struct dml2_core_ip_params)); 143 patch_ip_params_with_ip_caps(&core->clean_me_up.mode_lib.ip, in_out->ip_caps); 144 145 core->clean_me_up.mode_lib.ip.imall_supported = false; 146 } 147 148 memcpy(&core->clean_me_up.mode_lib.soc, in_out->soc_bb, sizeof(struct dml2_soc_bb)); 149 memcpy(&core->clean_me_up.mode_lib.ip_caps, in_out->ip_caps, sizeof(struct dml2_ip_capabilities)); 150 151 return true; 152 } 153 create_phantom_stream_from_main_stream(struct dml2_stream_parameters * phantom,const struct dml2_stream_parameters * main,const struct dml2_implicit_svp_meta * meta)154 static void create_phantom_stream_from_main_stream(struct dml2_stream_parameters *phantom, const struct dml2_stream_parameters *main, 155 const struct dml2_implicit_svp_meta *meta) 156 { 157 memcpy(phantom, main, sizeof(struct dml2_stream_parameters)); 158 159 phantom->timing.v_total = meta->v_total; 160 phantom->timing.v_active = meta->v_active; 161 phantom->timing.v_front_porch = meta->v_front_porch; 162 phantom->timing.vblank_nom = phantom->timing.v_total - phantom->timing.v_active; 163 phantom->timing.drr_config.enabled = false; 164 } 165 create_phantom_plane_from_main_plane(struct dml2_plane_parameters * phantom,const struct dml2_plane_parameters * main,const struct dml2_stream_parameters * phantom_stream,int phantom_stream_index,const struct dml2_stream_parameters * main_stream)166 static void create_phantom_plane_from_main_plane(struct dml2_plane_parameters *phantom, const struct dml2_plane_parameters *main, 167 const struct dml2_stream_parameters *phantom_stream, int phantom_stream_index, const struct dml2_stream_parameters *main_stream) 168 { 169 memcpy(phantom, main, sizeof(struct dml2_plane_parameters)); 170 171 phantom->stream_index = phantom_stream_index; 172 phantom->overrides.refresh_from_mall = dml2_refresh_from_mall_mode_override_force_disable; 173 phantom->overrides.legacy_svp_config = dml2_svp_mode_override_phantom_pipe_no_data_return; 174 phantom->composition.viewport.plane0.height = (long int unsigned) math_min2(math_ceil2( 175 (double)main->composition.scaler_info.plane0.v_ratio * (double)phantom_stream->timing.v_active, 16.0), 176 (double)main->composition.viewport.plane0.height); 177 phantom->composition.viewport.plane1.height = (long int unsigned) math_min2(math_ceil2( 178 (double)main->composition.scaler_info.plane1.v_ratio * (double)phantom_stream->timing.v_active, 16.0), 179 (double)main->composition.viewport.plane1.height); 180 phantom->immediate_flip = false; 181 phantom->dynamic_meta_data.enable = false; 182 phantom->cursor.num_cursors = 0; 183 phantom->cursor.cursor_width = 0; 184 phantom->tdlut.setup_for_tdlut = false; 185 } 186 expand_implict_subvp(const struct display_configuation_with_meta * display_cfg,struct dml2_display_cfg * svp_expanded_display_cfg,struct dml2_core_scratch * scratch)187 static void expand_implict_subvp(const struct display_configuation_with_meta *display_cfg, struct dml2_display_cfg *svp_expanded_display_cfg, 188 struct dml2_core_scratch *scratch) 189 { 190 unsigned int stream_index, plane_index; 191 const struct dml2_plane_parameters *main_plane; 192 const struct dml2_stream_parameters *main_stream; 193 const struct dml2_stream_parameters *phantom_stream; 194 195 memcpy(svp_expanded_display_cfg, &display_cfg->display_config, sizeof(struct dml2_display_cfg)); 196 memset(scratch->main_stream_index_from_svp_stream_index, 0, sizeof(int) * DML2_MAX_PLANES); 197 memset(scratch->svp_stream_index_from_main_stream_index, 0, sizeof(int) * DML2_MAX_PLANES); 198 memset(scratch->main_plane_index_to_phantom_plane_index, 0, sizeof(int) * DML2_MAX_PLANES); 199 200 if (!display_cfg->display_config.overrides.enable_subvp_implicit_pmo) 201 return; 202 203 /* disable unbounded requesting for all planes until stage 3 has been performed */ 204 if (!display_cfg->stage3.performed) { 205 svp_expanded_display_cfg->overrides.hw.force_unbounded_requesting.enable = true; 206 svp_expanded_display_cfg->overrides.hw.force_unbounded_requesting.value = false; 207 } 208 // Create the phantom streams 209 for (stream_index = 0; stream_index < display_cfg->display_config.num_streams; stream_index++) { 210 main_stream = &display_cfg->display_config.stream_descriptors[stream_index]; 211 scratch->main_stream_index_from_svp_stream_index[stream_index] = stream_index; 212 scratch->svp_stream_index_from_main_stream_index[stream_index] = stream_index; 213 214 if (display_cfg->stage3.stream_svp_meta[stream_index].valid) { 215 // Create the phantom stream 216 create_phantom_stream_from_main_stream(&svp_expanded_display_cfg->stream_descriptors[svp_expanded_display_cfg->num_streams], 217 main_stream, &display_cfg->stage3.stream_svp_meta[stream_index]); 218 219 // Associate this phantom stream to the main stream 220 scratch->main_stream_index_from_svp_stream_index[svp_expanded_display_cfg->num_streams] = stream_index; 221 scratch->svp_stream_index_from_main_stream_index[stream_index] = svp_expanded_display_cfg->num_streams; 222 223 // Increment num streams 224 svp_expanded_display_cfg->num_streams++; 225 } 226 } 227 228 // Create the phantom planes 229 for (plane_index = 0; plane_index < display_cfg->display_config.num_planes; plane_index++) { 230 main_plane = &display_cfg->display_config.plane_descriptors[plane_index]; 231 232 if (display_cfg->stage3.stream_svp_meta[main_plane->stream_index].valid) { 233 main_stream = &display_cfg->display_config.stream_descriptors[main_plane->stream_index]; 234 phantom_stream = &svp_expanded_display_cfg->stream_descriptors[scratch->svp_stream_index_from_main_stream_index[main_plane->stream_index]]; 235 create_phantom_plane_from_main_plane(&svp_expanded_display_cfg->plane_descriptors[svp_expanded_display_cfg->num_planes], 236 main_plane, phantom_stream, scratch->svp_stream_index_from_main_stream_index[main_plane->stream_index], main_stream); 237 238 // Associate this phantom plane to the main plane 239 scratch->phantom_plane_index_to_main_plane_index[svp_expanded_display_cfg->num_planes] = plane_index; 240 scratch->main_plane_index_to_phantom_plane_index[plane_index] = svp_expanded_display_cfg->num_planes; 241 242 // Increment num planes 243 svp_expanded_display_cfg->num_planes++; 244 245 // Adjust the main plane settings 246 svp_expanded_display_cfg->plane_descriptors[plane_index].overrides.legacy_svp_config = dml2_svp_mode_override_main_pipe; 247 } 248 } 249 } 250 pack_mode_programming_params_with_implicit_subvp(struct dml2_core_instance * core,const struct display_configuation_with_meta * display_cfg,const struct dml2_display_cfg * svp_expanded_display_cfg,struct dml2_display_cfg_programming * programming,struct dml2_core_scratch * scratch)251 static void pack_mode_programming_params_with_implicit_subvp(struct dml2_core_instance *core, const struct display_configuation_with_meta *display_cfg, 252 const struct dml2_display_cfg *svp_expanded_display_cfg, struct dml2_display_cfg_programming *programming, struct dml2_core_scratch *scratch) 253 { 254 unsigned int stream_index, plane_index, pipe_offset, stream_already_populated_mask, main_plane_index; 255 int total_pipe_regs_copied = 0; 256 int dml_internal_pipe_index = 0; 257 const struct dml2_plane_parameters *main_plane; 258 const struct dml2_plane_parameters *phantom_plane; 259 const struct dml2_stream_parameters *main_stream; 260 const struct dml2_stream_parameters *phantom_stream; 261 262 // Copy the unexpanded display config to output 263 memcpy(&programming->display_config, &display_cfg->display_config, sizeof(struct dml2_display_cfg)); 264 265 // Set the global register values 266 dml2_core_calcs_get_arb_params(&display_cfg->display_config, &core->clean_me_up.mode_lib, &programming->global_regs.arb_regs); 267 // Get watermarks uses display config for ref clock override, so it doesn't matter whether we pass the pre or post expansion 268 // display config 269 dml2_core_calcs_get_watermarks(&display_cfg->display_config, &core->clean_me_up.mode_lib, &programming->global_regs.wm_regs[0]); 270 271 // Check if FAMS2 is required 272 if (display_cfg->stage3.performed && display_cfg->stage3.success) { 273 programming->fams2_required = display_cfg->stage3.fams2_required; 274 275 dml2_core_calcs_get_global_fams2_programming(&core->clean_me_up.mode_lib, display_cfg, &programming->fams2_global_config); 276 } 277 278 // Only loop over all the main streams (the implicit svp streams will be packed as part of the main stream) 279 for (stream_index = 0; stream_index < programming->display_config.num_streams; stream_index++) { 280 main_stream = &svp_expanded_display_cfg->stream_descriptors[stream_index]; 281 phantom_stream = &svp_expanded_display_cfg->stream_descriptors[scratch->svp_stream_index_from_main_stream_index[stream_index]]; 282 283 // Set the descriptor 284 programming->stream_programming[stream_index].stream_descriptor = &programming->display_config.stream_descriptors[stream_index]; 285 286 // Set the odm combine factor 287 programming->stream_programming[stream_index].num_odms_required = display_cfg->mode_support_result.cfg_support_info.stream_support_info[stream_index].odms_used; 288 289 // Check if the stream has implicit SVP enabled 290 if (main_stream != phantom_stream) { 291 // If so, copy the phantom stream descriptor 292 programming->stream_programming[stream_index].phantom_stream.enabled = true; 293 memcpy(&programming->stream_programming[stream_index].phantom_stream.descriptor, phantom_stream, sizeof(struct dml2_stream_parameters)); 294 } else { 295 programming->stream_programming[stream_index].phantom_stream.enabled = false; 296 } 297 298 // Due to the way DML indexes data internally, it's easier to populate the rest of the display 299 // stream programming in the next stage 300 } 301 302 dml_internal_pipe_index = 0; 303 total_pipe_regs_copied = 0; 304 stream_already_populated_mask = 0x0; 305 306 // Loop over all main planes 307 for (plane_index = 0; plane_index < programming->display_config.num_planes; plane_index++) { 308 main_plane = &svp_expanded_display_cfg->plane_descriptors[plane_index]; 309 310 // Set the descriptor 311 programming->plane_programming[plane_index].plane_descriptor = &programming->display_config.plane_descriptors[plane_index]; 312 313 // Set the mpc combine factor 314 programming->plane_programming[plane_index].num_dpps_required = core->clean_me_up.mode_lib.mp.NoOfDPP[plane_index]; 315 316 // Setup the appropriate p-state strategy 317 if (display_cfg->stage3.performed && display_cfg->stage3.success) { 318 switch (display_cfg->stage3.pstate_switch_modes[plane_index]) { 319 case dml2_uclk_pstate_support_method_vactive: 320 case dml2_uclk_pstate_support_method_vblank: 321 case dml2_uclk_pstate_support_method_fw_subvp_phantom: 322 case dml2_uclk_pstate_support_method_fw_drr: 323 case dml2_uclk_pstate_support_method_fw_vactive_drr: 324 case dml2_uclk_pstate_support_method_fw_vblank_drr: 325 case dml2_uclk_pstate_support_method_fw_subvp_phantom_drr: 326 programming->plane_programming[plane_index].uclk_pstate_support_method = display_cfg->stage3.pstate_switch_modes[plane_index]; 327 break; 328 case dml2_uclk_pstate_support_method_reserved_hw: 329 case dml2_uclk_pstate_support_method_reserved_fw: 330 case dml2_uclk_pstate_support_method_reserved_fw_drr_fixed: 331 case dml2_uclk_pstate_support_method_reserved_fw_drr_var: 332 case dml2_uclk_pstate_support_method_not_supported: 333 case dml2_uclk_pstate_support_method_count: 334 default: 335 programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_uclk_pstate_support_method_not_supported; 336 break; 337 } 338 } else { 339 programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_uclk_pstate_support_method_not_supported; 340 } 341 342 dml2_core_calcs_get_mall_allocation(&core->clean_me_up.mode_lib, &programming->plane_programming[plane_index].surface_size_mall_bytes, dml_internal_pipe_index); 343 344 for (pipe_offset = 0; pipe_offset < programming->plane_programming[plane_index].num_dpps_required; pipe_offset++) { 345 // Assign storage for this pipe's register values 346 programming->plane_programming[plane_index].pipe_regs[pipe_offset] = &programming->pipe_regs[total_pipe_regs_copied]; 347 memset(programming->plane_programming[plane_index].pipe_regs[pipe_offset], 0, sizeof(struct dml2_dchub_per_pipe_register_set)); 348 total_pipe_regs_copied++; 349 350 // Populate the main plane regs 351 dml2_core_calcs_get_pipe_regs(svp_expanded_display_cfg, &core->clean_me_up.mode_lib, programming->plane_programming[plane_index].pipe_regs[pipe_offset], dml_internal_pipe_index); 352 353 // Multiple planes can refer to the same stream index, so it's only necessary to populate it once 354 if (!(stream_already_populated_mask & (0x1 << main_plane->stream_index))) { 355 dml2_core_calcs_get_stream_programming(&core->clean_me_up.mode_lib, &programming->stream_programming[main_plane->stream_index], dml_internal_pipe_index); 356 357 programming->stream_programming[main_plane->stream_index].uclk_pstate_method = programming->plane_programming[plane_index].uclk_pstate_support_method; 358 359 /* unconditionally populate fams2 params */ 360 dml2_core_calcs_get_stream_fams2_programming(&core->clean_me_up.mode_lib, 361 display_cfg, 362 &programming->stream_programming[main_plane->stream_index].fams2_params, 363 programming->stream_programming[main_plane->stream_index].uclk_pstate_method, 364 plane_index); 365 366 stream_already_populated_mask |= (0x1 << main_plane->stream_index); 367 } 368 dml_internal_pipe_index++; 369 } 370 } 371 372 for (plane_index = programming->display_config.num_planes; plane_index < svp_expanded_display_cfg->num_planes; plane_index++) { 373 phantom_plane = &svp_expanded_display_cfg->plane_descriptors[plane_index]; 374 main_plane_index = scratch->phantom_plane_index_to_main_plane_index[plane_index]; 375 main_plane = &svp_expanded_display_cfg->plane_descriptors[main_plane_index]; 376 377 programming->plane_programming[main_plane_index].phantom_plane.valid = true; 378 memcpy(&programming->plane_programming[main_plane_index].phantom_plane.descriptor, phantom_plane, sizeof(struct dml2_plane_parameters)); 379 380 dml2_core_calcs_get_mall_allocation(&core->clean_me_up.mode_lib, &programming->plane_programming[main_plane_index].svp_size_mall_bytes, dml_internal_pipe_index); 381 for (pipe_offset = 0; pipe_offset < programming->plane_programming[main_plane_index].num_dpps_required; pipe_offset++) { 382 // Assign storage for this pipe's register values 383 programming->plane_programming[main_plane_index].phantom_plane.pipe_regs[pipe_offset] = &programming->pipe_regs[total_pipe_regs_copied]; 384 memset(programming->plane_programming[main_plane_index].phantom_plane.pipe_regs[pipe_offset], 0, sizeof(struct dml2_dchub_per_pipe_register_set)); 385 total_pipe_regs_copied++; 386 387 // Populate the phantom plane regs 388 dml2_core_calcs_get_pipe_regs(svp_expanded_display_cfg, &core->clean_me_up.mode_lib, programming->plane_programming[main_plane_index].phantom_plane.pipe_regs[pipe_offset], dml_internal_pipe_index); 389 // Populate the phantom stream specific programming 390 if (!(stream_already_populated_mask & (0x1 << phantom_plane->stream_index))) { 391 dml2_core_calcs_get_global_sync_programming(&core->clean_me_up.mode_lib, &programming->stream_programming[main_plane->stream_index].phantom_stream.global_sync, dml_internal_pipe_index); 392 393 stream_already_populated_mask |= (0x1 << phantom_plane->stream_index); 394 } 395 396 dml_internal_pipe_index++; 397 } 398 } 399 } 400 core_dcn4_mode_support(struct dml2_core_mode_support_in_out * in_out)401 bool core_dcn4_mode_support(struct dml2_core_mode_support_in_out *in_out) 402 { 403 struct dml2_core_instance *core = (struct dml2_core_instance *)in_out->instance; 404 struct dml2_core_mode_support_locals *l = &core->scratch.mode_support_locals; 405 406 bool result; 407 unsigned int i, stream_index, stream_bitmask; 408 int unsigned odm_count, num_odm_output_segments, dpp_count; 409 410 expand_implict_subvp(in_out->display_cfg, &l->svp_expanded_display_cfg, &core->scratch); 411 412 l->mode_support_ex_params.mode_lib = &core->clean_me_up.mode_lib; 413 l->mode_support_ex_params.in_display_cfg = &l->svp_expanded_display_cfg; 414 l->mode_support_ex_params.min_clk_table = in_out->min_clk_table; 415 l->mode_support_ex_params.min_clk_index = in_out->min_clk_index; 416 l->mode_support_ex_params.out_evaluation_info = &in_out->mode_support_result.cfg_support_info.clean_me_up.support_info; 417 418 result = dml2_core_calcs_mode_support_ex(&l->mode_support_ex_params); 419 420 in_out->mode_support_result.cfg_support_info.is_supported = result; 421 422 if (result) { 423 in_out->mode_support_result.global.dispclk_khz = (unsigned int)(core->clean_me_up.mode_lib.ms.RequiredDISPCLK * 1000); 424 in_out->mode_support_result.global.dcfclk_deepsleep_khz = (unsigned int)(core->clean_me_up.mode_lib.ms.dcfclk_deepsleep * 1000); 425 in_out->mode_support_result.global.socclk_khz = (unsigned int)(core->clean_me_up.mode_lib.ms.SOCCLK * 1000); 426 427 in_out->mode_support_result.global.fclk_pstate_supported = l->mode_support_ex_params.out_evaluation_info->global_fclk_change_supported; 428 in_out->mode_support_result.global.uclk_pstate_supported = l->mode_support_ex_params.out_evaluation_info->global_dram_clock_change_supported; 429 430 in_out->mode_support_result.global.active.fclk_khz = (unsigned long)(core->clean_me_up.mode_lib.ms.FabricClock * 1000); 431 in_out->mode_support_result.global.active.dcfclk_khz = (unsigned long)(core->clean_me_up.mode_lib.ms.DCFCLK * 1000); 432 433 434 in_out->mode_support_result.global.svp_prefetch.fclk_khz = (unsigned long)core->clean_me_up.mode_lib.ms.FabricClock * 1000; 435 in_out->mode_support_result.global.svp_prefetch.dcfclk_khz = (unsigned long)core->clean_me_up.mode_lib.ms.DCFCLK * 1000; 436 437 in_out->mode_support_result.global.active.average_bw_sdp_kbps = 0; 438 in_out->mode_support_result.global.active.urgent_bw_dram_kbps = 0; 439 in_out->mode_support_result.global.svp_prefetch.average_bw_sdp_kbps = 0; 440 in_out->mode_support_result.global.svp_prefetch.urgent_bw_dram_kbps = 0; 441 442 in_out->mode_support_result.global.active.average_bw_sdp_kbps = (unsigned long)math_ceil2((l->mode_support_ex_params.out_evaluation_info->avg_bandwidth_required[dml2_core_internal_soc_state_sys_active][dml2_core_internal_bw_sdp] * 1000), 1.0); 443 in_out->mode_support_result.global.active.urgent_bw_sdp_kbps = (unsigned long)math_ceil2((l->mode_support_ex_params.out_evaluation_info->urg_bandwidth_required_flip[dml2_core_internal_soc_state_sys_active][dml2_core_internal_bw_sdp] * 1000), 1.0); 444 in_out->mode_support_result.global.svp_prefetch.average_bw_sdp_kbps = (unsigned long)math_ceil2((l->mode_support_ex_params.out_evaluation_info->avg_bandwidth_required[dml2_core_internal_soc_state_svp_prefetch][dml2_core_internal_bw_sdp] * 1000), 1.0); 445 in_out->mode_support_result.global.svp_prefetch.urgent_bw_sdp_kbps = (unsigned long)math_ceil2((l->mode_support_ex_params.out_evaluation_info->urg_bandwidth_required_flip[dml2_core_internal_soc_state_svp_prefetch][dml2_core_internal_bw_sdp] * 1000), 1.0); 446 447 in_out->mode_support_result.global.active.average_bw_dram_kbps = (unsigned long)math_ceil2((l->mode_support_ex_params.out_evaluation_info->avg_bandwidth_required[dml2_core_internal_soc_state_sys_active][dml2_core_internal_bw_dram] * 1000), 1.0); 448 in_out->mode_support_result.global.active.urgent_bw_dram_kbps = (unsigned long)math_ceil2((l->mode_support_ex_params.out_evaluation_info->urg_bandwidth_required_flip[dml2_core_internal_soc_state_sys_active][dml2_core_internal_bw_dram] * 1000), 1.0); 449 in_out->mode_support_result.global.svp_prefetch.average_bw_dram_kbps = (unsigned long)math_ceil2((l->mode_support_ex_params.out_evaluation_info->avg_bandwidth_required[dml2_core_internal_soc_state_svp_prefetch][dml2_core_internal_bw_dram] * 1000), 1.0); 450 in_out->mode_support_result.global.svp_prefetch.urgent_bw_dram_kbps = (unsigned long)math_ceil2((l->mode_support_ex_params.out_evaluation_info->urg_bandwidth_required_flip[dml2_core_internal_soc_state_svp_prefetch][dml2_core_internal_bw_dram] * 1000), 1.0); 451 dml2_printf("DML::%s: in_out->mode_support_result.global.active.urgent_bw_sdp_kbps = %ld\n", __func__, in_out->mode_support_result.global.active.urgent_bw_sdp_kbps); 452 dml2_printf("DML::%s: in_out->mode_support_result.global.svp_prefetch.urgent_bw_sdp_kbps = %ld\n", __func__, in_out->mode_support_result.global.svp_prefetch.urgent_bw_sdp_kbps); 453 dml2_printf("DML::%s: in_out->mode_support_result.global.active.urgent_bw_dram_kbps = %ld\n", __func__, in_out->mode_support_result.global.active.urgent_bw_dram_kbps); 454 dml2_printf("DML::%s: in_out->mode_support_result.global.svp_prefetch.urgent_bw_dram_kbps = %ld\n", __func__, in_out->mode_support_result.global.svp_prefetch.urgent_bw_dram_kbps); 455 456 for (i = 0; i < l->svp_expanded_display_cfg.num_planes; i++) { 457 in_out->mode_support_result.per_plane[i].dppclk_khz = (unsigned int)(core->clean_me_up.mode_lib.ms.RequiredDPPCLK[i] * 1000); 458 } 459 460 stream_bitmask = 0; 461 for (i = 0; i < l->svp_expanded_display_cfg.num_planes; i++) { 462 odm_count = 1; 463 dpp_count = l->mode_support_ex_params.out_evaluation_info->DPPPerSurface[i]; 464 num_odm_output_segments = 1; 465 466 switch (l->mode_support_ex_params.out_evaluation_info->ODMMode[i]) { 467 case dml2_odm_mode_bypass: 468 odm_count = 1; 469 dpp_count = l->mode_support_ex_params.out_evaluation_info->DPPPerSurface[i]; 470 break; 471 case dml2_odm_mode_combine_2to1: 472 odm_count = 2; 473 dpp_count = 2; 474 break; 475 case dml2_odm_mode_combine_3to1: 476 odm_count = 3; 477 dpp_count = 3; 478 break; 479 case dml2_odm_mode_combine_4to1: 480 odm_count = 4; 481 dpp_count = 4; 482 break; 483 case dml2_odm_mode_split_1to2: 484 case dml2_odm_mode_mso_1to2: 485 num_odm_output_segments = 2; 486 break; 487 case dml2_odm_mode_mso_1to4: 488 num_odm_output_segments = 4; 489 break; 490 case dml2_odm_mode_auto: 491 default: 492 odm_count = 1; 493 dpp_count = l->mode_support_ex_params.out_evaluation_info->DPPPerSurface[i]; 494 break; 495 } 496 497 in_out->mode_support_result.cfg_support_info.plane_support_info[i].dpps_used = dpp_count; 498 499 dml2_core_calcs_get_plane_support_info(&l->svp_expanded_display_cfg, &core->clean_me_up.mode_lib, &in_out->mode_support_result.cfg_support_info.plane_support_info[i], i); 500 501 stream_index = l->svp_expanded_display_cfg.plane_descriptors[i].stream_index; 502 503 in_out->mode_support_result.per_stream[stream_index].dscclk_khz = (unsigned int)core->clean_me_up.mode_lib.ms.required_dscclk_freq_mhz[i] * 1000; 504 dml2_printf("CORE_DCN4::%s: i=%d stream_index=%d, in_out->mode_support_result.per_stream[stream_index].dscclk_khz = %u\n", __func__, i, stream_index, in_out->mode_support_result.per_stream[stream_index].dscclk_khz); 505 506 if (!((stream_bitmask >> stream_index) & 0x1)) { 507 in_out->mode_support_result.cfg_support_info.stream_support_info[stream_index].odms_used = odm_count; 508 in_out->mode_support_result.cfg_support_info.stream_support_info[stream_index].num_odm_output_segments = num_odm_output_segments; 509 in_out->mode_support_result.cfg_support_info.stream_support_info[stream_index].dsc_enable = l->mode_support_ex_params.out_evaluation_info->DSCEnabled[i]; 510 in_out->mode_support_result.cfg_support_info.stream_support_info[stream_index].num_dsc_slices = l->mode_support_ex_params.out_evaluation_info->NumberOfDSCSlices[i]; 511 dml2_core_calcs_get_stream_support_info(&l->svp_expanded_display_cfg, &core->clean_me_up.mode_lib, &in_out->mode_support_result.cfg_support_info.stream_support_info[stream_index], i); 512 in_out->mode_support_result.per_stream[stream_index].dtbclk_khz = (unsigned int)(core->clean_me_up.mode_lib.ms.RequiredDTBCLK[i] * 1000); 513 stream_bitmask |= 0x1 << stream_index; 514 } 515 } 516 } 517 518 return result; 519 } 520 lookup_uclk_dpm_index_by_freq(unsigned long uclk_freq_khz,struct dml2_soc_bb * soc_bb)521 static int lookup_uclk_dpm_index_by_freq(unsigned long uclk_freq_khz, struct dml2_soc_bb *soc_bb) 522 { 523 int i; 524 525 for (i = 0; i < soc_bb->clk_table.uclk.num_clk_values; i++) { 526 if (uclk_freq_khz == soc_bb->clk_table.uclk.clk_values_khz[i]) 527 return i; 528 } 529 return 0; 530 } 531 core_dcn4_mode_programming(struct dml2_core_mode_programming_in_out * in_out)532 bool core_dcn4_mode_programming(struct dml2_core_mode_programming_in_out *in_out) 533 { 534 struct dml2_core_instance *core = (struct dml2_core_instance *)in_out->instance; 535 struct dml2_core_mode_programming_locals *l = &core->scratch.mode_programming_locals; 536 537 bool result = false; 538 unsigned int pipe_offset; 539 int dml_internal_pipe_index; 540 int total_pipe_regs_copied = 0; 541 int stream_already_populated_mask = 0; 542 543 int main_stream_index; 544 unsigned int plane_index; 545 546 expand_implict_subvp(in_out->display_cfg, &l->svp_expanded_display_cfg, &core->scratch); 547 548 l->mode_programming_ex_params.mode_lib = &core->clean_me_up.mode_lib; 549 l->mode_programming_ex_params.in_display_cfg = &l->svp_expanded_display_cfg; 550 l->mode_programming_ex_params.min_clk_table = in_out->instance->minimum_clock_table; 551 l->mode_programming_ex_params.cfg_support_info = in_out->cfg_support_info; 552 l->mode_programming_ex_params.programming = in_out->programming; 553 l->mode_programming_ex_params.min_clk_index = lookup_uclk_dpm_index_by_freq(in_out->programming->min_clocks.dcn4x.active.uclk_khz, 554 &core->clean_me_up.mode_lib.soc); 555 556 result = dml2_core_calcs_mode_programming_ex(&l->mode_programming_ex_params); 557 558 if (result) { 559 // If the input display configuration contains implict SVP, we need to use a special packer 560 if (in_out->display_cfg->display_config.overrides.enable_subvp_implicit_pmo) { 561 pack_mode_programming_params_with_implicit_subvp(core, in_out->display_cfg, &l->svp_expanded_display_cfg, in_out->programming, &core->scratch); 562 } else { 563 memcpy(&in_out->programming->display_config, in_out->display_cfg, sizeof(struct dml2_display_cfg)); 564 565 dml2_core_calcs_get_arb_params(&l->svp_expanded_display_cfg, &core->clean_me_up.mode_lib, &in_out->programming->global_regs.arb_regs); 566 dml2_core_calcs_get_watermarks(&l->svp_expanded_display_cfg, &core->clean_me_up.mode_lib, &in_out->programming->global_regs.wm_regs[0]); 567 568 dml_internal_pipe_index = 0; 569 570 for (plane_index = 0; plane_index < in_out->programming->display_config.num_planes; plane_index++) { 571 in_out->programming->plane_programming[plane_index].num_dpps_required = core->clean_me_up.mode_lib.mp.NoOfDPP[plane_index]; 572 573 if (in_out->programming->display_config.plane_descriptors[plane_index].overrides.legacy_svp_config == dml2_svp_mode_override_main_pipe) 574 in_out->programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_uclk_pstate_support_method_fw_subvp_phantom; 575 else if (in_out->programming->display_config.plane_descriptors[plane_index].overrides.legacy_svp_config == dml2_svp_mode_override_phantom_pipe) 576 in_out->programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_uclk_pstate_support_method_fw_subvp_phantom; 577 else if (in_out->programming->display_config.plane_descriptors[plane_index].overrides.legacy_svp_config == dml2_svp_mode_override_phantom_pipe_no_data_return) 578 in_out->programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_uclk_pstate_support_method_fw_subvp_phantom; 579 else { 580 if (core->clean_me_up.mode_lib.mp.MaxActiveDRAMClockChangeLatencySupported[plane_index] >= core->clean_me_up.mode_lib.soc.power_management_parameters.dram_clk_change_blackout_us) 581 in_out->programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_uclk_pstate_support_method_vactive; 582 else if (core->clean_me_up.mode_lib.mp.TWait[plane_index] >= core->clean_me_up.mode_lib.soc.power_management_parameters.dram_clk_change_blackout_us) 583 in_out->programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_uclk_pstate_support_method_vblank; 584 else 585 in_out->programming->plane_programming[plane_index].uclk_pstate_support_method = dml2_uclk_pstate_support_method_not_supported; 586 } 587 588 dml2_core_calcs_get_mall_allocation(&core->clean_me_up.mode_lib, &in_out->programming->plane_programming[plane_index].surface_size_mall_bytes, dml_internal_pipe_index); 589 590 for (pipe_offset = 0; pipe_offset < in_out->programming->plane_programming[plane_index].num_dpps_required; pipe_offset++) { 591 in_out->programming->plane_programming[plane_index].plane_descriptor = &in_out->programming->display_config.plane_descriptors[plane_index]; 592 593 // Assign storage for this pipe's register values 594 in_out->programming->plane_programming[plane_index].pipe_regs[pipe_offset] = &in_out->programming->pipe_regs[total_pipe_regs_copied]; 595 memset(in_out->programming->plane_programming[plane_index].pipe_regs[pipe_offset], 0, sizeof(struct dml2_dchub_per_pipe_register_set)); 596 total_pipe_regs_copied++; 597 598 // Populate 599 dml2_core_calcs_get_pipe_regs(&l->svp_expanded_display_cfg, &core->clean_me_up.mode_lib, in_out->programming->plane_programming[plane_index].pipe_regs[pipe_offset], dml_internal_pipe_index); 600 601 main_stream_index = in_out->programming->display_config.plane_descriptors[plane_index].stream_index; 602 603 // Multiple planes can refer to the same stream index, so it's only necessary to populate it once 604 if (!(stream_already_populated_mask & (0x1 << main_stream_index))) { 605 in_out->programming->stream_programming[main_stream_index].stream_descriptor = &in_out->programming->display_config.stream_descriptors[main_stream_index]; 606 in_out->programming->stream_programming[main_stream_index].num_odms_required = in_out->cfg_support_info->stream_support_info[main_stream_index].odms_used; 607 dml2_core_calcs_get_stream_programming(&core->clean_me_up.mode_lib, &in_out->programming->stream_programming[main_stream_index], dml_internal_pipe_index); 608 609 stream_already_populated_mask |= (0x1 << main_stream_index); 610 } 611 dml_internal_pipe_index++; 612 } 613 } 614 } 615 } 616 617 return result; 618 } 619 core_dcn4_populate_informative(struct dml2_core_populate_informative_in_out * in_out)620 bool core_dcn4_populate_informative(struct dml2_core_populate_informative_in_out *in_out) 621 { 622 struct dml2_core_internal_display_mode_lib *mode_lib = &in_out->instance->clean_me_up.mode_lib; 623 624 if (in_out->mode_is_supported) 625 in_out->programming->informative.voltage_level = in_out->instance->scratch.mode_programming_locals.mode_programming_ex_params.min_clk_index; 626 else 627 in_out->programming->informative.voltage_level = in_out->instance->scratch.mode_support_locals.mode_support_ex_params.min_clk_index; 628 629 dml2_core_calcs_get_informative(mode_lib, in_out->programming); 630 return true; 631 } 632 core_dcn4_calculate_mcache_allocation(struct dml2_calculate_mcache_allocation_in_out * in_out)633 bool core_dcn4_calculate_mcache_allocation(struct dml2_calculate_mcache_allocation_in_out *in_out) 634 { 635 memset(in_out->mcache_allocation, 0, sizeof(struct dml2_mcache_surface_allocation)); 636 637 dml2_core_calcs_get_mcache_allocation(&in_out->instance->clean_me_up.mode_lib, in_out->mcache_allocation, in_out->plane_index); 638 639 if (in_out->mcache_allocation->num_mcaches_plane0 > 0) 640 in_out->mcache_allocation->mcache_x_offsets_plane0[in_out->mcache_allocation->num_mcaches_plane0 - 1] = in_out->plane_descriptor->surface.plane0.width; 641 642 if (in_out->mcache_allocation->num_mcaches_plane1 > 0) 643 in_out->mcache_allocation->mcache_x_offsets_plane1[in_out->mcache_allocation->num_mcaches_plane1 - 1] = in_out->plane_descriptor->surface.plane1.width; 644 645 in_out->mcache_allocation->requires_dedicated_mall_mcache = false; 646 647 return true; 648 } 649