mirror of
https://git.proxmox.com/git/mirror_ubuntu-kernels.git
synced 2025-11-29 15:45:51 +00:00
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>
This commit is contained in:
parent
0701117efd
commit
6a068e64fb
@ -3851,7 +3851,9 @@ static void commit_planes_for_stream(struct dc *dc,
|
|||||||
* programming has completed (we turn on phantom OTG in order
|
* programming has completed (we turn on phantom OTG in order
|
||||||
* to complete the plane disable for phantom pipes).
|
* to complete the plane disable for phantom pipes).
|
||||||
*/
|
*/
|
||||||
dc->hwss.apply_ctx_to_hw(dc, context);
|
|
||||||
|
if (dc->hwss.disable_phantom_streams)
|
||||||
|
dc->hwss.disable_phantom_streams(dc, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update_type != UPDATE_TYPE_FAST)
|
if (update_type != UPDATE_TYPE_FAST)
|
||||||
|
|||||||
@ -1529,7 +1529,7 @@ static enum dc_status dce110_enable_stream_timing(
|
|||||||
return DC_OK;
|
return DC_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum dc_status apply_single_controller_ctx_to_hw(
|
enum dc_status dce110_apply_single_controller_ctx_to_hw(
|
||||||
struct pipe_ctx *pipe_ctx,
|
struct pipe_ctx *pipe_ctx,
|
||||||
struct dc_state *context,
|
struct dc_state *context,
|
||||||
struct dc *dc)
|
struct dc *dc)
|
||||||
@ -2356,7 +2356,7 @@ enum dc_status dce110_apply_ctx_to_hw(
|
|||||||
if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe)
|
if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
status = apply_single_controller_ctx_to_hw(
|
status = dce110_apply_single_controller_ctx_to_hw(
|
||||||
pipe_ctx,
|
pipe_ctx,
|
||||||
context,
|
context,
|
||||||
dc);
|
dc);
|
||||||
|
|||||||
@ -39,6 +39,10 @@ enum dc_status dce110_apply_ctx_to_hw(
|
|||||||
struct dc *dc,
|
struct dc *dc,
|
||||||
struct dc_state *context);
|
struct dc_state *context);
|
||||||
|
|
||||||
|
enum dc_status dce110_apply_single_controller_ctx_to_hw(
|
||||||
|
struct pipe_ctx *pipe_ctx,
|
||||||
|
struct dc_state *context,
|
||||||
|
struct dc *dc);
|
||||||
|
|
||||||
void dce110_enable_stream(struct pipe_ctx *pipe_ctx);
|
void dce110_enable_stream(struct pipe_ctx *pipe_ctx);
|
||||||
|
|
||||||
|
|||||||
@ -2671,7 +2671,7 @@ void dcn20_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx)
|
|||||||
tg->funcs->setup_vertical_interrupt2(tg, start_line);
|
tg->funcs->setup_vertical_interrupt2(tg, start_line);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dcn20_reset_back_end_for_pipe(
|
void dcn20_reset_back_end_for_pipe(
|
||||||
struct dc *dc,
|
struct dc *dc,
|
||||||
struct pipe_ctx *pipe_ctx,
|
struct pipe_ctx *pipe_ctx,
|
||||||
struct dc_state *context)
|
struct dc_state *context)
|
||||||
|
|||||||
@ -86,6 +86,10 @@ enum dc_status dcn20_enable_stream_timing(
|
|||||||
void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx);
|
void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx);
|
||||||
void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx);
|
void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx);
|
||||||
void dcn20_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx);
|
void dcn20_setup_vupdate_interrupt(struct dc *dc, struct pipe_ctx *pipe_ctx);
|
||||||
|
void dcn20_reset_back_end_for_pipe(
|
||||||
|
struct dc *dc,
|
||||||
|
struct pipe_ctx *pipe_ctx,
|
||||||
|
struct dc_state *context);
|
||||||
void dcn20_init_blank(
|
void dcn20_init_blank(
|
||||||
struct dc *dc,
|
struct dc *dc,
|
||||||
struct timing_generator *tg);
|
struct timing_generator *tg);
|
||||||
|
|||||||
@ -1474,9 +1474,44 @@ void dcn32_update_dsc_pg(struct dc *dc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dcn32_disable_phantom_streams(struct dc *dc, struct dc_state *context)
|
||||||
|
{
|
||||||
|
struct dce_hwseq *hws = dc->hwseq;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) {
|
||||||
|
struct pipe_ctx *pipe_ctx_old =
|
||||||
|
&dc->current_state->res_ctx.pipe_ctx[i];
|
||||||
|
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
|
||||||
|
|
||||||
|
if (!pipe_ctx_old->stream)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (dc_state_get_pipe_subvp_type(dc->current_state, pipe_ctx_old) != SUBVP_PHANTOM)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!pipe_ctx->stream || pipe_need_reprogram(pipe_ctx_old, pipe_ctx) ||
|
||||||
|
(pipe_ctx->stream && dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM)) {
|
||||||
|
struct clock_source *old_clk = pipe_ctx_old->clock_source;
|
||||||
|
|
||||||
|
if (hws->funcs.reset_back_end_for_pipe)
|
||||||
|
hws->funcs.reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state);
|
||||||
|
if (hws->funcs.enable_stream_gating)
|
||||||
|
hws->funcs.enable_stream_gating(dc, pipe_ctx_old);
|
||||||
|
if (old_clk)
|
||||||
|
old_clk->funcs->cs_power_down(old_clk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context)
|
void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
enum dc_status status = DC_OK;
|
||||||
|
struct dce_hwseq *hws = dc->hwseq;
|
||||||
|
|
||||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||||
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
|
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
|
||||||
@ -1497,16 +1532,39 @@ void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
for (i = 0; i < dc->res_pool->pipe_count; i++) {
|
||||||
struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i];
|
struct pipe_ctx *pipe_ctx_old =
|
||||||
|
&dc->current_state->res_ctx.pipe_ctx[i];
|
||||||
|
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
|
||||||
|
|
||||||
if (new_pipe->stream && dc_state_get_pipe_subvp_type(context, new_pipe) == SUBVP_PHANTOM) {
|
if (pipe_ctx->stream == NULL)
|
||||||
// If old context or new context has phantom pipes, apply
|
continue;
|
||||||
// the phantom timings now. We can't change the phantom
|
|
||||||
// pipe configuration safely without driver acquiring
|
if (dc_state_get_pipe_subvp_type(context, pipe_ctx) != SUBVP_PHANTOM)
|
||||||
// the DMCUB lock first.
|
continue;
|
||||||
dc->hwss.apply_ctx_to_hw(dc, context);
|
|
||||||
break;
|
if (pipe_ctx->stream == pipe_ctx_old->stream &&
|
||||||
|
pipe_ctx->stream->link->link_state_valid) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pipe_ctx_old->stream && !pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (hws->funcs.apply_single_controller_ctx_to_hw)
|
||||||
|
status = hws->funcs.apply_single_controller_ctx_to_hw(
|
||||||
|
pipe_ctx,
|
||||||
|
context,
|
||||||
|
dc);
|
||||||
|
|
||||||
|
ASSERT(status == DC_OK);
|
||||||
|
|
||||||
|
#ifdef CONFIG_DRM_AMD_DC_FP
|
||||||
|
if (hws->funcs.resync_fifo_dccg_dio)
|
||||||
|
hws->funcs.resync_fifo_dccg_dio(hws, dc, context);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -111,6 +111,8 @@ void dcn32_update_dsc_pg(struct dc *dc,
|
|||||||
|
|
||||||
void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context);
|
void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context);
|
||||||
|
|
||||||
|
void dcn32_disable_phantom_streams(struct dc *dc, struct dc_state *context);
|
||||||
|
|
||||||
void dcn32_init_blank(
|
void dcn32_init_blank(
|
||||||
struct dc *dc,
|
struct dc *dc,
|
||||||
struct timing_generator *tg);
|
struct timing_generator *tg);
|
||||||
|
|||||||
@ -109,6 +109,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = {
|
|||||||
.get_dcc_en_bits = dcn10_get_dcc_en_bits,
|
.get_dcc_en_bits = dcn10_get_dcc_en_bits,
|
||||||
.commit_subvp_config = dcn32_commit_subvp_config,
|
.commit_subvp_config = dcn32_commit_subvp_config,
|
||||||
.enable_phantom_streams = dcn32_enable_phantom_streams,
|
.enable_phantom_streams = dcn32_enable_phantom_streams,
|
||||||
|
.disable_phantom_streams = dcn32_disable_phantom_streams,
|
||||||
.subvp_pipe_control_lock = dcn32_subvp_pipe_control_lock,
|
.subvp_pipe_control_lock = dcn32_subvp_pipe_control_lock,
|
||||||
.update_visual_confirm_color = dcn10_update_visual_confirm_color,
|
.update_visual_confirm_color = dcn10_update_visual_confirm_color,
|
||||||
.subvp_pipe_control_lock_fast = dcn32_subvp_pipe_control_lock_fast,
|
.subvp_pipe_control_lock_fast = dcn32_subvp_pipe_control_lock_fast,
|
||||||
@ -159,6 +160,8 @@ static const struct hwseq_private_funcs dcn32_private_funcs = {
|
|||||||
.set_pixels_per_cycle = dcn32_set_pixels_per_cycle,
|
.set_pixels_per_cycle = dcn32_set_pixels_per_cycle,
|
||||||
.resync_fifo_dccg_dio = dcn32_resync_fifo_dccg_dio,
|
.resync_fifo_dccg_dio = dcn32_resync_fifo_dccg_dio,
|
||||||
.is_dp_dig_pixel_rate_div_policy = dcn32_is_dp_dig_pixel_rate_div_policy,
|
.is_dp_dig_pixel_rate_div_policy = dcn32_is_dp_dig_pixel_rate_div_policy,
|
||||||
|
.apply_single_controller_ctx_to_hw = dce110_apply_single_controller_ctx_to_hw,
|
||||||
|
.reset_back_end_for_pipe = dcn20_reset_back_end_for_pipe,
|
||||||
};
|
};
|
||||||
|
|
||||||
void dcn32_hw_sequencer_init_functions(struct dc *dc)
|
void dcn32_hw_sequencer_init_functions(struct dc *dc)
|
||||||
|
|||||||
@ -381,6 +381,7 @@ struct hw_sequencer_funcs {
|
|||||||
struct dc_cursor_attributes *cursor_attr);
|
struct dc_cursor_attributes *cursor_attr);
|
||||||
void (*commit_subvp_config)(struct dc *dc, struct dc_state *context);
|
void (*commit_subvp_config)(struct dc *dc, struct dc_state *context);
|
||||||
void (*enable_phantom_streams)(struct dc *dc, struct dc_state *context);
|
void (*enable_phantom_streams)(struct dc *dc, struct dc_state *context);
|
||||||
|
void (*disable_phantom_streams)(struct dc *dc, struct dc_state *context);
|
||||||
void (*subvp_pipe_control_lock)(struct dc *dc,
|
void (*subvp_pipe_control_lock)(struct dc *dc,
|
||||||
struct dc_state *context,
|
struct dc_state *context,
|
||||||
bool lock,
|
bool lock,
|
||||||
|
|||||||
@ -165,8 +165,15 @@ struct hwseq_private_funcs {
|
|||||||
void (*set_pixels_per_cycle)(struct pipe_ctx *pipe_ctx);
|
void (*set_pixels_per_cycle)(struct pipe_ctx *pipe_ctx);
|
||||||
void (*resync_fifo_dccg_dio)(struct dce_hwseq *hws, struct dc *dc,
|
void (*resync_fifo_dccg_dio)(struct dce_hwseq *hws, struct dc *dc,
|
||||||
struct dc_state *context);
|
struct dc_state *context);
|
||||||
|
enum dc_status (*apply_single_controller_ctx_to_hw)(
|
||||||
|
struct pipe_ctx *pipe_ctx,
|
||||||
|
struct dc_state *context,
|
||||||
|
struct dc *dc);
|
||||||
bool (*is_dp_dig_pixel_rate_div_policy)(struct pipe_ctx *pipe_ctx);
|
bool (*is_dp_dig_pixel_rate_div_policy)(struct pipe_ctx *pipe_ctx);
|
||||||
#endif
|
#endif
|
||||||
|
void (*reset_back_end_for_pipe)(struct dc *dc,
|
||||||
|
struct pipe_ctx *pipe_ctx,
|
||||||
|
struct dc_state *context);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dce_hwseq {
|
struct dce_hwseq {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user