Commit df60dcf5 authored by Ilya Bakoulin's avatar Ilya Bakoulin Committed by Alex Deucher
Browse files

drm/amd/display: Add 3DLUT FL HW bug workaround



[Why]
There is a known HW bug that causes the internal 3DLUT fetch signal to
be lost at VREADY, regardless of whether the OTG lock is being held or
not. A workaround is necessary to make sure that this internal signal
stays up after OTG unlock.

[How]
Set the 3DLUT_ENABLE bit immediately before and after the unlock. Also
use VUPDATE_KEEPOUT to prevent lock transition in the region between
VSTARTUP and VREADY, which could cause issues with this WA sequence.

Also including misc. 3DLUT DMA-related sequence fixes to address a few
regressions causing corruption.

Reviewed-by: default avatarDillon Varone <dillon.varone@amd.com>
Signed-off-by: default avatarIlya Bakoulin <Ilya.Bakoulin@amd.com>
Signed-off-by: default avatarRoman Li <roman.li@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent f79f4dd6
Loading
Loading
Loading
Loading
+22 −8
Original line number Diff line number Diff line
@@ -2650,7 +2650,8 @@ static enum surface_update_type det_surface_update(const struct dc *dc,
		elevate_update_type(&overall_type, type);
	}

	if (update_flags->bits.lut_3d) {
	if (update_flags->bits.lut_3d &&
			u->surface->mcm_luts.lut3d_data.lut3d_src != DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM) {
		type = UPDATE_TYPE_FULL;
		elevate_update_type(&overall_type, type);
	}
@@ -2926,10 +2927,20 @@ static void copy_surface_update_to_plane(
			sizeof(struct dc_transfer_func_distributed_points));
	}

	if (srf_update->func_shaper)
	if (srf_update->cm2_params) {
		surface->mcm_shaper_3dlut_setting = srf_update->cm2_params->component_settings.shaper_3dlut_setting;
		surface->mcm_lut1d_enable = srf_update->cm2_params->component_settings.lut1d_enable;
		surface->mcm_luts = srf_update->cm2_params->cm2_luts;
	}

	if (srf_update->func_shaper) {
		memcpy(&surface->in_shaper_func, srf_update->func_shaper,
		sizeof(surface->in_shaper_func));

		if (surface->mcm_shaper_3dlut_setting >= DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER)
			surface->mcm_luts.shaper = &surface->in_shaper_func;
	}

	if (srf_update->lut3d_func)
		memcpy(&surface->lut3d_func, srf_update->lut3d_func,
		sizeof(surface->lut3d_func));
@@ -2942,10 +2953,17 @@ static void copy_surface_update_to_plane(
		surface->sdr_white_level_nits =
				srf_update->sdr_white_level_nits;

	if (srf_update->blend_tf)
	if (srf_update->blend_tf) {
		memcpy(&surface->blend_tf, srf_update->blend_tf,
		sizeof(surface->blend_tf));

		if (surface->mcm_lut1d_enable)
			surface->mcm_luts.lut1d_func = &surface->blend_tf;
	}

	if (srf_update->cm2_params || srf_update->blend_tf)
		surface->lut_bank_a = !surface->lut_bank_a;

	if (srf_update->input_csc_color_matrix)
		surface->input_csc_color_matrix =
			*srf_update->input_csc_color_matrix;
@@ -2957,11 +2975,7 @@ static void copy_surface_update_to_plane(
	if (srf_update->gamut_remap_matrix)
		surface->gamut_remap_matrix =
			*srf_update->gamut_remap_matrix;
	if (srf_update->cm2_params) {
		surface->mcm_shaper_3dlut_setting = srf_update->cm2_params->component_settings.shaper_3dlut_setting;
		surface->mcm_lut1d_enable = srf_update->cm2_params->component_settings.lut1d_enable;
		surface->mcm_luts = srf_update->cm2_params->cm2_luts;
	}

	if (srf_update->cursor_csc_color_matrix)
		surface->cursor_csc_color_matrix =
			*srf_update->cursor_csc_color_matrix;
+6 −2
Original line number Diff line number Diff line
@@ -1458,10 +1458,14 @@ void dcn20_pipe_control_lock(
	} else {
		if (lock)
			pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg);
		else {
			if (dc->hwseq->funcs.perform_3dlut_wa_unlock)
				dc->hwseq->funcs.perform_3dlut_wa_unlock(pipe);
			else
				pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg);
		}
	}
}

