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 28 #include "dml2_dc_types.h" 29 #include "dml2_internal_types.h" 30 #include "dml2_utils.h" 31 #include "dml2_mall_phantom.h" 32 33 unsigned int dml2_helper_calculate_num_ways_for_subvp(struct dml2_context *ctx, struct dc_state *context) 34 { 35 uint32_t num_ways = 0; 36 uint32_t bytes_per_pixel = 0; 37 uint32_t cache_lines_used = 0; 38 uint32_t lines_per_way = 0; 39 uint32_t total_cache_lines = 0; 40 uint32_t bytes_in_mall = 0; 41 uint32_t num_mblks = 0; 42 uint32_t cache_lines_per_plane = 0; 43 uint32_t i = 0; 44 uint32_t mblk_width = 0; 45 uint32_t mblk_height = 0; 46 uint32_t full_vp_width_blk_aligned = 0; 47 uint32_t mall_alloc_width_blk_aligned = 0; 48 uint32_t mall_alloc_height_blk_aligned = 0; 49 50 for (i = 0; i < ctx->config.dcn_pipe_count; i++) { 51 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 52 53 // Find the phantom pipes 54 if (pipe->stream && pipe->plane_state && !pipe->top_pipe && !pipe->prev_odm_pipe && 55 ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe) == SUBVP_PHANTOM) { 56 bytes_per_pixel = pipe->plane_state->format >= SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616 ? 8 : 4; 57 mblk_width = ctx->config.mall_cfg.mblk_width_pixels; 58 mblk_height = bytes_per_pixel == 4 ? mblk_width = ctx->config.mall_cfg.mblk_height_4bpe_pixels : ctx->config.mall_cfg.mblk_height_8bpe_pixels; 59 60 /* full_vp_width_blk_aligned = FLOOR(vp_x_start + full_vp_width + blk_width - 1, blk_width) - 61 * FLOOR(vp_x_start, blk_width) 62 */ 63 full_vp_width_blk_aligned = ((pipe->plane_res.scl_data.viewport.x + 64 pipe->plane_res.scl_data.viewport.width + mblk_width - 1) / mblk_width * mblk_width) + 65 (pipe->plane_res.scl_data.viewport.x / mblk_width * mblk_width); 66 67 /* mall_alloc_width_blk_aligned_l/c = full_vp_width_blk_aligned_l/c */ 68 mall_alloc_width_blk_aligned = full_vp_width_blk_aligned; 69 70 /* mall_alloc_height_blk_aligned_l/c = CEILING(sub_vp_height_l/c - 1, blk_height_l/c) + blk_height_l/c */ 71 mall_alloc_height_blk_aligned = (pipe->stream->timing.v_addressable - 1 + mblk_height - 1) / 72 mblk_height * mblk_height + mblk_height; 73 74 /* full_mblk_width_ub_l/c = malldml2_mall_phantom.c_alloc_width_blk_aligned_l/c; 75 * full_mblk_height_ub_l/c = mall_alloc_height_blk_aligned_l/c; 76 * num_mblk_l/c = (full_mblk_width_ub_l/c / mblk_width_l/c) * (full_mblk_height_ub_l/c / mblk_height_l/c); 77 * (Should be divisible, but round up if not) 78 */ 79 num_mblks = ((mall_alloc_width_blk_aligned + mblk_width - 1) / mblk_width) * 80 ((mall_alloc_height_blk_aligned + mblk_height - 1) / mblk_height); 81 bytes_in_mall = num_mblks * ctx->config.mall_cfg.mblk_size_bytes; 82 // cache lines used is total bytes / cache_line size. Add +2 for worst case alignment 83 // (MALL is 64-byte aligned) 84 cache_lines_per_plane = bytes_in_mall / ctx->config.mall_cfg.cache_line_size_bytes + 2; 85 86 // For DCC we must cache the meat surface, so double cache lines required 87 if (pipe->plane_state->dcc.enable) 88 cache_lines_per_plane *= 2; 89 cache_lines_used += cache_lines_per_plane; 90 } 91 } 92 93 total_cache_lines = ctx->config.mall_cfg.max_cab_allocation_bytes / ctx->config.mall_cfg.cache_line_size_bytes; 94 lines_per_way = total_cache_lines / ctx->config.mall_cfg.cache_num_ways; 95 num_ways = cache_lines_used / lines_per_way; 96 if (cache_lines_used % lines_per_way > 0) 97 num_ways++; 98 99 return num_ways; 100 } 101 102 static void merge_pipes_for_subvp(struct dml2_context *ctx, struct dc_state *context) 103 { 104 int i; 105 106 /* merge pipes if necessary */ 107 for (i = 0; i < ctx->config.dcn_pipe_count; i++) { 108 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 109 110 // For now merge all pipes for SubVP since pipe split case isn't supported yet 111 112 /* if ODM merge we ignore mpc tree, mpo pipes will have their own flags */ 113 if (pipe->prev_odm_pipe) { 114 /*split off odm pipe*/ 115 pipe->prev_odm_pipe->next_odm_pipe = pipe->next_odm_pipe; 116 if (pipe->next_odm_pipe) 117 pipe->next_odm_pipe->prev_odm_pipe = pipe->prev_odm_pipe; 118 119 pipe->bottom_pipe = NULL; 120 pipe->next_odm_pipe = NULL; 121 pipe->plane_state = NULL; 122 pipe->stream = NULL; 123 pipe->top_pipe = NULL; 124 pipe->prev_odm_pipe = NULL; 125 if (pipe->stream_res.dsc) 126 ctx->config.svp_pstate.callbacks.release_dsc(&context->res_ctx, ctx->config.svp_pstate.callbacks.dc->res_pool, &pipe->stream_res.dsc); 127 memset(&pipe->plane_res, 0, sizeof(pipe->plane_res)); 128 memset(&pipe->stream_res, 0, sizeof(pipe->stream_res)); 129 } else if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) { 130 struct pipe_ctx *top_pipe = pipe->top_pipe; 131 struct pipe_ctx *bottom_pipe = pipe->bottom_pipe; 132 133 top_pipe->bottom_pipe = bottom_pipe; 134 if (bottom_pipe) 135 bottom_pipe->top_pipe = top_pipe; 136 137 pipe->top_pipe = NULL; 138 pipe->bottom_pipe = NULL; 139 pipe->plane_state = NULL; 140 pipe->stream = NULL; 141 memset(&pipe->plane_res, 0, sizeof(pipe->plane_res)); 142 memset(&pipe->stream_res, 0, sizeof(pipe->stream_res)); 143 } 144 } 145 } 146 147 static bool all_pipes_have_stream_and_plane(struct dml2_context *ctx, const struct dc_state *context) 148 { 149 int i; 150 151 for (i = 0; i < ctx->config.dcn_pipe_count; i++) { 152 const struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 153 154 if (!pipe->stream) 155 continue; 156 157 if (!pipe->plane_state) 158 return false; 159 } 160 return true; 161 } 162 163 static bool mpo_in_use(const struct dc_state *context) 164 { 165 int i; 166 167 for (i = 0; i < context->stream_count; i++) { 168 if (context->stream_status[i].plane_count > 1) 169 return true; 170 } 171 return false; 172 } 173 174 /* 175 * dcn32_get_num_free_pipes: Calculate number of free pipes 176 * 177 * This function assumes that a "used" pipe is a pipe that has 178 * both a stream and a plane assigned to it. 179 * 180 * @dc: current dc state 181 * @context: new dc state 182 * 183 * Return: 184 * Number of free pipes available in the context 185 */ 186 static unsigned int get_num_free_pipes(struct dml2_context *ctx, struct dc_state *state) 187 { 188 unsigned int i; 189 unsigned int free_pipes = 0; 190 unsigned int num_pipes = 0; 191 192 for (i = 0; i < ctx->config.dcn_pipe_count; i++) { 193 struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i]; 194 195 if (pipe->stream && !pipe->top_pipe) { 196 while (pipe) { 197 num_pipes++; 198 pipe = pipe->bottom_pipe; 199 } 200 } 201 } 202 203 free_pipes = ctx->config.dcn_pipe_count - num_pipes; 204 return free_pipes; 205 } 206 207 /* 208 * dcn32_assign_subvp_pipe: Function to decide which pipe will use Sub-VP. 209 * 210 * We enter this function if we are Sub-VP capable (i.e. enough pipes available) 211 * and regular P-State switching (i.e. VACTIVE/VBLANK) is not supported, or if 212 * we are forcing SubVP P-State switching on the current config. 213 * 214 * The number of pipes used for the chosen surface must be less than or equal to the 215 * number of free pipes available. 216 * 217 * In general we choose surfaces with the longest frame time first (better for SubVP + VBLANK). 218 * For multi-display cases the ActiveDRAMClockChangeMargin doesn't provide enough info on its own 219 * for determining which should be the SubVP pipe (need a way to determine if a pipe / plane doesn't 220 * support MCLK switching naturally [i.e. ACTIVE or VBLANK]). 221 * 222 * @param dc: current dc state 223 * @param context: new dc state 224 * @param index: [out] dc pipe index for the pipe chosen to have phantom pipes assigned 225 * 226 * Return: 227 * True if a valid pipe assignment was found for Sub-VP. Otherwise false. 228 */ 229 static bool assign_subvp_pipe(struct dml2_context *ctx, struct dc_state *context, unsigned int *index) 230 { 231 unsigned int i, pipe_idx; 232 unsigned int max_frame_time = 0; 233 bool valid_assignment_found = false; 234 unsigned int free_pipes = 2; //dcn32_get_num_free_pipes(dc, context); 235 bool current_assignment_freesync = false; 236 struct vba_vars_st *vba = &context->bw_ctx.dml.vba; 237 238 for (i = 0, pipe_idx = 0; i < ctx->config.dcn_pipe_count; i++) { 239 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 240 unsigned int num_pipes = 0; 241 unsigned int refresh_rate = 0; 242 243 if (!pipe->stream) 244 continue; 245 246 // Round up 247 refresh_rate = (pipe->stream->timing.pix_clk_100hz * 100 + 248 pipe->stream->timing.v_total * pipe->stream->timing.h_total - 1) 249 / (double)(pipe->stream->timing.v_total * pipe->stream->timing.h_total); 250 /* SubVP pipe candidate requirements: 251 * - Refresh rate < 120hz 252 * - Not able to switch in vactive naturally (switching in active means the 253 * DET provides enough buffer to hide the P-State switch latency -- trying 254 * to combine this with SubVP can cause issues with the scheduling). 255 */ 256 if (pipe->plane_state && !pipe->top_pipe && 257 ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe) == SUBVP_NONE && refresh_rate < 120 && 258 vba->ActiveDRAMClockChangeLatencyMarginPerState[vba->VoltageLevel][vba->maxMpcComb][vba->pipe_plane[pipe_idx]] <= 0) { 259 while (pipe) { 260 num_pipes++; 261 pipe = pipe->bottom_pipe; 262 } 263 264 pipe = &context->res_ctx.pipe_ctx[i]; 265 if (num_pipes <= free_pipes) { 266 struct dc_stream_state *stream = pipe->stream; 267 unsigned int frame_us = (stream->timing.v_total * stream->timing.h_total / 268 (double)(stream->timing.pix_clk_100hz * 100)) * 1000000; 269 if (frame_us > max_frame_time && !stream->ignore_msa_timing_param) { 270 *index = i; 271 max_frame_time = frame_us; 272 valid_assignment_found = true; 273 current_assignment_freesync = false; 274 /* For the 2-Freesync display case, still choose the one with the 275 * longest frame time 276 */ 277 } else if (stream->ignore_msa_timing_param && (!valid_assignment_found || 278 (current_assignment_freesync && frame_us > max_frame_time))) { 279 *index = i; 280 valid_assignment_found = true; 281 current_assignment_freesync = true; 282 } 283 } 284 } 285 pipe_idx++; 286 } 287 return valid_assignment_found; 288 } 289 290 /* 291 * enough_pipes_for_subvp: Function to check if there are "enough" pipes for SubVP. 292 * 293 * This function returns true if there are enough free pipes 294 * to create the required phantom pipes for any given stream 295 * (that does not already have phantom pipe assigned). 296 * 297 * e.g. For a 2 stream config where the first stream uses one 298 * pipe and the second stream uses 2 pipes (i.e. pipe split), 299 * this function will return true because there is 1 remaining 300 * pipe which can be used as the phantom pipe for the non pipe 301 * split pipe. 302 * 303 * @dc: current dc state 304 * @context: new dc state 305 * 306 * Return: 307 * True if there are enough free pipes to assign phantom pipes to at least one 308 * stream that does not already have phantom pipes assigned. Otherwise false. 309 */ 310 static bool enough_pipes_for_subvp(struct dml2_context *ctx, struct dc_state *state) 311 { 312 unsigned int i, split_cnt, free_pipes; 313 unsigned int min_pipe_split = ctx->config.dcn_pipe_count + 1; // init as max number of pipes + 1 314 bool subvp_possible = false; 315 316 for (i = 0; i < ctx->config.dcn_pipe_count; i++) { 317 struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i]; 318 319 // Find the minimum pipe split count for non SubVP pipes 320 if (pipe->stream && !pipe->top_pipe && 321 ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(state, pipe) == SUBVP_NONE) { 322 split_cnt = 0; 323 while (pipe) { 324 split_cnt++; 325 pipe = pipe->bottom_pipe; 326 } 327 328 if (split_cnt < min_pipe_split) 329 min_pipe_split = split_cnt; 330 } 331 } 332 333 free_pipes = get_num_free_pipes(ctx, state); 334 335 // SubVP only possible if at least one pipe is being used (i.e. free_pipes 336 // should not equal to the pipe_count) 337 if (free_pipes >= min_pipe_split && free_pipes < ctx->config.dcn_pipe_count) 338 subvp_possible = true; 339 340 return subvp_possible; 341 } 342 343 /* 344 * subvp_subvp_schedulable: Determine if SubVP + SubVP config is schedulable 345 * 346 * High level algorithm: 347 * 1. Find longest microschedule length (in us) between the two SubVP pipes 348 * 2. Check if the worst case overlap (VBLANK in middle of ACTIVE) for both 349 * pipes still allows for the maximum microschedule to fit in the active 350 * region for both pipes. 351 * 352 * @dc: current dc state 353 * @context: new dc state 354 * 355 * Return: 356 * bool - True if the SubVP + SubVP config is schedulable, false otherwise 357 */ 358 static bool subvp_subvp_schedulable(struct dml2_context *ctx, struct dc_state *context) 359 { 360 struct pipe_ctx *subvp_pipes[2]; 361 struct dc_stream_state *phantom = NULL; 362 uint32_t microschedule_lines = 0; 363 uint32_t index = 0; 364 uint32_t i; 365 uint32_t max_microschedule_us = 0; 366 int32_t vactive1_us, vactive2_us, vblank1_us, vblank2_us; 367 368 for (i = 0; i < ctx->config.dcn_pipe_count; i++) { 369 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 370 uint32_t time_us = 0; 371 372 /* Loop to calculate the maximum microschedule time between the two SubVP pipes, 373 * and also to store the two main SubVP pipe pointers in subvp_pipes[2]. 374 */ 375 if (pipe->stream && pipe->plane_state && !pipe->top_pipe && 376 ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe) == SUBVP_MAIN) { 377 phantom = ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(context, pipe->stream); 378 microschedule_lines = (phantom->timing.v_total - phantom->timing.v_front_porch) + 379 phantom->timing.v_addressable; 380 381 // Round up when calculating microschedule time (+ 1 at the end) 382 time_us = (microschedule_lines * phantom->timing.h_total) / 383 (double)(phantom->timing.pix_clk_100hz * 100) * 1000000 + 384 ctx->config.svp_pstate.subvp_prefetch_end_to_mall_start_us + 385 ctx->config.svp_pstate.subvp_fw_processing_delay_us + 1; 386 if (time_us > max_microschedule_us) 387 max_microschedule_us = time_us; 388 389 subvp_pipes[index] = pipe; 390 index++; 391 392 // Maximum 2 SubVP pipes 393 if (index == 2) 394 break; 395 } 396 } 397 vactive1_us = ((subvp_pipes[0]->stream->timing.v_addressable * subvp_pipes[0]->stream->timing.h_total) / 398 (double)(subvp_pipes[0]->stream->timing.pix_clk_100hz * 100)) * 1000000; 399 vactive2_us = ((subvp_pipes[1]->stream->timing.v_addressable * subvp_pipes[1]->stream->timing.h_total) / 400 (double)(subvp_pipes[1]->stream->timing.pix_clk_100hz * 100)) * 1000000; 401 vblank1_us = (((subvp_pipes[0]->stream->timing.v_total - subvp_pipes[0]->stream->timing.v_addressable) * 402 subvp_pipes[0]->stream->timing.h_total) / 403 (double)(subvp_pipes[0]->stream->timing.pix_clk_100hz * 100)) * 1000000; 404 vblank2_us = (((subvp_pipes[1]->stream->timing.v_total - subvp_pipes[1]->stream->timing.v_addressable) * 405 subvp_pipes[1]->stream->timing.h_total) / 406 (double)(subvp_pipes[1]->stream->timing.pix_clk_100hz * 100)) * 1000000; 407 408 if ((vactive1_us - vblank2_us) / 2 > max_microschedule_us && 409 (vactive2_us - vblank1_us) / 2 > max_microschedule_us) 410 return true; 411 412 return false; 413 } 414 415 /* 416 * dml2_svp_drr_schedulable: Determine if SubVP + DRR config is schedulable 417 * 418 * High level algorithm: 419 * 1. Get timing for SubVP pipe, phantom pipe, and DRR pipe 420 * 2. Determine the frame time for the DRR display when adding required margin for MCLK switching 421 * (the margin is equal to the MALL region + DRR margin (500us)) 422 * 3.If (SubVP Active - Prefetch > Stretched DRR frame + max(MALL region, Stretched DRR frame)) 423 * then report the configuration as supported 424 * 425 * @dc: current dc state 426 * @context: new dc state 427 * @drr_pipe: DRR pipe_ctx for the SubVP + DRR config 428 * 429 * Return: 430 * bool - True if the SubVP + DRR config is schedulable, false otherwise 431 */ 432 bool dml2_svp_drr_schedulable(struct dml2_context *ctx, struct dc_state *context, struct dc_crtc_timing *drr_timing) 433 { 434 bool schedulable = false; 435 uint32_t i; 436 struct pipe_ctx *pipe = NULL; 437 struct dc_crtc_timing *main_timing = NULL; 438 struct dc_crtc_timing *phantom_timing = NULL; 439 struct dc_stream_state *phantom_stream; 440 int16_t prefetch_us = 0; 441 int16_t mall_region_us = 0; 442 int16_t drr_frame_us = 0; // nominal frame time 443 int16_t subvp_active_us = 0; 444 int16_t stretched_drr_us = 0; 445 int16_t drr_stretched_vblank_us = 0; 446 int16_t max_vblank_mallregion = 0; 447 448 // Find SubVP pipe 449 for (i = 0; i < ctx->config.dcn_pipe_count; i++) { 450 pipe = &context->res_ctx.pipe_ctx[i]; 451 452 // We check for master pipe, but it shouldn't matter since we only need 453 // the pipe for timing info (stream should be same for any pipe splits) 454 if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe) 455 continue; 456 457 // Find the SubVP pipe 458 if (ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe) == SUBVP_MAIN) 459 break; 460 } 461 462 phantom_stream = ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(context, pipe->stream); 463 main_timing = &pipe->stream->timing; 464 phantom_timing = &phantom_stream->timing; 465 prefetch_us = (phantom_timing->v_total - phantom_timing->v_front_porch) * phantom_timing->h_total / 466 (double)(phantom_timing->pix_clk_100hz * 100) * 1000000 + 467 ctx->config.svp_pstate.subvp_prefetch_end_to_mall_start_us; 468 subvp_active_us = main_timing->v_addressable * main_timing->h_total / 469 (double)(main_timing->pix_clk_100hz * 100) * 1000000; 470 drr_frame_us = drr_timing->v_total * drr_timing->h_total / 471 (double)(drr_timing->pix_clk_100hz * 100) * 1000000; 472 // P-State allow width and FW delays already included phantom_timing->v_addressable 473 mall_region_us = phantom_timing->v_addressable * phantom_timing->h_total / 474 (double)(phantom_timing->pix_clk_100hz * 100) * 1000000; 475 stretched_drr_us = drr_frame_us + mall_region_us + SUBVP_DRR_MARGIN_US; 476 drr_stretched_vblank_us = (drr_timing->v_total - drr_timing->v_addressable) * drr_timing->h_total / 477 (double)(drr_timing->pix_clk_100hz * 100) * 1000000 + (stretched_drr_us - drr_frame_us); 478 max_vblank_mallregion = drr_stretched_vblank_us > mall_region_us ? drr_stretched_vblank_us : mall_region_us; 479 480 /* We consider SubVP + DRR schedulable if the stretched frame duration of the DRR display (i.e. the 481 * highest refresh rate + margin that can support UCLK P-State switch) passes the static analysis 482 * for VBLANK: (VACTIVE region of the SubVP pipe can fit the MALL prefetch, VBLANK frame time, 483 * and the max of (VBLANK blanking time, MALL region)). 484 */ 485 if (stretched_drr_us < (1 / (double)drr_timing->min_refresh_in_uhz) * 1000000 * 1000000 && 486 subvp_active_us - prefetch_us - stretched_drr_us - max_vblank_mallregion > 0) 487 schedulable = true; 488 489 return schedulable; 490 } 491 492 493 /* 494 * subvp_vblank_schedulable: Determine if SubVP + VBLANK config is schedulable 495 * 496 * High level algorithm: 497 * 1. Get timing for SubVP pipe, phantom pipe, and VBLANK pipe 498 * 2. If (SubVP Active - Prefetch > Vblank Frame Time + max(MALL region, Vblank blanking time)) 499 * then report the configuration as supported 500 * 3. If the VBLANK display is DRR, then take the DRR static schedulability path 501 * 502 * @dc: current dc state 503 * @context: new dc state 504 * 505 * Return: 506 * bool - True if the SubVP + VBLANK/DRR config is schedulable, false otherwise 507 */ 508 static bool subvp_vblank_schedulable(struct dml2_context *ctx, struct dc_state *context) 509 { 510 struct pipe_ctx *pipe = NULL; 511 struct pipe_ctx *subvp_pipe = NULL; 512 bool found = false; 513 bool schedulable = false; 514 uint32_t i = 0; 515 uint8_t vblank_index = 0; 516 uint16_t prefetch_us = 0; 517 uint16_t mall_region_us = 0; 518 uint16_t vblank_frame_us = 0; 519 uint16_t subvp_active_us = 0; 520 uint16_t vblank_blank_us = 0; 521 uint16_t max_vblank_mallregion = 0; 522 struct dc_crtc_timing *main_timing = NULL; 523 struct dc_crtc_timing *phantom_timing = NULL; 524 struct dc_crtc_timing *vblank_timing = NULL; 525 struct dc_stream_state *phantom_stream; 526 enum mall_stream_type pipe_mall_type; 527 528 /* For SubVP + VBLANK/DRR cases, we assume there can only be 529 * a single VBLANK/DRR display. If DML outputs SubVP + VBLANK 530 * is supported, it is either a single VBLANK case or two VBLANK 531 * displays which are synchronized (in which case they have identical 532 * timings). 533 */ 534 for (i = 0; i < ctx->config.dcn_pipe_count; i++) { 535 pipe = &context->res_ctx.pipe_ctx[i]; 536 pipe_mall_type = ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe); 537 538 // We check for master pipe, but it shouldn't matter since we only need 539 // the pipe for timing info (stream should be same for any pipe splits) 540 if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe) 541 continue; 542 543 if (!found && pipe_mall_type == SUBVP_NONE) { 544 // Found pipe which is not SubVP or Phantom (i.e. the VBLANK pipe). 545 vblank_index = i; 546 found = true; 547 } 548 549 if (!subvp_pipe && pipe_mall_type == SUBVP_MAIN) 550 subvp_pipe = pipe; 551 } 552 // Use ignore_msa_timing_param flag to identify as DRR 553 if (found && context->res_ctx.pipe_ctx[vblank_index].stream->ignore_msa_timing_param) { 554 // SUBVP + DRR case 555 schedulable = dml2_svp_drr_schedulable(ctx, context, &context->res_ctx.pipe_ctx[vblank_index].stream->timing); 556 } else if (found) { 557 phantom_stream = ctx->config.svp_pstate.callbacks.get_paired_subvp_stream(context, subvp_pipe->stream); 558 main_timing = &subvp_pipe->stream->timing; 559 phantom_timing = &phantom_stream->timing; 560 vblank_timing = &context->res_ctx.pipe_ctx[vblank_index].stream->timing; 561 // Prefetch time is equal to VACTIVE + BP + VSYNC of the phantom pipe 562 // Also include the prefetch end to mallstart delay time 563 prefetch_us = (phantom_timing->v_total - phantom_timing->v_front_porch) * phantom_timing->h_total / 564 (double)(phantom_timing->pix_clk_100hz * 100) * 1000000 + 565 ctx->config.svp_pstate.subvp_prefetch_end_to_mall_start_us; 566 // P-State allow width and FW delays already included phantom_timing->v_addressable 567 mall_region_us = phantom_timing->v_addressable * phantom_timing->h_total / 568 (double)(phantom_timing->pix_clk_100hz * 100) * 1000000; 569 vblank_frame_us = vblank_timing->v_total * vblank_timing->h_total / 570 (double)(vblank_timing->pix_clk_100hz * 100) * 1000000; 571 vblank_blank_us = (vblank_timing->v_total - vblank_timing->v_addressable) * vblank_timing->h_total / 572 (double)(vblank_timing->pix_clk_100hz * 100) * 1000000; 573 subvp_active_us = main_timing->v_addressable * main_timing->h_total / 574 (double)(main_timing->pix_clk_100hz * 100) * 1000000; 575 max_vblank_mallregion = vblank_blank_us > mall_region_us ? vblank_blank_us : mall_region_us; 576 577 // Schedulable if VACTIVE region of the SubVP pipe can fit the MALL prefetch, VBLANK frame time, 578 // and the max of (VBLANK blanking time, MALL region) 579 // TODO: Possibly add some margin (i.e. the below conditions should be [...] > X instead of [...] > 0) 580 if (subvp_active_us - prefetch_us - vblank_frame_us - max_vblank_mallregion > 0) 581 schedulable = true; 582 } 583 return schedulable; 584 } 585 586 /* 587 * subvp_validate_static_schedulability: Check which SubVP case is calculated and handle 588 * static analysis based on the case. 589 * 590 * Three cases: 591 * 1. SubVP + SubVP 592 * 2. SubVP + VBLANK (DRR checked internally) 593 * 3. SubVP + VACTIVE (currently unsupported) 594 * 595 * @dc: current dc state 596 * @context: new dc state 597 * @vlevel: Voltage level calculated by DML 598 * 599 * Return: 600 * bool - True if statically schedulable, false otherwise 601 */ 602 bool dml2_svp_validate_static_schedulability(struct dml2_context *ctx, struct dc_state *context, enum dml_dram_clock_change_support pstate_change_type) 603 { 604 bool schedulable = true; // true by default for single display case 605 struct vba_vars_st *vba = &context->bw_ctx.dml.vba; 606 uint32_t i, pipe_idx; 607 uint8_t subvp_count = 0; 608 uint8_t vactive_count = 0; 609 610 for (i = 0, pipe_idx = 0; i < ctx->config.dcn_pipe_count; i++) { 611 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; 612 enum mall_stream_type pipe_mall_type = ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(context, pipe); 613 614 if (!pipe->stream) 615 continue; 616 617 if (pipe->plane_state && !pipe->top_pipe && 618 pipe_mall_type == SUBVP_MAIN) 619 subvp_count++; 620 621 // Count how many planes that aren't SubVP/phantom are capable of VACTIVE 622 // switching (SubVP + VACTIVE unsupported). In situations where we force 623 // SubVP for a VACTIVE plane, we don't want to increment the vactive_count. 624 if (vba->ActiveDRAMClockChangeLatencyMargin[vba->pipe_plane[pipe_idx]] > 0 && 625 pipe_mall_type == SUBVP_NONE) { 626 vactive_count++; 627 } 628 pipe_idx++; 629 } 630 631 if (subvp_count == 2) { 632 // Static schedulability check for SubVP + SubVP case 633 schedulable = subvp_subvp_schedulable(ctx, context); 634 } else if (pstate_change_type == dml_dram_clock_change_vblank_w_mall_sub_vp) { 635 // Static schedulability check for SubVP + VBLANK case. Also handle the case where 636 // DML outputs SubVP + VBLANK + VACTIVE (DML will report as SubVP + VBLANK) 637 if (vactive_count > 0) 638 schedulable = false; 639 else 640 schedulable = subvp_vblank_schedulable(ctx, context); 641 } else if (pstate_change_type == dml_dram_clock_change_vactive_w_mall_sub_vp && 642 vactive_count > 0) { 643 // For single display SubVP cases, DML will output dm_dram_clock_change_vactive_w_mall_sub_vp by default. 644 // We tell the difference between SubVP vs. SubVP + VACTIVE by checking the vactive_count. 645 // SubVP + VACTIVE currently unsupported 646 schedulable = false; 647 } 648 return schedulable; 649 } 650 651 static void set_phantom_stream_timing(struct dml2_context *ctx, struct dc_state *state, 652 struct pipe_ctx *ref_pipe, 653 struct dc_stream_state *phantom_stream, 654 unsigned int dc_pipe_idx, 655 unsigned int svp_height, 656 unsigned int svp_vstartup) 657 { 658 unsigned int i; 659 double line_time, fp_and_sync_width_time; 660 struct pipe_ctx *pipe; 661 uint32_t phantom_vactive, phantom_bp, pstate_width_fw_delay_lines; 662 static const double cvt_rb_vblank_max = ((double) 460 / (1000 * 1000)); 663 664 // Find DML pipe index (pipe_idx) using dc_pipe_idx 665 for (i = 0; i < ctx->config.dcn_pipe_count; i++) { 666 pipe = &state->res_ctx.pipe_ctx[i]; 667 668 if (!pipe->stream) 669 continue; 670 671 if (i == dc_pipe_idx) 672 break; 673 } 674 675 // Calculate lines required for pstate allow width and FW processing delays 676 pstate_width_fw_delay_lines = ((double)(ctx->config.svp_pstate.subvp_fw_processing_delay_us + 677 ctx->config.svp_pstate.subvp_pstate_allow_width_us) / 1000000) * 678 (ref_pipe->stream->timing.pix_clk_100hz * 100) / 679 (double)ref_pipe->stream->timing.h_total; 680 681 // DML calculation for MALL region doesn't take into account FW delay 682 // and required pstate allow width for multi-display cases 683 /* Add 16 lines margin to the MALL REGION because SUB_VP_START_LINE must be aligned 684 * to 2 swaths (i.e. 16 lines) 685 */ 686 phantom_vactive = svp_height + pstate_width_fw_delay_lines + ctx->config.svp_pstate.subvp_swath_height_margin_lines; 687 688 phantom_stream->timing.v_front_porch = 1; 689 690 line_time = phantom_stream->timing.h_total / ((double)phantom_stream->timing.pix_clk_100hz * 100); 691 fp_and_sync_width_time = (phantom_stream->timing.v_front_porch + phantom_stream->timing.v_sync_width) * line_time; 692 693 if ((svp_vstartup * line_time) + fp_and_sync_width_time > cvt_rb_vblank_max) { 694 svp_vstartup = (cvt_rb_vblank_max - fp_and_sync_width_time) / line_time; 695 } 696 697 // For backporch of phantom pipe, use vstartup of the main pipe 698 phantom_bp = svp_vstartup; 699 700 phantom_stream->dst.y = 0; 701 phantom_stream->dst.height = phantom_vactive; 702 phantom_stream->src.y = 0; 703 phantom_stream->src.height = phantom_vactive; 704 705 phantom_stream->timing.v_addressable = phantom_vactive; 706 707 phantom_stream->timing.v_total = phantom_stream->timing.v_addressable + 708 phantom_stream->timing.v_front_porch + 709 phantom_stream->timing.v_sync_width + 710 phantom_bp; 711 phantom_stream->timing.flags.DSC = 0; // Don't need DSC for phantom timing 712 } 713 714 static struct dc_stream_state *enable_phantom_stream(struct dml2_context *ctx, struct dc_state *state, unsigned int dc_pipe_idx, unsigned int svp_height, unsigned int vstartup) 715 { 716 struct pipe_ctx *ref_pipe = &state->res_ctx.pipe_ctx[dc_pipe_idx]; 717 struct dc_stream_state *phantom_stream = ctx->config.svp_pstate.callbacks.create_phantom_stream( 718 ctx->config.svp_pstate.callbacks.dc, 719 state, 720 ref_pipe->stream); 721 722 /* stream has limited viewport and small timing */ 723 memcpy(&phantom_stream->timing, &ref_pipe->stream->timing, sizeof(phantom_stream->timing)); 724 memcpy(&phantom_stream->src, &ref_pipe->stream->src, sizeof(phantom_stream->src)); 725 memcpy(&phantom_stream->dst, &ref_pipe->stream->dst, sizeof(phantom_stream->dst)); 726 set_phantom_stream_timing(ctx, state, ref_pipe, phantom_stream, dc_pipe_idx, svp_height, vstartup); 727 728 ctx->config.svp_pstate.callbacks.add_phantom_stream(ctx->config.svp_pstate.callbacks.dc, 729 state, 730 phantom_stream, 731 ref_pipe->stream); 732 return phantom_stream; 733 } 734 735 static void enable_phantom_plane(struct dml2_context *ctx, 736 struct dc_state *state, 737 struct dc_stream_state *phantom_stream, 738 unsigned int dc_pipe_idx) 739 { 740 struct dc_plane_state *phantom_plane = NULL; 741 struct dc_plane_state *prev_phantom_plane = NULL; 742 struct pipe_ctx *curr_pipe = &state->res_ctx.pipe_ctx[dc_pipe_idx]; 743 744 while (curr_pipe) { 745 if (curr_pipe->top_pipe && curr_pipe->top_pipe->plane_state == curr_pipe->plane_state) { 746 phantom_plane = prev_phantom_plane; 747 } else { 748 phantom_plane = ctx->config.svp_pstate.callbacks.create_phantom_plane( 749 ctx->config.svp_pstate.callbacks.dc, 750 state, 751 curr_pipe->plane_state); 752 if (!phantom_plane) 753 return; 754 } 755 756 memcpy(&phantom_plane->address, &curr_pipe->plane_state->address, sizeof(phantom_plane->address)); 757 memcpy(&phantom_plane->scaling_quality, &curr_pipe->plane_state->scaling_quality, 758 sizeof(phantom_plane->scaling_quality)); 759 memcpy(&phantom_plane->src_rect, &curr_pipe->plane_state->src_rect, sizeof(phantom_plane->src_rect)); 760 memcpy(&phantom_plane->dst_rect, &curr_pipe->plane_state->dst_rect, sizeof(phantom_plane->dst_rect)); 761 memcpy(&phantom_plane->clip_rect, &curr_pipe->plane_state->clip_rect, sizeof(phantom_plane->clip_rect)); 762 memcpy(&phantom_plane->plane_size, &curr_pipe->plane_state->plane_size, 763 sizeof(phantom_plane->plane_size)); 764 memcpy(&phantom_plane->tiling_info, &curr_pipe->plane_state->tiling_info, 765 sizeof(phantom_plane->tiling_info)); 766 memcpy(&phantom_plane->dcc, &curr_pipe->plane_state->dcc, sizeof(phantom_plane->dcc)); 767 //phantom_plane->tiling_info.gfx10compatible.compat_level = curr_pipe->plane_state->tiling_info.gfx10compatible.compat_level; 768 phantom_plane->format = curr_pipe->plane_state->format; 769 phantom_plane->rotation = curr_pipe->plane_state->rotation; 770 phantom_plane->visible = curr_pipe->plane_state->visible; 771 772 /* Shadow pipe has small viewport. */ 773 phantom_plane->clip_rect.y = 0; 774 phantom_plane->clip_rect.height = phantom_stream->timing.v_addressable; 775 776 ctx->config.svp_pstate.callbacks.add_phantom_plane(ctx->config.svp_pstate.callbacks.dc, phantom_stream, phantom_plane, state); 777 778 curr_pipe = curr_pipe->bottom_pipe; 779 prev_phantom_plane = phantom_plane; 780 } 781 } 782 783 static void add_phantom_pipes_for_main_pipe(struct dml2_context *ctx, struct dc_state *state, unsigned int main_pipe_idx, unsigned int svp_height, unsigned int vstartup) 784 { 785 struct dc_stream_state *phantom_stream = NULL; 786 unsigned int i; 787 788 // The index of the DC pipe passed into this function is guarenteed to 789 // be a valid candidate for SubVP (i.e. has a plane, stream, doesn't 790 // already have phantom pipe assigned, etc.) by previous checks. 791 phantom_stream = enable_phantom_stream(ctx, state, main_pipe_idx, svp_height, vstartup); 792 enable_phantom_plane(ctx, state, phantom_stream, main_pipe_idx); 793 794 for (i = 0; i < ctx->config.dcn_pipe_count; i++) { 795 struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i]; 796 797 // Build scaling params for phantom pipes which were newly added. 798 // We determine which phantom pipes were added by comparing with 799 // the phantom stream. 800 if (pipe->plane_state && pipe->stream && pipe->stream == phantom_stream && 801 ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(state, pipe) == SUBVP_PHANTOM) { 802 pipe->stream->use_dynamic_meta = false; 803 pipe->plane_state->flip_immediate = false; 804 if (!ctx->config.svp_pstate.callbacks.build_scaling_params(pipe)) { 805 // Log / remove phantom pipes since failed to build scaling params 806 } 807 } 808 } 809 } 810 811 static bool remove_all_phantom_planes_for_stream(struct dml2_context *ctx, struct dc_stream_state *stream, struct dc_state *context) 812 { 813 int i, old_plane_count; 814 struct dc_stream_status *stream_status = NULL; 815 struct dc_plane_state *del_planes[MAX_SURFACES] = { 0 }; 816 817 for (i = 0; i < context->stream_count; i++) 818 if (context->streams[i] == stream) { 819 stream_status = &context->stream_status[i]; 820 break; 821 } 822 823 if (stream_status == NULL) { 824 return false; 825 } 826 827 old_plane_count = stream_status->plane_count; 828 829 for (i = 0; i < old_plane_count; i++) 830 del_planes[i] = stream_status->plane_states[i]; 831 832 for (i = 0; i < old_plane_count; i++) { 833 if (!ctx->config.svp_pstate.callbacks.remove_phantom_plane(ctx->config.svp_pstate.callbacks.dc, stream, del_planes[i], context)) 834 return false; 835 ctx->config.svp_pstate.callbacks.release_phantom_plane(ctx->config.svp_pstate.callbacks.dc, context, del_planes[i]); 836 } 837 838 return true; 839 } 840 841 bool dml2_svp_remove_all_phantom_pipes(struct dml2_context *ctx, struct dc_state *state) 842 { 843 int i; 844 bool removed_pipe = false; 845 struct dc_stream_state *phantom_stream = NULL; 846 847 for (i = 0; i < ctx->config.dcn_pipe_count; i++) { 848 struct pipe_ctx *pipe = &state->res_ctx.pipe_ctx[i]; 849 // build scaling params for phantom pipes 850 if (pipe->plane_state && pipe->stream && ctx->config.svp_pstate.callbacks.get_pipe_subvp_type(state, pipe) == SUBVP_PHANTOM) { 851 phantom_stream = pipe->stream; 852 853 remove_all_phantom_planes_for_stream(ctx, phantom_stream, state); 854 ctx->config.svp_pstate.callbacks.remove_phantom_stream(ctx->config.svp_pstate.callbacks.dc, state, phantom_stream); 855 ctx->config.svp_pstate.callbacks.release_phantom_stream(ctx->config.svp_pstate.callbacks.dc, state, phantom_stream); 856 857 removed_pipe = true; 858 } 859 860 if (pipe->plane_state) { 861 pipe->plane_state->is_phantom = false; 862 } 863 } 864 return removed_pipe; 865 } 866 867 868 /* Conditions for setting up phantom pipes for SubVP: 869 * 1. Not force disable SubVP 870 * 2. Full update (i.e. DC_VALIDATE_MODE_AND_PROGRAMMING) 871 * 3. Enough pipes are available to support SubVP (TODO: Which pipes will use VACTIVE / VBLANK / SUBVP?) 872 * 4. Display configuration passes validation 873 * 5. (Config doesn't support MCLK in VACTIVE/VBLANK || dc->debug.force_subvp_mclk_switch) 874 */ 875 bool dml2_svp_add_phantom_pipe_to_dc_state(struct dml2_context *ctx, struct dc_state *state, struct dml_mode_support_info_st *mode_support_info) 876 { 877 unsigned int dc_pipe_idx, dml_pipe_idx; 878 unsigned int svp_height, vstartup; 879 880 if (ctx->config.svp_pstate.force_disable_subvp) 881 return false; 882 883 if (!all_pipes_have_stream_and_plane(ctx, state)) 884 return false; 885 886 if (mpo_in_use(state)) 887 return false; 888 889 merge_pipes_for_subvp(ctx, state); 890 // to re-initialize viewport after the pipe merge 891 for (int i = 0; i < ctx->config.dcn_pipe_count; i++) { 892 struct pipe_ctx *pipe_ctx = &state->res_ctx.pipe_ctx[i]; 893 894 if (!pipe_ctx->plane_state || !pipe_ctx->stream) 895 continue; 896 897 ctx->config.svp_pstate.callbacks.build_scaling_params(pipe_ctx); 898 } 899 900 if (enough_pipes_for_subvp(ctx, state) && assign_subvp_pipe(ctx, state, &dc_pipe_idx)) { 901 dml_pipe_idx = dml2_helper_find_dml_pipe_idx_by_stream_id(ctx, state->res_ctx.pipe_ctx[dc_pipe_idx].stream->stream_id); 902 svp_height = mode_support_info->SubViewportLinesNeededInMALL[dml_pipe_idx]; 903 vstartup = dml_get_vstartup_calculated(&ctx->v20.dml_core_ctx, dml_pipe_idx); 904 905 add_phantom_pipes_for_main_pipe(ctx, state, dc_pipe_idx, svp_height, vstartup); 906 907 return true; 908 } 909 910 return false; 911 } 912