Commit 2d7f3d1a authored by Wenjing Liu's avatar Wenjing Liu Committed by Alex Deucher
Browse files

drm/amd/display: Implement wait_for_odm_update_pending_complete



[WHY]
Odm update is doubled buffered. We need to wait for ODM update to be
completed before optimizing bandwidth or programming new udpates.

[HOW]
implement wait_for_odm_update_pending_complete function to wait for:
1. odm configuration update is no longer pending in timing generator.
2. no pending dpg pattern update for each active OPP.

Cc: Mario Limonciello <mario.limonciello@amd.com>
Cc: Alex Deucher <alexander.deucher@amd.com>
Cc: stable@vger.kernel.org
Reviewed-by: default avatarAlvin Lee <alvin.lee2@amd.com>
Acked-by: default avatarAlex Hung <alex.hung@amd.com>
Signed-off-by: default avatarWenjing Liu <wenjing.liu@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 94040c2c
Loading
Loading
Loading
Loading
+55 −1
Original line number Diff line number Diff line
@@ -1302,6 +1302,54 @@ static void disable_vbios_mode_if_required(
	}
}

/**
 * wait_for_blank_complete - wait for all active OPPs to finish pending blank
 * pattern updates
 *
 * @dc: [in] dc reference
 * @context: [in] hardware context in use
 */
static void wait_for_blank_complete(struct dc *dc,
		struct dc_state *context)
{
	struct pipe_ctx *opp_head;
	struct dce_hwseq *hws = dc->hwseq;
	int i;

	if (!hws->funcs.wait_for_blank_complete)
		return;

	for (i = 0; i < MAX_PIPES; i++) {
		opp_head = &context->res_ctx.pipe_ctx[i];

		if (!resource_is_pipe_type(opp_head, OPP_HEAD) ||
				dc_state_get_pipe_subvp_type(context, opp_head) == SUBVP_PHANTOM)
			continue;

		hws->funcs.wait_for_blank_complete(opp_head->stream_res.opp);
	}
}

static void wait_for_odm_update_pending_complete(struct dc *dc, struct dc_state *context)
{
	struct pipe_ctx *otg_master;
	struct timing_generator *tg;
	int i;

	for (i = 0; i < MAX_PIPES; i++) {
		otg_master = &context->res_ctx.pipe_ctx[i];
		if (!resource_is_pipe_type(otg_master, OTG_MASTER) ||
				dc_state_get_pipe_subvp_type(context, otg_master) == SUBVP_PHANTOM)
			continue;
		tg = otg_master->stream_res.tg;
		if (tg->funcs->wait_odm_doublebuffer_pending_clear)
			tg->funcs->wait_odm_doublebuffer_pending_clear(tg);
	}

	/* ODM update may require to reprogram blank pattern for each OPP */
	wait_for_blank_complete(dc, context);
}

static void wait_for_no_pipes_pending(struct dc *dc, struct dc_state *context)
{
	int i;
@@ -1993,6 +2041,11 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
		context->stream_count == 0) {
		/* Must wait for no flips to be pending before doing optimize bw */
		wait_for_no_pipes_pending(dc, context);
		/*
		 * optimized dispclk depends on ODM setup. Need to wait for ODM
		 * update pending complete before optimizing bandwidth.
		 */
		wait_for_odm_update_pending_complete(dc, context);
		/* pplib is notified if disp_num changed */
		dc->hwss.optimize_bandwidth(dc, context);
		/* Need to do otg sync again as otg could be out of sync due to otg
@@ -3496,7 +3549,7 @@ static void commit_planes_for_stream_fast(struct dc *dc,
		top_pipe_to_program->stream->update_flags.raw = 0;
}

static void wait_for_outstanding_hw_updates(struct dc *dc, const struct dc_state *dc_context)
static void wait_for_outstanding_hw_updates(struct dc *dc, struct dc_state *dc_context)
{
/*
 * This function calls HWSS to wait for any potentially double buffered
@@ -3534,6 +3587,7 @@ static void wait_for_outstanding_hw_updates(struct dc *dc, const struct dc_state
			}
		}
	}
	wait_for_odm_update_pending_complete(dc, dc_context);
}

static void commit_planes_for_stream(struct dc *dc,
+1 −0
Original line number Diff line number Diff line
@@ -384,6 +384,7 @@ static const struct opp_funcs dcn10_opp_funcs = {
		.opp_set_disp_pattern_generator = NULL,
		.opp_program_dpg_dimensions = NULL,
		.dpg_is_blanked = NULL,
		.dpg_is_pending = NULL,
		.opp_destroy = opp1_destroy
};

+14 −0
Original line number Diff line number Diff line
@@ -337,6 +337,19 @@ bool opp2_dpg_is_blanked(struct output_pixel_processor *opp)
		(double_buffer_pending == 0);
}

bool opp2_dpg_is_pending(struct output_pixel_processor *opp)
{
	struct dcn20_opp *oppn20 = TO_DCN20_OPP(opp);
	uint32_t double_buffer_pending;
	uint32_t dpg_en;

	REG_GET(DPG_CONTROL, DPG_EN, &dpg_en);

	REG_GET(DPG_STATUS, DPG_DOUBLE_BUFFER_PENDING, &double_buffer_pending);

	return (dpg_en == 1 && double_buffer_pending == 1);
}

void opp2_program_left_edge_extra_pixel (
		struct output_pixel_processor *opp,
		bool count)
@@ -363,6 +376,7 @@ static struct opp_funcs dcn20_opp_funcs = {
		.opp_set_disp_pattern_generator = opp2_set_disp_pattern_generator,
		.opp_program_dpg_dimensions = opp2_program_dpg_dimensions,
		.dpg_is_blanked = opp2_dpg_is_blanked,
		.dpg_is_pending = opp2_dpg_is_pending,
		.opp_dpg_set_blank_color = opp2_dpg_set_blank_color,
		.opp_destroy = opp1_destroy,
		.opp_program_left_edge_extra_pixel = opp2_program_left_edge_extra_pixel,
+2 −0
Original line number Diff line number Diff line
@@ -159,6 +159,8 @@ void opp2_program_dpg_dimensions(

bool opp2_dpg_is_blanked(struct output_pixel_processor *opp);

bool opp2_dpg_is_pending(struct output_pixel_processor *opp);

void opp2_dpg_set_blank_color(
		struct output_pixel_processor *opp,
		const struct tg_color *color);
+1 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ static struct opp_funcs dcn201_opp_funcs = {
		.opp_set_disp_pattern_generator = opp2_set_disp_pattern_generator,
		.opp_program_dpg_dimensions = opp2_program_dpg_dimensions,
		.dpg_is_blanked = opp2_dpg_is_blanked,
		.dpg_is_pending = opp2_dpg_is_pending,
		.opp_dpg_set_blank_color = opp2_dpg_set_blank_color,
		.opp_destroy = opp1_destroy,
		.opp_program_left_edge_extra_pixel = opp2_program_left_edge_extra_pixel,
Loading