static void dcn20_detect_pipe_changes(struct dc_state *old_state,
		struct dc_state *new_state,
+57 −3
Original line number Diff line number Diff line
@@ -506,7 +506,7 @@ void dcn401_populate_mcm_luts(struct dc *dc,
	dcn401_get_mcm_lut_xable_from_pipe_ctx(dc, pipe_ctx, &shaper_xable, &lut3d_xable, &lut1d_xable);

	/* 1D LUT */
	if (mcm_luts.lut1d_func && lut3d_xable != MCM_LUT_DISABLE) {
	if (mcm_luts.lut1d_func) {
		memset(&m_lut_params, 0, sizeof(m_lut_params));
		if (mcm_luts.lut1d_func->type == TF_TYPE_HWPWL)
			m_lut_params.pwl = &mcm_luts.lut1d_func->pwl;
@@ -521,7 +521,7 @@ void dcn401_populate_mcm_luts(struct dc *dc,
				mpc->funcs->populate_lut(mpc, MCM_LUT_1DLUT, m_lut_params, lut_bank_a, mpcc_id);
		}
		if (mpc->funcs->program_lut_mode)
			mpc->funcs->program_lut_mode(mpc, MCM_LUT_1DLUT, lut1d_xable, lut_bank_a, mpcc_id);
			mpc->funcs->program_lut_mode(mpc, MCM_LUT_1DLUT, lut1d_xable && m_lut_params.pwl, lut_bank_a, mpcc_id);
	}

	/* Shaper */
@@ -669,11 +669,17 @@ bool dcn401_set_mcm_luts(struct pipe_ctx *pipe_ctx,
{
	struct dpp *dpp_base = pipe_ctx->plane_res.dpp;
	int mpcc_id = pipe_ctx->plane_res.hubp->inst;
	struct mpc *mpc = pipe_ctx->stream_res.opp->ctx->dc->res_pool->mpc;
	struct dc *dc = pipe_ctx->stream_res.opp->ctx->dc;
	struct mpc *mpc = dc->res_pool->mpc;
	bool result;
	const struct pwl_params *lut_params = NULL;
	bool rval;

	if (plane_state->mcm_luts.lut3d_data.lut3d_src == DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM) {
		dcn401_populate_mcm_luts(dc, pipe_ctx, plane_state->mcm_luts, plane_state->lut_bank_a);
		return true;
	}

	mpc->funcs->set_movable_cm_location(mpc, MPCC_MOVABLE_CM_LOCATION_BEFORE, mpcc_id);
	pipe_ctx->plane_state->mcm_location = MPCC_MOVABLE_CM_LOCATION_BEFORE;
	// 1D LUT
@@ -1814,6 +1820,54 @@ void dcn401_interdependent_update_lock(struct dc *dc,
	}
}

void dcn401_perform_3dlut_wa_unlock(struct pipe_ctx *pipe_ctx)
{
	/* If 3DLUT FL is enabled and 3DLUT is in use, follow the workaround sequence for pipe unlock to make sure that
	 * HUBP will properly fetch 3DLUT contents after unlock.
	 *
	 * This is meant to work around a known HW issue where VREADY will cancel the pending 3DLUT_ENABLE signal regardless
	 * of whether OTG lock is currently being held or not.
	 */
	struct pipe_ctx *wa_pipes[MAX_PIPES] = { NULL };
	struct pipe_ctx *odm_pipe, *mpc_pipe;
	int i, wa_pipe_ct = 0;

	for (odm_pipe = pipe_ctx; odm_pipe != NULL; odm_pipe = odm_pipe->next_odm_pipe) {
		for (mpc_pipe = odm_pipe; mpc_pipe != NULL; mpc_pipe = mpc_pipe->bottom_pipe) {
			if (mpc_pipe->plane_state && mpc_pipe->plane_state->mcm_luts.lut3d_data.lut3d_src
						== DC_CM2_TRANSFER_FUNC_SOURCE_VIDMEM
					&& mpc_pipe->plane_state->mcm_shaper_3dlut_setting
						== DC_CM2_SHAPER_3DLUT_SETTING_ENABLE_SHAPER_3DLUT) {
				wa_pipes[wa_pipe_ct++] = mpc_pipe;
			}
		}
	}

	if (wa_pipe_ct > 0) {
		if (pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout)
			pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout(pipe_ctx->stream_res.tg, true);

		for (i = 0; i < wa_pipe_ct; ++i) {
			if (wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl)
				wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl(wa_pipes[i]->plane_res.hubp, true);
		}

		pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg);
		if (pipe_ctx->stream_res.tg->funcs->wait_update_lock_status)
			pipe_ctx->stream_res.tg->funcs->wait_update_lock_status(pipe_ctx->stream_res.tg, false);

		for (i = 0; i < wa_pipe_ct; ++i) {
			if (wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl)
				wa_pipes[i]->plane_res.hubp->funcs->hubp_enable_3dlut_fl(wa_pipes[i]->plane_res.hubp, true);
		}

		if (pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout)
			pipe_ctx->stream_res.tg->funcs->set_vupdate_keepout(pipe_ctx->stream_res.tg, false);
	} else {
		pipe_ctx->stream_res.tg->funcs->unlock(pipe_ctx->stream_res.tg);
	}
}

void dcn401_program_outstanding_updates(struct dc *dc,
		struct dc_state *context)
{
+2 −0
Original line number Diff line number Diff line
@@ -95,4 +95,6 @@ void dcn401_reset_back_end_for_pipe(
void dcn401_reset_hw_ctx_wrap(
		struct dc *dc,
		struct dc_state *context);
void dcn401_perform_3dlut_wa_unlock(struct pipe_ctx *pipe_ctx);

#endif /* __DC_HWSS_DCN401_H__ */
+1 −0
Original line number Diff line number Diff line
@@ -138,6 +138,7 @@ static const struct hwseq_private_funcs dcn401_private_funcs = {
	.apply_single_controller_ctx_to_hw = dce110_apply_single_controller_ctx_to_hw,
	.reset_back_end_for_pipe = dcn401_reset_back_end_for_pipe,
	.populate_mcm_luts = NULL,
	.perform_3dlut_wa_unlock = dcn401_perform_3dlut_wa_unlock,
};

void dcn401_hw_sequencer_init_functions(struct dc *dc)
Loading