diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c | 117 |
1 files changed, 108 insertions, 9 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c index 76f8b40b2165..3e44b7998429 100644 --- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c +++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c @@ -700,6 +700,7 @@ enum dc_status dcn20_enable_stream_timing( if (false == pipe_ctx->clock_source->funcs->program_pix_clk( pipe_ctx->clock_source, &pipe_ctx->stream_res.pix_clk_params, + dp_get_link_encoding_format(&pipe_ctx->link_config.dp_link_settings), &pipe_ctx->pll_settings)) { BREAK_TO_DEBUGGER(); return DC_ERROR_UNEXPECTED; @@ -1308,6 +1309,22 @@ static void dcn20_detect_pipe_changes(struct pipe_ctx *old_pipe, struct pipe_ctx } return; } + + /* For SubVP we need to unconditionally enable because any phantom pipes are + * always removed then newly added for every full updates whenever SubVP is in use. + * The remove-add sequence of the phantom pipe always results in the pipe + * being blanked in enable_stream_timing (DPG). + */ + if (new_pipe->stream && new_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) + new_pipe->update_flags.bits.enable = 1; + + /* Phantom pipes are effectively disabled, if the pipe was previously phantom + * we have to enable + */ + if (old_pipe->plane_state && old_pipe->plane_state->is_phantom && + new_pipe->plane_state && !new_pipe->plane_state->is_phantom) + new_pipe->update_flags.bits.enable = 1; + if (old_pipe->plane_state && !new_pipe->plane_state) { new_pipe->update_flags.bits.disable = 1; return; @@ -1742,7 +1759,14 @@ void dcn20_program_front_end_for_ctx( || context->res_ctx.pipe_ctx[i].update_flags.bits.opp_changed) { struct hubbub *hubbub = dc->res_pool->hubbub; - if (hubbub->funcs->program_det_size && context->res_ctx.pipe_ctx[i].update_flags.bits.disable) + /* Phantom pipe DET should be 0, but if a pipe in use is being transitioned to phantom + * then we want to do the programming here (effectively it's being disabled). If we do + * the programming later the DET won't be updated until the OTG for the phantom pipe is + * turned on (i.e. in an MCLK switch) which can come in too late and cause issues with + * DET allocation. + */ + if (hubbub->funcs->program_det_size && (context->res_ctx.pipe_ctx[i].update_flags.bits.disable || + (context->res_ctx.pipe_ctx[i].plane_state && context->res_ctx.pipe_ctx[i].plane_state->is_phantom))) hubbub->funcs->program_det_size(hubbub, dc->current_state->res_ctx.pipe_ctx[i].plane_res.hubp->inst, 0); hws->funcs.plane_atomic_disconnect(dc, &dc->current_state->res_ctx.pipe_ctx[i]); DC_LOG_DC("Reset mpcc for pipe %d\n", dc->current_state->res_ctx.pipe_ctx[i].pipe_idx); @@ -1759,8 +1783,17 @@ void dcn20_program_front_end_for_ctx( while (pipe) { if (hws->funcs.program_pipe) hws->funcs.program_pipe(dc, pipe, context); - else - dcn20_program_pipe(dc, pipe, context); + else { + /* Don't program phantom pipes in the regular front end programming sequence. + * There is an MPO transition case where a pipe being used by a video plane is + * transitioned directly to be a phantom pipe when closing the MPO video. However + * the phantom pipe will program a new HUBP_VTG_SEL (update takes place right away), + * but the MPO still exists until the double buffered update of the main pipe so we + * will get a frame of underflow if the phantom pipe is programmed here. + */ + if (pipe->stream && pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) + dcn20_program_pipe(dc, pipe, context); + } pipe = pipe->bottom_pipe; } @@ -1784,8 +1817,6 @@ void dcn20_program_front_end_for_ctx( pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start(pipe->plane_res.hubp); } } - if (hws->funcs.program_mall_pipe_config) - hws->funcs.program_mall_pipe_config(dc, context); } void dcn20_post_unlock_program_front_end( @@ -1810,7 +1841,9 @@ void dcn20_post_unlock_program_front_end( */ for (i = 0; i < dc->res_pool->pipe_count; i++) { struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; - if (pipe->plane_state && !pipe->top_pipe && pipe->update_flags.bits.enable) { + // Don't check flip pending on phantom pipes + if (pipe->plane_state && !pipe->top_pipe && pipe->update_flags.bits.enable && + pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) { struct hubp *hubp = pipe->plane_res.hubp; int j = 0; @@ -1837,6 +1870,47 @@ void dcn20_post_unlock_program_front_end( dc->hwss.disable_plane(dc, &dc->current_state->res_ctx.pipe_ctx[i]); } } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i]; + + /* If an active, non-phantom pipe is being transitioned into a phantom + * pipe, wait for the double buffer update to complete first before we do + * phantom pipe programming (HUBP_VTG_SEL updates right away so that can + * cause issues). + */ + if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM && + old_pipe->stream && old_pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) { + old_pipe->stream_res.tg->funcs->wait_for_state( + old_pipe->stream_res.tg, + CRTC_STATE_VBLANK); + old_pipe->stream_res.tg->funcs->wait_for_state( + old_pipe->stream_res.tg, + CRTC_STATE_VACTIVE); + } + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + if (pipe->plane_state && !pipe->top_pipe) { + /* Program phantom pipe here to prevent a frame of underflow in the MPO transition + * case (if a pipe being used for a video plane transitions to a phantom pipe, it + * can underflow due to HUBP_VTG_SEL programming if done in the regular front end + * programming sequence). + */ + if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) + dcn20_program_pipe(dc, pipe, context); + } + } + + /* Only program the MALL registers after all the main and phantom pipes + * are done programming. + */ + if (hwseq->funcs.program_mall_pipe_config) + hwseq->funcs.program_mall_pipe_config(dc, context); + /* WA to apply WM setting*/ if (hwseq->wa.DEGVIDCN21) dc->res_pool->hubbub->funcs->apply_DEDCN21_147_wa(dc->res_pool->hubbub); @@ -1864,18 +1938,34 @@ void dcn20_prepare_bandwidth( { struct hubbub *hubbub = dc->res_pool->hubbub; unsigned int compbuf_size_kb = 0; + unsigned int cache_wm_a = context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns; + unsigned int i; dc->clk_mgr->funcs->update_clocks( dc->clk_mgr, context, false); + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + // At optimize don't restore the original watermark value + if (pipe->stream && pipe->stream->mall_stream_config.type != SUBVP_NONE) { + context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 4U * 1000U * 1000U * 1000U; + break; + } + } + /* program dchubbub watermarks */ dc->wm_optimized_required = hubbub->funcs->program_watermarks(hubbub, &context->bw_ctx.bw.dcn.watermarks, dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000, false); + // Restore the real watermark so we can commit the value to DMCUB + // DMCUB uses the "original" watermark value in SubVP MCLK switch + context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = cache_wm_a; + /* decrease compbuf size */ if (hubbub->funcs->program_compbuf_size) { if (context->bw_ctx.dml.ip.min_comp_buffer_size_kbytes) @@ -1894,6 +1984,16 @@ void dcn20_optimize_bandwidth( struct hubbub *hubbub = dc->res_pool->hubbub; int i; + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; + + // At optimize don't need to restore the original watermark value + if (pipe->stream && pipe->stream->mall_stream_config.type != SUBVP_NONE) { + context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 4U * 1000U * 1000U * 1000U; + break; + } + } + /* program dchubbub watermarks */ hubbub->funcs->program_watermarks(hubbub, &context->bw_ctx.bw.dcn.watermarks, @@ -2498,9 +2598,8 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx) tg->funcs->set_early_control(tg, early_control); - if (pipe_ctx->stream_res.stream_enc->funcs->set_input_mode) - pipe_ctx->stream_res.stream_enc->funcs->set_input_mode(pipe_ctx->stream_res.stream_enc, - timing->pixel_encoding == PIXEL_ENCODING_YCBCR420 ? 2 : 1); + if (dc->hwseq->funcs.set_pixels_per_cycle) + dc->hwseq->funcs.set_pixels_per_cycle(pipe_ctx); /* enable audio only within mode set */ if (pipe_ctx->stream_res.audio != NULL) { |