Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amd/display: Update phantom pipe enable / disable sequence

Previously we would call apply_ctx_to_hw to enable and disable
phantom pipes. However, apply_ctx_to_hw can potentially update
non-phantom pipes as well which is undesired. Instead of calling
apply_ctx_to_hw as a whole, call the relevant helpers for each
phantom pipe when enabling / disabling which will avoid us modifying
hardware state for non-phantom pipes unknowingly.

The use case is for an FRL display where FRL_Update is requested
by the display. In this case link_state_valid flag is cleared in
a passive callback thread and should be handled in the next stream /
link update. However, due to the call to apply_ctx_to_hw for the
phantom pipes during a flip, the main pipes were modified outside
of the desired sequence (driver does not handle link_state_valid = 0
on flips).

Cc: stable@vger.kernel.org # 6.6+
Reviewed-by: Samson Tam <samson.tam@amd.com>
Acked-by: Hamza Mahfooz <hamza.mahfooz@amd.com>
Signed-off-by: Alvin Lee <alvin.lee2@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>

authored by

Alvin Lee and committed by
Alex Deucher
6a068e64 0701117e

+93 -12
+3 -1
drivers/gpu/drm/amd/display/dc/core/dc.c
··· 3851 3851 * programming has completed (we turn on phantom OTG in order 3852 3852 * to complete the plane disable for phantom pipes). 3853 3853 */ 3854 - dc->hwss.apply_ctx_to_hw(dc, context); 3854 + 3855 + if (dc->hwss.disable_phantom_streams) 3856 + dc->hwss.disable_phantom_streams(dc, context); 3855 3857 } 3856 3858 3857 3859 if (update_type != UPDATE_TYPE_FAST)
+2 -2
drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c
··· 1529 1529 return DC_OK; 1530 1530 } 1531 1531 1532 - static enum dc_status apply_single_controller_ctx_to_hw( 1532 + enum dc_status dce110_apply_single_controller_ctx_to_hw( 1533 1533 struct pipe_ctx *pipe_ctx, 1534 1534 struct dc_state *context, 1535 1535 struct dc *dc) ··· 2356 2356 if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe) 2357 2357 continue; 2358 2358 2359 - status = apply_single_controller_ctx_to_hw( 2359 + status = dce110_apply_single_controller_ctx_to_hw( 2360 2360 pipe_ctx, 2361 2361 context, 2362 2362 dc);
+4
drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.h
··· 39 39 struct dc *dc, 40 40 struct dc_state *context); 41 41 42 + enum dc_status dce110_apply_single_controller_ctx_to_hw( 43 + struct pipe_ctx *pipe_ctx, 44 + struct dc_state *context, 45 + struct dc *dc); 42 46 43 47 void dce110_enable_stream(struct pipe_ctx *pipe_ctx); 44 48
+1 -1
drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
··· 2671 2671 tg->funcs->setup_vertical_interrupt2(tg, start_line); 2672 2672 } 2673 2673 2674 - static void dcn20_reset_back_end_for_pipe( 2674 + void dcn20_reset_back_end_for_pipe( 2675 2675 struct dc *dc, 2676 2676 struct pipe_ctx *pipe_ctx, 2677 2677 struct dc_state *context)
+4
drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.h
··· 86 86 void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx); 87 87 void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx); 88 88 void dcn20_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx); 89 + void dcn20_reset_back_end_for_pipe( 90 + struct dc *dc, 91 + struct pipe_ctx *pipe_ctx, 92 + struct dc_state *context); 89 93 void dcn20_init_blank( 90 94 struct dc *dc, 91 95 struct timing_generator *tg);
+66 -8
drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
··· 1474 1474 } 1475 1475 } 1476 1476 1477 + void dcn32_disable_phantom_streams(struct dc *dc, struct dc_state *context) 1478 + { 1479 + struct dce_hwseq *hws = dc->hwseq; 1480 + int i; 1481 + 1482 + for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { 1483 + struct pipe_ctx *pipe_ctx_old = 1484 + &dc->current_state->res_ctx.pipe_ctx[i]; 1485 + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1486 + 1487 + if (!pipe_ctx_old->stream) 1488 + continue; 1489 + 1490 + if (dc_state_get_pipe_subvp_type(dc->current_state, pipe_ctx_old) != SUBVP_PHANTOM) 1491 + continue; 1492 + 1493 + if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe) 1494 + continue; 1495 + 1496 + if (!pipe_ctx->stream || pipe_need_reprogram(pipe_ctx_old, pipe_ctx) || 1497 + (pipe_ctx->stream && dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM)) { 1498 + struct clock_source *old_clk = pipe_ctx_old->clock_source; 1499 + 1500 + if (hws->funcs.reset_back_end_for_pipe) 1501 + hws->funcs.reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); 1502 + if (hws->funcs.enable_stream_gating) 1503 + hws->funcs.enable_stream_gating(dc, pipe_ctx_old); 1504 + if (old_clk) 1505 + old_clk->funcs->cs_power_down(old_clk); 1506 + } 1507 + } 1508 + } 1509 + 1477 1510 void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context) 1478 1511 { 1479 1512 unsigned int i; 1513 + enum dc_status status = DC_OK; 1514 + struct dce_hwseq *hws = dc->hwseq; 1480 1515 1481 1516 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1482 1517 struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; ··· 1532 1497 } 1533 1498 } 1534 1499 for (i = 0; i < dc->res_pool->pipe_count; i++) { 1535 - struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i]; 1500 + struct pipe_ctx *pipe_ctx_old = 1501 + &dc->current_state->res_ctx.pipe_ctx[i]; 1502 + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; 1536 1503 1537 - if (new_pipe->stream && dc_state_get_pipe_subvp_type(context, new_pipe) == SUBVP_PHANTOM) { 1538 - // If old context or new context has phantom pipes, apply 1539 - // the phantom timings now. We can't change the phantom 1540 - // pipe configuration safely without driver acquiring 1541 - // the DMCUB lock first. 1542 - dc->hwss.apply_ctx_to_hw(dc, context); 1543 - break; 1504 + if (pipe_ctx->stream == NULL) 1505 + continue; 1506 + 1507 + if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM) 1508 + continue; 1509 + 1510 + if (pipe_ctx->stream == pipe_ctx_old->stream && 1511 + pipe_ctx->stream->link->link_state_valid) { 1512 + continue; 1544 1513 } 1514 + 1515 + if (pipe_ctx_old->stream && !pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) 1516 + continue; 1517 + 1518 + if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe) 1519 + continue; 1520 + 1521 + if (hws->funcs.apply_single_controller_ctx_to_hw) 1522 + status = hws->funcs.apply_single_controller_ctx_to_hw( 1523 + pipe_ctx, 1524 + context, 1525 + dc); 1526 + 1527 + ASSERT(status == DC_OK); 1528 + 1529 + #ifdef CONFIG_DRM_AMD_DC_FP 1530 + if (hws->funcs.resync_fifo_dccg_dio) 1531 + hws->funcs.resync_fifo_dccg_dio(hws, dc, context); 1532 + #endif 1545 1533 } 1546 1534 } 1547 1535
+2
drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.h
··· 111 111 112 112 void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context); 113 113 114 + void dcn32_disable_phantom_streams(struct dc *dc, struct dc_state *context); 115 + 114 116 void dcn32_init_blank( 115 117 struct dc *dc, 116 118 struct timing_generator *tg);
+3
drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_init.c
··· 109 109 .get_dcc_en_bits = dcn10_get_dcc_en_bits, 110 110 .commit_subvp_config = dcn32_commit_subvp_config, 111 111 .enable_phantom_streams = dcn32_enable_phantom_streams, 112 + .disable_phantom_streams = dcn32_disable_phantom_streams, 112 113 .subvp_pipe_control_lock = dcn32_subvp_pipe_control_lock, 113 114 .update_visual_confirm_color = dcn10_update_visual_confirm_color, 114 115 .subvp_pipe_control_lock_fast = dcn32_subvp_pipe_control_lock_fast, ··· 160 159 .set_pixels_per_cycle = dcn32_set_pixels_per_cycle, 161 160 .resync_fifo_dccg_dio = dcn32_resync_fifo_dccg_dio, 162 161 .is_dp_dig_pixel_rate_div_policy = dcn32_is_dp_dig_pixel_rate_div_policy, 162 + .apply_single_controller_ctx_to_hw = dce110_apply_single_controller_ctx_to_hw, 163 + .reset_back_end_for_pipe = dcn20_reset_back_end_for_pipe, 163 164 }; 164 165 165 166 void dcn32_hw_sequencer_init_functions(struct dc *dc)
+1
drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h
··· 381 381 struct dc_cursor_attributes *cursor_attr); 382 382 void (*commit_subvp_config)(struct dc *dc, struct dc_state *context); 383 383 void (*enable_phantom_streams)(struct dc *dc, struct dc_state *context); 384 + void (*disable_phantom_streams)(struct dc *dc, struct dc_state *context); 384 385 void (*subvp_pipe_control_lock)(struct dc *dc, 385 386 struct dc_state *context, 386 387 bool lock,
+7
drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer_private.h
··· 165 165 void (*set_pixels_per_cycle)(struct pipe_ctx *pipe_ctx); 166 166 void (*resync_fifo_dccg_dio)(struct dce_hwseq *hws, struct dc *dc, 167 167 struct dc_state *context); 168 + enum dc_status (*apply_single_controller_ctx_to_hw)( 169 + struct pipe_ctx *pipe_ctx, 170 + struct dc_state *context, 171 + struct dc *dc); 168 172 bool (*is_dp_dig_pixel_rate_div_policy)(struct pipe_ctx *pipe_ctx); 169 173 #endif 174 + void (*reset_back_end_for_pipe)(struct dc *dc, 175 + struct pipe_ctx *pipe_ctx, 176 + struct dc_state *context); 170 177 }; 171 178 172 179 struct dce_hwseq {